Mediapipe人脸关键点检测

Mediapipe介绍

MediaPipe是由google制作的开源的、跨平台的机器学习框架,可以将一些模型部署到不同的平台和设备上使用的同时,也能保住检测速度。

mediapipe功能
从图中可以发现,能在Python上实现的功能包括人脸检测(Face Detection)、人脸关键点(Face Mesh),手部关键点(Hands)等。利用C++能实现更丰富的功能,我们可以后续探索。

环境部署

  1. Python环境:建议3.6版本以上
  2. Python主要模块:opencv-contrib-python;numpy; pandas; matplotlib
  3. MediaPipe模块:mediapipe

安装方法:使用以下pip命令安装

pip install mediapipe

测试环境:导入如下库,如果不报错说明导入成功

import cv2
import mediapipe as mp
import pandas as pd 
import numpy as np 
import matplotlib.pyplot as plt

人脸关键点检测

模型调用与配置

# 调用关键点检测模型
mp_face_mesh = mp.solutions.face_mesh
face_mesh = mp_face_mesh.FaceMesh(static_image_mode=True,  
                                  max_num_faces=3,         
                                  refine_landmarks=True,  
                                  min_detection_confidence=0.5, 
                                  min_tracking_confidence=0.5) 

FaceMesh参数说明

  • static_image_mode=True, 检测静态图片设置为False,检测视频设置为True,默认为False
  • max_num_faces=3, 能检测的最大人脸数,默认为1
  • refine_landmarks=True, 定位嘴唇、眼睛、瞳孔的关键点,设置为True,否则设置为False
  • min_detection_confidence=0.5, 人脸检测的置信度
  • min_tracking_confidence=0.5) 人脸追踪的置信度(检测图像时可以忽略)

输出结果解析

# 读取图像
img1 = cv2.imread("./images/img1.jpg")
# 将BGR图像转为RGB图像
_img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2RGB)
# 使用模型获取关键点
results = face_mesh.process(_img1)
  • 利用opencv读取图像的颜色通道为BGR,需要利用cv2.cvtColor方法将颜色通道转换为RGB
  • 使用FaceMesh模型的process方法检测图像中的关键点
# 输出关键点
landmarks = results.multi_face_landmarks
print(landmarks)
# 提取关键点坐标
print(landmarks[0].landmark)

landmarks中以类似列表的结构(可迭代对象)存储了关键点,结构中每个“landmark”关键字段存储了关键点的坐标,包含x,y,z,xy分别通过图像宽度和高度归一化为[0.0,1.0].z表示关键点深度,以头部中心的深度为原点,该值越小,关键点距离相机越近.

# 获取每个人脸的关键点的数量
print(len(landmarks[0].landmark))

当模型配置refine_landmarks=True,获得478个人脸关键点;当模型配置refine_landmarks=False,获得468个人脸关键点,缺少瞳孔的关键点。
关键点位置可以查看该图像:https://github.com/google/mediapipe/blob/master/mediapipe/modules/face_geometry/data/canonical_face_model_uv_visualization.png

绘制面网

利用mediapipe提供的绘制模块直接绘制

# mediapipe提供的绘制模块
mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
# 利用mp_drawing绘制面网
annotated_image = img1.copy()
# 循环获取每一个人脸的关键点
for face_landmarks in results.multi_face_landmarks:
    mp_drawing.draw_landmarks(image=annotated_image, landmark_list=face_landmarks,
                              # 选取关键点
                              connections=mp_face_mesh.FACEMESH_TESSELATION,
                              # 绘制关键点,若为None,表示不绘制关键点,也可以指定点的颜色、粗细、半径
                              landmark_drawing_spec=mp_drawing.DrawingSpec(color=(0,0,255),thickness=2,circle_radius=2),
                              # 绘制连接线的格式
                              connection_drawing_spec=mp_drawing_styles.get_default_face_mesh_tesselation_style())
    
