公司动态

树莓派实时仰卧起坐计数系统:离线轻量级动作识别全流程

📅 2026/9/3 12:33:04
树莓派实时仰卧起坐计数系统:离线轻量级动作识别全流程
简介本资源是一个面向深度学习初学者与嵌入式/边缘端开发者的轻量级健身动作识别实战项目聚焦仰卧起坐计数这一典型场景解决无GPU设备下实时人体姿态估计与动作判别难题适用于个人健身APP开发、智能硬件集成及课程设计等低算力部署需求。压缩包共423个文件35.6MB含348张标注用人体姿态图像jpg、46个核心Python脚本涵盖PyTorch轻量化网络构建、数据加载、训练推理及Qt标注工具逻辑、8张界面与热力图示例png/gif、6个JSON格式关键点标注文件、4个Qt UI界面定义ui及1个ONNX模型与1个训练权重pth结构清晰模块分离明确。已有60人学习下载提供从摄像头采集→Qt图形化标注→姿态特征提取→轻量CNNLSTM动作分类→实时计数可视化全流程代码与文档附带操作演示GIF、标注工具截图及完整说明开箱即用支持快速二次开发与性能调优。1. 这不是“又一个AI健身App”而是一套可落地、可复刻、真正跑在树莓派和老旧笔记本上的仰卧起坐计数系统我去年帮社区老年活动中心做一套居家健身辅助工具核心需求很朴素老人在家铺个垫子做仰卧起坐手机或旧平板放旁边不连WiFi、不上传视频、不依赖云服务就能实时数个数、判动作是否标准、语音提醒“第5个再坚持一下”。听起来简单但市面上所有标榜“AI健身”的App要么要求iPhone 12以上iOS 16要么必须联网调用云端API要么一开摄像头就烫手关机。我们最终交付的这套系统主程序在树莓派4B4GB内存上稳定运行CPU占用率峰值不超过65%单帧推理耗时83ms全程离线所有代码开源训练数据自己采、标注工具自己写、模型自己剪枝——它不是Demo是能放进抽屉里、插上电就干活的实体设备。标题里那个长长的后缀“_从零实现数据采集标注训练部署全流程_适用于无GPU环境的实时动作识别与健身计数_包含PyTorch轻量化网络设计Qt标注工具开发与.zip”不是营销话术是实打实的工作流切片。它拆解了整个项目最硬的四块骨头怎么拿到真实人体视频数据采集→ 怎么让标注不靠人力堆时间Qt工具→ 怎么让模型小到能在ARM芯片上跑PyTorch轻量化→ 怎么把算法塞进一个带界面的本地程序部署闭环。这四个环节环环相扣漏掉任何一个所谓“实时计数”就是空中楼阁。比如你用MediaPipe直接拿关键点省了训练但它的默认模型在树莓派上每秒只能跑3帧根本卡不住动作节奏又比如你用YOLOv8-pose精度高但模型体积120MB树莓派SD卡都装不下。我们选的路是“重投入、轻交付”前期花三周写标注工具、两周做数据增强、一个月调参剪枝换来的是最终用户双击exe就能运行连Python环境都不用装。关键词里反复出现的“轻量级”在这里不是指模型参数少而是指整套系统的资源占用边界清晰、可预测、可收敛。它意味着CPU使用率不超过70%留出余量给系统进程、内存常驻≤380MB树莓派Swap分区不触发、单次启动时间8秒老人等不了、误检率4.7%数错10个里不能错半次。这些数字不是拍脑袋定的是我们在社区中心实测27位老人、累计1362组动作后统计出来的。标题最后那个“.zip”是项目交付物的真实形态——一个压缩包解压后双击run.bat弹出Qt界面点“开始计数”摄像头亮起屏幕上跳动数字语音报数“1…2…3…”。没有服务器没有账号没有隐私泄露风险也没有任何需要用户理解的技术概念。这就是我们定义的“轻量级”。2. 为什么必须从零造轮子数据采集与标注的底层逻辑重构2.1 真实场景数据比公开数据集更“脏”也更“真”市面上所有公开的人体姿态数据集——COCO、MPII、PoseTrack——都是在专业影棚里用多机位、高分辨率、均匀打光、穿紧身衣的模特拍的。而我们的目标用户65岁张阿姨穿着厚棉睡衣、客厅灯光昏暗、摄像头是二手华为Mate9前置镜头分辨率仅1080p自动对焦慢半拍、背景里还有一只猫来回走动。直接拿COCO预训练模型微调结果是衣服褶皱被识别成肘关节猫尾巴晃动触发“起身”判定灯光阴影让髋部关键点漂移±15像素。我们试过用OpenPose在COCO上训好的模型对张阿姨视频的F1-score只有0.51连及格线都没摸到。所以第一件事不是调模型而是建自己的数据集。我们定了三条铁律拍摄设备统一全部用红米Note102021年千元机前置摄像头固定三脚架距离垫子1.8米环境强约束只在上午9-11点自然光下拍摄背景用纯灰布帘RGB值128,128,128杜绝反光和杂色动作标准化请社区健身教练示范标准仰卧起坐肩胛骨离地≥15cm、下放时肩胛骨触垫、全程腰背贴地每个动作录3遍每遍30秒覆盖快/中/慢三种节奏。最终采集了127人年龄52-78岁男女各半每人21组视频7种速度×3次重复总时长42.6小时原始视频文件大小1.2TB。但这只是“原料”离能喂给模型的“饲料”还差得远。2.2 Qt标注工具不是“画框”而是构建动作语义的翻译器公开标注工具LabelImg、CVAT本质是“像素级画框”适合目标检测。但姿态估计要标的是关节拓扑关系动作时序状态。比如仰卧起坐关键不是标出“膝盖在哪”而是定义“躯干屈曲角度30°且髋关节角速度15°/s”才叫“起身阶段”。如果用传统工具一帧一帧标17个关键点21组视频×30秒×30帧18900帧按每帧标1分钟算一个人就要315小时——这根本不现实。我们用Qt C重写了标注逻辑核心突破在三个层面骨架模板预置加载视频时自动生成17节点标准人体骨架基于COCO拓扑用户只需拖拽节点到对应关节系统自动计算初始骨骼长度比例后续帧用光流法追踪人工只需每5帧校正一次动作状态机嵌入界面右侧有状态栏显示当前帧所属动作阶段“准备”“起身”“顶点”“下放”“触垫”用户点击状态按钮工具自动在时间轴上标记该状态起止帧并生成状态转移图物理约束校验标完一帧系统实时计算各关节角度如髋角、膝角若超出人体生理极限如髋角180°弹窗提示“疑似标注错误”并高亮异常关节。这个工具把单帧标注时间从60秒压到8秒更重要的是它把“标关键点”升级为“定义动作语义”。最终产出的标注文件不是JSON数组而是结构化CSVvideo_id,frame_id,stage,hip_angle,knee_angle,spine_flexion,tracked 001,127,起身,42.3,156.7,28.1,True 001,128,起身,45.1,155.2,31.4,True ...这种格式让后续训练时能直接用角度特征做损失函数而不是单纯回归坐标——这是精度提升的关键伏笔。2.3 数据增强不是“加噪声”而是模拟真实退化链公开数据增强RandomRotation、ColorJitter对COCO有效但对我们的数据无效。因为真实退化不是随机的老旧手机摄像头的摩尔纹有固定方向LED灯频闪导致运动模糊呈周期性棉质睡衣纹理会随身体弯曲产生规律性形变。我们构建了“退化链模拟器”硬件层退化用ffmpeg模拟红米Note10的ISP处理流程——先加Bayer阵列马赛克4×4再经双线性插值重建最后叠加CMOS热噪声σ12.7光照层退化用OpenCV生成渐变阴影模拟窗帘遮挡强度按时间轴正弦变化模拟云层飘过运动层退化对关键点轨迹施加LSTM预测误差用真实老人动作数据训的LSTM输出预测偏差作为抖动向量。增强后的数据模型在测试集上的mAP提升11.3%但更关键的是线上误检率下降了37%——因为模型学会了区分“真实动作抖动”和“摄像头抖动”。这印证了一个经验面向边缘设备的AI数据增强的本质是让模型提前适应硬件缺陷而不是追求图像美观。提示Qt标注工具编译时务必关闭Qt WebEngine模块它占内存320MB用QPainter替代QWebEngineView渲染视频帧。我们实测关闭后内存占用从680MB降到210MB标注流畅度提升3倍。3. 轻量级不是“砍参数”而是用PyTorch做外科手术式模型精简3.1 为什么不用现成轻量模型MobileNetV3HRNet的陷阱初版我们试过MobileNetV3 backbone接HRNet head参数量1.8M理论FLOPs 2.1G看起来很轻。但在树莓派上实测单帧推理124msCPU满载风扇狂转。问题出在HRNet的“高分辨率分支保持”机制——它为了维持关键点精度强制保留4个尺度的特征图每个尺度都要做跨尺度融合内存带宽成了瓶颈。树莓派的LPDDR4带宽仅25GB/s而HRNet在256×256输入下特征图交换需18GB/s几乎榨干带宽。我们转向“单尺度强后处理”路线用TinyPoseICCV 2021思想但彻底重写。核心决策是放弃像素级关键点回归改用“区域投票几何约束”。具体分三步Stage1粗定位用深度可分离卷积Depthwise Separable Conv构建5层CNN输出16×16热图每个关节一个通道分辨率为输入的1/16Stage2精修正对热图峰值位置裁剪32×32局部区域送入3层小MLP预测该区域内的亚像素偏移dx, dyStage3几何滤波用预存的“仰卧起坐人体比例模板”肩宽:髋宽1.23±0.07对17个关键点做RANSAC拟合剔除偏离模板超过2σ的异常点。这个架构把参数量压到412KFLOPs降至0.43G内存占用峰值210MB最关键的是——它把计算瓶颈从内存带宽转移到CPU缓存。树莓派的L2缓存1MB足够放下整个模型权重避免频繁访存。实测单帧耗时稳定在83ms±5ms功耗仅1.8W。3.2 PyTorch里的“减法艺术”三处关键剪枝实录轻量化不是删层是精准切除冗余计算。我们在PyTorch里做了三处手术激活函数替换把所有ReLU6换成HardSwishx * F.relu6(x 3) / 6在低比特量化下精度损失0.3%但ARM NEON指令集有原生支持加速1.7倍BatchNorm融合训练完后用torch.quantization.fuse_modules()将ConvBNReLU融合为单一Conv层减少32%的kernel launch开销通道剪枝不是按L1范数剪而是用动作敏感度分析——冻结模型对每个通道注入高斯噪声σ0.1统计“髋角误差增幅”剪掉增幅0.5°的通道。最终剪掉23%通道精度仅降0.8%但推理速度提升21%。注意PyTorch 2.0的torch.compile()对我们的模型无效——它优化的是GPU kernel而我们跑在CPU上。必须用torch.jit.trace()导出ScriptModule再用torch.jit.optimize_for_inference()做CPU专属优化。实测后者比前者快1.4倍。3.3 训练策略用角度损失替代坐标损失精度跃升的底层原因传统姿态估计用MSE Loss回归坐标但我们发现对仰卧起坐计数关节角度误差比坐标误差重要10倍。比如髋角误差5°可能导致“起身”判为“未起身”但坐标误差10像素在1080p画面里只占0.9%不影响计数。所以我们设计了复合损失函数L_total 0.6 * L_angle 0.3 * L_heatmap 0.1 * L_reg # L_angle: 各关节角度髋、膝、脊柱的MAE权重按生物力学重要性分配 # L_heatmap: 热图KL散度保证基础定位能力 # L_reg: L2权重衰减防过拟合训练时用AdamWlr3e-4但学习率预热只做200步不是常规的1000步因为小模型收敛快长预热反而降低最终精度。验证集用“动作阶段F1-score”代替mAP因为计数依赖阶段识别准确率。最终模型在测试集上髋角MAE2.1°膝角MAE3.4°脊柱屈曲角MAE1.8°为后续规则引擎打下坚实基础。4. 从模型到产品Qt部署闭环与实时计数规则引擎4.1 Qt不是“做个UI”而是构建低延迟数据管道很多项目把PyTorch模型封装成DLLQt调用结果卡顿严重。问题在于Python GIL锁死、数据拷贝多次、线程调度混乱。我们的解法是全C部署用LibTorchPyTorch C前端加载.pt模型视频采集用QtMultimedia的QVideoSink直接获取YUV420帧避免RGB转换开销图像预处理resize、normalize用OpenCV的cv::dnn::blobFromImage()启用NEON加速关键点后处理热图解析、RANSAC全部用Eigen库手写不调OpenCV。整个Pipeline在Qt主线程外用QThread独立运行帧率锁定30FPS。实测端到端延迟摄像头捕获→屏幕显示数字仅112ms完全满足实时性要求。对比方案PythonOpenCV方案延迟280ms且偶发卡顿。4.2 计数规则引擎用物理规则堵住AI的“幻觉”模型输出关键点但“数个数”是逻辑判断。我们没用LSTM或Transformer做序列建模太重而是设计了一套基于物理约束的有限状态机FSM状态定义5个状态——Prep准备、Up起身、Top顶点、Down下放、Touch触垫转移条件全部用角度阈值速度阈值例如Prep → Up当hip_angle 90° AND d_hip_angle/dt 12°/sUp → Top当hip_angle 30° AND |d_hip_angle/dt| 2°/s计数触发仅当状态序列完整经过Prep→Up→Top→Down→Touch且Touch状态持续≥0.3秒才计1次。这套规则把误计数率从模型原始输出的12.7%压到3.9%。更妙的是它能诊断动作质量如果Up→Top耗时2.1秒语音提示“起身太慢注意发力”如果Touch时脊柱屈曲角5°提示“下放时腰没贴地”。这才是健身助手的价值不是冷冰冰的数字。4.3 零GPU环境下的极致优化树莓派实测配置清单所有优化最终要落在硬件上。以下是树莓派4B4GB的实测配置OSRaspberry Pi OS Lite64-bit禁用桌面环境仅启ssh和cameraPython3.9.2系统自带不装Anaconda避免环境臃肿PyTorch1.13.1cpu官方预编译包pip install torch1.13.1cpu torchvision0.14.1cpu -f https://download.pytorch.org/whl/torch_stable.htmlOpenCV4.5.5源码编译时加-D CMAKE_BUILD_TYPERELEASE -D CMAKE_INSTALL_PREFIX/usr -D OPENCV_DNNON -D ENABLE_NEONON -D ENABLE_VFPV3ONQt6.5.0用./configure -no-opengl -no-gui -no-widgets -skip qtwebengine最小化编译。最终打包体积主程序12.3MB模型文件3.8MB总安装包20MB。用户下载zip解压双击start.shLinux或run.batWindows自动检查依赖缺失则静默安装全程无需命令行。实操心得树莓派上cv2.VideoCapture(0)默认用V4L2驱动但延迟高。必须加参数cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(M,J,P,G))启用MJPG压缩延迟从180ms降到65ms。这个参数在OpenCV文档里藏得很深但它是实时性的生死线。5. 常见问题与排查技巧实录那些文档里不会写的坑5.1 摄像头兼容性问题不是所有USB摄像头都“即插即用”我们测试了17款USB摄像头只有8款在树莓派上稳定工作。问题根源在UVC协议版本雷蛇Kiyo ProUVC 1.5支持H.264硬件编码但树莓派固件不识别需更新rpi-update罗技C920UVC 1.1MJPG模式完美但YUY2模式下白平衡失效国产杂牌多数只支持YUY2且驱动不规范cap.read()返回空帧概率37%。解决方案强制指定像素格式和分辨率cap cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FOURCC, cv2.VideoWriter_fourcc(M,J,P,G)) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) cap.set(cv2.CAP_PROP_FPS, 30)如果仍失败用v4l2-ctl --list-devices查设备ID再v4l2-ctl -d /dev/video0 --set-fmt-videowidth640,height480,pixelformatMJPG手动设置。5.2 Qt界面黑屏不是代码错是OpenGL上下文冲突在树莓派上Qt默认用OpenGL渲染但树莓派的VC4驱动对OpenGL ES支持不稳定常导致QVideoWidget黑屏。根治方法编译Qt时加-no-opengl运行时加环境变量export QT_QPA_PLATFORMeglfs在代码中强制用Raster绘图QApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);我们曾花两天调试黑屏最后发现是QVideoSink和QPainter争抢GPU上下文。切换到Raster后CPU占用增加8%但稳定性100%。5.3 模型精度骤降检查你的归一化参数PyTorch模型训练时预处理是transforms.Normalize(mean[0.485, 0.456, 0.406], std[0.229, 0.224, 0.225])但OpenCV读图是BGR顺序且像素范围0-255。很多人直接img / 255.0忘了BGR→RGB转换和均值方差。正确做法img cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # 先转RGB img img.astype(np.float32) / 255.0 # 再归一化 img (img - [0.485, 0.456, 0.406]) / [0.229, 0.224, 0.225] # 最后标准化漏掉cv2.cvtColor精度直接掉15%——因为模型在RGB上训的喂BGR就是喂错数据。5.4 计数不准时间戳不同步引发的幽灵bugQt的QTimer和OpenCV的cap.read()时间戳不同步导致状态机判断时序错乱。例如模型在t100ms输出“Top”状态但Qt界面在t105ms才刷新此时实际已进入“Down”状态。修复方案用QElapsedTimer做统一时钟QElapsedTimer timer; timer.start(); while(running) { cap.read(frame); auto t_capture timer.elapsed(); // 统一时间基准 // ... 推理、状态判断、UI更新全部基于t_capture }这个改动让计数一致性从92%提升到99.4%。5.5 部署包太大用UPX压缩PyTorch二进制LibTorch的libtorch.so有120MB是包体积大头。用UPX压缩upx --ultra-brute libtorch.so压缩后32MB解压运行速度不变UPX是运行时解压。注意必须用UPX 4.0旧版本不支持ARM64。我在社区中心交付那天张阿姨第一次用做完15个仰卧起坐屏幕跳出“完成平均速度1.8秒/个腰背全程贴地”她笑着拍大腿“这比我家老头掐表准”——那一刻我知道技术的价值不在参数多炫而在它能否稳稳托住一个普通人的日常。这套系统里没有一行代码是为炫技而写每个优化都来自老人一句“再快点”、一次“没数对”的抱怨。如果你也在做边缘AI落地记住轻量级的终点不是模型多小而是用户打开它时心里想的不是“这玩意儿怎么用”而是“今天我能做几个”。本文还有配套的精品资源点击获取