关键点检测:人脸68点定位与人体姿态估计详解

引言

关键点检测是计算机视觉的核心「标注-定位」任务,直接识别图像/视频中特定解剖学或物理特征的精确坐标。它是人脸识别对齐、虚拟试妆/骨骼动画、健身姿态分析等热门应用的前置基础。

📂 所属阶段:第二阶段 — 深度学习视觉基础(CNN 篇)
🔗 相关章节:语义分割 (Semantic Segmentation) · Vision Transformer (ViT) 详解


1. 快速入门:任务定义与核心类型

1.1 任务核心

输入:单张/连续图像 ( I \in \mathbb{R}^{H \times W \times C} )
输出:( N ) 个关键点的坐标集合 ( {(x_i, y_i, v_i)}_{i=1}^N )(( v_i ) 可选,表示可见度/置信度)

1.2 主流检测场景

按应用场景可分为4类高频场景:

场景常用点数/模型代表框架工具
人脸对齐/表情分析dlib 68点、MediaPipe 468点dlib、MediaPipe Face
人体姿态/动作分析COCO 17点、MPII 16点MediaPipe Pose、OpenPose
手势交互MediaPipe 21点MediaPipe Hands
物体/足部关键点自定义/足部专用模型自定义CNN/Transformer

2. 实战上手:三大高频场景的代码实现

2.1 人脸68点定位:dlib + OpenCV

dlib的68点模型是人脸对齐的经典方案,精度高,适合离线批量处理。

前置准备

需安装依赖:

pip install opencv-python dlib
# dlib的shape_predictor_68_face_landmarks.dat需单独下载:
# http://dlib.net/files/shape_predictor_68_face_landmarks.dat.bz2

完整代码

import cv2
import dlib

# 1. 初始化dlib检测器和预测器
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor("shape_predictor_68_face_landmarks.dat")

