Skip to content

MediaPipe 框架基础

MediaPipe 简介

MediaPipe 是由 Google Research 开发的一个强大的、跨平台的框架,用于构建多模态的机器学习管道。它提供了一套预构建的解决方案,可以快速实现人体姿态估计、手部识别、面部检测等复杂的计算机视觉任务,同时具有出色的性能和实时处理能力。

MediaPipe 的核心优势

  1. 易用性强 - 提供了简单直观的 Python API,无需深入了解底层实现细节即可使用
  2. 性能卓越 - 优化的 C++ 后端确保了高效的推理速度,支持实时处理
  3. 跨平台支持 - 可在 Windows、Linux、macOS、iOS、Android 等多个平台运行
  4. 预训练模型 - 提供了多个已训练好的模型,开箱即用
  5. 灵活的架构 - 采用数据流图的设计模式,易于扩展和定制
  6. 丰富的解决方案 - 包括姿态估计、手部检测、面部识别、物体检测等多种功能

LeBot 中的应用

在 LeBot 轮腿机器人项目中,MediaPipe 主要用于:

  • 人体姿态识别和追踪
  • 手势识别和控制
  • 面部检测和表情识别
  • 身体动作的实时分析
  • 基于人类动作的机器人行为学习

MediaPipe 的架构

MediaPipe 采用了数据流图(Data Flow Graph)的架构,这是其核心设计理念。

数据流图的基本概念

数据流图由以下几个核心组件组成:

1. 节点(Node/Calculator)

节点是数据流图中的基本处理单元。每个节点都执行特定的计算任务,如图像预处理、模型推理、结果后处理等。

输入数据 → [节点处理] → 输出数据

2. 流(Stream)

流是节点之间的数据传输渠道。每条流都有特定的数据类型(如图像、姿态关键点等)。

3. 包(Packet)

包是在流中传输的数据单位。每个包都包含数据和时间戳信息。

数据包结构:
┌─────────────────┐
│   时间戳        │
├─────────────────┤
│   数据内容      │
└─────────────────┘

典型的处理流程

原始视频输入

[图像预处理] → 标准化、缩放、格式转换

[模型推理] → 运行神经网络模型

[结果处理] → 后处理、过滤

[结果可视化] → 绘制关键点、连接线

输出结果

MediaPipe 的主要解决方案

1. Pose Detection(姿态检测)

用于检测人体的 33 个关键点,包括肩膀、肘部、膝盖、脚踝等。

主要特点:

  • 检测 33 个身体关键点
  • 实时处理能力(30 FPS+)
  • 支持多人检测
  • 提供置信度和可见性信息

2. Hand Detection(手部检测)

检测手部的 21 个关键点,用于手势识别和控制。

主要特点:

  • 检测 21 个手部关键点
  • 区分左手和右手
  • 高精度的手势识别
  • 支持多手追踪

3. Face Detection(面部检测)

检测面部和 468 个面部关键点,用于面部识别和表情分析。

主要特点:

  • 检测面部的 468 个关键点
  • 提取面部特征
  • 支持多面部检测
  • 出色的旋转和光照不变性

4. Object Detection(物体检测)

用于检测图像中的各种物体。

5. Hair Segmentation(头发分割)

用于图像处理和增强应用。

MediaPipe 安装与环境配置

系统要求

  • Python 3.7 或更高版本
  • pip 包管理工具
  • 支持的操作系统:Linux、macOS、Windows

安装步骤

1. 创建虚拟环境(推荐)

bash
# 创建虚拟环境
python3 -m venv mediapipe_env

# 激活虚拟环境
# 在 Linux/macOS 上:
source mediapipe_env/bin/activate

# 在 Windows 上:
mediapipe_env\Scripts\activate

2. 安装 MediaPipe

bash
# 安装最新版本的 MediaPipe
pip install mediapipe

# 安装特定版本(如有需要)
pip install mediapipe==0.8.11

# 验证安装
python -c "import mediapipe as mp; print(mp.__version__)"

3. 安装依赖库

MediaPipe 需要一些依赖库的支持:

