MediaPipe姿态估计教程:自定义关键点可视化样式
1. 引言
1.1 学习目标
本文将带你深入掌握如何基于 Google MediaPipe 的 Pose 模型,实现人体骨骼关键点检测,并重点讲解如何自定义关键点与骨架的可视化样式。通过本教程,你将能够:
- 快速部署本地化的人体姿态估计系统
- 理解 MediaPipe 关键点输出结构
- 自定义关键点颜色、大小、连接线样式
- 构建个性化的火柴人骨架图(如荧光风格、渐变连线等)
适合计算机视觉初学者、AI 应用开发者以及对动作识别、健身分析、虚拟试衣等场景感兴趣的工程师。
1.2 前置知识
- Python 基础语法
- OpenCV 与 Matplotlib 图像处理基础
- HTML/CSS/Flask(可选,用于 WebUI 扩展)
1.3 教程价值
不同于官方默认的“红点+白线”可视化方案,本文提供完全可编程的渲染控制能力,帮助你在项目中实现更具辨识度和美观性的骨骼图展示,适用于产品级应用集成。
2. 环境准备与基础运行
2.1 安装依赖
确保已安装以下核心库:
pip install mediapipe opencv-python flask numpy✅ 推荐使用 Python 3.8+ 环境,避免版本兼容问题。
2.2 启动本地服务(WebUI 版)
假设你已获取预置镜像环境,启动后可通过平台 HTTP 按钮访问 Web 界面。若需手动运行,可使用如下 Flask 示例代码构建简易上传接口:
from flask import Flask, request, send_file import cv2 import numpy as np import mediapipe as mp app = Flask(__name__) mp_pose = mp.solutions.pose pose = mp_pose.Pose(static_image_mode=True, model_complexity=2) @app.route('/upload', methods=['POST']) def upload_image(): file = request.files['image'] img = cv2.imdecode(np.frombuffer(file.read(), np.uint8), cv2.IMREAD_COLOR) rgb_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) results = pose.process(rgb_img) # 使用自定义绘图函数(后续定义) annotated_img = draw_custom_landmarks(img.copy(), results.pose_landmarks) _, buffer = cv2.imencode('.jpg', annotated_img) return send_file(io.BytesIO(buffer), mimetype='image/jpeg') if __name__ == '__main__': app.run(host='0.0.0.0', port=5000)3. 核心概念快速入门
3.1 MediaPipe Pose 关键点体系
MediaPipe Pose 模型共输出33 个 3D 关键点,覆盖:
- 面部:鼻尖、左/右眼、耳等
- 上肢:肩、肘、腕、手部关键点
- 躯干:脊柱、髋部
- 下肢:膝、踝、脚尖
每个关键点包含(x, y, z, visibility)四维数据,其中visibility表示该点是否被遮挡。
📌 提示:坐标为归一化值(0~1),需乘以图像宽高转换为像素坐标。
3.2 默认可视化方式
MediaPipe 提供了mp.solutions.drawing_utils模块用于绘制关键点和连接线:
import mediapipe as mp mp_drawing = mp.solutions.drawing_utils mp_pose = mp.solutions.pose # 默认绘制 mp_drawing.draw_landmarks(image, results.pose_landmarks, mp_pose.POSE_CONNECTIONS)但其样式固定,难以满足个性化需求。
4. 分步实践教程:自定义可视化样式
4.1 自定义关键点绘制函数
我们绕过默认绘图工具,手动实现关键点渲染逻辑,从而实现完全控制。
import cv2 import numpy as np def draw_custom_landmarks(image, landmarks, circle_color=(0, 255, 0), circle_radius=5, font_scale=0.4): """ 自定义关键点绘制函数 :param image: 输入图像 (BGR) :param landmarks: MediaPipe 关键点对象 :param circle_color: 圆点半径颜色 (B, G, R) :param circle_radius: 圆点半径 :param font_scale: 编号字体大小 """ h, w, _ = image.shape if not landmarks: return image for idx, landmark in enumerate(landmarks.landmark): cx, cy = int(landmark.x * w), int(landmark.y * h) # 绘制彩色圆点 cv2.circle(image, (cx, cy), circle_radius, circle_color, -1) # 可选:标注关键点编号 cv2.putText(image, str(idx), (cx + 5, cy + 5), cv2.FONT_HERSHEY_SIMPLEX, font_scale, (255, 255, 255), 1) return image✅效果:所有关键点变为绿色实心圆,并可显示编号。
4.2 自定义骨架连接线样式
接下来,我们手动绘制骨骼连接线,支持自定义颜色、粗细、透明度。
def draw_custom_connections(image, landmarks, connections, line_color=(255, 255, 0), line_thickness=2, alpha=0.7): """ 自定义连接线绘制(支持半透明) :param image: 输入图像 :param landmarks: 关键点 :param connections: 连接关系列表(如 mp_pose.POSE_CONNECTIONS) :param line_color: 线条颜色 :param line_thickness: 线条粗细 :param alpha: 透明度(0~1) """ overlay = image.copy() h, w, _ = image.shape for connection in connections: start_idx = connection[0] end_idx = connection[1] start = landmarks.landmark[start_idx] end = landmarks.landmark[end_idx] x1, y1 = int(start.x * w), int(start.y * h) x2, y2 = int(end.x * w), int(end.y * h) cv2.line(overlay, (x1, y1), (x2, y2), line_color, line_thickness) # 融合叠加层实现透明效果 cv2.addWeighted(overlay, alpha, image, 1 - alpha, 0, image) return image✅优势:支持透明线条,避免遮挡原图细节。
4.3 综合调用示例
将上述两个函数组合,实现完整自定义渲染:
# 主流程示例 image = cv2.imread("person.jpg") rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB) results = pose.process(rgb_image) if results.pose_landmarks: # 先画连接线(底层) image = draw_custom_connections( image, results.pose_landmarks, mp_pose.POSE_CONNECTIONS, line_color=(0, 255, 255), # 青色连线 line_thickness=3, alpha=0.6 ) # 再画关键点(顶层) image = draw_custom_landmarks( image, results.pose_landmarks, circle_color=(0, 0, 255), # 红色圆点 circle_radius=6 ) cv2.imwrite("output_custom_skeleton.jpg", image)📌输出效果:青色半透明骨架 + 红色高亮关键点,视觉层次清晰。
4.4 高级技巧:按身体区域差异化着色
我们可以根据连接部位(如上肢、下肢)设置不同颜色,增强可读性。
def get_connection_color(connection_idx): """根据连接索引返回颜色""" upper_body = [ (11,13), (13,15), (12,14), (14,16), # 手臂 (11,12), (11,23), (12,24) # 肩背 ] lower_body = [ (23,25), (25,27), (24,26), (26,28), # 腿部 (23,24), (27,29), (28,30) # 跨部与脚 ] conn_tuple = tuple(sorted(connection_idx)) if conn_tuple in [tuple(sorted(c)) for c in upper_body]: return (255, 0, 0) # 蓝色:上肢 elif conn_tuple in [tuple(sorted(c)) for c in lower_body]: return (0, 0, 255) # 红色:下肢 else: return (0, 255, 0) # 绿色:躯干/其他 # 修改 draw_custom_connections 中的颜色获取方式: for connection in connections: # ... 获取 x1,y1,x2,y2 ... color = get_connection_color((start_idx, end_idx)) cv2.line(overlay, (x1, y1), (x2, y2), color, line_thickness)🎯应用场景:运动康复分析、舞蹈动作评分系统。
5. 常见问题解答
5.1 如何提高小尺寸人物的关键点精度?
- 使用更高分辨率输入图像(建议 ≥ 640×480)
- 设置
model_complexity=2(最高精度模式) - 避免远距离或模糊图像
5.2 如何关闭某些连接线(如面部)?
修改connections参数,传入自定义连接列表:
CUSTOM_CONNECTIONS = [ (11,13), (13,15), (12,14), (14,16), # 只保留手臂 (23,25), (25,27), (24,26), (26,28) # 只保留腿部 ] draw_custom_connections(image, landmarks, CUSTOM_CONNECTIONS, ...)5.3 如何导出关键点坐标?
landmark_data = [] for i, lm in enumerate(results.pose_landmarks.landmark): landmark_data.append({ 'id': i, 'x': lm.x, 'y': lm.y, 'z': lm.z, 'visibility': lm.visibility })可保存为 JSON 或 CSV 文件用于后续分析。
6. 总结
6.1 学习路径建议
- 掌握 MediaPipe Pose 基础 API 调用
- 实现默认可视化 → 自定义样式过渡
- 扩展至视频流实时处理(
cv2.VideoCapture) - 结合动作分类模型(如 LSTM)实现行为识别
6.2 资源推荐
- MediaPipe 官方文档
- GitHub 示例仓库:
google/mediapipe - 可视化灵感参考:OpenPose、PoseNet
💡获取更多AI镜像
想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。