dlib人脸68关键点检测与轮廓绘制实战

张开发
2026/4/13 16:25:03 15 分钟阅读

分享文章

dlib人脸68关键点检测与轮廓绘制实战
dlib 人脸 68 关键点检测与轮廓绘制实战本文以两段完整的 Python 代码为主线逐步拆解 dlibshape_predictor_68模型的调用方式并重点对比两种轮廓绘制策略顺序连线drawLine与凸包轮廓drawConvexHull。读者可直接复制代码运行。一、技术背景人脸关键点Landmark检测是人脸分析的核心基础其下游任务包括应用依赖的关键点人脸对齐Face Alignment眼角、鼻尖、嘴角 5 点表情识别眉毛、嘴唇区域变化量活体检测眼睛/嘴唇开合幅度3D 人脸重建全 68 点三维坐标拟合AR 特效贴图实时轮廓区域定位dlib 提供的shape_predictor_68_face_landmarks模型基于级联回归树Cascade Regression Trees在检测到人脸框后迭代回归出 68 个关键点的精确坐标推理速度快、精度高。二、68 点分布总览68 个关键点按照解剖区域划分如下区域索引范围点数下颌轮廓0 – 1617左眉17 – 215右眉22 – 265鼻梁27 – 304鼻底31 – 355左眼36 – 416右眼42 – 476外嘴唇48 – 5912内嘴唇60 – 678点 0在左侧下颌角点 16在右侧下颌角点 27在鼻根索引沿顺时针方向递增。三、完整检测流程整个流程分为六步核心依赖两个 dlib 对象get_frontal_face_detector()— 基于 HOG 线性分类器的人脸检测器返回人脸框列表shape_predictor(.dat)— 级联回归树关键点预测器输入人脸框输出 68 个(x, y)坐标四、代码一关键点检测与标注3关键点检测.py4.1 初始化检测器与预测器importnumpyasnpimportcv2importdlib# HOG人脸检测器内置无需加载文件detectordlib.get_frontal_face_detector()# 68点关键点预测器需要下载 .dat 文件# 下载地址https://github.com/davisking/dlib-modelspredictordlib.shape_predictor(shape_predictor_68_face_landmarks.dat).dat文件说明模型文件约 99MB使用级联回归树存储。首次使用需从 GitHub dlib-models 仓库下载放于脚本同级目录即可。4.2 检测人脸并预测关键点imgcv2.imread(handou2.jpg)# 参数 0上采样次数0不上采样速度最快1上采样一次检测更多小人脸facesdetector(img,0)forfaceinfaces:# predictor 返回 dlib.full_object_detection 对象shapepredictor(img,face)# 将 68 个 dlib.point 对象转为 numpy 数组shape(68, 2)landmarksnp.array([[p.x,p.y]forpinshape.parts()])关键参数解析参数含义推荐值detector(img, n)中的n上采样次数增大可检测远处小人脸但速度成倍下降0 或 1shape.parts()返回 68 个dlib.point对象的列表—4.3 绘制关键点与编号foridx,pointinenumerate(landmarks):pos[point[0],point[1]]# 绘制实心圆绿色半径 2cv2.circle(img,pos,2,(0,255,0),1)# 在圆旁标注索引编号红色抗锯齿字体cv2.putText(img,str(idx),pos,cv2.FONT_HERSHEY_SIMPLEX,0.4,(0,0,255),1,cv2.LINE_AA)cv2.imshow(img,img)cv2.waitKey(0)cv2.destroyAllWindows()cv2.LINE_AA抗锯齿线条相比默认的cv2.LINE_8文字边缘更平滑适合小字号渲染。五、代码二结构化轮廓绘制4轮廓绘制.py5.1 两种绘制方法设计思路代码定义了两个辅助函数分别应对不同区域的轮廓特点5.2drawLine顺序连线适合开放曲线defdrawLine(start,end):ptsshape[start:end]# 切片取对应区域的点集forlinrange(1,len(pts)):ptAtuple(pts[l-1])# 前一个点ptBtuple(pts[l])# 当前点cv2.line(image,ptA,ptB,(0,255,0),2)适用区域开放轮廓有明确起止点drawLine(0,17)# 下颌轮廓左→右弧线drawLine(17,22)# 左眉由内向外drawLine(22,27)# 右眉drawLine(27,36)# 鼻梁 鼻底上→下注意shape[start:end]是 Python 切片不含end位置的点。因此drawLine(0, 17)实际绘制 0~16 共 17 个点之间的 16 段线。5.3drawConvexHull凸包轮廓适合封闭区域defdrawConvexHull(start,end):Facialshape[start:end1]# 含 end1 补偿切片mouthHullcv2.convexHull(Facial)# 计算凸包cv2.drawContours(image,[mouthHull],-1,(0,255,0),2)适用区域封闭轮廓需包裹整体drawConvexHull(36,41)# 左眼6点drawConvexHull(42,47)# 右眼6点drawConvexHull(48,59)# 外嘴唇12点drawConvexHull(60,67)# 内嘴唇8点cv2.convexHull原理给定一组点计算能包裹所有点的最小凸多边形Graham Scan 算法时间复杂度 O(n log n)。眼眶、嘴唇等区域轮廓近似凸形因此效果优良。drawLinevsdrawConvexHull关键区别drawLine(start, end)中切片shape[start:end]不含enddrawConvexHull(start, end)中切片shape[start:end1]含end1 补偿5.4 索引速查表六、两段代码输出效果对比对比项3关键点检测.py4轮廓绘制.py输出内容68 个绿色圆点 红色编号连线 凸包轮廓无编号视觉效果调试友好点位清晰结构干净贴近人脸轮廓适合场景标注验证、模型调试特效贴图、视觉展示信息密度高每点均有索引低只保留结构线七、完整代码整合7.1 代码一关键点检测importnumpyasnpimportcv2importdlib imgcv2.imread(handou2.jpg)detectordlib.get_frontal_face_detector()predictordlib.shape_predictor(shape_predictor_68_face_landmarks.dat)facesdetector(img,0)forfaceinfaces:shapepredictor(img,face)landmarksnp.array([[p.x,p.y]forpinshape.parts()])foridx,pointinenumerate(landmarks):pos[point[0],point[1]]cv2.circle(img,pos,2,(0,255,0),1)cv2.putText(img,str(idx),pos,cv2.FONT_HERSHEY_SIMPLEX,0.4,(0,0,255),1,cv2.LINE_AA)cv2.imshow(img,img)cv2.waitKey(0)cv2.destroyAllWindows()7.2 代码二结构化轮廓绘制importnumpyasnpimportdlibimportcv2 imagecv2.imread(handou2.jpg)detectordlib.get_frontal_face_detector()predictordlib.shape_predictor(shape_predictor_68_face_landmarks.dat)defdrawLine(start,end):ptsshape[start:end]forlinrange(1,len(pts)):cv2.line(image,tuple(pts[l-1]),tuple(pts[l]),(0,255,0),2)defdrawConvexHull(start,end):Facialshape[start:end1]hullcv2.convexHull(Facial)cv2.drawContours(image,[hull],-1,(0,255,0),2)facesdetector(image,1)forfaceinfaces:shapepredictor(image,face)shapenp.array([[p.x,p.y]forpinshape.parts()])# 凸包封闭区域drawConvexHull(36,41)# 左眼drawConvexHull(42,47)# 右眼drawConvexHull(48,59)# 外嘴唇drawConvexHull(60,67)# 内嘴唇# 顺序连线开放区域drawLine(0,17)# 下颌drawLine(17,22)# 左眉drawLine(22,27)# 右眉drawLine(27,36)# 鼻子cv2.imshow(image,image)cv2.waitKey(0)cv2.destroyAllWindows()八、常见问题与注意事项Q1运行报错RuntimeError: Unable to open shape_predictor_68_face_landmarks.dat模型文件缺失从以下地址下载bz2 压缩包解压后约 99MBhttps://github.com/davisking/dlib-models/raw/master/shape_predictor_68_face_landmarks.dat.bz2将.dat文件放到 Python 脚本同级目录。Q2detector(img, 0)和detector(img, 1)有什么区别参数效果速度影响n0原始分辨率检测速度最快基准n1图像放大 2x 后检测可找到更小/更远的人脸约慢 4xn2放大 4x极小人脸也可检测约慢 16x代码一用n0静态图追求速度代码二用n1精度优先确保关键点准确。Q3drawConvexHull中为什么要写end1Python 切片a[start:end]不含end而drawLine利用了这一点终止点不需要绘制。但drawConvexHull需要完整的闭合区域点集如左眼的 6 个点全部参与凸包计算所以要写end1。九、扩展方向方向说明眨眼检测EAR计算眼睛纵横比EAR 阈值时判断为闭眼打哈欠检测MAR计算嘴部开合比MAR 阈值判断张嘴驾驶疲劳监测结合眨眼频率 打哈欠触发告警人脸对齐用眼角坐标做仿射变换将人脸旋转至水平MediaPipe 替代谷歌 MediaPipe 提供 468 点检测精度更高支持实时小结本文完整介绍了 dlibshape_predictor_68模型的调用链路核心要点如下两步检测先用get_frontal_face_detector()找人脸框再用shape_predictor精细化到 68 个点坐标转换np.array([[p.x, p.y] for p in shape.parts()])是固定范式转为 numpy 数组便于后续处理开放曲线用drawLine下颌、眉毛、鼻子封闭区域用drawConvexHull眼睛、嘴唇切片陷阱drawLine用[start:end]drawConvexHull用[start:end1]务必区分掌握 68 点检测后即可在此基础上快速实现疲劳检测、表情分析、AR 特效等更复杂的人脸应用。ector()找人脸框再用shape_predictor精细化到 68 个点 2. **坐标转换**np.array([[p.x, p.y] for p in shape.parts()])是固定范式转为 numpy 数组便于后续处理 3. **开放曲线用drawLine**下颌、眉毛、鼻子**封闭区域用drawConvexHull**眼睛、嘴唇 4. **切片陷阱**drawLine用[start:end]drawConvexHull用[start:end1]务必区分掌握 68 点检测后即可在此基础上快速实现疲劳检测、表情分析、AR 特效等更复杂的人脸应用。

更多文章