关于 mediapipe-pose-detection
MediaPipe Pose Detection 是用于分析视频姿态关键点的技能,内容侧重反向跳分析。它为使用 kinemotion 的开发者介绍置信度调整、平滑、视频处理、可视化和人工验证。
主要功能
- 01面向跳跃的身体关键点参考
- 02检测与跟踪置信度预设
- 03关键点滤波与平滑
- 04视频旋转和坐标说明
- 05骨架调试叠加层
- 06人工验证阶段检测
适用场景
- 01调整跳跃视频的姿态跟踪
- 02平滑抖动的关键点
- 03排查关键点丢失或左右互换
- 04验证起跳与落地帧检测
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ kinemotioninc/ kinemotion --skill mediapipe-pose-detection安装后在 Claude Code 中输入/mediapipe-pose-detection确认已加载。
详细介绍
MediaPipe 姿态检测
跳跃分析的关键地标
下半身(跳跃分析的重点)
| 地标 | 左侧索引 | 右侧索引 | 用途 |
|---|---|---|---|
| 髋部 | 23 | 24 | 质心、跳跃高度 |
| 膝盖 | 25 | 26 | 三关节伸展、落地 |
| 脚踝 | 27 | 28 | 检测是否触地 |
| 脚跟 | 29 | 30 | 起跳/落地时机 |
| 脚趾 | 31 | 32 | 前脚掌触地 |
上半身(次要)
| 地标 | 左侧索引 | 右侧索引 | 用途 |
|---|---|---|---|
| 肩部 | 11 | 12 | 跟踪手臂摆动 |
| 肘部 | 13 | 14 | 手臂动作 |
| 手腕 | 15 | 16 | 手臂摆动时机 |
参考点
| 地标 | 索引 | 用途 |
|---|---|---|
| 鼻子 | 0 | 头部位置 |
| 左眼 | 2 | 面部朝向 |
| 右眼 | 5 | 面部朝向 |
置信度阈值
默认设置
min_detection_confidence = 0.5 # Initial pose detection
min_tracking_confidence = 0.5 # Frame-to-frame tracking
质量预设(auto_tuning.py)
| 预设 | 检测 | 跟踪 | 用途 |
|---|---|---|---|
fast | 0.3 | 0.3 | 快速处理,可容忍错误 |
balanced | 0.5 | 0.5 | 默认设置,准确度良好 |
accurate | 0.7 | 0.7 | 准确度最高,但速度较慢 |
调整指南
- 提高阈值的情况:地标抖动、误检测
- 降低阈值的情况:地标缺失、跟踪丢失
- 典型调整幅度:每次 ±0.1
常见问题及解决方案
地标抖动
症状:地标在不同帧之间不规则跳动
解决方案:
- 应用 Butterworth 低通滤波器(截止频率为 6-10 Hz)
- 提高跟踪置信度
- 在实时应用中使用 One-Euro 滤波器
# Butterworth filter (filtering.py)
from kinemotion.core.filtering import butterworth_filter
smoothed = butterworth_filter(landmarks, cutoff=8.0, fps=30)
# One-Euro filter (smoothing.py)
from kinemotion.core.smoothing import one_euro_filter
smoothed = one_euro_filter(landmarks, min_cutoff=1.0, beta=0.007)
左右混淆
症状:MediaPipe 在视频中途交换左右地标
原因:摄像机位于 90° 侧向角度时发生遮挡
解决方案:
- 使用 45° 斜向摄像机角度(推荐)
- 后处理以检测并纠正交换
- 尽可能使用单腿跟踪
跟踪丢失
症状:地标连续数帧消失
原因:
- 运动员移出画面
- 快速运动导致运动模糊
- 器材/衣物造成遮挡
解决方案:
- 确保视频中始终能看到运动员全身
- 使用更高的帧率(60+ fps)
- 对缺失帧进行插值(最多 3-5 帧)
# Simple linear interpolation for gaps
import numpy as np
def interpolate_gaps(landmarks, max_gap=5):
# Fill NaN gaps with linear interpolation
for i in range(landmarks.shape[1]):
mask = np.isnan(landmarks[:, i])
if mask.sum() > 0 and mask.sum() <= max_gap:
landmarks[:, i] = np.interp(
np.arange(len(landmarks)),
np.where(~mask)[0],
landmarks[~mask, i]
)
return landmarks
置信度分数较低
症状:可见度分数持续低于阈值
原因:
- 光线不佳(逆光、阴影)
- 衣物与背景对比度低
- 部分遮挡
解决方案:
- 改善光线(正面照明、光线均匀)
- 确保衣物与背景形成对比
- 移除摄像机视野中的障碍物
视频处理(video_io.py)
旋转处理
手机视频通常带有必须处理的旋转元数据:
# video_io.py handles this automatically
# Reads EXIF rotation and applies correction
from kinemotion.core.video_io import read_video_frames
frames, fps, dimensions = read_video_frames("mobile_video.mp4")
# Frames are correctly oriented regardless of source
手动旋转(如有需要)
# FFmpeg rotation options
ffmpeg -i input.mp4 -vf "transpose=1" output.mp4 # 90° clockwise
ffmpeg -i input.mp4 -vf "transpose=2" output.mp4 # 90° counter-clockwise
ffmpeg -i input.mp4 -vf "hflip" output.mp4 # Horizontal flip
帧尺寸
始终从第一帧读取实际帧尺寸,而非元数据:
# Correct approach
cap = cv2.VideoCapture(video_path)
ret, frame = cap.read()
height, width = frame.shape[:2]
# Incorrect (may be wrong for rotated videos)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
坐标系统
MediaPipe 输出
- 归一化坐标:(0.0, 0.0) 到 (1.0, 1.0)
- 原点:左上角
- X:从左到右
- Y:从上到下
- Z:深度(相对值,朝向摄像机为负)
转换为像素坐标
def normalized_to_pixel(landmark, width, height):
x = int(landmark.x * width)
y = int(landmark.y * height)
return x, y
可见度分数
每个地标都有一个可见度分数(0.0-1.0):
-
0.5:很可能可见且准确
- < 0.5:可能被遮挡或为估算值
- = 0.0:未检测到
调试叠加层(debug_overlay.py)
骨架绘制
# Key connections for jump visualization
POSE_CONNECTIONS = [
(23, 25), (25, 27), (27, 29), (27, 31), # Left leg
(24, 26), (26, 28), (28, 30), (28, 32), # Right leg
(23, 24), # Hips
(11, 23), (12, 24), # Torso
]
颜色编码
| 元素 | 颜色(BGR) | 含义 |
|---|---|---|
| 骨架 | (0, 255, 0) | 绿色 - 跟踪正常 |
| 低置信度 | (0, 165, 255) | 橙色 - 可见度 < 0.5 |
| 关键角度 | (255, 0, 0) | 蓝色 - 测量的角度 |
| 阶段标记 | (0, 0, 255) | 红色 - 起跳/落地 |
性能优化
降低延迟
- 使用
model_complexity=0以实现最快推理 - 批量分析时,每隔 N 帧处理一帧
- 如果可用,使用 GPU 加速
import mediapipe as mp
pose = mp.solutions.pose.Pose(
model_complexity=0, # 0=Lite, 1=Full, 2=Heavy
min_detection_confidence=0.5,
min_tracking_confidence=0.5,
static_image_mode=False # False for video (uses tracking)
)
内存管理
- 处理完成后释放姿势估计器:
pose.close() - 处理大型文件时,将视频分块处理
- 使用生成器遍历帧
与 kinemotion 集成
文件位置
- 姿势估计:
src/kinemotion/core/pose.py - 视频 I/O:
src/kinemotion/core/video_io.py - 滤波:
src/kinemotion/core/filtering.py - 平滑:
src/kinemotion/core/smoothing.py - 自动调优:
src/kinemotion/core/auto_tuning.py
典型工作流
Video → read_video_frames() → pose.process() → filter/smooth → analyze
用于验证的人工观察
在开发过程中,使用逐帧人工观察来确定真实值并验证姿势检测的准确性。
何时使用人工观察
- 算法开发:验证新的阶段检测方法
- 参数调优:比较检测到的帧与实际帧
- 调试:调查姿势检测失败问题
- 真实值收集:构建验证数据集
真实值数据收集流程
步骤 1:生成调试视频
uv run kinemotion cmj-analyze video.mp4 --output debug.mp4
步骤 2:逐帧人工分析
在逐帧工具(QuickTime、支持逐帧前进的 VLC 或视频编辑器)中打开调试视频。
步骤 3:记录观察结果
对于每个关键阶段,记录事件发生的帧编号:
=== MANUAL OBSERVATION: PHASE DETECTION ===
Video: ________________________
FPS: _____ Total Frames: _____
PHASE DETECTION (frame numbers)
| Phase | Detected | Manual | Error | Notes |
|-------|----------|--------|-------|-------|
| Standing End | ___ | ___ | ___ | |
| Lowest Point | ___ | ___ | ___ | |
| Takeoff | ___ | ___ | ___ | |
| Peak Height | ___ | ___ | ___ | |
| Landing | ___ | ___ | ___ | |
LANDMARK QUALITY (per phase)
| Phase | Hip Visible | Knee Visible | Ankle Visible | Notes |
|-------|-------------|--------------|---------------|-------|
| Standing | Y/N | Y/N | Y/N | |
| Countermovement | Y/N | Y/N | Y/N | |
| Flight | Y/N | Y/N | Y/N | |
| Landing | Y/N | Y/N | Y/N | |
阶段检测标准
站立结束:髋部开始向下移动前的最后一帧
- 观察:髋部开始下降,膝盖开始弯曲
最低点:髋部达到最低高度的帧
- 观察:下蹲最深的位置,髋部处于最低 Y 坐标
起跳:双脚离开地面的第一帧
- 观察:脚尖/脚跟关键点与地面分离
- 注意:由于检测延迟,可能比肉眼看到的离地晚 1-2 帧
最高点:髋部达到最高高度的帧
- 观察:飞行过程中髋部处于最高 Y 坐标
落地:脚部接触地面的第一帧
- 观察:脚跟或脚尖关键点触及地面
- 注意:算法可能会晚 1-2 帧检测到(基于速度)
关键点质量评估
对于每个关键点,观察:
| 质量 | 标准 |
|---|---|
| 良好 | 关键点稳定,位于身体部位的正确位置 |
| 抖动 | 关键点在帧间振荡 ±5-10 像素 |
| 偏移 | 关键点持续偏离实际位置 |
| 丢失 | 关键点缺失或严重不准确 |
| 互换 | 左右关键点互换 |
观察结果记录格式
验证时,请提供结构化数据:
## Ground Truth: [video_name]
**Video Info:**
- Frames: 215
- FPS: 60
- Duration: 3.58s
- Camera: 45° oblique
**Phase Detection Comparison:**
| Phase | Detected | Manual | Error (frames) | Error (ms) |
|-------|----------|--------|----------------|------------|
| Standing End | 64 | 64 | 0 | 0 |
| Lowest Point | 91 | 88 | +3 (late) | +50 |
| Takeoff | 104 | 104 | 0 | 0 |
| Landing | 144 | 142 | +2 (late) | +33 |
**Error Analysis:**
- Mean absolute error: 1.25 frames (21ms)
- Bias detected: Landing consistently late
- Accuracy: 2/4 perfect, 4/4 within ±3 frames
**Landmark Issues Observed:**
- Frame 87-92: Hip jitter during lowest point
- Frame 140-145: Ankle tracking unstable at landing
可接受的误差阈值
在 60fps 下(每帧 16.67ms):
| 误差级别 | 帧数 | 时间 | 解释 |
|---|---|---|---|
| 完美 | 0 | 0ms | 完全匹配 |
| 极佳 | ±1 | ±17ms | 在人工观察误差范围内 |
| 良好 | ±2 | ±33ms | 对大多数指标而言可以接受 |
| 可接受 | ±3 | ±50ms | 可能影响精确计时指标 |
| 需要调查 | >3 | >50ms | 算法可能需要调整 |
偏差检测
查找多个视频中的系统性模式:
| 模式 | 含义 | 操作 |
|---|---|---|
| 持续 +N 帧 | 算法检测偏晚 | 提前调整阈值 |
| 持续 -N 帧 | 算法检测偏早 | 延后调整阈值 |
| 波动 ±N 帧 | 正常波动 | 无需操作 |
| 误差增大 | 跟踪效果下降 | 检查关键点质量 |
与 basic-memory 集成
存储地面实况观察结果:
# Save validation results
write_note(
title="CMJ Phase Detection Validation - [video_name]",
content="[structured observation data]",
folder="biomechanics"
)
# Search previous validations
search_notes("phase detection ground truth")
# Build context for analysis
build_context("memory://biomechanics/*")
示例:CMJ 验证研究参考
请参阅 basic-memory,查看完整验证研究:
biomechanics/cmj-phase-detection-validation-45deg-oblique-view-ground-truthbiomechanics/cmj-landing-detection-bias-root-cause-analysisbiomechanics/cmj-landing-detection-impact-vs-contact-method-comparison
验证研究的主要发现:
- 站立结束:准确率 100%(误差 0 帧)
- 起跳:平均误差约 0.7 帧(极佳)
- 最低点:平均误差约 2.3 帧(波动较大)
- 落地:持续偏差 +1-2 帧(需调查)
评论
支持 Markdown