1. 项目概述与核心价值
去年在健身房带学员训练时,发现一个普遍痛点:很多人在做自重训练时,常常记不清自己完成了多少组动作。特别是俯卧撑和引体向上这类基础动作,训练者要么需要频繁中断查看训练日志,要么干脆凭感觉估算——这直接影响了训练效果的可量化性。当时我就想,能不能用计算机视觉技术解决这个问题?
经过多次技术选型,最终确定基于YOLO系列模型构建姿态估计系统。选择YOLO主要考虑三点:首先是实时性,YOLOv8在RTX 3060上能达到100+FPS;其次是多目标处理能力,可以同时监测健身房多个训练者;最重要的是其开源生态完善,社区提供了丰富的预训练模型和部署方案。
这个系统的核心功能是通过摄像头捕捉人体关键点,分析关节角度变化规律来实现动作计数。比如俯卧撑的典型特征就是肘关节角度周期性变化,当角度小于90度时判定为下压阶段,恢复伸直时计数+1。相比传统传感器方案,视觉方案无需穿戴设备,更适合健身房开放环境。
2. 技术方案设计与选型
2.1 YOLO模型选型对比
在YOLOv5、v7和v8之间做了详细测试对比:
- YOLOv5n(nano版)仅6MB大小,在树莓派上能跑15FPS,但关键点检测精度只有82%
- YOLOv7-w6达到94%精度,但模型体积增大到120MB
- YOLOv8s最终以89MB体积实现92%精度,在Jetson Xavier上实现45FPS
考虑到健身房实际部署需要平衡算力和精度,最终选择YOLOv8s作为基础模型。这里有个重要经验:不要盲目追求最新版本,v8的精度提升主要来自新的损失函数设计,但对姿态估计任务而言,v7的辅助头设计在某些场景反而更稳定。
2.2 关键点定义方案
采用COCO格式的17个关键点定义:
code复制0-nose 1-Leye 2-Reye 3-Lear 4-Rear
5-Lsho 6-Rsho 7-Lelb 8-Relb 9-Lwri
10-Rwri 11-Lhip 12-Rhip 13-Lkne
14-Rkne 15-Lank 16-Rank
对于俯卧撑计数,主要关注5/6/7/8号关键点(肩部和肘部)。引体向上则需要额外监测11/12号髋关节关键点。在实际标注时发现,健身房常见着装(背心/短裤)会导致髋关节关键点遮挡,后来通过数据增强增加了服装变异样本才解决。
2.3 动作判定算法
以俯卧撑为例,核心判定逻辑:
python复制def count_pushup(shoulder, elbow, wrist):
# 计算肘关节角度
angle = calculate_angle(shoulder, elbow, wrist)
# 状态机维护
if angle < 90 and not self.down_flag:
self.down_flag = True
elif angle > 160 and self.down_flag:
self.counter += 1
self.down_flag = False
return self.counter
这里有几个关键参数需要动态调整:
- 角度阈值要根据不同体型做自适应(胖瘦人群关节弯曲度不同)
- 需要添加时间窗口过滤抖动(建议300ms内的状态变化忽略)
- 对于不标准动作要设置置信度阈值(如手臂未完全伸直不计入)
3. 数据准备与模型训练
3.1 数据采集方案
搭建了多角度采集系统:
- 手机摄像头(1080P@30fps)从正面、侧面、俯视三个角度同步录制
- 邀请10位不同体型志愿者完成标准/非标准动作
- 最终获得约15小时原始视频(含20000+有效动作样本)
标注工具使用CVAT,关键技巧:
- 对模糊帧采用线性插值标注
- 设置快捷键加速肩肘关键点标注
- 导出时选择YOLO格式并保留原始图片尺寸
3.2 数据增强策略
针对健身房特殊环境设计的增强方案:
yaml复制augmentation:
- degrees: (-15, 15) # 旋转增强
- perspective: 0.001 # 透视变换
- flipud: 0.3 # 上下翻转
- fliplr: 0.5 # 左右翻转
- mosaic: 1.0 # 马赛克增强
- mixup: 0.2 # 图像混合
- copy_paste: 0.5 # 关键点粘贴
特别注意添加了光照变化和阴影模拟,因为健身房灯光条件复杂。实测显示加入copy_paste增强后,模型对局部遮挡的鲁棒性提升23%。
3.3 模型训练细节
使用YOLOv8s-pose预训练模型,关键配置:
python复制model = YOLO('yolov8s-pose.pt')
results = model.train(
data='coco-pose.yaml',
epochs=300,
imgsz=640,
device='0,1', # 双卡训练
optimizer='AdamW',
lr0=0.001,
warmup_epochs=5,
box=7.5, # 检测头权重
pose=0.5, # 姿态头权重
fl_gamma=1.5 # 焦点损失
)
训练过程中的重要发现:
- 姿态头学习率应该比检测头低20%
- warmup阶段对稳定训练至关重要
- 超过250epoch后会出现过拟合,需早停
最终在验证集上达到:
- 检测mAP@0.5: 0.947
- 关键点OKS: 0.892
- 推理速度:48FPS(Tesla T4)
4. 系统部署与优化
4.1 边缘设备部署方案
测试了三种硬件平台:
| 设备 | 推理速度 | 功耗 | 成本 | 适用场景 |
|---|---|---|---|---|
| Jetson AGX Orin | 58FPS | 30W | 高 | 专业健身房 |
| Jetson Xavier NX | 28FPS | 15W | 中 | 普通健身房 |
| Raspberry Pi 5 | 3FPS | 5W | 低 | 家庭使用 |
选择Jetson Xavier NX作为主力部署平台,使用TensorRT加速:
bash复制yolo export model=yolov8s-pose.pt format=engine device=0
优化后速度从原生ONNX的18FPS提升到28FPS。关键技巧:
- 启用FP16精度模式
- 调整检测阈值到0.6减少误报
- 使用异步推理管道
4.2 计数逻辑优化
原始方案存在两个问题:
- 快速半程动作会被漏计
- 多人交叉干扰
改进方案:
python复制class ActionCounter:
def __init__(self):
self.buffer = deque(maxlen=5) # 时序缓冲
self.thresholds = {
'pushup': {'down':85, 'up':150},
'pullup': {'down':30, 'up':170}
}
def update(self, pose):
self.buffer.append(pose)
if len(self.buffer) == 5:
# 计算移动平均角度
avg_angle = np.mean([p.elbow_angle for p in self.buffer])
# 动态调整阈值
curr_thresh = self.thresholds[self.action_type]
if avg_angle < curr_thresh['down'] * 0.9:
self.adjust_thresholds(scale=0.95)
同时添加了基于IOU的多人跟踪算法,使用OC-SORT解决交叉问题。
4.3 用户界面设计
采用Gradio快速搭建演示界面:
python复制demo = gr.Interface(
fn=process_video,
inputs=gr.Video(),
outputs=[
gr.HTML(label="计数结果"),
gr.Image(label="姿态可视化")
],
examples=[["pushup_sample.mp4"]]
)
实际部署时改用Flask+WebSocket实现低延迟视频流:
python复制@app.route('/video_feed')
def video_feed():
return Response(
generate_frames(),
mimetype='multipart/x-mixed-replace; boundary=frame'
)
前端使用JavaScript解析WebSocket数据,实时更新计数和姿势提示。
5. 常见问题与解决方案
5.1 误检问题排查
现象:镜面反射导致重复计数
解决方案:
- 在预处理中添加镜像检测算法
- 对检测框添加ROI限制(只关注地面以上1.5m区域)
- 后处理中过滤对称姿态
现象:宽松衣物导致关键点漂移
解决方案:
- 训练数据添加更多宽松服装样本
- 在角度计算时使用加权平均(肩部关键点权重更高)
- 添加速度约束(相邻帧关键点移动不超过20像素)
5.2 性能优化记录
问题:树莓派上帧率不足3FPS
优化步骤:
- 将输入分辨率从640降至320
- 使用OpenCV的DNN模块替代PyTorch
- 量化模型到INT8
- 禁用非关键输出(如不显示置信度)
优化后达到8FPS,内存占用从1.2GB降至400MB。关键发现:在ARM平台使用OpenCV的DNN比ONNX Runtime快2倍。
5.3 实际部署经验
环境适配:
- 健身房强光环境下需要调整曝光补偿
- 摄像头高度建议1.8-2.2米,倾斜30度
- 避免直对镜面或玻璃门
用户反馈改进:
- 添加语音提示功能(使用edge-tts实现)
- 对不标准动作给出可视化指引
- 生成训练报告(含动作幅度曲线)
6. 效果评估与扩展方向
在1000次俯卧撑测试中:
- 标准动作识别率:98.7%
- 半程动作识别率:89.2%
- 误检率:1.3%
下一步计划:
- 扩展支持深蹲、卷腹等20种常见动作
- 集成生理参数估计(通过呼吸频率预测力竭时间)
- 开发团体课多人同步分析功能
这个项目的关键收获是:计算机视觉在垂直领域的应用,必须深入理解行业细节。比如最初没考虑健身房的镜面问题,导致第一版demo完全不可用。现在系统已经在本地的三个健身房试运行,教练们最欣赏的是它能自动生成学员的动作质量报告。