bash
# 安装 OpenCV(用于图像处理)
pip install opencv-python

# 安装 NumPy(用于数值计算)
pip install numpy

# 安装 Matplotlib(用于可视化)
pip install matplotlib

# 安装所有推荐的依赖
pip install mediapipe opencv-python numpy matplotlib scipy scikit-image

验证安装

创建一个简单的测试脚本 test_mediapipe.py

python
import mediapipe as mp
import cv2

# 初始化 MediaPipe Pose
mp_pose = mp.solutions.pose
pose = mp_pose.Pose()

print("MediaPipe 安装成功!")
print(f"版本:{mp.__version__}")
print("Pose 模型已加载")

# 清理资源
pose.close()

运行测试:

bash
python test_mediapipe.py

MediaPipe Pose 的详细说明

关键点索引

MediaPipe Pose 检测的 33 个关键点对应的索引和名称:

python
LANDMARKS = {
    0: "NOSE",                      # 鼻子
    1: "LEFT_EYE_INNER",            # 左眼内侧
    2: "LEFT_EYE",                  # 左眼
    3: "LEFT_EYE_OUTER",            # 左眼外侧
    4: "RIGHT_EYE_INNER",           # 右眼内侧
    5: "RIGHT_EYE",                 # 右眼
    6: "RIGHT_EYE_OUTER",           # 右眼外侧
    7: "LEFT_EAR",                  # 左耳
    8: "RIGHT_EAR",                 # 右耳
    9: "MOUTH_LEFT",                # 左嘴角
    10: "MOUTH_RIGHT",              # 右嘴角
    11: "LEFT_SHOULDER",            # 左肩
    12: "RIGHT_SHOULDER",           # 右肩
    13: "LEFT_ELBOW",               # 左肘
    14: "RIGHT_ELBOW",              # 右肘
    15: "LEFT_WRIST",               # 左手腕
    16: "RIGHT_WRIST",              # 右手腕
    17: "LEFT_PINKY",               # 左小指
    18: "RIGHT_PINKY",              # 右小指
    19: "LEFT_INDEX",               # 左食指
    20: "RIGHT_INDEX",              # 右食指
    21: "LEFT_THUMB",               # 左拇指
    22: "RIGHT_THUMB",              # 右拇指
    23: "LEFT_HIP",                 # 左髋
    24: "RIGHT_HIP",                # 右髋
    25: "LEFT_KNEE",                # 左膝
    26: "RIGHT_KNEE",               # 右膝
    27: "LEFT_ANKLE",               # 左脚踝
    28: "RIGHT_ANKLE",              # 右脚踝
    29: "LEFT_HEEL",                # 左脚后跟
    30: "RIGHT_HEEL",               # 右脚后跟
    31: "LEFT_FOOT_INDEX",          # 左脚尖
    32: "RIGHT_FOOT_INDEX"          # 右脚尖
}

关键点数据结构

每个关键点都包含以下信息:

python
landmark = {
    'x': float,      # 归一化的 X 坐标 (0.0 - 1.0)
    'y': float,      # 归一化的 Y 坐标 (0.0 - 1.0)
    'z': float,      # 深度信息 (相对于髋部中心)
    'visibility': float  # 可见性 (0.0 - 1.0)
}

坐标系说明:

  • X:从左到右,0 = 图像左边界,1 = 图像右边界
  • Y:从上到下,0 = 图像上边界,1 = 图像下边界
  • Z:从近到远,-1 = 摄像头前方,+1 = 摄像头后方

连接关系

相邻的关键点通过连接线形成人体骨骼结构。主要的连接包括:

头部区域:
- 眼睛 ↔ 耳朵
- 眼睛 ↔ 鼻子

躯干区域:
- 肩膀 ↔ 肘部 ↔ 手腕
- 髋部 ↔ 膝盖 ↔ 脚踝 ↔ 脚尖

躯干连接:
- 肩膀 ↔ 髋部

MediaPipe 基本使用示例

示例 1:从摄像头实时检测姿态

python
import cv2
import mediapipe as mp
import numpy as np

