ShuttlePoseReview 是一个面向羽毛球爱好者的动作复盘项目。它从普通手机录制的视频中提取人体 2D 骨架,识别明显重发力窗口,并把每次重发力动作拆解为三个可解释指标:击球时机、发力链、回位恢复。
项目目标是帮助业余球友更清楚地看到:这一拍有没有打到更合适的位置,发力是否从身体传到手腕,打完以后是否能及时回到下一拍准备状态。
- 上传一段羽毛球视频,生成本地复盘任务。
- Android 端可直接从手机相册选择视频,在本机完成抽帧、姿态识别和复盘。
- Android 端当前支持处理视频前 60 秒,适合训练后一段连续回合的快速复盘。
- 对视频做预处理,转为更适合浏览器和算法处理的 MP4。
- 使用人体姿态模型提取近端球员的 2D 骨架。
- 在视频上叠加骨架,生成可播放的动作复盘页面。
- 支持导出已经叠加姿态骨架的 MP4 视频,便于保存、分享或二次剪辑。
- 已复盘过的视频会在本地缓存结果,下次打开可直接查看,无需重复等待分析。
- 自动识别明显重发力窗口,而不是把所有放网、轻挡、过渡球都计为一次重发力。
- 为每个重发力窗口输出三项分数、动作等级参考和可展开证据卡。
- 输出结构化 JSON,方便后续做训练记录、横向对比和算法评估。
这一版重点完善 Android 端的真实使用体验,让复盘结果更接近 PC 端展示方式,也让普通球友更容易读懂评分依据。
- 开放 60 秒处理上限:Android 端现在会处理导入视频的前 60 秒,覆盖更多连续回合和多拍场景。
- 主页面正式落地:视频处理完成后进入复盘主页面,集中展示骨架叠加视频、击球状态、三项分数和时间线。
- 新增可读证据卡:击球、发力、回位三项都可以展开查看,底层姿态指标会被整理成等级、解释、置信度和训练建议。
- 中羽动作近似评估:基于单次动作的综合表现给出动作参考等级,用于复盘讨论,不等同于真实比赛水平判定。
- 更清晰的端上规则评价:不依赖 LLM 生成自由文案,而是用稳定规则把分数映射为
S / A / B / C / D等级和固定解释。 - 视觉细节优化:证据按钮颜色与上方三项分数保持一致,击球时机、发力链、回位恢复的视觉关联更明确。
推荐优先从 GitHub Releases 下载最新 APK:
https://github.com/waylean/shuttleposereview/releases
Android 构建方式:
cd apps/android
./gradlew :app:assembleDebugWindows PowerShell:
cd apps/android
.\gradlew.bat :app:assembleDebug安装后,点击“选择或导入视频”,等待复盘完成即可在结果页查看骨架叠加视频、重发力时间线和三项动作指标。结果页底部的“下载姿态合成视频”可以导出带骨架的 MP4。
演示视频文件:
assets/demo/badminton_review_demo.mp4
为了让结果更稳定,建议输入视频满足以下条件:
- 视频建议控制在 60 秒内,最好是一段连续回合或一个连续多拍片段。
- 如果直接上传更长的视频,Android 端当前会优先处理前 60 秒。
- 近端球员需要清晰可见,身体、手臂和脚步不要长期被遮挡。
- 手机低视角、侧后方或正后方拍摄都可以尝试,但同一用户做趋势对比时,最好保持相近机位。
- 当前更适合分析杀球、高远球、平抽、重发力过渡等明显挥拍动作;放网、轻挡等小动作可能不会单独计入重发力窗口。
上传视频
-> 视频预处理
-> 人体 2D pose 提取
-> 近端球员骨架与动作窗口分析
-> 三项指标计算
-> 生成复盘页面、叠加视频和 JSON 结果
Web MVP 的本地运行说明见:
apps/web/README.md
当前主要算法实现:
work/scripts/build_2d_action_review.py
完整公式说明:
docs/scoring_formula_spec.md
ShuttlePoseReview 当前不会直接判断“真实球速”或“真实发力大小”。系统先从骨架中计算关节角、速度、相对高度、躯干尺度和动作窗口,再把这些可观测代理变量转化为动作复盘指标。
击球时机回答的问题是:这一拍是否在更合适的位置和准备状态下完成发力。
核心观察量:
| 子项 | 含义 |
|---|---|
| 手腕高度 | 发力点附近,手腕是否处在更容易完成高点击球的位置 |
| 发力点肘角 | 肘部是否处在较合理的击球伸展区间 |
| 准备期姿态 | 击球前是否有架拍、抬手、侧身或肩髋打开迹象 |
| 主动手臂可见度 | 当前骨架数据是否足够可读 |
公式摘要:
timing_score
= clamp(
0.46 * height_score
+ 0.24 * elbow_score
+ 0.20 * prep_score
+ 0.10 * confidence_score
)
其中:
height_score = 0.55 * max_height_score + 0.45 * contact_height_score
elbow_score = band_score(elbow_angle_at_event; ideal=145°, tolerance=70°)
prep_score = 0.62 * prep_height_score + 0.38 * twist_score
合理性:
- 羽毛球重发力动作通常需要更好的击球高度和提前准备。
- 肘角不是越直越好,而是需要处在一个相对可发力的伸展区间。
- 准备期姿态可以区分“提前架拍发力”和“仓促抡拍”。
发力链回答的问题是:这一拍是否呈现出从下肢、躯干、手臂到手腕的连续加速节奏。
系统不会只看某一帧的最大速度,而是按事件帧 e 切出三个时间窗口:
leg_band = [e - 0.65F, e - 0.22F]
trunk_arm_band = [e - 0.38F, e - 0.06F]
wrist_band = [e - 0.18F, e + 0.08F]
其中 F 是视频帧率。
能量代理:
leg_energy = P80(knee_angular_speed in leg_band)
trunk_energy = P80(abs(twist_t - twist_{t-1}) * F in trunk_arm_band)
elbow_energy = P82(elbow_angular_speed in trunk_arm_band)
wrist_energy = P88(normalized_wrist_speed in wrist_band)
综合公式:
chain_score
= clamp(
0.32 * energy_score
+ 0.26 * order_score
+ 0.18 * wrist_late_score
+ 0.14 * knee_load_score
+ 0.10 * confidence_score
)
合理性:
energy_score判断这一拍是否真的有明显动作能量。order_score判断能量中心是否大体从下肢、躯干、肘部传到手腕。wrist_late_score判断手腕速度峰值是否贴近重发力事件帧。knee_load_score用击球前屈膝程度作为下肢参与的简化代理。
回位恢复回答的问题是:这一拍打完后,身体是否能较快回到可以衔接下一拍的状态。
计算窗口:
recover = [e + 0.12F, e + 1.20F]
稳定帧条件:
normalized_wrist_speed <= 1.15
elbow_angular_speed <= 360°/s
knee_angular_speed <= 300°/s
综合公式:
recovery_score
= clamp(
0.54 * recovery_time_score
+ 0.28 * residual_score
+ 0.18 * posture_score
)
合理性:
- 恢复时间越短,说明打完后越快回到可控制状态。
- 残余动作越小,说明随挥后身体没有继续大幅散开。
- 肩髋分离角回落,说明身体姿态更接近下一拍准备状态。
当前指标更适合:
- 同一用户、同一机位、相似动作之间做趋势对比。
- 帮助业余球友发现动作问题方向。
- 为训练复盘提供结构化参考。
当前指标不适合:
- 直接比较不同机位、不同距离、不同人的绝对水平。
- 测得真实羽毛球速度。
- 恢复出真实 3D 发力链或真实肌肉输出。
当前 Web MVP 使用 Python 虚拟环境运行:
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python -m uvicorn apps.web.main:app --host 127.0.0.1 --port 8787打开:
http://127.0.0.1:8787
如果端口被占用,可以换成:
python -m uvicorn apps.web.main:app --host 127.0.0.1 --port 8788系统还需要可用的 ffmpeg 命令,用于视频预处理。
一次分析通常会生成:
*_2d_action_review.html # 交互式复盘页面
*_2d_review_overlay.mp4 # 骨架叠加视频
*_2d_action_review.json # 结构化分析结果
每次重发力的完整公式证据位于:
stroke_metrics[].score_breakdown
这使得每个总分都可以追溯到具体的窗口、角度、速度、子分数和权重。
本项目受到多个开源项目和工具的启发与支持,包括但不限于:
- Good-Badminton:提供了羽毛球视频分析方向的重要启发。
- Va6lue/BST-Badminton-Stroke-type-Transformer(BST/BTS):提供了从骨架序列理解羽毛球动作类型的参考思路。
- MediaPipe:用于人体姿态和骨架点位提取。
- OpenCV:用于视频处理、帧读取和骨架叠加。
- FFmpeg:用于视频预处理和格式转换。
- FastAPI / Uvicorn:用于本地 Web MVP 的上传和任务服务。
