新手入门MediaPipe系列:手势识别+姿态检测+脸部关键点检测

目录

一、MediaPipe手势识别(基于手部关键点的延伸)

[1.1 核心功能概述](#1.1 核心功能概述)

[1.2 完整实战代码](#1.2 完整实战代码)

[1.3 代码逐模块详细解析](#1.3 代码逐模块详细解析)

[1.3.1 基础模块(复用+简单补充)](#1.3.1 基础模块(复用+简单补充))

[1.3.2 视频采集与预处理(完全复用,简要说明)](#1.3.2 视频采集与预处理(完全复用,简要说明))

[1.3.3 核心:手势判断逻辑(新增重点)](#1.3.3 核心:手势判断逻辑(新增重点))

[1.3.4 手势显示与程序退出(新增显示逻辑)](#1.3.4 手势显示与程序退出(新增显示逻辑))

二、MediaPipe人体姿态检测(全身关键点定位)

[2.1 核心功能概述](#2.1 核心功能概述)

[2.2 完整实战代码](#2.2 完整实战代码)

[2.3 代码逐模块详细解析](#2.3 代码逐模块详细解析)

[2.3.1 库导入与姿态检测器初始化(核心新增)](#2.3.1 库导入与姿态检测器初始化(核心新增))

[2.3.2 静态图片读取与预处理](#2.3.2 静态图片读取与预处理)

[2.3.3 关键点坐标输出与可视化](#2.3.3 关键点坐标输出与可视化)

[2.3.4 3D姿态可视化(新增亮点)](#2.3.4 3D姿态可视化(新增亮点))

[2.3.5 程序退出与资源释放](#2.3.5 程序退出与资源释放)

2.4功能拓展思路

[三、MediaPipe脸部关键点检测(Face Mesh)](#三、MediaPipe脸部关键点检测(Face Mesh))

[3.1 核心功能概述](#3.1 核心功能概述)

[3.2 完整实战代码](#3.2 完整实战代码)

[3.3 代码逐模块详细解析](#3.3 代码逐模块详细解析)

[3.3.1 库导入与脸部网格初始化(核心新增)](#3.3.1 库导入与脸部网格初始化(核心新增))

[3.3.2 摄像头采集与视频预处理](#3.3.2 摄像头采集与视频预处理)

[3.3.3 核心:关键点标注与脸部网格绘制](#3.3.3 核心:关键点标注与脸部网格绘制)


在上一篇博客中,我们已经掌握了MediaPipe+OpenCV实现实时手部关键点检测的核心方法,了解了MediaPipe轻量化、高精度的优势,以及OpenCV与MediaPipe配合的关键要点。本节课我们将基于手部检测的基础,拓展学习MediaPipe的另外三个核心视觉检测功能------手势识别、人体姿态检测、脸部关键点检测,继续用实战代码拆解逻辑,帮大家快速上手MediaPipe的更多应用场景,夯实计算机视觉入门基础。

本文将保持和上一篇一致的结构,每一个功能都包含「核心功能概述→完整实战代码→逐模块详细解析→运行前置条件→新手避坑要点→功能拓展」,确保新手能跟着代码一步步操作,既能跑通效果,也能理解背后的逻辑,避免"复制粘贴式学习"。

一、MediaPipe手势识别(基于手部关键点的延伸)

手势识别是手部关键点检测的核心延伸应用,我们在上一篇手部关键点检测的基础上,通过计算关键点之间的距离,判断手指的伸直状态,进而实现0-10的手势计数(none~ten),可直接用于简单的数字交互、手势控制等场景。

1.1 核心功能概述

本次手势识别代码基于MediaPipe手部检测模块,实现以下核心功能:

  • 调用电脑默认摄像头,采集实时视频流,实时检测画面中最多2只手的关键点;

  • 通过计算特定关键点之间的距离,判断每根手指的伸直状态,用flag计数统计伸直的手指数量;

  • 在视频画面上实时显示识别到的手势(none/one/two/.../ten),同时绘制手部关键点及骨骼连接;

  • 支持ESC键退出识别,自动释放摄像头资源,兼容上一篇的基础配置,降低学习成本。

1.2 完整实战代码

python 复制代码
import cv2
import mediapipe as mp
gesture = ["none", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"]
flag = 0

mp_drawing = mp.solutions.drawing_utils
mp_hands = mp.solutions.hands

hands = mp_hands.Hands(
    static_image_mode=False,
    max_num_hands=2,
    min_detection_confidence=0.75,
    min_tracking_confidence=0.75)

cap = cv2.VideoCapture(0)
while True:
    flag = 0
    ret, frame = cap.read()
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    # 因为摄像头是镜像的,所以将摄像头水平翻转
    # 不是镜像的可以不翻转
    frame = cv2.flip(frame, 1)
    results = hands.process(frame)
    frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)

    #    if results.multi_handedness:
    #        for hand_label in results.multi_handedness:
    #            print(hand_label)

    if results.multi_hand_landmarks:
        for hand_landmarks in results.multi_hand_landmarks:
            # print('hand_landmarks:', hand_landmarks)
            # 计算关键点的距离,用于判断手指是否伸直
            p0_x = hand_landmarks.landmark[0].x
            p0_y = hand_landmarks.landmark[0].y
            p5_x = hand_landmarks.landmark[5].x
            p5_y = hand_landmarks.landmark[5].y
            distance_0_5 = pow(p0_x - p5_x, 2) + pow(p0_y - p5_y, 2)
            base = distance_0_5 / 0.6

            p4_x = hand_landmarks.landmark[4].x
            p4_y = hand_landmarks.landmark[4].y
            distance_5_4 = pow(p5_x - p4_x, 2) + pow(p5_y - p4_y, 2)

            p8_x = hand_landmarks.landmark[8].x
            p8_y = hand_landmarks.landmark[8].y
            distance_0_8 = pow(p0_x - p8_x, 2) + pow(p0_y - p8_y, 2)

            p12_x = hand_landmarks.landmark[12].x
            p12_y = hand_landmarks.landmark[12].y
            distance_0_12 = pow(p0_x - p12_x, 2) + pow(p0_y - p12_y, 2)

            p16_x = hand_landmarks.landmark[16].x
            p16_y = hand_landmarks.landmark[16].y
            distance_0_16 = pow(p0_x - p16_x, 2) + pow(p0_y - p16_y, 2)

            p20_x = hand_landmarks.landmark[20].x
            p20_y = hand_landmarks.landmark[20].y
            distance_0_20 = pow(p0_x - p20_x, 2) + pow(p0_y - p20_y, 2)

            if distance_0_8 > base:
                flag += 1
            if distance_0_12 > base:
                flag += 1
            if distance_0_16 > base:
                flag += 1
            if distance_0_20 > base:
                flag += 1
            if distance_5_4 > base * 0.3:
                flag += 1
            if flag >= 10:
                flag = 10
            # 关键点可视化
            mp_drawing.draw_landmarks(frame,
                                      hand_landmarks,
                                      mp_hands.HAND_CONNECTIONS)

    cv2.putText(frame, gesture[flag], (50, 50), 0, 1.3, (0, 0, 255), 3)
    cv2.imshow('MediaPipe Hands', frame)
    if cv2.waitKey(1) & 0xFF == 27:
        break
cap.release()
cv2.destroyAllWindows()

效果展示:

1.3 代码逐模块详细解析

手势识别代码基于上一篇的手部关键点检测,大部分基础模块(库导入、手部检测器初始化、视频采集)完全复用,重点新增了「手势判断逻辑」,我们重点解析新增部分,复用部分简要带过,避免冗余。

1.3.1 基础模块(复用+简单补充)

python 复制代码
import cv2
import mediapipe as mp
gesture = ["none", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine", "ten"]
flag = 0

mp_drawing = mp.solutions.drawing_utils
mp_hands = mp.solutions.hands

hands = mp_hands.Hands(
    static_image_mode=False,
    max_num_hands=2,
    min_detection_confidence=0.75,
    min_tracking_confidence=0.75)

cap = cv2.VideoCapture(0)

新增核心变量解析(重点):

  • gesture = [...]:手势列表,索引0对应"无手势(none)",索引1对应"1根手指(one)",依次到索引10对应"10根手指(ten)"(实际最多5根手指,设到10是为了避免flag溢出,后续会做限制)。

  • flag = 0:手势计数标志,用于统计伸直的手指数量,初始值为0(默认无手势),每检测到一根伸直的手指,flag加1,最终通过flag索引gesture列表,得到识别结果。

其余模块(mp_drawing、mp_hands初始化、摄像头调用)与上一篇手部检测完全一致,参数含义可参考上一篇,此处不再重复解析,重点关注后续的手势判断逻辑。

1.3.2 视频采集与预处理(完全复用,简要说明)

python 复制代码
while True:
    flag = 0  # 每次循环重置flag,避免上一帧的计数影响当前帧
    ret, frame = cap.read()
    frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)  # BGR转RGB,适配MediaPipe
    frame = cv2.flip(frame, 1)  # 水平翻转,解决摄像头镜像问题
    results = hands.process(frame)  # 手部关键点检测
    frame = cv2.cvtColor(frame, cv2.COLOR_RGB2BGR)  # RGB转BGR,适配OpenCV显示

重点注意:flag = 0 必须放在while循环内部(每帧重置),否则会导致flag持续累加(比如上一帧检测到2根手指,下一帧未检测到手,flag仍为2),造成手势识别错误。

1.3.3 核心:手势判断逻辑(新增重点)

手势判断的核心原理:通过计算「手指指尖关键点」与「手腕/指根关键点」之间的距离,判断手指是否伸直------距离大于设定的阈值,视为手指伸直,flag加1;距离小于阈值,视为手指弯曲,不计数。

python 复制代码
if results.multi_hand_landmarks:
    for hand_landmarks in results.multi_hand_landmarks:
        # 1. 计算基准距离(手腕0号关键点与食指根5号关键点的距离)
        p0_x = hand_landmarks.landmark[0].x
        p0_y = hand_landmarks.landmark[0].y
        p5_x = hand_landmarks.landmark[5].x
        p5_y = hand_landmarks.landmark[5].y
        distance_0_5 = pow(p0_x - p5_x, 2) + pow(p0_y - p5_y, 2)
        base = distance_0_5 / 0.6  # 基准阈值,用于判断手指是否伸直

        # 2. 计算各手指关键点距离(指尖与手腕/指根)
        # 拇指:指根5号与指尖4号的距离
        p4_x = hand_landmarks.landmark[4].x
        p4_y = hand_landmarks.landmark[4].y
        distance_5_4 = pow(p5_x - p4_x, 2) + pow(p5_y - p4_y, 2)

        # 食指:手腕0号与指尖8号的距离
        p8_x = hand_landmarks.landmark[8].x
        p8_y = hand_landmarks.landmark[8].y
        distance_0_8 = pow(p0_x - p8_x, 2) + pow(p0_y - p8_y, 2)

        # 中指:手腕0号与指尖12号的距离
        p12_x = hand_landmarks.landmark[12].x
        p12_y = hand_landmarks.landmark[12].y
        distance_0_12 = pow(p0_x - p12_x, 2) + pow(p0_y - p12_y, 2)

        # 无名指:手腕0号与指尖16号的距离
        p16_x = hand_landmarks.landmark[16].x
        p16_y = hand_landmarks.landmark[16].y
        distance_0_16 = pow(p0_x - p16_x, 2) + pow(p0_y - p16_y, 2)

        # 小指:手腕0号与指尖20号的距离
        p20_x = hand_landmarks.landmark[20].x
        p20_y = hand_landmarks.landmark[20].y
        distance_0_20 = pow(p0_x - p20_x, 2) + pow(p0_y - p20_y, 2)

        # 3. 根据距离阈值,判断手指是否伸直,累加flag
        if distance_0_8 > base:  # 食指伸直
            flag += 1
        if distance_0_12 > base:  # 中指伸直
            flag += 1
        if distance_0_16 > base:  # 无名指伸直
            flag += 1
        if distance_0_20 > base:  # 小指伸直
            flag += 1
        if distance_5_4 > base * 0.3:  # 拇指伸直(阈值稍小,适配拇指结构)
            flag += 1
        if flag >= 10:  # 限制最大flag为10(避免索引越界)
            flag = 10

        # 4. 手部关键点可视化(与上一篇一致)
        mp_drawing.draw_landmarks(frame,
                                  hand_landmarks,
                                  mp_hands.HAND_CONNECTIONS)

逐点解析(新手必看):

  • 基准距离计算:选取「手腕0号关键点」和「食指根5号关键点」的欧氏距离(此处用平方和替代,避免开方运算,提升速度),除以0.6得到base基准阈值。基准阈值的作用是:适配不同距离的手势(比如手靠近摄像头时,关键点距离变大,base也会变大;手远离时,base变小),避免因距离变化导致识别错误。

  • 各手指距离计算

    • 拇指:特殊处理,计算「指根5号」与「指尖4号」的距离(因为拇指与手腕的距离过近,无法准确判断);

    • 食指、中指、无名指、小指:统一计算「手腕0号」与「各自指尖(8、12、16、20号)」的距离,逻辑更简单,识别更稳定。

  • 手指伸直判断

    • 食指~小指:距离大于base,视为伸直;

    • 拇指:距离大于base×0.3,视为伸直(拇指结构特殊,伸直时与指根的距离比其他手指小,所以阈值适当缩小);

    • flag累加后限制为10,因为gesture列表最大索引为10,避免flag溢出导致程序报错。

1.3.4 手势显示与程序退出(新增显示逻辑)

python 复制代码
cv2.putText(frame, gesture[flag], (50, 50), 0, 1.3, (0, 0, 255), 3)
cv2.imshow('MediaPipe Hands', frame)
if cv2.waitKey(1) & 0xFF == 27:
    break
cap.release()
cv2.destroyAllWindows()

新增部分:cv2.putText(...),在视频画面的(50,50)位置,用红色(0,0,255)、字号1.3、线条粗细3的字体,显示当前识别到的手势(gesture[flag]),让识别结果直观可见。其余退出逻辑、资源释放与上一篇完全一致。

二、MediaPipe人体姿态检测(全身关键点定位)

人体姿态检测是MediaPipe另一核心功能,可实时检测人体33个关键点(涵盖头部、躯干、四肢),用于动作识别、健身计数、姿态矫正等场景。与手部检测、手势识别不同,姿态检测支持静态图片和动态视频两种模式,本次代码以静态图片检测为例,后续可轻松拓展为实时视频检测。

2.1 核心功能概述

  • 读取本地静态图片(img.png),检测图片中人体的33个关键点;

  • 打印每个关键点的三维坐标(x、y归一化坐标,z深度坐标),统计关键点总数;

  • 在原图上绘制人体关键点及骨骼连接线条,生成带关键点标注的图片;

  • 生成人体姿态的3D可视化图表,直观查看关键点的空间位置关系;

  • 支持按键退出,自动释放窗口资源,代码结构清晰,新手易上手。

2.2 完整实战代码

python 复制代码
import cv2
import mediapipe as mp

if __name__ == '__main__':
    '''
    mp_pose.Pose()其参数:
    1)static_image_mode:静态图像还是连续帧视频;
    2)model_complexity:人体姿态估计模型,0表示速度最快,精度最低(三者之中),1表示速度中间,精度中间(三者之中),2表示速度最慢,精度最高(三者之中);
    3)smooth_landmarks:是否平滑关键点;
    4)enable_segmentation:是否对人体进行抠图;
    5)min_detection_confidence:检测置信度阈值;
    6)min_tracking_confidence:各帧之间跟踪置信度阈值;
    '''
    mp_pose = mp.solutions.pose
    pose = mp_pose.Pose(static_image_mode=True,
                        model_complexity=1,
                        smooth_landmarks=True,
                        # enable_segmentation=True,
                        min_detection_confidence=0.5,
                        min_tracking_confidence=0.5)
    drawing = mp.solutions.drawing_utils

    # read img BGR to RGB
    img = cv2.imread("img.png")
    cv2.imshow("input", img)
    img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
    results = pose.process(img)
    img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)
    print(len(results.pose_landmarks.landmark))
    for i in range(len(results.pose_landmarks.landmark)):
        x=results.pose_landmarks.landmark[i].x
        y=results.pose_landmarks.landmark[i].y
        z=results.pose_landmarks.landmark[i].z
        print(x,y,z)
    drawing.draw_landmarks(img, results.pose_landmarks, mp_pose.POSE_CONNECTIONS)
    cv2.imshow("keypoint", img)

    drawing.plot_landmarks(results.pose_world_landmarks, mp_pose.POSE_CONNECTIONS)

    cv2.waitKey(0)
    cv2.destroyAllWindows()

效果展示:

2.3 代码逐模块详细解析

姿态检测使用MediaPipe的mp_pose模块,与手部检测模块(mp_hands)逻辑相似,但参数和关键点更多,重点解析姿态检测专属的模块和参数,基础模块(库导入、颜色转换)简要带过。

2.3.1 库导入与姿态检测器初始化(核心新增)

python 复制代码
import cv2
import mediapipe as mp

if __name__ == '__main__':
    mp_pose = mp.solutions.pose  # 导入姿态检测核心模块
    pose = mp_pose.Pose(static_image_mode=True,
                        model_complexity=1,
                        smooth_landmarks=True,
                        # enable_segmentation=True,
                        min_detection_confidence=0.5,
                        min_tracking_confidence=0.5)
    drawing = mp.solutions.drawing_utils  # 绘图工具,与手部检测一致

核心解析:

  • mp_pose = mp.solutions.pose:MediaPipe姿态检测核心模块,内置33个人体关键点检测模型,支持静态图片和动态视频两种模式,模型采用BlazePose架构,兼顾精度和速度。

  • pose = mp_pose.Pose(...):初始化姿态检测器,6个核心参数(新手重点关注前4个),详细说明如下:

    • static_image_mode:检测模式,True为静态图片模式(本次使用),False为动态视频模式。静态模式下,每帧都重新检测关键点;动态模式下,会跟踪已检测到的人体,提升帧率。

    • model_complexity:模型复杂度(0/1/2),权衡速度和精度:

      • 0:速度最快,精度最低,适合低性能设备(如树莓派);

      • 1:速度和精度均衡(默认),适合普通电脑;

      • 2:速度最慢,精度最高,适合对精度要求高的场景(如专业动作识别)。

    • smooth_landmarks:是否平滑关键点,True表示平滑(减少关键点抖动,提升稳定性),False表示不平滑(适合静态图片,影响不大)。

    • enable_segmentation:是否对人体进行抠图(分离人体和背景),True表示启用抠图,会生成人体掩码,可用于背景替换等场景;本次注释掉,暂不启用。

    • min_detection_confidence:最小检测置信度(0.0~1.0),与手部检测一致,值越大,检测越精准,越难检测到人体。

    • min_tracking_confidence:最小追踪置信度(0.0~1.0),仅动态模式(static_image_mode=False)生效,值越大,追踪越稳定。

  • drawing = mp.solutions.drawing_utils:绘图工具,用于绘制人体关键点和骨骼连接,与手部检测、手势识别完全一致,无需修改。

2.3.2 静态图片读取与预处理

python 复制代码
# 读取本地图片,OpenCV默认BGR格式
img = cv2.imread("img.png")
cv2.imshow("input", img)  # 显示原始图片
# 颜色空间转换:BGR→RGB,适配MediaPipe
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
# 执行姿态检测
results = pose.process(img)
# 颜色空间转换:RGB→BGR,适配OpenCV显示
img = cv2.cvtColor(img, cv2.COLOR_RGB2BGR)

新手必注意:

  • cv2.imread("img.png"):读取本地图片,需确保"img.png"文件与代码文件在同一文件夹下,否则需填写完整路径(如"D:/images/img.png"),否则会读取失败,后续代码报错。

  • 颜色空间转换(BGR↔RGB)是必做步骤,与手部检测、手势识别一致,遗漏会导致检测结果错误或画面颜色失真。

2.3.3 关键点坐标输出与可视化

python 复制代码
# 打印关键点总数(固定33个)
print(len(results.pose_landmarks.landmark))
# 遍历33个关键点,打印每个关键点的三维坐标
for i in range(len(results.pose_landmarks.landmark)):
    x=results.pose_landmarks.landmark[i].x
    y=results.pose_landmarks.landmark[i].y
    z=results.pose_landmarks.landmark[i].z
    print(x,y,z)
# 绘制关键点和骨骼连接(核心)
drawing.draw_landmarks(img, results.pose_landmarks, mp_pose.POSE_CONNECTIONS)
# 显示带关键点标注的图片
cv2.imshow("keypoint", img)

核心解析:

  • results.pose_landmarks:存储检测到的人体关键点信息,是一个列表,包含33个关键点(固定数量),每个关键点有x、y、z三个坐标(x、y为归一化坐标,z为深度坐标)。

  • mp_pose.POSE_CONNECTIONS:MediaPipe内置的人体骨骼连接规则,定义了33个关键点之间的连接关系(如头部→颈部、颈部→肩部、肩部→肘部等),无需手动定义,绘图工具会自动连接。

  • 关键点坐标含义:与手部检测一致,x、y取值0~1(相对于图片宽高),z以人体骨盆为原点,值越小,关键点越靠近摄像头;若需将x、y转换为像素坐标,需乘以图片宽高(如int(x*w)、int(y*h))。

2.3.4 3D姿态可视化(新增亮点)

python 复制代码
drawing.plot_landmarks(results.pose_world_landmarks, mp_pose.POSE_CONNECTIONS)

这是姿态检测的亮点功能:results.pose_world_landmarks 存储的是关键点的3D世界坐标(而非归一化坐标),drawing.plot_landmarks 会生成一个3D可视化窗口,展示人体姿态的空间位置关系,可拖动窗口旋转查看,直观理解关键点的三维分布(适合新手学习人体关键点的位置)。

2.3.5 程序退出与资源释放

python 复制代码
cv2.waitKey(0)  # 等待按键输入(任意按键退出)
cv2.destroyAllWindows()  # 关闭所有窗口,释放资源

与手部检测不同:cv2.waitKey(0) 表示"等待任意按键输入后退出"(适合静态图片查看),而动态视频检测用cv2.waitKey(1)(每帧停留1毫秒)。

2.4功能拓展思路

  • 拓展为实时视频姿态检测:将静态图片读取(cv2.imread)改为摄像头采集(cv2.VideoCapture(0)),外层添加while循环,修改为动态模式(static_image_mode=False),实现实时姿态检测;

  • 动作识别:通过判断关键点的位置关系,识别简单动作(如站立、蹲下、举手、弯腰),比如"蹲下"时,膝盖关键点(25、26号)与髋关节关键点(23、24号)的距离变小;

  • 健身计数:比如计数深蹲、俯卧撑次数,通过检测人体姿态的变化(如深蹲时膝盖弯曲幅度),触发计数逻辑;

  • 人体抠图与背景替换:启用enable_segmentation=True,获取人体掩码,结合OpenCV的.bitwise_and函数,实现背景替换(如将背景换成纯色、图片);

  • 多人体检测:MediaPipe姿态检测支持多人体同时检测,无需修改参数,直接读取包含多个人体的图片/视频即可。

三、MediaPipe脸部关键点检测(Face Mesh)

MediaPipe的Face Mesh(脸部网格)功能,可实时检测脸部478个关键点,涵盖额头、眼睛、鼻子、嘴巴、脸颊、下巴等所有脸部区域,精度极高,可用于人脸表情识别、虚拟化妆、人脸特效等场景。本次代码实现实时视频脸部关键点检测,标注关键点序号,绘制脸部网格,贴合新手实战需求。

3.1 核心功能概述

  • 调用电脑默认摄像头,采集实时视频流,实时检测画面中最多2张人脸;

  • 检测每张人脸的478个关键点,打印关键点总数,可选打印每个关键点的三维坐标;

  • 在视频画面上标注每个关键点的序号(0~477),绘制脸部网格(FACEMESH_TESSELATION),直观呈现关键点分布;

  • 使用MediaPipe内置的网格绘制风格,让脸部网格更清晰、美观;

  • 支持ESC键退出检测,自动释放摄像头资源,兼容前三个功能的基础逻辑。

3.2 完整实战代码

python 复制代码
import cv2
import mediapipe as mp
# 初始化 Mediapipe 模块
mp_face_mesh = mp.solutions.face_mesh
mp_drawing = mp.solutions.drawing_utils
mp_drawing_styles = mp.solutions.drawing_styles
# 设置 Face Mesh 参数
face_mesh = mp_face_mesh.FaceMesh(
   static_image_mode=False,
   max_num_faces=2,
   refine_landmarks=True,
   min_detection_confidence=0.5,
   min_tracking_confidence=0.5
)
# 打开摄像头
cap = cv2.VideoCapture(0)
while cap.isOpened():
   success, frame = cap.read()
   h, w = frame.shape[:2]
   if not success:
       print("无法读取摄像头画面")
       break
   # 转换颜色空间
   frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
   results = face_mesh.process(frame_rgb)
   # 绘制关键点
   if results.multi_face_landmarks:
       for face_landmarks in results.multi_face_landmarks:
           print(len(face_landmarks.landmark))    # 478
           for i in range(len(face_landmarks.landmark)):
               x = face_landmarks.landmark[i].x
               y = face_landmarks.landmark[i].y
               # z = face_landmarks.landmark[i].z
               # print(x,y,z)
               cv2.putText(frame, str(i), (int(x * w), int(y * h)), cv2.FONT_HERSHEY_SIMPLEX, 0.3, (0, 255, 0), 2)
           mp_drawing.draw_landmarks(
               image=frame,
               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()
           )
   # 显示结果
   cv2.imshow('Face Mesh', frame)
   if cv2.waitKey(1)==27:
       break
cap.release()
cv2.destroyAllWindows()

3.3 代码逐模块详细解析

脸部关键点检测使用MediaPipe的mp_face_mesh模块,新增了专属的绘图风格模块(mp_drawing_styles),关键点数量(478个)远多于手部和姿态检测,重点解析专属模块、参数和绘制逻辑,基础模块简要带过。

3.3.1 库导入与脸部网格初始化(核心新增)

python 复制代码
import cv2
import mediapipe as mp
# 初始化 Mediapipe 模块(脸部网格专属)
mp_face_mesh = mp.solutions.face_mesh
mp_drawing = mp.solutions.drawing_utils  # 绘图工具(复用)
mp_drawing_styles = mp.solutions.drawing_styles  # 脸部绘图风格(新增)
# 设置 Face Mesh 参数,初始化脸部检测器
face_mesh = mp_face_mesh.FaceMesh(
   static_image_mode=False,
   max_num_faces=2,
   refine_landmarks=True,
   min_detection_confidence=0.5,
   min_tracking_confidence=0.5
)

核心解析(新手重点关注):

  • mp_face_mesh = mp.solutions.face_mesh:MediaPipe脸部网格核心模块,内置478个人脸关键点检测模型,采用Face Mesh架构,能高精度定位脸部所有区域的关键点,支持实时检测。

  • mp_drawing_styles = mp.solutions.drawing_styles:脸部绘图风格专属模块,内置多种预设的绘图风格(如网格风格、轮廓风格),无需手动设置线条颜色、粗细,让绘制效果更美观。

  • face_mesh = mp_face_mesh.FaceMesh(...):初始化脸部检测器,5个核心参数,详细说明如下:

    • static_image_mode:检测模式,False为动态视频模式(本次使用),True为静态图片模式,逻辑与手部、姿态检测一致。

    • max_num_faces:最多可检测的人脸数量,默认值为1,本次设为2,支持同时检测两张人脸。

    • refine_landmarks:是否优化关键点精度,True表示优化(重点优化眼睛、嘴唇等细节部位的关键点),False表示不优化,新手建议设为True,提升检测精度。

    • min_detection_confidencemin_tracking_confidence:与前三个功能一致,分别控制检测精度和追踪稳定性,新手设为0.5即可。

3.3.2 摄像头采集与视频预处理

python 复制代码
cap = cv2.VideoCapture(0)  # 调用默认摄像头
while cap.isOpened():  # 循环条件:摄像头正常打开
   success, frame = cap.read()  # 读取摄像头帧
   h, w = frame.shape[:2]  # 获取画面宽高(用于关键点坐标转换)
   if not success:
       print("无法读取摄像头画面")
       break
   # 颜色空间转换:BGR→RGB,适配MediaPipe
   frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
   # 执行脸部关键点检测
   results = face_mesh.process(frame_rgb)

补充说明:

  • cap.isOpened():比while True更严谨的循环条件,会判断摄像头是否正常打开,若摄像头异常(如未连接、被占用),会直接退出循环,避免报错。

  • h, w = frame.shape[:2]:获取画面宽高,后续将关键点的归一化坐标(x、y)转换为像素坐标(int(x*w)、int(y*h)),用于标注关键点序号。

  • 异常处理:if not success: break,若摄像头无法读取帧(如遮挡、异常),打印提示并退出循环,提升程序稳定性。

3.3.3 核心:关键点标注与脸部网格绘制

这是脸部检测的核心模块,包含"关键点序号标注"和"脸部网格绘制"两个功能,逻辑与手部检测类似,但关键点更多、绘制风格更特殊。

python 复制代码
if results.multi_face_landmarks:  # 判断是否检测到人脸关键点
   for face_landmarks in results.multi_face_landmarks:  # 遍历每张人脸
       print(len(face_landmarks.landmark))    # 打印关键点总数(固定478个)
       # 遍历478个关键点,标注序号
       for i in range(len(face_landmarks.landmark)):
           x = face_landmarks.landmark[i].x
           y = face_landmarks.landmark[i].y
           # z = face_landmarks.landmark[i].z  # 深度坐标,可选打印
           # print(x,y,z)
           # 标注关键点序号(字体缩小,避免遮挡)
           cv2.putText(frame, str(i), (int(x * w), int(y * h)), 
                       cv2.FONT_HERSHEY_SIMPLEX, 0.3, (0, 255, 0), 2)
       # 绘制脸部网格(核心,使用内置风格)
       mp_drawing.draw_landmarks(
           image=frame,  # 要绘制的画面
           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()  # 内置网格风格
       )

逐点解析(新手必看):

  • results.multi_face_landmarks:存储所有检测到的人脸关键点信息,是一个列表,每张人脸对应一个face_landmarks对象,每个对象包含478个关键点。

  • 关键点序号标注

    • 字体设为0.3(较小),颜色为绿色(0,255,0),线条粗细2,避免序号过大遮挡脸部网格和其他关键点;

    • z轴深度坐标被注释,若需要查看,取消注释即可,z值以脸部中心点为原点,值越小,关键点越靠近摄像头。

以上就是mediapipe的一些进阶、其他用法功能。

相关推荐
CoovallyAIHub1 天前
语音AI Agent编排框架!Pipecat斩获10K+ Star,60+集成开箱即用,亚秒级对话延迟接近真人反应速度!
深度学习·算法·计算机视觉
CoovallyAIHub2 天前
Moonshine:比 Whisper 快 100 倍的端侧语音识别神器,Star 6.6K!
深度学习·算法·计算机视觉
CoovallyAIHub2 天前
速度暴涨10倍、成本暴降6倍!Mercury 2用扩散取代自回归,重新定义LLM推理速度
深度学习·算法·计算机视觉
CoovallyAIHub2 天前
OpenClaw一脚踩碎传统CV?机器终于不再只是看世界
深度学习·算法·计算机视觉
CoovallyAIHub2 天前
仅凭单目相机实现3D锥桶定位?UNet-RKNet破解自动驾驶锥桶检测难题
深度学习·算法·计算机视觉
CoovallyAIHub7 天前
仿生学突破:SILD模型如何让无人机在电力线迷宫中发现“隐形威胁”
深度学习·算法·计算机视觉
CoovallyAIHub7 天前
从春晚机器人到零样本革命:YOLO26-Pose姿态估计实战指南
深度学习·算法·计算机视觉
CoovallyAIHub7 天前
Le-DETR:省80%预训练数据,这个实时检测Transformer刷新SOTA|Georgia Tech & 北交大
深度学习·算法·计算机视觉
CoovallyAIHub7 天前
强化学习凭什么比监督学习更聪明?RL的“聪明”并非来自算法,而是因为它学会了“挑食”
深度学习·算法·计算机视觉
CoovallyAIHub7 天前
YOLO-IOD深度解析:打破实时增量目标检测的三重知识冲突
深度学习·算法·计算机视觉