# # 利用opencv显示图像,在jupyter中显示效果一般
# cv2.imshow("image",annotated_image)
# if cv2.waitKey(0) == ord("q"):
#     cv2.destroyAllWindows()

# 利用matplotlib展示
plt.figure(figsize=(50, 20))
plt.imshow(annotated_image[:, :, ::-1])

下图中关键点包括瞳孔关键点
面网使用mp_face_mesh.FACEMESH_TESSELATION可以选取所需关键点位置,将这些点进行连接,绘制面网。 使用 mp_drawing_styles.get_default_face_mesh_tesselation_style()可以设置连接线的格式
使用mp_face_mesh.FACEMESH_CONTOURS可以选取轮廓点,将其连接成线,使用mp_drawing_styles.get_default_face_mesh_contours_style()可以设置连接线的格式

视频演示

调用摄像头画面进行人脸关键点检测

import time
# 获取摄像头,0/1为摄像头编号
cap = cv2.VideoCapture(0)
# 循环读取视频每一帧
while True:
    success,frame = cap.read()
    if success:
        start = time.time()
        results = face_mesh.process(cv2.cvtColor(frame, cv2.COLOR_BGR2RGB))
        # 复制图像
        annotated_image = frame.copy()
        # 解封此行代码,可以将关键点绘制在黑色图像上,该代码能生成一张黑色图像
        # annotated_image = np.zeros(annotated_image.shape, dtype='uint8')
        # 如果检测到关键点
        if results.multi_face_landmarks:
            for face_landmarks in results.multi_face_landmarks:
                # 利用mp_drawing绘制图像
                mp_drawing.draw_landmarks(image=annotated_image, landmark_list=face_landmarks,
                                          connections=mp_face_mesh.FACEMESH_TESSELATION,
                                          landmark_drawing_spec=None,
                                          connection_drawing_spec=mp_drawing_styles.get_default_face_mesh_tesselation_style())

                mp_drawing.draw_landmarks(image=annotated_image, landmark_list=face_landmarks,
                                          connections=mp_face_mesh.FACEMESH_IRISES,
                                          landmark_drawing_spec=None,
                                          connection_drawing_spec=mp_drawing_styles.get_default_face_mesh_iris_connections_style())

                mp_drawing.draw_landmarks(image=annotated_image, landmark_list=face_landmarks,
                                          connections=mp_face_mesh.FACEMESH_CONTOURS,
                                          landmark_drawing_spec=None,
                                          connection_drawing_spec=mp_drawing_styles.get_default_face_mesh_contours_style())
            end = time.time()
            fps = 1/(end-start)
        
            annotated_image = cv2.putText(annotated_image,str(int(fps)),(30,50),cv2.FONT_HERSHEY_SIMPLEX,2,(0,0,255),1)
        # 如果没有检测到关键点,在黑色背景上显示“NO FACE TO DETECT”
        else:
            annotated_image = np.zeros(annotated_image.shape, dtype='uint8')
            annotated_image = cv2.putText(annotated_image,str("NO FACE TO DETECT"),(300,400),cv2.FONT_HERSHEY_SIMPLEX,2,(0,0,255),1)
        
        cv2.imshow("image",annotated_image)
        if cv2.waitKey(30) == ord("q"):
            cv2.destroyAllWindows()
            break
# 释放摄像头
cap.release()

np.zeros(shape,dtype)可以创建一个给定维度(shape)的全零数组

  • shape:创建的新数组的(维度),如(4,7,3),表示创建一个三维数组,第一个维度有4个元素,第二个维度有7个元素,第三个维度有3个元素.annotated_image.shape可以获取图像的维度(height,width,channel)
  • dtype:创建新数组的数据类型,当dtype =unit8时为图像数据类型,其取值范围在0~255.

检测效果

面部关键点检测

可通过下方链接下载程序
源程序下载

猜你喜欢

转载自blog.csdn.net/weixin_40062244/article/details/128283144