news 2026/9/3 12:32:53

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
树莓派实时仰卧起坐计数系统:离线轻量级动作识别全流程

简介:本资源是一个面向深度学习初学者与嵌入式/边缘端开发者的轻量级健身动作识别实战项目,聚焦仰卧起坐计数这一典型场景,解决无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图形化标注→姿态特征提取→轻量CNN+LSTM动作分类→实时计数可视化全流程代码与文档,附带操作演示GIF、标注工具截图及完整说明,开箱即用,支持快速二次开发与性能调优。

1. 这不是“又一个AI健身App”,而是一套可落地、可复刻、真正跑在树莓派和老旧笔记本上的仰卧起坐计数系统

我去年帮社区老年活动中心做一套居家健身辅助工具,核心需求很朴素:老人在家铺个垫子做仰卧起坐,手机或旧平板放旁边,不连WiFi、不上传视频、不依赖云服务,就能实时数个数、判动作是否标准、语音提醒“第5个,再坚持一下”。听起来简单?但市面上所有标榜“AI健身”的App,要么要求iPhone 12以上+iOS 16,要么必须联网调用云端API,要么一开摄像头就烫手关机。我们最终交付的这套系统,主程序在树莓派4B(4GB内存)上稳定运行,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,连及格线都没摸到。

所以第一件事,不是调模型,而是建自己的数据集。我们定了三条铁律:

  • 拍摄设备统一:全部用红米Note10(2021年千元机),前置摄像头,固定三脚架,距离垫子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数组,而是结构化CSV:

video_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 为什么不用现成轻量模型?MobileNetV3+HRNet的陷阱

初版我们试过MobileNetV3 backbone接HRNet head,参数量1.8M,理论FLOPs 2.1G,看起来很轻。但在树莓派上实测:单帧推理124ms,CPU满载,风扇狂转。问题出在HRNet的“高分辨率分支保持”机制——它为了维持关键点精度,强制保留4个尺度的特征图,每个尺度都要做跨尺度融合,内存带宽成了瓶颈。树莓派的LPDDR4带宽仅25GB/s,而HRNet在256×256输入下,特征图交换需18GB/s,几乎榨干带宽。

我们转向“单尺度+强后处理”路线:用TinyPose(ICCV 2021)思想,但彻底重写。核心决策是:放弃像素级关键点回归,改用“区域投票+几何约束”。具体分三步:

  • Stage1:粗定位:用深度可分离卷积(Depthwise Separable Conv)构建5层CNN,输出16×16热图(每个关节一个通道),分辨率为输入的1/16;
  • Stage2:精修正:对热图峰值位置,裁剪32×32局部区域,送入3层小MLP,预测该区域内的亚像素偏移(dx, dy);
  • Stage3:几何滤波:用预存的“仰卧起坐人体比例模板”(肩宽:髋宽=1.23±0.07),对17个关键点做RANSAC拟合,剔除偏离模板超过2σ的异常点。

这个架构把参数量压到412K,FLOPs降至0.43G,内存占用峰值210MB,最关键的是——它把计算瓶颈从内存带宽转移到CPU缓存。树莓派的L2缓存1MB,足够放下整个模型权重,避免频繁访存。实测单帧耗时稳定在83ms(±5ms),功耗仅1.8W。

3.2 PyTorch里的“减法艺术”:三处关键剪枝实录

轻量化不是删层,是精准切除冗余计算。我们在PyTorch里做了三处手术:

  • 激活函数替换:把所有ReLU6换成HardSwish(x * F.relu6(x + 3) / 6),在低比特量化下精度损失<0.3%,但ARM NEON指令集有原生支持,加速1.7倍;
  • BatchNorm融合:训练完后,用torch.quantization.fuse_modules()将Conv+BN+ReLU融合为单一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权重衰减,防过拟合

训练时,用AdamW(lr=3e-4),但学习率预热只做200步(不是常规的1000步),因为小模型收敛快,长预热反而降低最终精度。验证集用“动作阶段F1-score”代替mAP,因为计数依赖阶段识别准确率。最终模型在测试集上,髋角MAE=2.1°,膝角MAE=3.4°,脊柱屈曲角MAE=1.8°,为后续规则引擎打下坚实基础。

4. 从模型到产品:Qt部署闭环与实时计数规则引擎

4.1 Qt不是“做个UI”,而是构建低延迟数据管道

很多项目把PyTorch模型封装成DLL,Qt调用,结果卡顿严重。问题在于:Python GIL锁死、数据拷贝多次、线程调度混乱。我们的解法是全C++部署

  • 用LibTorch(PyTorch C++前端)加载.pt模型;
  • 视频采集用QtMultimedia的QVideoSink,直接获取YUV420帧,避免RGB转换开销;
  • 图像预处理(resize、normalize)用OpenCV的cv::dnn::blobFromImage(),启用NEON加速;
  • 关键点后处理(热图解析、RANSAC)全部用Eigen库手写,不调OpenCV。

