使用 MediaPipe 检测面部五官

人工智能 人脸识别
本文将重点介绍如何使用 MediaPipe 检测和跟踪特定的面部特征,包括鼻子、嘴巴、眼睛和虹膜。

面部识别和检测已成为许多现代应用中不可或缺的组成部分,包括用于设备解锁和社交媒体应用中实时效果的添加。然而,准确高效地检测面部特征,包括鼻子、嘴巴、眼睛甚至虹膜,可能是一个挑战性的过程。幸运的是,由Google开发的开源框架MediaPipe提供了一个解决方案,它提供了强大的预训练机器学习模型,允许开发者以高精度跟踪和分析面部标志点。

MediaPipe为计算机视觉任务提供了一套全面的预构建解决方案,包括手部跟踪、姿态估计和面部标志点检测。轻量级设计确保了实时性能,使其成为集成到移动和基于网络的应用中的最佳选择。

本文将重点介绍如何使用MediaPipe检测和跟踪特定的面部特征,包括鼻子、嘴巴、眼睛和虹膜。通过本指南的结束,读者不仅将全面了解MediaPipe的功能,而且还能够在自己的项目中实现面部特征检测。这将有助于探索如何轻松利用MediaPipe的强大功能检测这些关键的面部特征。

开始使用

步骤1:安装必要的库

pip install opencv-python mediapip
# 避坑:记得先使用 pip install msvc-runtime 命令安装msvc-runtime, 不然会报错
# ImportError: DLL load failed while importing _framework_bindings: 动态链接库(DLL)初始化例程失败。

步骤2:导入库

# coding: utf-8
import mediapipe as mp
import cv2
import os

步骤3:初始化 FaceMesh 模型并定义面部特征标志点

class FaceMeshDetector:
    def __init__(self, static_image_mode=False, max_num_faces=1, refine_landmarks=False, min_detection_con=0.5,
                 min_tracking_con=0.5):
        # 初始化面部网格检测的参数
        self.static_image_mode = static_image_mode  # 是否处理图像(True)或视频流(False)
        self.max_num_faces = max_num_faces  # 要检测的最大面孔数
        self.refine_landmarks = refine_landmarks  # 是否为了更好的精度细化虹膜标志点
        self.min_detection_con = min_detection_con  # 面部检测的最小置信度
        self.min_tracking_con = min_tracking_con  # 跟踪的最小置信度

        # 初始化Mediapipe面部网格解决方案
        self.mpFaceMesh = mp.solutions.face_mesh
        self.faceMesh = self.mpFaceMesh.FaceMesh(self.static_image_mode,
                                                 self.max_num_faces,
                                                 self.refine_landmarks,
                                                 self.min_detection_con,
                                                 self.min_tracking_con)

        # 存储特定面部特征的标志点索引
        # 这些是Mediapipe为左右眼、虹膜、鼻子和嘴巴预定义的索引

        self.LEFT_EYE_LANDMARKS = [463, 398, 384, 385, 386, 387, 388, 466, 263, 249, 390, 373, 374,
                                   380, 381, 382, 362]  # 左眼标志点

        self.RIGHT_EYE_LANDMARKS = [33, 246, 161, 160, 159, 158, 157, 173, 133, 155, 154, 153, 145,
                                    144, 163, 7]  # 右眼标志点

        self.LEFT_IRIS_LANDMARKS = [474, 475, 477, 476]  # 左虹膜标志点
        self.RIGHT_IRIS_LANDMARKS = [469, 470, 471, 472]  # 右虹膜标志点

        self.NOSE_LANDMARKS = [193, 168, 417, 122, 351, 196, 419, 3, 248, 236, 456, 198, 420, 131, 360, 49, 279, 48,
                               278, 219, 439, 59, 289, 218, 438, 237, 457, 44, 19, 274]  # 鼻子标志点

        self.MOUTH_LANDMARKS = [0, 267, 269, 270, 409, 306, 375, 321, 405, 314, 17, 84, 181, 91, 146, 61, 185, 40, 39,
                                37]  # 嘴巴标志点

