简介:这套基于PP-TinyPose的健身做操辅助工具源码,面向Python开发者、计算机视觉学习者及毕业设计选题学生,聚焦利用姿态估计技术识别人体关键点,辅助运动动作规范与科学训练。项目完整度较高,共112个文件、压缩包约165MB,主要包含38个Python脚本(主程序、视频预处理、界面演示等)、26个编译后的pyc文件、4组模型权重参数(.pdiparams/.pdmodel)、6个YAML配置文件、UI界面文件、JSON数据及MP4示例视频,并附带项目说明与依赖列表,便于快速搭建运行环境。当前已有104人学习下载,适合作为人工智能或计算机视觉课程的实践项目。通过阅读和运行这套代码,能够深入理解PP-TinyPose在真实场景中的调用方式、视频关键帧处理流程以及从模型推理到交互界面的完整实现思路,为后续开展运动分析或智能健身应用开发提供扎实参考。
1. 为什么健身做操辅助工具选择 PP-TinyPose
先给结论:我们不需要“看懂人在做什么”,只需要知道“人做得到不到位”。健身做操辅助工具的核心是把摄像头画面里的人体骨骼抽出来,再把肩、肘、腕、髋、膝、踝这几个关节的角度变成可计算的数字。PP-TinyPose 在这里的定位是轻量级姿态估计模型,它能在 CPU 上跑出可用帧率,对单人或小范围多人场景足够稳,所以很多 Python 源码项目拿它来做健身纠错、跟练打卡和动作计数。
标题里那个python开发基于PP-TinyPose的健身做操辅助工具程序源码.zip,落地时其实不是一个大模型工程,而是“姿态估计模型 + 动作规则 + 视频流控制 + 结果展示”的组合。我一般把它拆成四条线:模型推理线负责出 17 个关键点坐标;规则线负责把坐标换算成角度和计数;输出线负责在画面上画骨架和提示;打包线负责让源码 zip 在别人电脑上能解压即跑。这条线对新手友好,对老手来说真正值得花时间的反而是角度阈值、状态机和计数的防抖逻辑。
2. 先理解 PP-TinyPose 的姿态估计基础与工程取舍
2.1 PP-TinyPose 在 PaddleDetection 全家桶里的位置
PP-TinyPose 是 PaddleDetection 里常见的轻量级关键点检测方案。和 OpenPose 那种 bottom-up 思路不同,PP-TinyPose 走的是 top-down 思路:先从画面里检测出人框,再在框内做关键点回归。这个思路意味着人越少效果越稳;两个人互相遮挡时,检测框重叠会直接拉低关键点精度。做居家健身辅助工具时,摄像头正对单人是最理想的,这点很关键。
PaddleDetection 把 PP-TinyPose 和前置检测器打包成一套推理流程。前置检测器负责给人框,PP-TinyPose 负责在每个人框里输出 17 个 COCO 格式关键点。工程上我们不需要自己写网络结构,官方推理脚本已经完成了解码、后处理和坐标还原,我们要做的是把关键点数组接到自己的逻辑里。源码 zip 里如果带着deploy/python/keypoint_infer.py,那推理入口基本就在这。
2.2 输入图像归一化与关键点输出格式
关键点输出一般是一个[人数, 17, 3]的结构,最后一维是x, y, score。x 和 y 已经还原回原图分辨率,score 是关键点置信度,范围 0 到 1。做健身辅助时,我一般只取 score 大于 0.5 的骨架点参与计算,低于这个阈值的点位置不可信,宁可不算也不要拿噪声去算角度。
模型输入前需要做归一化,官方脚本会处理 resize、归一化和通道顺序。自定义推理时常见的错误是直接把 OpenCV 的 BGR 帧传给模型,结果通道对不上。正确的顺序是:cv2.resize到模型输入尺寸,用cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)转 RGB,再按模型配置做标准化。这个细节看起来小,实际经常造成“检测框在但骨架乱飘”。
2.3 为什么不用 OpenPose 或 MediaPipe 而用 PP-TinyPose
MediaPipe 也有姿态估计,轻量且易用,但它的输出逻辑和 Paddle 生态的解析方式不一样。OpenPose 精度高,但是体积大、CPU 慢,做本地源码工具并不划算。选择 PP-TinyPose 的主要原因有三个:第一,它能在 CPU 上用较短推理延迟跑出单路视频流;第二,PaddleDetection 自带导出和推理工具,不用自己拼后处理;第三,如果后续要换国产加速硬件或用 PaddleLite 转部署,同一套模型能少踩一遍格式坑。
如果你跑的是健身做操辅助工具,需要 25 帧左右的关键点输出才能让计数不卡顿。GPU 随意,CPU 上则要控制输入分辨率,一般 128x96 或 192x128 的输入足够判断大动作;再高就会拖慢帧率。这里要提醒一点:模型输入分辨率决定的是“人体姿态”的精度,不是画面显示分辨率。显示可以 1080p,推理输入缩到小图即可。
提示:在源码里看到
tinypose_128x96或tinypose_256x192这类目录名,指的就是模型输入尺寸 MMxNN,前者更适合 CPU 实时,后者精度更高但更慢。
3. 搭建本地 Python 工程:依赖、配置与最小推理代码
3.1 建立项目目录并正确配置 Python 环境
先不要急着双击运行,先把环境做干净。项目目录我一般按“模型、代码、测试图片、配置”四块组织,避免把权重和源码混在一起:
fitness_pose/ ├── .venv/ ├── model/ │ └── pptinypose_128x96/ ├── src/ │ ├── detector.py │ ├── skeleton.py │ └── counter.py ├── configs/ │ └── infer_cfg.yml ├── tests/ │ └── squat.jpg └── requirements.txt创建虚拟环境时,用 python 安装教程里最常见的步骤即可:
cd fitness_pose python -m venv .venv source .venv/bin/activate注意 Windows 下激活命令是.venv\Scripts\activate,macOS/Linux 下才是source。激活后建议先把基础包装上:
pip install --upgrade pip pip install paddlepaddle opencv-python numpy其中paddlepaddle是 CPU 版,带 GPU 的机器可以按自己 CUDA 环境换成paddlepaddle-gpu。这里我故意不装 pandas 之类的大包,健身辅助工具的推理链路用不到。装完后跑python -c "import paddle; print(paddle.__version__)"确认环境能用,后面所有报错都先回到这一步,看是环境问题还是代码问题。
3.2 用官方推理脚本验证模型是否连通
推理入口不建议自己重写,尤其是后处理那段。PaddleDetection 的deploy/python/keypoint_infer.py已经能把帧或者视频文件变成带关键点的可视化结果。先用一张手机拍的全身照验证模型和依赖:
python deploy/python/keypoint_infer.py \ --model_dir=model/pptinypose_128x96 \ --image_file=tests/squat.jpg \ --device=CPU \ --threshold=0.5 \ --save_dir=output/这段命令的参数含义:--model_dir指向导出的模型目录,目录里至少要有inference.pdmodel、inference.pdiparams和inference.yml;--image_file是输入图片;--device=CPU强制用 CPU;--threshold是关键点置信度阈值,低于 0.5 的点不画;--save_dir指定输出目录。如果这一步能生成带骨架的图片,说明依赖和模型都通,接下来才可以接入摄像头。
3.3 把摄像头帧接入姿态估计主循环
官方脚本能处理单张图,但做操辅助工具要处理摄像头连续帧,所以我会把它封装成一个可复用的检测器。核心循环如下:
import cv2 from detector import PoseDetector det = PoseDetector( model_dir="model/pptinypose_128x96", device="CPU", threshold=0.5, ) cap = cv2.VideoCapture(0) if not cap.isOpened(): raise RuntimeError("无法打开摄像头,检查索引 0 是否被占用") while True: ok, frame = cap.read() if not ok: break keypoints, scores = det.infer(frame) for idx, (x, y) in enumerate(keypoints): if scores[idx] >= det.threshold: cv2.circle(frame, (int(x), int(y)), 4, (0, 255, 0), -1) cv2.imshow("fitness_pose", frame) if cv2.waitKey(1) & 0xFF == 27: break cap.release() cv2.destroyAllWindows()PoseDetector内部负责调keypoint_infer.py对应的 Python API,整个循环只要关心三件事:读帧、取关键点、画骨架。cv2.waitKey(1)括号里的 1 表示每帧等待 1 毫秒,同时给 OpenCV 处理窗口事件的机会;改成 0 会导致画面卡在按任意键才继续。det.infer返回的是归一化到原图尺寸的x, y坐标,所以可以直接画在原帧上,不需要手动缩放。若返回的是相对坐标,就需要乘回frame.shape[1]和frame.shape[0],这个要看封装层的约定。
3.4 检测不到人时先检查这几个参数
运行后如果画面里没人,或者骨架偶尔消失,我先检查三处:置信度阈值是否设得过高、模型输入尺寸是否太大拖慢 CPU、前后帧之间是否做了关键点跟踪。PP-TinyPose 本身不做跨帧跟踪,每帧独立输出。如果分数忽高忽低,可以在帧层面做个轻量级临时处理:上一帧有关键点、这一帧缺失时,沿用上一帧坐标,最多沿用 3 帧。这个策略做动作计数时很实用,但要注意别让静止画面“冻结”太久。
下面的参数表是 CPU 场景下我通常会调的:
| 参数 | 建议值 | 作用 |
|---|---|---|
| threshold | 0.4~0.6 | 控制关键点置信度过滤,越低越容易画出噪声 |
| warmup_frames | 5 | 推理时跳过前 5 帧,让 CPU 调度和内存预分配稳定 |
| box_thresh | 0.5 | 控制前置人框置信度,多人遮挡时提高这个值 |
| input_size | 128x96 或 256x192 | 越小越快,越大约准,做操场景先选小尺寸 |
4. 把关键点变成健身动作:夹角计算、动作计数与做操质量判断
4.1 COCO 17 关键点索引映射
PP-TinyPose 输出的是 COCO 17 点格式,索引顺序直接决定角度公式取哪几个点。做操辅助工具最常用的是肩、肘、腕、髋、膝、踝这 12 个点:
| 索引 | 关键点 | 索引 | 关键点 |
|---|---|---|---|
| 5 | 左肩 | 6 | 右肩 |
| 7 | 左肘 | 8 | 右肘 |
| 9 | 左腕 | 10 | 右腕 |
| 11 | 左髋 | 12 | 右髋 |
| 13 | 左膝 | 14 | 右膝 |
| 15 | 左踝 | 16 | 右踝 |
取点时最容易被绕晕的是“左右”方向。有些模型按画面视角的左右标,有些按人物自身的左右标,建议先在测试图上把每个索引号的 x 坐标打印出来,对比左右肩的 x 大小,确定自己手里的模型是哪一种。这个方向一旦反了,左右对称性检查就会完全错误。
4.2 用余弦定理计算肘关节和膝关节角度
角度计算用三个关键点构成两条向量,求向量夹角的余弦值。以右肘角为例,点分别是右肩、右肘、右腕:
import numpy as np def angle_between(a, b, c): ba = a - b bc = c - b cosine = np.dot(ba, bc) / ( np.linalg.norm(ba) * np.linalg.norm(bc) + 1e-6 ) return float(np.degrees(np.arccos(np.clip(cosine, -1.0, 1.0)))) right_elbow_angle = angle_between( keypoints[6], keypoints[8], keypoints[10] )np.clip(cosine, -1.0, 1.0)是为了避免浮点误差导致arccos收到略大于 1 或小于 -1 的值而返回 NaN。分母里加1e-6是为了防止三点完全重合时除零。这个函数同样能算膝盖角、髋角、肩角,只需要换传入的索引。
肩关节和髋关节在身体没有侧转时,基本能反映躯干角度变化。肘角和膝角是健身动作里最容易定义阈值的两个量,因为它们对“伸直”和“弯曲”区分明显。做操动作质量判断不追求医学级角度,只追求稳定一致,因此阈值范围比精确数值更重要。
4.3 用阈值状态机完成动作计数而不是裸阈值
做计数时最忌讳的是每帧单独判断“是否达到阈值”。比如深蹲,膝盖角小于 90 度算下蹲,大于 170 度算站直。如果一帧膝盖角是 91 度,下一帧是 89 度,计数会不停地重复触发,所以需要状态机。
def count_squat(knee_angle, state): if knee_angle < 90 and state["phase"] != "down": state["phase"] = "down" elif knee_angle > 160 and state["phase"] == "down": state["count"] += 1 state["phase"] = "up" return state["count"]状态变量phase只经历up -> down -> up的切换,只有从 down 回到 up 时才计数一次。先进入 down 状态,再回到 up 状态,这样一段完整动作只触发一次。参数 90 和 160 是阈值,phase初始值是"up"。如果你要计数的是向上举手臂,就把阈值换成肘角 < 90 表示上举、> 150 表示放下,思路不变。
这个状态机对噪声还不够,我一般会再加一个“连续 N 帧满足条件才切换”。比如膝盖角连续 5 帧小于 90 度才确认进入 down,连续 5 帧大于 160 度才确认回到 up。这样即使有 1 到 2 帧的偶然抖动,计数不会乱。这个连续帧数stable_frames是动作灵敏度参数,我通常取 3 到 5,拿摄像头的真实帧率微调。
4.4 做操质量判断:左右角度差和躯干倾斜
做操辅助工具除了计数,还要能提醒“这次动作不标准”。最实用的指标是左右对称度和躯干倾斜度。左右对称度用左肘角和右肘角的差值,差值的绝对值超过 15 到 20 度时提示身体歪。躯干倾斜度用左肩到左髋的向量和垂直方向的夹角,超过 15 度提示弯腰。
def quality_report(kpt, threshold=15.0): left_elbow = angle_between(kpt[5], kpt[7], kpt[9]) right_elbow = angle_between(kpt[6], kpt[8], kpt[10]) asymmetry = abs(left_elbow - right_elbow) torso_vec = kpt[5] - kpt[11] vertical = np.array([0.0, 1.0]) cos_tilt = np.dot(torso_vec, vertical) / (np.linalg.norm(torso_vec) + 1e-6) tilt = abs(np.degrees(np.arccos(np.clip(cos_tilt, -1.0, 1.0)))) if asymmetry > threshold: return "左右肩臂不对称", asymmetry if tilt > threshold: return "躯干倾斜", tilt return "动作基本正常", max(asymmetry, tilt)这段代码每次都返回提示文字和偏差值。实际产品里不要直接显示“动作基本正常”,容易让用户疲劳;更好的做法是只在偏差超过阈值时显示红色提示,其他时间保持安静。threshold可以按动作类型分别配置,比如开合跳关注手肘和膝盖,深蹲关注膝盖和躯干,而不是一套阈值通吃。
5. 打包与分发:整理源码 zip、冻结依赖与常见坑
5.1 源码 zip 里到底应该放什么
标题里的 zip 代表的是交付物,不是项目目录本身。我一般不会把paddlepaddle这种 400MB 以上的依赖打进 zip,也不会把模型权重打进去。压缩包只放 Python 源码、配置、测试图片和requirements.txt,模型权重让用户按 README 里的下载脚本自己拉。否则 zip 解压后用户跑不起来,大概率是模型权重路径对不上,而不是代码写错。
requirements.txt不要用pip freeze一股脑导出,那会把本地环境里所有包都带上。只需要手写推理链路真正依赖的包:
paddlepaddle==2.5.1 opencv-python==4.8.1.78 numpy==1.24.3这里列出来的版本范围只是为了演示固定版本的重要性,具体以你的模型和部署设备环境为准。手写的好处是用户能一眼看出要装什么,坏处是版本没有全局锁,所以我通常在 README 里再写一句“以上版本均为最低测试版本,更新小版本不影响运行”。
5.2 打包前要清理的三类文件
第一类是虚拟环境和缓存,.venv、__pycache__、*.pyc会让 zip 体积膨胀且在不同电脑上不可移植。第二类是模型输出和临时目录,比如output/、inference_result/下的一大堆推理图片。第三类是隐私数据,测试图片里如果有完整人脸,放进 zip 发布前要想清楚要不要模糊处理。一个稳妥的打包命令是:
zip -r fitness_pose.zip . \ -x ".venv/*" \ -x "__pycache__/*" \ -x "*.pyc" \ -x "output/*" \ -x "model/*"这条命令用-x排除路径和通配符。由于 zip 默认会保留空目录,建议打包前先删掉output等目录,或者接受 zip 里多个空目录,这对运行没有影响。
5.3 验证 zip 可复现的三步命令
给别人发源码 zip 之前,我会先换一个干净目录验证一遍。第一步看压缩包完整性,第二步解压,第三步按新环境安装依赖并跑通最小命令:
unzip -t fitness_pose.zip cd /tmp && unzip -q fitness_pose.zip cd fitness_pose python -m venv .venv && source .venv/bin/activate pip install -r requirements.txt python src/detector.py --demo如果pip install因为网速或源的问题失败,常见做法是在 README 里给出国内镜像源命令。这一步不是为了演示打包,而是要回答“为什么在我电脑上能跑,在用户电脑上就跑不起来”这类问题。
5.4 发布 zip 前最后一个动作:跑一次带计数的回归测试
给动作计数代码发一个新 zip 版本时,我会固定用同一段做操视频做回归测试。视频时长 30 秒,内容包含 10 次完整动作,代码跑完后自动打印count=10才允许发布。把这段回归测试放进tests/test_counter.py,用pytest执行,比每次手工摆姿势靠谱得多。最终 zip 里带上这个回归测试文件和测试视频的下载地址,源码包的专业度会高一个档次。
本文还有配套的精品资源,点击获取