0. 前言
人脸处理是人工智能中的一个热门话题,人脸处理可以使用计算机视觉算法从人脸中自动提取大量信息,例如身份、意图和情感。在计算机视觉中,面部关键点(也称为面部特征点)的定位通常是许多面部分析方法和算法中的关键步骤。例如,面部表情识别、头部姿态估计和疲倦检测系统都依赖于面部特征点检测提供的面部信息。在本文中,我们将使用OpenCV、dlib以及face_recognition检测面部特征点。
1. 面部特征点简介
面部特征点检测算法的目标是自动识别图像或视频中面部特征点的位置。更具体地说,这些关键点是描述面部组件位置(例如,嘴角或眼角)的主要点,或者是连接面部组件和面部轮廓主要点及其插值点。形式上,给定表示为I的面部图像,特征点检测算法检测D个特征点的位置,其中x和y表示图像的面部特征点的坐标。
2. 使用 OpenCV 检测面部特征点
OpenCV人脸特征点API称为Facemark。它包括特征点检测的三种不同实现:
- FacemarkLBF
- FacemarkKamezi
- FacemarkAAM
以下示例展示了如何使用这些算法来检测面部标志:
import cv2
import numpy as np
# 加载图片
image = cv2.imread("example",0)
# 检测人脸
cas = cv2.CascadeClassifier("haarcascade_frontalface_alt2.xml")
faces = cas.detectMultiScale(image , 1.5, 5)
print("faces", faces)
# 创建特征点检测器并对其进行测试
print("testing LBF")
# 第一种面部特征点检测方法,第一行代码
# 创建特征点检测器
facemark = cv2.face.createFacemarkLBF()
# 第一种面部特征点检测方法,第二行代码
# 加载检测器模型
facemark.loadModel("lbfmodel.yaml")
# 第一种面部特征点检测方法,第三行代码
# 检测面部特征点
ok, landmarks = facemark.fit(image , faces)
print ("landmarks LBF", ok, landmarks)
# 测试其他特征点检测算法
print("testing AAM")
facemark = cv2.face.createFacemarkAAM()
facemark .loadModel("aam.xml")
ok, landmarks = facemark.fit(image , faces)
print ("landmarks AAM", ok, landmarks)
print("testing Kazemi")
facemark = cv2.face.createFacemarkKazemi()
facemark .loadModel("face_landmark_model.dat")
ok, landmarks = facemark.fit(image , faces)
print ("landmarks Kazemi", ok, landmarks)
上述示例使用OpenCV提供的三种不同算法来检测面部特征点。
3. 用 dlib 检测面部特征点
我们也可以使用dlib库来检测面部特征点,接下来,我们加载测试图像,然后使用dlib执行人脸检测,最后使用人脸特征检测器获取检测面部特征点。想要运行以下代码,首先需要下载检测面部特征点检测器文件shape_predictor_68_face_landmarks.dat。
# 加载图像并转换为灰度图像
test_face = cv2.imread("example.png")
gray = cv2.cvtColor(test_face, cv2.COLOR_BGR2GRAY)
# 人脸检测
detector = dlib.get_frontal_face_detector()
rects = detector(gray, 0)
# 检测面部特征点
p = "shape_predictor_68_face_landmarks.dat"
# 第二种面部特征点检测方法,第一行代码
predictor = dlib.shape_predictor(p)
# 第二种面部特征点检测方法,第二行代码
shape = predictor(gray, rect)
shape是一个dlib full_object_detection对象,用于表示图像中对象的位置,接下来需要将其转换为numpy数组,编写shape_to_np()函数执行此转换:
def shape_to_np(dlib_shape, dtype="int"):
# 初始化 (x, y) 坐标列表
coordinates = np.zeros((dlib_shape.num_parts, 2), dtype=dtype)
# 循环所有面部特征点,并将其转换为 (x, y) 坐标的元组
for i in range(0, dlib_shape.num_parts):
coordinates[i] = (dlib_shape.part(i).x, dlib_shape.part(i).y)
# 返回 (x,y) 坐标的列表
return coordinates
最后,在图像中绘制了 68 个面部特征点。我们可以使用灵活的方式以所需的格式在图像中绘制特征点,接下来,介绍集中常用的绘制检测到的面部特征点的不同方法:
(1)使用线条绘制面部特征点形状,以连接绘制脸部的不同部分的轮廓(例如鼻子、眼睛等):
# 定义不同特征点取值切片
JAWLINE_POINTS = list(range(0, 17))
RIGHT_EYEBROW_POINTS = list(range(17, 22))
LEFT_EYEBROW_POINTS = list(range(22, 27))
NOSE_BRIDGE_POINTS = list(range(27, 31))
LOWER_NOSE_POINTS = list(range(31, 36))
RIGHT_EYE_POINTS = list(range(36, 42))
LEFT_EYE_POINTS = list(range(42, 48))
MOUTH_OUTLINE_POINTS = list(range(48, 61))
MOUTH_INNER_POINTS = list(range(61, 68))
ALL_POINTS = list(range(0, 68))
# 使用线条绘制面部特征点
def draw_shape_lines_all(np_shape, image):
draw_shape_lines_range(np_shape, image, JAWLINE_POINTS)
draw_shape_lines_range(np_shape, image, RIGHT_EYEBROW_POINTS)
draw_shape_lines_range(np_shape, image, LEFT_EYEBROW_POINTS)
draw_shape_lines_range(np_shape, image, NOSE_BRIDGE_POINTS)
draw_shape_lines_range(np_shape, image, LOWER_NOSE_POINTS)
draw_shape_lines_range(np_shape, image, RIGHT_EYE_POINTS, True)
draw_shape_lines_range(np_shape, image, LEFT_EYE_POINTS, True)
draw_shape_lines_range(np_shape, image, MOUTH_OUTLINE_POINTS, True)
draw_shape_lines_range(np_shape, image, MOUTH_INNER_POINTS, True)
# 连接不同的点来绘制曲线形状
def draw_shape_lines_range(np_shape, image, range_points, is_closed=False):
np_shape_display = np_shape[range_points]
points = np.array(np_shape_display, dtype=np.int32)
cv2.polylines(image, [points], is_closed, (255, 255, 0), thickness=2, lineType=cv2.LINE_8)
# 函数调用
draw_shape_lines_all(shape, test_face)
cv2.imshow("Landmarks detection using dlib", test_face)
cv2.waitKey(0)
(2)调用draw_shape_lines_range()函数,可以仅绘制指定面部组件轮廓线,例如下颚线JAWLINE_POINTS:
draw_shape_lines_range(shape, test_face, JAWLINE_POINTS)
(3)绘制所有特征点及其位序:
# 绘制指定的特征点
def draw_shape_points_pos_range(np_shape, image, points):
np_shape_display = np_shape[points]
draw_shape_points_pos(np_shape_display, image)
# 使用每个特征点及其位序绘制形状
def draw_shape_points_pos(np_shape, image):
for idx, (x, y) in enumerate(np_shape):
# 绘制每个检测到的特征点的位序
cv2.putText(image, str(idx + 1), (x, y), cv2.FONT_HERSHEY_SIMPLEX, 0.4, (0, 0, 255))
# 在每个特征点位置上绘制一个点
cv2.circle(image, (x, y), 2, (0, 255, 0), -1)
# 可以用两种方法来绘制检测到的所有特征点及其位序
# 方法1
draw_shape_points_pos(shape, test_face)
# 方法2
draw_shape_points_pos_range(shape, test_face, ALL_POINTS)
(4)我们也可以仅绘制所有特征点:
# 绘制指定特征点
def draw_shape_points_range(np_shape, image, points):
np_shape_display = np_shape[points]
draw_shape_points(np_shape_display, image)
# 绘制所有特征点
def draw_shape_points(np_shape, image):
for (x, y) in np_shape:
cv2.circle(image, (x, y), 2, (0, 255, 0), -1)
# 可以用两种方法绘制所有特征点
# 方法1
draw_shape_points(shape, test_face)
# 方法2
draw_shape_points_range(shape, test_face, ALL_POINTS)
(5)利用上述函数,我们可以仅绘制指定特征点,例如仅绘制眼部和鼻子特征点:
draw_shape_points_pos_range(shape, test_face, LEFT_EYE_POINTS + RIGHT_EYE_POINTS + NOSE_BRIDGE_POINTS)
dlib还提供了检测与双眼和鼻尖位置相对应的 5 个面部特征点检测器,如果想要使用此检测器,需要首先下载shape_predictor_5_face_landmarks.dat,然后加载它:
p = "shape_predictor_5_face_landmarks.dat"
4. 使用 face_recognition 检测面部特征点
如果想要使用face_recognition包检测和绘制面部特征点,需要调用face_recognition.face_landmarks()函数:
# 加载图像
image = cv2.imread("example.png")
image_68 = image.copy()
# 将图像从 BGR 颜色转换为 RGB 颜色
rgb = image[:, :, ::-1]
# 检测 68 个特征点
# 第三种面部特征点检测方法,第一行代码
face_landmarks_list_68 = face_recognition.face_landmarks(rgb)
此函数返回图像中每个人脸的面部特征(例如眼睛和鼻子)字典,如果打印检测到的特征,可以看到如下输出:
[{'chin': [(113, 251), (111, 283), (115, 315), (122, 346), (136, 376), (154, 402), (177, 425), (203, 442), (231, 447), (260, 442), (285, 426), (306, 403), (323, 377), (334, 347), (340, 315), (343, 282), (343, 251)], 'left_eyebrow': [(123, 223), (140, 211), (163, 208), (185, 211), (206, 220)], 'right_eyebrow': [(240, 221), (263, 212), (288, 209), (312, 211), (332, 223)], 'nose_bridge': [(225, 249), (225, 272), (225, 295), (226, 319)], 'nose_tip': [(201, 337), (213, 340), (226, 343), (239, 339), (252, 336)], 'left_eye': [(144, 248), (158, 239), (175, 240), (188, 254), (173, 255), (156, 254)], 'right_eye': [(262, 254), (276, 240), (293, 239), (308, 248), (295, 254), (278, 255)], 'top_lip': [(185, 377), (200, 370), (216, 364), (226, 367), (238, 364), (255, 370), (274, 377), (267, 378), (238, 378), (227, 380), (215, 379), (192, 378)], 'bottom_lip': [(274, 377), (257, 391), (240, 399), (228, 400), (215, 398), (200, 391), (185, 377), (192, 378), (215, 381), (227, 382), (239, 380), (267, 378)]}]
最后绘制检测到的特征点:
for face_landmarks in face_landmarks_list_68:
for facial_feature in face_landmarks.keys():
for p in face_landmarks[facial_feature]:
cv2.circle(image_68, p, 2, (255, 255, 0), -1)
face_recognition.face_landmarks()函数的用法如下:
face_landmarks(face_image, face_locations=None, model="large")
默认情况下会检测到 68 个特征点,如果model=”small”,只会检测 5 个特征点:
# 检测 5 个特征点
face_landmarks_list_5 = face_recognition.face_landmarks(rgb, None, "small")
如果打印返回的结果 face_landmarks_list_5,可以得到以下输出:
[{'nose_tip': [(227, 343)], 'left_eye': [(145, 248), (191, 253)], 'right_eye': [(307, 248), (262, 252)]}]
在这种情况下,生成的字典仅包含眼睛和鼻尖的面部标志位置。
接下来,绘制检测到的特征点:
for face_landmarks in face_landmarks_list_5:
for facial_feature in face_landmarks.keys():
for p in face_landmarks[facial_feature]:
cv2.circle(image_68, p, 2, (255, 255, 0), -1)
在图中,可以看到使用face_recognition包检测到的 68 个和 5 个面部特征点。
概括
在本文中,介绍了如何使用OpenCV的Facemark API、
dlib的shape_predictor()函数以及face_recognition的face_landmarks()函数进行面部特征点检测。
系列链接
OpenCV-Python实战(1)——OpenCV简介与图像处理基础
OpenCV-Python实战(2)——图像与视频文件的处理
OpenCV-Python实战(3)——OpenCV中绘制图形与文本
OpenCV-Python实战(4)——OpenCV常见图像处理技术
OpenCV-Python实战(5)——OpenCV图像运算
OpenCV-Python实战(6)——OpenCV中的色彩空间和色彩映射
OpenCV-Python实战(7)——直方图详解
OpenCV-Python实战(8)——直方图均衡化
OpenCV-Python实战(9)——OpenCV用于图像分割的阈值技术
OpenCV-Python实战(10)——OpenCV轮廓检测
OpenCV-Python实战(11)——OpenCV轮廓检测相关应用
OpenCV-Python实战(12)——一文详解AR增强现实
OpenCV-Python实战(13)——OpenCV与机器学习的碰撞
OpenCV-Python实战(14)——人脸检测详解
版权声明:本文为博主盼小辉丶原创文章,版权归属原作者,如果侵权,请联系我们删除!
原文链接:https://blog.csdn.net/LOVEmy134611/article/details/121094208