代码定义了一个类,指定为FaceMeshDetector,它使用MediaPipe开发的FaceMesh解决方案来检测面部标志点。这次检测的重点是特定区域,即眼睛、虹膜、鼻子和嘴巴。识别出的标志点从图像中提取出来,并以像素坐标的形式返回。

__init__方法

__init__方法的目的是初始化检测器,这是通过配置MediaPipe的FaceMesh解决方案并存储眼睛、虹膜、鼻子和嘴巴的特定标志点索引来实现的。

步骤4:处理图像以检测面部标志点,提取我们想要的面部特征的坐标

def findMeshInFace(self, img): # 初始化一个字典来存储面部特征的标志点 landmarks = {}

  def findMeshInFace(self, img):
      # 初始化一个字典来存储面部特征的标志点
      landmarks = {}

      # 将输入图像转换为RGB,因为Mediapipe需要RGB图像
      imgRGB = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

      # 处理图像以使用FaceMesh模型找到面部标志点
      results = self.faceMesh.process(imgRGB)

      # 检查是否检测到任何面孔
      if results.multi_face_landmarks:
          # 遍历检测到的面孔(这里,max_num_faces = 1,所以通常只有一个面孔)
          for faceLms in results.multi_face_landmarks:
              # 在标志点字典中初始化列表以存储每个面部特征的坐标
              landmarks["left_eye_landmarks"] = []
              landmarks["right_eye_landmarks"] = []
              landmarks["left_iris_landmarks"] = []
              landmarks["right_iris_landmarks"] = []
              landmarks["nose_landmarks"] = []
              landmarks["mouth_landmarks"] = []
              landmarks["all_landmarks"] = []  # 存储所有面部标志点以完成面部网格

              # 遍历所有面部标志点
              for i, lm in enumerate(faceLms.landmark):
                  h, w, ic = img.shape  # 获取图像高度、宽度和通道数
                  x, y = int(lm.x * w), int(lm.y * h)  # 将归一化坐标转换为像素值

                  # 存储所有标志点的坐标
                  landmarks["all_landmarks"].append((x, y))

                  # 根据预定义的索引存储特定特征的标志点
                  if i in self.LEFT_EYE_LANDMARKS:
                      landmarks["left_eye_landmarks"].append((x, y))  # 左眼
                  if i in self.RIGHT_EYE_LANDMARKS:
                      landmarks["right_eye_landmarks"].append((x, y))  # 右眼
                  if i in self.LEFT_IRIS_LANDMARKS:
                      landmarks["left_iris_landmarks"].append((x, y))  # 左虹膜
                  if i in self.RIGHT_IRIS_LANDMARKS:
                      landmarks["right_iris_landmarks"].append((x, y))  # 右虹膜
                  if i in self.NOSE_LANDMARKS:
                      landmarks["nose_landmarks"].append((x, y))  # 鼻子
                  if i in self.MOUTH_LANDMARKS:
                      landmarks["mouth_landmarks"].append((x, y))  # 嘴巴

      # 返回处理后的图像和特征标志点的字典
      return img, landmarks

findMeshInFace方法

这个方法处理输入图像,检测面部标志点,并返回带有面部特征坐标的图像。

步骤5:为图像定义主函数

使用细化虹膜标志点的FaceMeshDetector以获得更好的精度

# 使用细化虹膜标志点的FaceMeshDetector以获得更好的精度
detector = FaceMeshDetector(refine_landmarks=True)

# 定义我们感兴趣的面部特征(眼睛、鼻子、嘴巴、虹膜和所有标志点)
face_parts = ["left_eye_landmarks", "right_eye_landmarks", "nose_landmarks",
              "mouth_landmarks", "all_landmarks", "left_iris_landmarks",
              "right_iris_landmarks"]