整个Pipeline在Qt主线程外,用QThread独立运行,帧率锁定30FPS。实测端到端延迟(摄像头捕获→屏幕显示数字)仅112ms,完全满足实时性要求。对比方案:Python+OpenCV方案延迟280ms,且偶发卡顿。

4.2 计数规则引擎:用物理规则堵住AI的“幻觉”

模型输出关键点,但“数个数”是逻辑判断。我们没用LSTM或Transformer做序列建模(太重),而是设计了一套基于物理约束的有限状态机(FSM):

  • 状态定义:5个状态——Prep(准备)、Up(起身)、Top(顶点)、Down(下放)、Touch(触垫);
  • 转移条件:全部用角度阈值+速度阈值,例如:
    Prep → Uphip_angle < 90° AND d_hip_angle/dt > 12°/s
    Up → Tophip_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环境下的极致优化:树莓派实测配置清单

所有优化最终要落在硬件上。以下是树莓派4B(4GB)的实测配置:

  • OS:Raspberry Pi OS Lite(64-bit),禁用桌面环境,仅启sshcamera
  • Python:3.9.2(系统自带),不装Anaconda,避免环境臃肿;
  • PyTorch:1.13.1+cpu(官方预编译包),pip install torch==1.13.1+cpu torchvision==0.14.1+cpu -f https://download.pytorch.org/whl/torch_stable.html
  • OpenCV:4.5.5,源码编译时加-D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr -D OPENCV_DNN=ON -D ENABLE_NEON=ON -D ENABLE_VFPV3=ON
  • Qt:6.5.0,用./configure -no-opengl -no-gui -no-widgets -skip qtwebengine最小化编译。

最终打包体积:主程序12.3MB,模型文件3.8MB,总安装包<20MB。用户下载zip解压,双击start.sh(Linux)或run.bat(Windows),自动检查依赖,缺失则静默安装,全程无需命令行。

实操心得:树莓派上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 Pro:UVC 1.5,支持H.264硬件编码,但树莓派固件不识别,需更新rpi-update
  • 罗技C920:UVC 1.1,MJPG模式完美,但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-video=width=640,height=480,pixelformat=MJPG手动设置。

5.2 Qt界面黑屏:不是代码错,是OpenGL上下文冲突

在树莓派上,Qt默认用OpenGL渲染,但树莓派的VC4驱动对OpenGL ES支持不稳定,常导致QVideoWidget黑屏。
根治方法

  • 编译Qt时加-no-opengl
  • 运行时加环境变量:export QT_QPA_PLATFORM=eglfs
  • 在代码中强制用Raster绘图:QApplication::setAttribute(Qt::AA_UseSoftwareOpenGL);

我们曾花两天调试黑屏,最后发现是QVideoSinkQPainter争抢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 计数不准:时间戳不同步引发的幽灵bug

Qt的QTimer和OpenCV的cap.read()时间戳不同步,导致状态机判断时序错乱。例如:模型在t=100ms输出“Top”状态,但Qt界面在t=105ms才刷新,此时实际已进入“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落地,记住:轻量级的终点,不是模型多小,而是用户打开它时,心里想的不是“这玩意儿怎么用”,而是“今天我能做几个”。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/3 12:32:33

mysql安装及基础设置

关系型数据库 MySQL是一种关系型数据库管理系统&#xff0c;采用了关系模型来组织数据的数据库&#xff0c;关系数据库将数据保存在不同的表中&#xff0c;用户通过查询 sql 来检索数据库中的数据。 yum 方式安装 mysql 安装默认版本的 mysql # yum -y install mysql-server…

作者头像 李华
网站建设 2026/9/3 12:31:25

QtScrcpy 手机投屏实操指南:3 步投屏、无线连接与多设备控制

QtScrcpy 手机投屏实操指南&#xff1a;3 步投屏、无线连接与多设备控制 【免费下载链接】QtScrcpy Android real-time display control software 项目地址: https://gitcode.com/GitHub_Trending/qt/QtScrcpy 把手机接上电脑后想"看到"屏幕不难&#xff0c;难…

作者头像 李华
网站建设 2026/9/3 12:29:20

校园电竞赛事全流程策划指南:从赛制设计到现场执行

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/3 12:28:04

游戏作弊码技术解析:从输入检测到效果执行的实现原理

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/3 12:27:54

R语言生信分析:KEGG富集结果可视化与桑基图绘制实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/3 12:24:54

20个经典模拟电路深度解析:从原理到实践,夯实硬件工程师核心技能

这次我们来看一个对电子工程师和硬件开发者至关重要的基础技能集&#xff1a;20个经典模拟电路。无论是准备技术面试、巩固基础知识&#xff0c;还是进行电路设计实践&#xff0c;这些电路都是绕不开的核心。它们不仅是笔试和面试中的高频考点&#xff0c;更是理解复杂电子系统…

作者头像 李华