进阶:基于 dlib 的 68 点人脸关键点检测实现
在上一篇文章中,我们介绍了如何使用 dlib 和 OpenCV 进行基础的人脸检测。本文将在此基础上,进一步讲解如何检测人脸的 68 个关键点,这些关键点涵盖了眼睛、眉毛、鼻子、嘴巴和下颌等面部特征,是实现表情分析、人脸对齐、美颜特效等高级功能的基础。
一、人脸关键点检测原理
dlib 的 68 点人脸关键点检测基于以下技术组合:
- 先进行人脸检测:使用上一篇介绍的 HOG 检测器定位人脸区域
- 关键点预测模型:通过预训练的
shape_predictor
模型,在检测到的人脸区域内预测 68 个特征点坐标 - 特征点分布:68 个点按面部区域分组:
- 0-16:下颌线
- 17-21:左眉毛
- 22-26:右眉毛
- 27-30:鼻子桥
- 31-35:鼻尖
- 36-41:左眼
- 42-47:右眼
- 48-67:嘴巴
这种结构化的特征点分布,使得我们可以精确分析面部各个器官的位置和形态。
二、准备工作:获取关键点预测模型
与基础人脸检测不同,关键点检测需要额外的模型文件:
- 下载模型:从dlib 官方模型库下载
shape_predictor_68_face_landmarks.dat.bz2
主页会提供文件
- 解压文件:使用解压工具提取出
shape_predictor_68_face_landmarks.dat
- 放置位置:将模型文件放在与代码相同的目录下,或在代码中使用绝对路径引用
提示:如果下载速度慢,可以搜索国内镜像站点或通过 CSDN 等平台获取该模型文件
三、完整代码实现与解析
1. 完整代码
import cv2
import dlib
import numpy as np # 新增:用于处理关键点坐标# 1. 读取图像
img = cv2.imread("zjl2.png")
if img is None:print("Error: 无法读取图像,请检查路径是否正确!")exit()# 2. 初始化人脸检测器
detector = dlib.get_frontal_face_detector()# 3. 检测人脸
faces = detector(img, 0) # 0表示不上采样# 4. 加载关键点预测模型
# 注意:确保模型文件路径正确
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")# 5. 遍历每个人脸,检测并绘制关键点
for face in faces:# 5.1 预测当前人脸的关键点shape = predictor(img, face) # 输入:图像和人脸框# 5.2 将关键点转换为numpy数组(便于后续处理)# shape.parts()返回所有关键点对象,每个对象有x和y属性landmarks = np.array([[p.x, p.y] for p in shape.parts()])# 5.3 绘制每个关键点for idx, point in enumerate(landmarks):# 获取当前关键点坐标pos = (point[0], point[1])# 绘制实心圆标记关键点cv2.circle(img, pos, radius=2, color=(0, 255, 0), thickness=-1)# 标记关键点索引(便于理解各点对应的面部位置)cv2.putText(img, str(idx), pos, cv2.FONT_HERSHEY_SIMPLEX, fontScale=0.4, # 字体大小color=(255, 255, 255), # 白色文字thickness=1, lineType=cv2.LINE_AA) # 抗锯齿线条# 6. 显示结果
cv2.imshow("68 Face Landmarks", img)
cv2.waitKey(0) # 等待按键输入
cv2.destroyAllWindows() # 释放窗口资源
运行后的图像
2. 关键代码解析
(1)模型加载
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")
这行代码是关键点检测的核心,shape_predictor
类会加载预训练模型。如果运行时出现 "无法找到模型文件" 的错误,请检查:
- 模型文件名是否正确(注意不要遗漏
.dat
后缀) - 模型文件是否与代码在同一目录,或路径是否设置正确
(2)关键点预测
shape = predictor(img, face)
predictor
对象的调用需要两个参数:
- 原始图像(
img
) - 已检测到的人脸框(
face
)
返回的shape
对象包含了 68 个关键点的信息,通过shape.parts()
可以获取所有关键点的列表。
(3)坐标转换与绘制
landmarks = np.array([[p.x, p.y] for p in shape.parts()])
将 dlib 的关键点对象转换为 NumPy 数组,便于后续的坐标访问和处理。每个关键点的坐标存储形式为[x, y]
。
绘制部分使用了两个 OpenCV 函数:
cv2.circle()
:绘制实心圆标记关键点位置cv2.putText()
:标记每个关键点的索引(0-67),帮助我们理解各点对应的面部区域
四、运行结果与常见问题
1. 预期效果
运行代码后,会显示一张标记了 68 个绿色关键点的图像,每个点都有对应的索引编号。通过这些编号,你可以清晰看到:
- 0-16 号点勾勒出下颌轮廓
- 36-47 号点分别标记左右眼的轮廓
- 48-67 号点标记了嘴巴的形状
2. 常见问题解决
问题描述 | 可能原因 | 解决方案 |
---|---|---|
报错 "Can't open shape_predictor_68_face_landmarks.dat" | 模型文件路径错误或文件不存在 | 1. 检查文件路径是否正确;2. 确认文件已正确解压;3. 使用绝对路径如"C:/models/shape_predictor_68_face_landmarks.dat" |
部分人脸没有检测到关键点 | 人脸检测失败或人脸质量差 | 1. 调整上采样参数(如detector(img, 1) );2. 使用更清晰的正面人脸图像 |
关键点标记混乱 | 图像分辨率过低或人脸倾斜严重 | 1. 使用高清图像;2. 尽量使用正面、姿态端正的人脸图像 |