ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

Python+MediaPipe+OpenCV实现深蹲姿势识别与计数源码解析

Python+MediaPipe+OpenCV实现深蹲姿势识别与计数源码解析 简介本资源是一套面向健身教练、运动科学学习者及Python计算机视觉初学者的深蹲姿势分析实践代码包聚焦于利用开源技术实现人体姿态评估与动作质量判别。压缩包共含3个Python源文件总大小2.43MB核心涵盖视频流实时捕获、关键帧姿态解析及演示可视化三大功能模块分别对应运动数据采集、OpenCV姿态估计模型调用、关节角度计算与结果呈现等关键环节。代码结构清晰模块职责分明已封装基础依赖调用与典型参数配置便于快速部署调试。目前已有222人下载学习适合希望掌握OpenCV图像处理、人体关键点检测如OpenPose轻量集成、运动生物力学指标提取如髋膝踝角度动态分析及Matplotlib可视化联动的实践者可直接复用于深蹲教学反馈系统开发或拓展至其他力量训练动作分析场景。 深蹲姿势分析-python源码.zip这是我最近整理完的一个小项目。名字起得比较直白内容也确实不绕弯子用 Python 加 MediaPipe 加 OpenCV 做了一套深蹲动作识别与计数工具打开摄像头就能实时检测也能丢一段视频进去离线分析。核心功能就三块实时捕捉人体骨骼关键点、计算膝盖和髋关节角度、用动作状态机判断每次深蹲是否标准并自动计数。这个包适合三类人拿去看一是正在学姿态识别、但不想自己从头训练模型的人二是想做个健身辅助工具、需要现成思路的开发者三是课程设计或毕业设计选了动作识别方向、想找一个能落地的参考项目。源码已经整理成 zip 压缩包解压后按 README 里的步骤把依赖装好直接就能跑起来。1. 项目总体设计与思路拆解1.1 为什么选 MediaPipe而不是自己训练姿态模型先说选型。做人体姿态估计业内绕不开的无非三条路OpenPose、MediaPipe或者自己从头训一个关键点检测网络。OpenPose 精度不错但依赖重、模型大CPU 上跑实时基本别想自己训模型的成本更夸张要标几万张人体图片要有 GPU 环境还要处理数据增强、损失函数、后处理一堆东西。对于“深蹲姿势分析”这种单场景轻量级需求属于典型的杀鸡用牛刀。MediaPipe 的 Pose 模块则是把预训练好的 BlazePose 模型封装成了开箱即用的 Python 接口pip 一条命令装完CPU 上就能实时跑 30 帧以上直接输出人体 33 个关键点的坐标和置信度。打个比方MediaPipe 就像一个已经认识所有骨骼位置的老师傅你只需要把画面交给他再从他嘴里读出每个关节的位置坐标剩下的判断和计数逻辑完全由自己掌控。所以在项目里我把所有“检测人体”的脏活累活都交给 MediaPipe自己只做三件事从 landmark 里抽取需要的关节坐标用三点夹角公式计算膝盖角度再写一个状态机把角度序列翻译成“下蹲”“站起”“完成一次”。这种分工最大的优势是把复杂度隔离在模块边界之外核心代码加起来不过 200 行别人拿到源码包想改也好改。1.2 项目要解决的三个核心问题这个项目不是单纯做一个深蹲计数器它围绕的是健身场景里最常见的三个问题。第一个问题是动作是否标准。很多人健身时其实完全不知道自己蹲得够不够深、膝关节角度有没有达到 90 度附近。这里我选择用膝盖弯曲角度作为核心判据站直时膝盖角在 170 度到 180 度下蹲到标准位置时大约在 90 度左右整个过程角度从大变小再变大天然就是一个干净的波形信号。第二个问题是每一次完整动作怎么界定。深蹲不是“蹲下去”就算一次而是从站姿到下蹲、再回到站姿才算完成。如果只靠一个固定角度阈值判断会在临界点来回抖动造成重复计数。所以我设计了一个简单的状态机用 UP 和 DOWN 两个状态描述当前身体处于“站起”还是“下蹲”状态切换时才更新计数。第三个问题是使用场景。健身房里用平板或手机摄像头看回家想回看自己的动作视频这两种需求差异很大。源码里同时实现了摄像头实时模式和视频文件离线模式通过命令行参数切换不必为两种模式维护两套逻辑。1.3 技术栈与源码包结构规划技术栈比较克制核心依赖只有三个opencv-python 负责读取视频帧和画面绘制mediapipe 负责姿态关键点检测numpy 负责少数数值计算。代码里所有的关节角度计算其实只用了 math 库安装环境时会少踩很多依赖冲突的坑。源码压缩包内部结构我特意整理成了适合二次开发的形态而不是把所有代码塞进一个文件里文件作用main.py入口负责视频读取、循环调度、画面绘制pose_utils.py角度计算、角度平滑、landmark 索引映射config.py阈值参数、摄像头索引、显示选项等所有可调配置requirements.txt依赖清单README.md安装步骤、运行命令、参数说明demo_squat.mp4一段用于测试的深蹲演示视频之所以最后打包成 zip而不是直接贴代码是因为这个项目涉及的模块文件、模型配置和测试视频比较多zip 能保持完整的目录结构下载时也更方便校验完整性。而且 zip 是跨平台通用的压缩格式Windows、macOS、Linux 都能直接解压拿到包的人不需要额外装 7-Zip 或 WinRAR。2. 核心细节解析与实操要点2.1 骨骼关键点索引与膝盖角度计算MediaPipe Pose 输出的 landmark 是 33 个点的数组每个点包含 x、y、z 和 visibility。对深蹲来说关心的主要是髋关节、膝关节和踝关节左髋索引 23、左膝 25、左踝 27右髋 24、右膝 26、右踝 28。需要提醒的是索引如果不查文档硬记非常容易搞混我前期就因为在代码里把 24 和 23 用反了导致一侧膝盖角度算出来始终是钝角排查了半天。角度计算我用的是经典的三点夹角公式。以膝盖为顶点把髋关节和踝关节看作另外两个点用反正切函数分别求出两条向量的方向角再取差值绝对值import math def calc_angle(a, b, c): # a 和 c 分别是关节两端的点b 是顶点 ba math.atan2(a.y - b.y, a.x - b.x) bc math.atan2(c.y - b.y, c.x - b.x) angle abs(math.degrees(ba - bc)) if angle 180: angle 360 - angle return angle有同学可能会问为什么不直接算大腿和竖直方向的夹角因为三点夹角是纯几何定义跟摄像头摆放角度无关不受人体出现在画面左右位置的影响鲁棒性更好。不过也要承认这种方法依赖单目摄像头当人体深度方向变化过大、脚和髋不在同一平面时误差会变大所以在实测时我要求人尽量侧对摄像头这样膝盖弯曲的弧度在画面里最明显。2.2 角度平滑与置信度过滤MediaPipe 返回的 landmark 坐标并非每帧都稳定尤其画面有轻微抖动或肢体遮挡时角度值会出现毛刺。如果不做平滑画面上显示的角度会在真实值附近反复横跳状态机也容易误判。我做了两层防抖。第一层是 visibility 过滤MediaPipe 会对每个关键点给出一个 0 到 1 之间的置信度低于 0.5 的直接认定当前帧无效保留上一帧的角度值。第二层是滑动平均保留最近 5 帧的角度做平均相当于把高频抖动滤掉一层。实测下来这个组合对普通手机拍摄的视频效果非常明显角度曲线从锯齿状变成了平滑的弧线。调参的时候注意一个权衡平滑窗口越大曲线越干净但动作的真实转折点也会被延迟导致计数时机偏晚。5 帧窗口在 30 帧每秒的视频里大约是 0.17 秒的延迟体感基本无感我会建议新手先按这个配置来。2.3 状态机计数与滞回区间角度平滑解决的是“看着不乱跳”的问题但计数逻辑里还有一个更隐蔽的坑如果在角度阈值边缘抖动会出现蹲到一半上下反复横跳、计数疯狂增加的情况。比如把“下蹲”阈值设在 100 度深蹲到 99 度时触发了 DOWN但下一秒身体微抬到 101 度又回到 UP然后再蹲又触发一次实际只做了一次动作却可能被计两三次。解决方法是给阈值加一个滞回区间让进入和离开某个状态使用不同的阈值。这个思路在很多控制系统里都有比如空调压缩机启动温度和停止温度不一样就是为了避免频繁启停。具体到深蹲计数UP 0 DOWN 1 def update_state_machine(angle, state, count, down_threshold100, up_threshold135): if state UP and angle down_threshold: state DOWN elif state DOWN and angle up_threshold: state UP count 1 return state, count这里下蹲到 100 度以下才进入 DOWN 状态站起到 135 度以上才回到 UP 同时计数加一。100 到 135 之间的区间就是滞回带角度在这个范围内抖动不会触发状态翻转。这个设计是整套计数逻辑里最值得注意的部分改代码时千万别把两个阈值改成同一个值否则立刻回到重复计数的老问题。3. 实操过程与核心环节实现3.1 环境准备Python 版本与依赖安装项目基于 Python 3.9 开发用 3.8 到 3.11 实测都能顺利跑通。Python 3.12 存在一部分老版本 numpy 和 opencv wheel 不兼容的问题建议先建虚拟环境再装依赖避免污染系统环境。python -m venv squat_env source squat_env/bin/activate pip install -r requirements.txtrequirements.txt 的内容大概是这样的opencv-python4.8.0 mediapipe0.10.0 numpy1.24.0国内网络环境下mediapipe 这个包体积不小直接 pip 安装容易超时。可以把 pip 源切换到清华镜像速度会快很多。如果你是第一次用 Python装完后在命令行敲python -c import mediapipe, cv2没有报错就说明环境正常。IDE 我推荐 VSCode 加 Python 插件调试时可以看到每一帧的 landmark 坐标对理解代码逻辑很有帮助。3.2 核心代码拆解主循环、角度抽取与画面绘制主程序 main.py 是一个标准的生产者-消费者循环读一帧画面、交给 MediaPipe 检测、抽取坐标、计算角度、更新状态机、把结果画到画面上。中间任何一步返回异常都会退出循环并释放摄像头资源。import cv2 import mediapipe as mp mp_pose mp.solutions.pose pose mp_pose.Pose( static_image_modeFalse, model_complexity1, min_detection_confidence0.5, min_tracking_confidence0.5, ) cap cv2.VideoCapture(0) # 0 是默认摄像头换视频时改成视频路径 state UP count 0 angle_history [] while cap.isOpened(): ret, frame cap.read() if not ret: break rgb_frame cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results pose.process(rgb_frame) if results.pose_landmarks: landmarks results.pose_landmarks.landmark left_angle get_knee_angle(landmarks, sideleft) right_angle get_knee_angle(landmarks, sideright) angle (left_angle right_angle) / 2 angle smooth_angle(angle, angle_history) state, count update_state_machine(angle, state, count) cv2.putText(frame, fKnee Angle: {angle:.1f}, (20, 40), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) cv2.putText(frame, fCount: {count}, (20, 80), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) cv2.putText(frame, fState: {DOWN if state DOWN else UP}, (20, 120), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2) cv2.imshow(Squat Analysis, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()这段代码是精简后的主循环实际源码包里还多了取两侧膝盖角度均值的逻辑。之所以取均值而不是只看一侧是因为人下蹲时身体可能轻微左右不对称取均值对判断总体动作深度更公平。当然代价是如果某一侧关键点被遮挡均值就会偏所以代码里保留了 visibility 过滤一旦某侧置信度不够就自动只依赖另一侧。3.3 源码包的导入、解压与运行命令拿到 zip 压缩包后先别急着双击养成先确认文件完整性的习惯。Linux 和 macOS 上可以用file deep_squat_analysis.zip查看真实文件类型正常会输出Zip archive dataWindows 用户直接看文件后缀和大小如果下载后只有几 KB基本是下载中断了。解压命令方面Linux 和 macOSunzip 深蹲姿势分析-python源码.zip -d squat_analysisWindows 可以用资源管理器解压也可以在 PowerShell 里用Expand-Archive这个命令比第三方工具稳定且遇到中文文件名乱码的概率更低。解压完成后进入目录确认有 main.py 和 requirements.txt 两个文件再安装依赖。运行方式分成两种# 摄像头实时模式 python main.py --camera 0 # 视频离线模式 python main.py --video demo_squat.mp4--camera 0里的 0 是摄像头索引笔记本自带摄像头一般是 0外接 USB 摄像头可能需要改成 1这块我见过太多人卡住后面常见问题里会细说。离线分析时视频尽量选侧面视角拍的人物完整出现在画面里效果最好。3.4 判定标准如何进一步细化膝盖角度只是判断深蹲深度的一个维度。很多人下蹲时膝盖角度到了 90 度但上身过度前倾或者膝盖明显超过脚尖这些动作仍然有受伤风险。所以在源码包里我在 config.py 里预留了髋关节角度的计算位置思路跟膝盖角度一样用肩、髋、膝三点计算躯干与大腿的夹角再判断躯干是否低于水平线。更进一步可以统计膝盖在水平方向相对脚尖的位置取膝关节和踝关节的屏幕坐标差值如果膝盖 x 坐标超出脚尖 x 坐标一定像素就认为膝盖前探过度。这些规则不建议一次性全加先跑通主流程再逐个扩展否则变量太多反而排查困难。4. 常见问题与排查技巧实录4.1 拿到 zip 压缩包后解压失败或报错这个项目是 zip 分发自然要聊几句 zip 相关的问题。最常见的是下载完提示file is not a zip file原因几乎都是文件没下载完整或者网站把它存成了 .html 后缀。处理办法很简单Linux 用file命令看真实格式Windows 用 7-Zip 打开确认如果发现是网页重定向产生的 html 文件重新找下载链接别反复尝试重命名。另一个高频报错是invalid zip archive: could not find eocd。EOCD 是 zip 格式最末尾的结束标记找不到它说明文件被截断。这种情况可以用内置修复命令恢复zip -FF damaged.zip --out repaired.zip这个命令会扫描 zip 中残留的本地文件头尽可能重建目录结构。如果核心源码文件都被修复出来了就能正常解压。需要说明的是如果 zip 包本身带密码且密码丢失修复和恢复都比较麻烦。这类密码恢复工具只建议用来找回自己加密的备份文件个人项目源码通常没必要加密码加了反而给使用者制造障碍我打包时就没有设置密码。现象可能原因解决办法file is not a zip file下载不完整或文件后缀错误重新下载用 file/7-Zip 检查真实格式could not find eocd压缩包被截断用 zip -FF 尝试修复解压后中文文件名乱码zip 编码不一致用 7-Zip 或 Expand-Archive 解压有密码但忘记密码加密时使用的是自定义密码密码恢复工具只用于找回自己的备份4.2 Python 环境与依赖装不上的问题pip install mediapipe慢到想砸电脑是绝大多数人遇到的第一个坎。解决办法就是把 pip 指向清华镜像pip install -r requirements.txt -i https://pypi.tuna.tsinghua.edu.cn/simple装完之后如果 import mediapipe 直接报 DLL load failed大多数情况是缺少 Visual C 运行库。Windows 用户装一下 Microsoft Visual C Redistributable 2015-2022 x64这个问题基本就消失了。macOS 不太会遇到这个但个别版本需要xcode-select --install装命令行工具。另一个容易忽略的是 numpy 版本冲突。因为 mediapipe 对 numpy 1.x 的老版本有依赖如果你之前装过 numpy 2.0可能会出现类型转换报错。稳妥的做法是顺序执行先建干净虚拟环境再按 requirements.txt 安装让 pip 自动解析依赖树而不是手动逐个 pip install。4.3 识别效果差、计数不准确怎么调检测效果不理想优先排查的是拍摄角度和遮挡。MediaPipe 对侧脸、背面、身体被遮挡的情况非常敏感而深蹲又是前后方向动作所以最好的拍摄角度是正侧面让髋、膝、踝三个点始终可见。如果画面中检测不到人先确认人物和摄像头距离是否太远建议占比超过画面高度的三分之一。角度值持续乱跳时优先上调滑动平均窗口把config.py里的SMOOTH_WINDOW从 5 调到 8 或 10。代价是动作响应会稍微迟钝但计数稳定性提高明显。计数偏多时优先检查滞回区间把DOWN_THRESHOLD调低、UP_THRESHOLD调高让两个状态切换吃得更深。还有一个小细节是 MediaPipe 默认只追踪画面中的一个人如果画面里出现了别人或者镜子里的自己检测会不稳定尽量保持画面干净。4.4 摄像头打开失败或画面卡顿cv2.VideoCapture(0)打不开摄像头时最常见原因是摄像头索引不对。笔记本自带摄像头是 0外接 USB 摄像头经常会变成 1 或 2。改索引比想象中更玄学有时候插拔一次 USB 口索引就变了所以我把摄像头索引也放进了 config.py方便大家不用改代码直接调。画面卡顿一般是分辨率太高。MediaPipe 在 1080p 下 CPU 占用会拉到接近满载帧率自然上不去。我实测把分辨率固定到 640x480 后从十几帧直接跳到稳定 30 帧完全够用。可以在打开摄像头后加这两行cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)5. 后续可以怎么玩从计数到动作打分5.1 把判定规则升级成标准分制目前的版本在画面上只显示膝盖角度、动作状态和计数这满足计数需求但对“姿势是否标准”的判断比较粗糙。我设想过一个更完整的方案把膝盖角、髋关节角、膝盖前探距离三个维度分别量化打分。比如膝盖角度在 80 到 100 度之间给满分低于 70 或高于 120 扣分髋关节角度反映躯干前倾程度前倾小于 30 度算合格膝盖水平位移不超过脚尖算合格。三个维度的分数汇总成 0 到 100 的标准分低于 60 就在画面上用红色显示“注意姿势”。这个升级不需要换模型只是在现有 landmark 基础上多算几个角度代码量也不大适合作为二次开发的第一个练手方向。5.2 加一个语音提示或音效如果真要在健身时用眼睛盯着屏幕是不现实的。一套完整的深蹲辅助工具应该能“听见”反馈蹲到位时响一声站起时响一声或者直接播放“下蹲”“起立”的语音指令。实现上可以用 pygame 播放音效文件也可以调用系统自带的 tts 引擎合成语音。这个功能我在分支版本里做过一版接入点就在更新状态机之后状态切换时触发播放即可对主流程侵入很小。5.3 记录运动日志做长期数据追踪另一个顺手就能扩展的点是输出运动日志。目前可以每隔一帧把时间戳、膝盖角度、动作状态写入 CSV 文件练完一次就能看到每一次深蹲的深度曲线。如果你有兴趣还可以把单次深蹲的曲线长度、最低点角度、动作持续时间存成一条记录一段时间后就能直观看到自己的稳定性和耐力变化。这是从“计数工具”走向“运动分析工具”比较自然的一步。我在实际使用中发现把角度序列画成曲线比看实时数字直观得多深蹲效率高不高一眼就能看出来。源码包里我没有把曲线绘制加进去但已经在 README 里留了扩展思路有兴趣的话可以自己加上。真要总结这个项目给我的感受那就是姿态估计的入门门槛已经低到不可思议关键不在模型而在于你如何把模型的输出转化成有用的业务逻辑。代码里最花时间的地方不是调 API而是想明白怎么用状态机处理动作时序、怎么用滞回区间压制抖动。这些经验放在任何一个传感器数据处理场景里都通用。整个项目我在录好的视频上反复测试了一个晚上确认计数稳定后才放到摄像头实时环境里跑实际测试下来稳得很。本文还有配套的精品资源点击获取
返回列表