# 初始化 MediaPipe
mp_pose = mp.solutions.pose
mp_drawing = mp.solutions.drawing_utils
pose = mp_pose.Pose(
    static_image_mode=False,          # 实时视频模式
    model_complexity=1,               # 0=轻量级, 1=完整, 2=重量级
    smooth_landmarks=True,            # 启用平滑处理
    min_detection_confidence=0.7,     # 检测置信度
    min_tracking_confidence=0.5       # 追踪置信度
)

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

while True:
    success, frame = cap.read()
    if not success:
        print("Failed to read frame")
        break
    
    # 获取图像尺寸
    h, w, c = frame.shape
    
    # 转换颜色空间(BGR → RGB)
    frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    
    # 进行姿态检测
    results = pose.process(frame_rgb)
    
    # 绘制检测结果
    if results.pose_landmarks:
        mp_drawing.draw_landmarks(
            frame,
            results.pose_landmarks,
            mp_pose.POSE_CONNECTIONS,
            mp_drawing.DrawingSpec(color=(0, 255, 0), thickness=2, circle_radius=2),
            mp_drawing.DrawingSpec(color=(255, 0, 0), thickness=2)
        )
    
    # 显示帧率
    cv2.imshow('MediaPipe Pose Detection', frame)
    
    # 按 'q' 退出
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# 清理资源
cap.release()
cv2.destroyAllWindows()
pose.close()

示例 2:提取并处理关键点数据

python
import cv2
import mediapipe as mp
import math

mp_pose = mp.solutions.pose
pose = mp_pose.Pose()

cap = cv2.VideoCapture(0)

def calculate_distance(point1, point2):
    """计算两个关键点之间的距离"""
    return math.sqrt((point1.x - point2.x)**2 + (point1.y - point2.y)**2)

def calculate_angle(point1, point2, point3):
    """计算三个关键点形成的角度"""
    # 向量 1: point2 -> point1
    a = math.sqrt((point1.x - point2.x)**2 + (point1.y - point2.y)**2)
    # 向量 2: point2 -> point3
    b = math.sqrt((point3.x - point2.x)**2 + (point3.y - point2.y)**2)
    # 向量 1 和向量 2
    c = math.sqrt((point1.x - point3.x)**2 + (point1.y - point3.y)**2)
    
    # 使用余弦定律计算角度
    angle = math.acos((a**2 + b**2 - c**2) / (2 * a * b))
    return math.degrees(angle)

