dlib 人脸关键点可视化进阶指南:线条与凸包绘制 + 实战案例
人脸识别领域中,人脸关键点检测 是非常核心的环节。它能精确定位五官位置,为表情识别、人脸对齐、AR 特效、医疗分析提供坚实基础。
前面我们学习了如何用 dlib 标出 68 个点位,本篇文章更进一步,带你用 线条和凸包 描绘面部轮廓,让可视化效果更加直观、清晰。
一、为什么要画线和凸包?
画点虽然能标出特征位置,但信息密度不高,很难一眼看出面部轮廓形状。
通过把点用线段连起来,并用凸包闭合嘴巴、眼睛,我们能得到更加形象的面部结构,如同简化版的"线稿人脸"。
这样做有几个好处:
-
直观:能快速看出关键点是否检测准确。
-
调试方便:用于验证模型质量,检查是否漏点或错位。
-
后续处理:方便做 ROI 提取(如嘴巴区域、眼睛区域),便于后续图像处理。
二、dlib 关键点模型与区域编号
dlib 的 shape_predictor_68_face_landmarks.dat
模型输出 68 个点,每个点都有固定编号,常用的分区如下:
区域 | 编号范围 | 点数 |
---|---|---|
脸部轮廓 | 0--16 | 17 |
左眉 | 17--21 | 5 |
右眉 | 22--26 | 5 |
鼻梁鼻翼 | 27--35 | 9 |
右眼 | 36--41 | 6 |
左眼 | 42--47 | 6 |
嘴外轮廓 | 48--59 | 12 |
嘴内轮廓 | 60--67 | 8 |
这样我们就能指定任意区域,单独画出来。
三、核心代码与逐行解析
import numpy as np
import dlib
import cv2
# =============== 工具函数 ===============
def drawLine(start, end):
"""
按顺序连接指定范围的点,画成折线。
适合画脸部轮廓、眉毛、鼻梁。
"""
pts = np.array(shape[start:end])
for l in range(1, len(pts)):
ptA = tuple(pts[l - 1])
ptB = tuple(pts[l])
cv2.line(image, ptA, ptB, (0, 255, 0), 2)
def drawConvexHull(start, end):
"""
将指定范围的点包成凸多边形,适合画眼睛、嘴巴这种闭合区域。
"""
Facial = shape[start:end+1]
hull = cv2.convexHull(Facial)
cv2.drawContours(image, [hull], -1, (0, 255, 0), 2)
# =============== 主程序 ===============
image = cv2.imread("face3.jpg")
detector = dlib.get_frontal_face_detector()
faces = detector(image, 0)
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
for face in faces:
shape = predictor(image, face)
shape = np.matrix([[p.x, p.y] for p in shape.parts()])
# 1. 画凸包区域
drawConvexHull(36, 41) # 右眼
drawConvexHull(42, 47) # 左眼
drawConvexHull(48, 59) # 嘴外
drawConvexHull(60, 67) # 嘴内
# 2. 画折线区域
drawLine(0, 17) # 脸部轮廓
drawLine(17, 22) # 左眉
drawLine(22, 27) # 右眉
drawLine(27, 36) # 鼻子
cv2.imshow("Frame", image)
cv2.waitKey()
cv2.destroyAllWindows()
运行后,你会看到完整的人脸轮廓、眉毛、鼻梁、嘴唇、眼睛都被绿色线条描出来。
四、知识点详解
1️⃣ 凸包(Convex Hull)
凸包是计算几何中的基本概念,它是包含一组点的最小凸多边形。
OpenCV 的 cv2.convexHull()
可以直接生成封闭轮廓,非常适合画嘴巴、眼睛这种闭合区域。
2️⃣ 折线绘制
cv2.line()
用于画线段。我们把连续点按顺序两两连接,就能画出面部轮廓。
3️⃣ 颜色与粗细
-
(0, 255, 0)
是绿色,可以换成蓝色(255, 0, 0)
或红色(0, 0, 255)
区分不同区域。 -
粗细参数可以调整,比如嘴巴画粗一些,轮廓画细一些。
五、效果展示与对比
可视化方式 | 效果 |
---|---|
画点 | 离散点,信息量低,难以直观看出五官形状 |
画线 | 轮廓清晰,眉毛、鼻梁等结构可见 |
凸包 | 封闭区域,适合眼睛、嘴巴,效果更直观 |
建议:结合三种方式一起用,既能看到关键点编号,又能看到轮廓。
六、进阶玩法
1️⃣ 给不同区域加不同颜色
cv2.polylines(image, [shape[0:17]], False, (0,255,0), 2) # 脸部绿色
cv2.polylines(image, [shape[17:22]], False, (255,0,0), 2) # 左眉蓝色
cv2.polylines(image, [shape[22:27]], False, (255,0,0), 2) # 右眉蓝色
2️⃣ 实时摄像头关键点轮廓
cap = cv2.VideoCapture(0)
while True:
ret, frame = cap.read()
faces = detector(frame, 0)
for face in faces:
shape = predictor(frame, face)
shape = np.matrix([[p.x, p.y] for p in shape.parts()])
drawConvexHull(48, 59) # 实时画嘴巴
cv2.imshow("Live", frame)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
3️⃣ 表情分析
-
嘴巴开合程度:用嘴巴上边点和下边点的距离衡量张嘴幅度。
-
眉毛抬起:眉毛和眼睛距离增加,可判断惊讶表情。
-
眼睛闭合:上下眼皮点的距离接近 0,可检测眨眼。
4️⃣ 融合面部特效
你可以用这些轮廓区域做遮罩,比如把嘴巴区域涂成红色,模拟口红效果;把眼睛画成猫眼,做 AR 滤镜。
七、性能与精度优化
-
检测速度
-
用
detector(image, 0)
检测大脸,速度快。 -
用
detector(image, 1)
适合远处人脸,精度更高但更慢。
-
-
小模型加速
如果只需要对齐功能,可以换
shape_predictor_5_face_landmarks.dat
,仅预测眼睛和鼻尖,速度显著提升。 -
多线程处理
在视频流处理场景,可以多线程并行,提高 FPS。
八、应用场景
-
美颜相机:用凸包圈出嘴唇、眼睛区域,再做磨皮、美白、虚拟口红。
-
疲劳驾驶监测:根据眼睛闭合程度判断困倦。
-
AR 滤镜:把眼镜、胡子、帽子贴合到人脸上,实时跟随。
-
医疗辅助:分析面部对称性,用于术前设计或康复跟踪。
九、总结
通过 drawLine()
和 drawConvexHull()
,我们能把离散的 68 个点变成有结构的人脸轮廓,帮助调试、分析、可视化,甚至直接用于人脸表情识别和特效叠加。
练习建议:
给不同五官区域设置不同颜色,做一张"彩色人脸线稿"。
用嘴巴开合距离做一个"张嘴检测",尝试控制屏幕上的动画。
改造成实时版本,看轮廓跟随头部运动的效果,测试稳定性。