for item in range(len(face_parts)):
    # 从指定的文件路径读取图像
    image = cv2.imread(r"D:\test.jpg")  # 将<YourImagePath>替换为实际的图像路径
    save_path = r'D:'

    # 使用FaceMeshDetector在当前帧中找到面部标志点
    image, landmarks = detector.findMeshInFace(image)

    # 尝试绘制指定面部部分(本例中为鼻子)的标志点
    try:
        for landmark in landmarks[face_parts[item]]:
            # 在每个标志点坐标处绘制一个小绿圈
            cv2.circle(image, (landmark[0], landmark[1]), 3, (0, 255, 0), -1)  # 圆圈参数:中心,半径,颜色,厚度
    except KeyError:
        # 如果未找到指定部分的标志点,则跳过绘制
        pass

    # 在帧上显示正在检测的面部特征的名称(例如,“nose_landmarks”)
    cv2.putText(image, f"{face_parts[item]}", (20, 70), cv2.FONT_HERSHEY_PLAIN, 5, (0, 255, 0), 5)
    # cv2.putText参数:图像,文本,位置,字体,字体大小,颜色,厚度

    # 在标题为“Image”的窗口中显示带有检测到的标志点的修改后的帧
    # cv2.imshow("Image", image)
    # 保存图像
    cv2.imwrite(os.path.join(save_path, face_parts[item] + '.jpg'), image)
    # 等待按键以关闭显示的图像窗口
    cv2.waitKey(0)

以下表示上述图像的每个面部特征的结果。

步骤6:为视频定义主函数

# 使用细化的虹膜标志点初始化FaceMeshDetector以提高精度
detector = FaceMeshDetector(refine_landmarks=True)

# 定义我们感兴趣的面部特征(眼睛、鼻子、嘴巴、虹膜和所有标志点)
face_parts = ["left_eye_landmarks", "right_eye_landmarks", "nose_landmarks",
              "mouth_landmarks", "all_landmarks", "left_iris_landmarks",
              "right_iris_landmarks"]

# 指定要检测的面部特征(索引2在这里指的是鼻子标志点)
face_part = 2

# 从文件"woman_face.mp4"捕获视频
cap = cv2.VideoCapture("<YourVideoPath>") # 使用0表示网络摄像头

# 开始一个循环,逐帧处理视频
while True:
    # 从视频捕获中读取下一帧
    success, image = cap.read()

    # 使用FaceMeshDetector在当前帧中找到面部标志点
    image, landmarks = detector.findMeshInFace(image)

    # 如果读取帧不成功(例如,视频结束),则跳出循环
    if not success:
        break

    # 尝试绘制指定面部部分(本例中为鼻子)的标志点
    try:
        for landmark in landmarks[face_parts[face_part]]:
            # 在每个标志点坐标处绘制一个小绿圈
            cv2.circle(image, (landmark[0], landmark[1]), 3, (0, 255, 0), -1)
    except KeyError:
        # 如果未找到指定部分的标志点,则跳过绘制
        pass

    # 在帧上显示正在检测的面部特征的名称(例如,“nose_landmarks”)
    cv2.putText(image, f"{face_parts[face_part]}", (20, 70), cv2.FONT_HERSHEY_PLAIN, 5, (0, 255, 0), 5)

    # 在标题为“Image”的窗口中显示带有检测到的标志点的修改后的帧
    cv2.imshow("Image", image)

    # 等待按键1毫秒,并检查用户是否按下了'q'键以退出
    key = cv2.waitKey(1)
    if key & 0xFF == ord('q'):
        break
责任编辑:赵宁宁 来源: 小白玩转Python
相关推荐

2012-12-18 09:16:21

IBM计算机感官

2018-05-11 14:10:17

Python人脸识别

2023-12-06 13:56:24

智能数据

2020-01-03 08:00:00

面部识别人工智能AI

2021-06-23 09:25:57

鸿蒙HarmonyOS应用

2018-11-28 14:53:44

物联网网关物联网IOT

2021-11-05 11:01:47

人工智能元宇宙面部识别

2017-09-04 20:06:32

深度学习检测人脸追踪

2021-06-18 11:58:08

人工智能AI面部识别

2021-12-15 16:54:05

区块链面部识别技术

2022-09-21 07:57:56

面部识别身份认证。Web

2022-08-03 10:43:42

安全风险影子IT

2024-09-14 09:31:25

2014-12-16 10:28:49

2019-05-24 10:30:38

2021-12-13 16:16:42

Java开发工具

2012-04-05 12:16:15

HTC

2020-03-13 08:18:09

面部识别生物识别人工智能

2022-01-04 08:00:00

面部识别安全技术

2022-11-25 14:46:48

首席数据官技术简历
点赞
收藏

51CTO技术栈公众号