def draw_68_landmarks(img_path, save_path=None):
    # 2. 读取并预处理图像
    img = cv2.imread(img_path)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    # 3. 检测人脸框和关键点
    faces = detector(gray, 1)  # 1是上采样次数,减少漏检
    for face in faces:
        # 先绘制人脸框
        x1, y1, x2, y2 = face.left(), face.top(), face.right(), face.bottom()
        cv2.rectangle(img, (x1, y1), (x2, y2), (255, 0, 0), 2)
        
        # 提取并绘制68个关键点
        shape = predictor(gray, face)
        for i in range(68):
            x, y = shape.part(i).x, shape.part(i).y
            cv2.circle(img, (x, y), 2, (0, 255, 0), -1)
            # 可选:标注点编号(适合调试)
            # cv2.putText(img, str(i), (x-5, y-5), cv2.FONT_HERSHEY_SIMPLEX, 0.3, (0, 255, 255), 1)
    
    # 4. 展示/保存结果
    cv2.imshow("dlib 68 Landmarks", img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    if save_path:
        cv2.imwrite(save_path, img)

# 测试
draw_68_landmarks("test_face.jpg", "result_face.jpg")

2.2 人体姿态估计:MediaPipe Pose

MediaPipe是Google开源的轻量化工具,适合实时移动端/PC端部署,支持单/多人17点COCO模型。

前置准备

pip install opencv-python mediapipe

实时摄像头姿态检测

import cv2
import mediapipe as mp

# 1. 初始化MediaPipe组件
mp_pose = mp.solutions.pose
mp_draw = mp.solutions.drawing_utils
mp_styles = mp.solutions.drawing_styles

pose = mp_pose.Pose(
    static_image_mode=False,  # 设为False表示视频模式,启用追踪
    model_complexity=1,       # 0/1/2,精度和速度平衡选1
    enable_segmentation=False,
    min_detection_confidence=0.5,
    min_tracking_confidence=0.5
)

# 2. 打开摄像头
cap = cv2.VideoCapture(0)

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break
    
    # 3. 预处理 + 检测姿态
    frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    results = pose.process(frame_rgb)
    
    # 4. 绘制关键点和骨骼连接
    if results.pose_landmarks:
        mp_draw.draw_landmarks(
            frame,
            results.pose_landmarks,
            mp_pose.POSE_CONNECTIONS,
            mp_styles.get_default_pose_landmarks_style(),
            mp_styles.get_default_pose_connections_style()
        )
    
    # 5. 显示结果
    cv2.imshow("MediaPipe Pose", frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

2.3 手部21点追踪:MediaPipe Hands

手势交互的基础,同样支持实时部署,单/双手都可检测。

前置准备

和Pose共用MediaPipe,无需额外安装。

简单手势判断(剪刀石头布方向简化)

import cv2
import mediapipe as mp

mp_hands = mp.solutions.hands
mp_draw = mp.solutions.drawing_utils

hands = mp_hands.Hands(
    static_image_mode=False,
    max_num_hands=1,
    min_detection_confidence=0.5,
    min_tracking_confidence=0.5
)

# 定义指尖和指根的索引(从wrist=0开始,拇指1-4,食指5-8...)
FINGER_TIPS = [4, 8, 12, 16, 20]
FINGER_MCP = [2, 5, 9, 13, 17]  # 指根(拇指用IP关节)

def get_simple_gesture(hand_landmarks):
    fingers_up = [0]*5
    # 拇指(左右判断:x坐标,左手<右手)
    if hand_landmarks.landmark[FINGER_TIPS[0]].x < hand_landmarks.landmark[FINGER_TIPS[0]-1].x:
        # 左手
        if hand_landmarks.landmark[FINGER_TIPS[0]].x > hand_landmarks.landmark[FINGER_MCP[0]].x:
            fingers_up[0] = 1
    else:
        # 右手
        if hand_landmarks.landmark[FINGER_TIPS[0]].x < hand_landmarks.landmark[FINGER_MCP[0]].x:
            fingers_up[0] = 1
    # 其他四指(y坐标,越往上越小)
    for i in range(1,5):
        if hand_landmarks.landmark[FINGER_TIPS[i]].y < hand_landmarks.landmark[FINGER_TIPS[i]-2].y:
            fingers_up[i] = 1
    # 简化判断
    if fingers_up == [1,0,0,0,0]:
        return "Thumbs Up"
    elif fingers_up == [0,1,1,0,0]:
        return "Scissors"
    elif fingers_up == [0,0,0,0,0]:
        return "Rock"
    elif fingers_up == [1,1,1,1,1]:
        return "Paper"
    else:
        return "Unknown"

cap = cv2.VideoCapture(0)

while cap.isOpened():
    ret, frame = cap.read()
    if not ret:
        break
    frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    results = hands.process(frame_rgb)
    
    if results.multi_hand_landmarks:
        for hand_landmarks in results.multi_hand_landmarks:
            mp_draw.draw_landmarks(frame, hand_landmarks, mp_hands.HAND_CONNECTIONS)
            gesture = get_simple_gesture(hand_landmarks)
            cv2.putText(frame, gesture, (50, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
    
    cv2.imshow("MediaPipe Hands + Simple Gesture", frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

3. 技术速览:深度学习方法核心

3.1 核心算法方向

  1. Top-Down(先检测后定位):用目标检测找到人/脸,再在框内检测关键点 → 精度高,但多人场景速度慢(依赖目标检测速度)
  2. Bottom-Up(先定位后关联):先检测所有关键点,再用PAFs(亲和场)等方法关联到不同个体 → 多人场景速度快,OpenPose是代表

3.2 常用损失函数

  • MSE/MAE Loss:经典热图回归(每个关键点对应一张高斯热图,峰值即坐标)
  • Wing Loss:专门为关键点设计,对小误差(像素级对齐)更敏感
  • Smooth L1 Loss:结合MSE和MAE的优点,减少梯度震荡

4. 学习与部署建议

1. 先掌握**MediaPipe三件套**(Face/Pose/Hands),快速跑通实时应用 2. 再学习dlib的传统+机器学习结合方案,理解预训练模型作用 3. 最后看OpenPose论文/源码,了解Bottom-Up的核心逻辑 - **实时优化**:降低输入分辨率(640×480→256×256)、每3-5帧检测一次其余用追踪、混合精度推理 - **移动端优化**:使用MediaPipe的Lite模型、TensorFlow Lite/ONNX Runtime Mobile

相关教程

🔗 扩展资源