文章目录
- 一、检测的思想
- 二、代码实现
一、检测的思想
- 在代码中我们将基于dlib库中的方法,调用别人已经训练好的人脸关键点定位模型,实现对人脸关键点的定位,这里我们将调用使用68个关键点来对人脸进行关键点定位的模型。
- 68个关键点定位后的效果如下图:
- 显示出的这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个关键点用于嘴内部的关键点定位
- 人脸关键点定位的实现可以通过以下链接内容了解:
- https://blog.csdn.net/weixin_73504499/article/details/142990867?spm=1001.2014.3001.5501
- 根据每个人脸关键部位的关键点画出各部位的轮廓,效果如下:
二、代码实现
-
眼睛和嘴的绘制方式与其他部位有所不同,嘴和眼睛用凸包的形式画出轮廓
- 凸包:在二维欧几里得空间中,凸包可以想象为一条刚好包着所有点的橡皮圈。换句话说,给定二维平面上的点集,凸包就是将最外层的点连接起来构成的凸多边形,它能包含点集中所有的点。
-
在检测轮廓之前需要对人脸进行检测,以下链接是基于dlib库的人脸检测
- https://blog.csdn.net/weixin_73504499/article/details/142977202?spm=1001.2014.3001.5501
-
眼睛和嘴的绘制函数如下:
def drawConvexHull(start, end):# 将指定的点构成一个凸包,绘制成轮廓,一般眼睛、嘴使用凸包来绘制Facial = shape[start: end + 1] # shape --> 包含了68个关键点坐标mouthHull = cv2.convexHull(Facial) # 凸包函数 --> 返回凸包的顶点# 绘制出轮廓cv2.drawContours(image, [mouthHull], -1, (0, 255, 0), 2)
-
其他部位的绘制函数如下:
def drawLine(start, end): # 将指定的点连接起来pts = shape[start: end] # 获取点集 shape --> 包含了68个关键点坐标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)
-
完整代码如下:
import numpy as np import dlib import cv2""" 绘制眉毛、鼻子、脸颊的轮廓 """ def drawLine(start, end): # 将指定的点连接起来pts = shape[start: end] # 获取点集 shape --> 包含了68个关键点坐标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] # shape --> 包含了68个关键点坐标mouthHull = cv2.convexHull(Facial) # 凸包函数 --> 返回凸包的顶点# 绘制出轮廓cv2.drawContours(image, [mouthHull], -1, (0, 255, 0), 2)image = cv2.imread('kobe_2.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: # 对获取到得到 faces ,逐个遍历shape = predictor(image, face) # 获取68个关键点# 将关键点转换为坐标(x, y)的形式shape = np.array([[p.x, p.y] for p in shape.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("Frame", image) cv2.waitKey() # 关闭窗口 cv2.destroyAllWindows()
-
结果如下:
-
以下是通过打开电脑的摄像头,对画面中出现的人脸进行关键部位的轮廓检测,完整代码如下:
def drawLine(start, end): pts = 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]mouthHull = cv2.convexHull(Facial) cv2.drawContours(image, [mouthHull], -1, (0, 255, 0), 2)cap = cv2.VideoCapture(0) # 0-->打开电脑自带的摄像头, 1-->打开电脑外接的摄像头detector = dlib.get_frontal_face_detector() # 构造脸部位置检测器# 获取人脸关键点定位模型 predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")if not cap.isOpened(): # 判断摄像头是否正常打开print("Cannot open camera")exit()while True: # 若正常打开摄像头则对摄像头拍摄的每一帧画面进行循环处理ret, image = cap.read() # 如果正确读取一帧图像,ret为True, image-->读取的画面image = cv2.flip(image, 1) # 图片翻转,水平翻转(镜像)# 如果没有正确读取到图像,则退出循环if not ret:print("不能读取摄像头")breakfaces = detector(image, 0) # 检测人脸方框位置for face in faces: # 对获取到得到 faces ,逐个遍历shape = predictor(image, face) # 获取关键点# 将关键点转换为坐标(x, y)的形式shape = np.array([[p.x, p.y] for p in shape.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("Frame", image)# 检查是否按下ESC键(ASCII码27),如果按下则退出循环if cv2.waitKey(10) == 27:break# 释放摄像头资源 cap.release() # 关闭所有OpenCV创建的窗口 cv2.destroyAllWindows()