while True:
    success, frame = cap.read()
    if not success:
        break
    
    frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
    results = pose.process(frame_rgb)
    
    if results.pose_landmarks:
        landmarks = results.pose_landmarks.landmark
        
        # 获取关键点
        left_shoulder = landmarks[11]
        right_shoulder = landmarks[12]
        left_elbow = landmarks[13]
        right_elbow = landmarks[14]
        left_wrist = landmarks[15]
        right_wrist = landmarks[16]
        
        # 计算肩宽
        shoulder_width = calculate_distance(left_shoulder, right_shoulder)
        
        # 计算左手臂角度
        left_arm_angle = calculate_angle(left_shoulder, left_elbow, left_wrist)
        
        # 计算右手臂角度
        right_arm_angle = calculate_angle(right_shoulder, right_elbow, right_wrist)
        
        # 打印结果
        print(f"肩宽: {shoulder_width:.3f}")
        print(f"左手臂角度: {left_arm_angle:.1f}°")
        print(f"右手臂角度: {right_arm_angle:.1f}°")
    
    cv2.imshow('Pose Detection', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()
pose.close()

示例 3:从图像文件检测姿态

python
import cv2
import mediapipe as mp
import os

mp_pose = mp.solutions.pose
mp_drawing = mp.solutions.drawing_utils
pose = mp_pose.Pose(static_image_mode=True)

# 处理图像文件夹
image_folder = "path/to/images"
output_folder = "path/to/output"

os.makedirs(output_folder, exist_ok=True)

for image_name in os.listdir(image_folder):
    if not image_name.endswith(('.jpg', '.png', '.jpeg')):
        continue
    
    image_path = os.path.join(image_folder, image_name)
    image = cv2.imread(image_path)
    
    if image is None:
        continue
    
    h, w, c = image.shape
    image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    
    results = pose.process(image_rgb)
    
    if results.pose_landmarks:
        mp_drawing.draw_landmarks(
            image,
            results.pose_landmarks,
            mp_pose.POSE_CONNECTIONS
        )
    
    # 保存结果图像
    output_path = os.path.join(output_folder, f"posed_{image_name}")
    cv2.imwrite(output_path, image)
    print(f"已处理: {image_name}")

pose.close()

MediaPipe 的高级特性

1. 平滑处理(Smoothing)

MediaPipe 提供了时间平滑功能,可以减少关键点检测中的抖动。

python
pose = mp_pose.Pose(
    smooth_landmarks=True,           # 启用平滑
    smooth_segmentation=True         # 启用分割平滑
)

2. 模型复杂度选择

python
# 轻量级模型 - 速度快,精度较低
# 适合实时应用和移动设备
pose_light = mp_pose.Pose(model_complexity=0)

# 完整模型 - 平衡速度和精度
# 推荐用于大多数应用
pose_full = mp_pose.Pose(model_complexity=1)

# 重量级模型 - 精度最高,速度最慢
# 适合离线处理和高精度要求
pose_heavy = mp_pose.Pose(model_complexity=2)

3. 性能优化

python
# 使用 GPU 加速(如果可用)
import os
os.environ['CUDA_VISIBLE_DEVICES'] = '0'

# 调整检测置信度以平衡精度和速度
pose = mp_pose.Pose(
    min_detection_confidence=0.5,    # 降低置信度可以提高检测率
    min_tracking_confidence=0.3      # 但可能增加误检
)

常见问题与解决方案

问题 1:检测效果不好

原因: 光照条件差、角度不合适、置信度设置过高

解决方案:

  • 改善光照条件
  • 调整摄像头角度
  • 降低 min_detection_confidencemin_tracking_confidence
  • 确保人体完全在画面内

问题 2:性能不足,帧率低

原因: 模型过于复杂、硬件性能不足

解决方案:

  • 降低模型复杂度(从 2 → 1 → 0)
  • 减少输入图像尺寸
  • 启用多线程处理
  • 考虑使用 GPU 加速

问题 3:关键点不准确

原因: 检测置信度不适合、背景复杂

解决方案:

  • 调整置信度参数
  • 改善背景简洁度
  • 确保人体姿态在模型训练范围内

LeBot 中的应用案例

案例 1:动作识别

使用 MediaPipe 检测人类的动作,然后让 LeBot 机器人复制这些动作。

python
# 伪代码示例
def recognize_and_replicate_action():
    # 1. 检测人类的姿态
    human_landmarks = detect_human_pose()
    
    # 2. 提取关键特征
    features = extract_features(human_landmarks)
    
    # 3. 映射到机器人关节
    robot_angles = map_to_robot_joints(features)
    
    # 4. 发送命令到机器人
    send_command_to_robot(robot_angles)

案例 2:手势控制

使用 MediaPipe Hand 检测用户的手势,控制 LeBot 的运动。

python
# 检测手部关键点
mp_hands = mp.solutions.hands
hands = mp_hands.Hands()

# 根据手势识别控制命令
def recognize_gesture(hand_landmarks):
    # 分析手指的位置和方向
    # 返回控制命令(前进、后退、转向等)

总结

MediaPipe 是一个强大的、易于使用的计算机视觉框架,特别适合实时姿态检测和人体动作识别。在 LeBot 项目中,我们可以利用 MediaPipe 快速实现复杂的视觉功能,而无需深入学习底层的深度学习知识。

通过掌握 MediaPipe 的基本概念和使用方法,你能够:

  1. 快速构建原型应用
  2. 实现实时视觉处理
  3. 集成人体姿态识别功能
  4. 开发创新的人机交互方式

推荐资源

由 LeBot 开发团队编写