简介:这份资源是基于Mediapipe实现动作识别的Python毕业设计源码包,面向计算机视觉、机器学习方向的本科或研究生毕业设计选题者,也适合想入门姿态估计与动作分类的开发者。项目以Mediapipe的Pose模块为核心,通过实时检测并跟踪头部、肩部、肘部、手腕、髋部、膝盖、脚踝等关键关节,结合SVM、随机森林或CNN等模型完成动作分类,并借助OpenCV处理视频流、matplotlib展示识别结果,覆盖数据预处理、模型训练、实时检测与结果展示等完整模块。压缩包共7个文件,包含3个py源码、2个csvi与2个csv数据文件,整体约97KB,体积轻量便于快速运行与二次开发。目前已有242人学习下载,读者可据此理解Mediapipe管道与计算节点机制,掌握关键点序列到动作标签的建模思路,并参考代码结构完成自己的毕业设计系统搭建与论文撰写。
1. 从一份能跑通的 MediaPipe 动作识别源码说起
如果你正在做计算机方向的毕业设计,选题又落在「人体动作识别」这个方向,大概率会遇到一个很现实的问题:算法论文看了一堆,但真正要交出一个能演示、能答辩、能写进论文系统实现章节的东西,却迟迟搭不起框架。这份基于 MediaPipe 的动作识别 Python 源码包,解决的正是这个从零到一的问题。它把摄像头采集、人体关键点提取、动作判定、界面展示这几件事串成了一条完整链路,适合计算机、软件工程、电子信息等专业做毕业设计的学生,也适合想快速验证姿态识别效果的开发者。你拿到手不是一堆散落的脚本,而是一个能直接跑起来、能改、能往论文里写的工程雏形。
2. MediaPipe 姿态估计的底层逻辑与源码结构拆解
2.1 为什么选 MediaPipe 而不是自己训模型
做动作识别,绕不开「人体关键点检测」这一步。传统做法是自己标注数据集、训练一个姿态估计网络,比如 OpenPose 或者 HRNet,光是环境配置和权重下载就能耗掉一周,更别说训练需要的显卡资源。MediaPipe 的思路完全不同,它把 Google 已经训练好的轻量级模型封装成开箱即用的 API,你只需要调用几行代码就能拿到 33 个人体关键点的坐标。
这背后的技术选型理由很实在。MediaPipe Pose 用的是 BlazePose 架构,分两阶段:先用人脸检测器推断人体 ROI 区域,再在 ROI 内跑关键点回归网络。整个模型量化后只有几 MB,在普通笔记本 CPU 上就能跑到 30 FPS 左右,这对毕业设计演示场景来说完全够用。源码包里选择 MediaPipe 而不是其他方案,核心考量就是「把精力留给动作识别逻辑本身,而不是耗在姿态估计的工程细节上」。
从源码结构看,整个工程大致分四层:视频采集层负责读摄像头或视频文件,关键点提取层调用 MediaPipe 拿到坐标,动作判定层根据坐标做逻辑判断,展示层用 OpenCV 画骨架和文字。这种分层设计的好处是,你想换动作类型,只需要改判定层,其他部分不用动。
2.2 关键点坐标系与归一化处理
MediaPipe 返回的关键点坐标是归一化的,x 和 y 都在 0 到 1 之间,原点是图像左上角。这一点如果不搞清楚,后面算角度和距离会直接翻车。源码里通常会有一个转换步骤,把归一化坐标乘以图像宽高,还原成像素坐标,方便后续计算。
import cv2 import mediapipe as mp mp_pose = mp.solutions.pose pose = mp_pose.Pose( static_image_mode=False, # 视频流模式,逐帧检测 model_complexity=1, # 模型复杂度 0/1/2,越高越准但越慢 smooth_landmarks=True, # 平滑关键点,减少抖动 min_detection_confidence=0.5, # 检测置信度阈值 min_tracking_confidence=0.5 # 跟踪置信度阈值 ) cap = cv2.VideoCapture(0) while cap.isOpened(): ret, frame = cap.read() if not ret: break # MediaPipe 要求 RGB 输入 rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) results = pose.process(rgb) if results.pose_landmarks: h, w, _ = frame.shape # 取左肩(11)和左肘(13)的像素坐标 l_shoulder = results.pose_landmarks.landmark[11] l_elbow = results.pose_landmarks.landmark[13] sx, sy = int(l_shoulder.x * w), int(l_shoulder.y * h) ex, ey = int(l_elbow.x * w), int(l_elbow.y * h) cv2.line(frame, (sx, sy), (ex, ey), (0, 255, 0), 2) cv2.imshow('Pose', frame) if cv2.waitKey(1) & 0xFF == ord('q'): break cap.release() cv2.destroyAllWindows()这段代码是整个工程的骨架。static_image_mode=False表示处理视频流,MediaPipe 会在帧之间做跟踪,比逐帧独立检测快很多。model_complexity控制模型大小,0 是最轻量的,适合低配机器;2 最准但帧率会掉。smooth_landmarks开启后关键点不会疯狂跳动,但如果你要做快速动作识别,可以关掉它减少延迟。min_detection_confidence和min_tracking_confidence这两个参数是玄学重灾区,调低了误检多,调高了丢帧多,一般从 0.5 起步,根据实际画面微调。
关键点索引是固定的,11 是左肩、12 是右肩、13 是左肘、14 是右肘,以此类推到脚踝。源码里的动作判定逻辑就是围绕这些索引展开的。
2.3 动作判定逻辑怎么写
拿到关键点之后,动作识别的核心就是「用坐标算特征,用特征做分类」。最简单的做法是算关节角度。比如判断手臂是否举起,可以算肩膀到肘部再到手腕的夹角,角度接近 180 度就是伸直举起。
import math def calculate_angle(a, b, c): """计算 b 点处的夹角,a/b/c 均为 (x, y) 像素坐标""" angle = math.degrees( math.atan2(c[1] - b[1], c[0] - b[0]) - math.atan2(a[1] - b[1], a[0] - b[0]) ) angle = abs(angle) if angle > 180: angle = 360 - angle return angle # 假设已拿到左肩、左肘、左腕坐标 angle = calculate_angle(shoulder, elbow, wrist) if angle > 160: action = "手臂伸直" elif angle < 90: action = "手臂弯曲"calculate_angle用的是atan2差值法,比向量点积法更稳定,不会因为坐标顺序搞反而算出错误角度。源码里通常会封装一个动作判定类,把「举手」「下蹲」「挥手」这些动作写成独立方法,每个方法内部调用角度计算和阈值比较。阈值不是拍脑袋定的,需要你对着摄像头试几组数据,找到区分度最好的分界点。
3. 环境搭建与源码运行:从 Python 安装到摄像头调通
3.1 Python 环境与依赖安装的稳妥路径
拿到源码包第一件事不是急着跑,而是把环境理顺。MediaPipe 对 Python 版本有要求,目前稳定支持的是 Python 3.8 到 3.11,3.12 在某些平台上会有兼容问题。如果你机器上装了多个版本,建议用虚拟环境隔离,避免和系统里其他包打架。
# 创建虚拟环境,python 版本指定 3.9 比较稳 python -m venv venv # Windows 激活 venv\Scripts\activate # macOS / Linux 激活 source venv/bin/activate # 安装核心依赖 pip install mediapipe opencv-python numpy # 如果要用界面,补一个 pip install pillowmediapipe会自动带上它需要的依赖,但opencv-python和numpy建议显式装,方便控制版本。装完之后用pip list确认一下,mediapipe的版本号记下来,写论文环境章节要用。如果安装过程中卡在下载 wheel 文件,换国内镜像源,这是血泪经验,别硬等。
提示:虚拟环境目录不要提交到代码仓库,源码包里如果有
.gitignore,确认里面已经排除了venv/和__pycache__/。
3.2 摄像头权限与视频源切换
源码默认读的是摄像头,索引 0 通常是内置摄像头。如果你外接了一个 USB 摄像头,可能要改成 1 或 2。有些笔记本有隐私开关,物理遮挡了摄像头,代码跑起来黑屏,先检查硬件开关。
# 读摄像头 cap = cv2.VideoCapture(0) # 读视频文件,方便反复调试 # cap = cv2.VideoCapture("test_video.mp4") # 检查是否打开成功 if not cap.isOpened(): print("摄像头打开失败,检查索引或权限") exit()调试阶段强烈建议先用视频文件跑,因为摄像头前做动作很累,而且每次动作幅度不一致,不好对比。录一段自己做的标准动作视频,反复跑,把判定阈值调准了再切回摄像头。源码里如果有--source参数,直接命令行传参切换,比改代码方便。
3.3 运行入口与参数配置
源码包一般会有一个main.py或者run.py作为入口。运行之前先看一眼有没有配置文件,比如config.yaml或者settings.py,里面通常放着摄像头索引、置信度阈值、动作判定阈值这些可调参数。
# 直接运行 python main.py # 如果有参数 python main.py --camera 0 --confidence 0.6 --show_fps--confidence控制检测置信度,画面里人多或者背景杂乱时调高一点,减少误检。--show_fps打开后画面左上角会显示帧率,方便你判断性能瓶颈在哪。如果帧率低于 15,先把model_complexity降到 0,再考虑缩小输入分辨率。
4. 动作识别效果调优:参数、阈值与常见误判
4.1 置信度阈值与跟踪平滑的取舍
MediaPipe 的min_detection_confidence和min_tracking_confidence这两个参数,直接决定关键点稳不稳。检测置信度管的是「这一帧有没有人」,跟踪置信度管的是「这一帧的关键点和上一帧是不是同一个人」。两个都调高,关键点稳但容易丢;都调低,关键点跳但不容易丢。
实际调参时,我一般会这样分场景:单人做动作演示,两个都设 0.6 到 0.7,画面干净、关键点稳;多人或者背景有干扰,检测置信度降到 0.4,跟踪置信度保持 0.5,先保证不丢人。smooth_landmarks在演示场景建议开着,动作判定会平滑很多,但如果你要做快速手势识别,关掉它响应更快。
4.2 动作判定阈值的标定方法
阈值标定是动作识别里最耗时间的一步。以「举手」为例,手臂举过头顶时,肩膀到肘部再到手腕的角度接近 180 度,但每个人手臂长度和柔韧性不同,有人 160 度就算举起来了,有人要 170 度。源码里如果写死了 160,换个人可能就判不准。
标定的做法是:录一段标准动作视频,在代码里把角度值打印出来,观察动作做到位时的角度范围,取一个能区分「举起」和「放下」的中间值。比如举起时角度在 155 到 180 之间,放下时在 30 到 80 之间,那阈值设在 120 左右就比较稳。
# 调试时打印角度 print(f"当前角度: {angle:.1f}") # 根据打印结果调整阈值 RAISE_THRESHOLD = 120注意:阈值不要只测自己一个人,找两三个同学各做几组,取交集范围,否则答辩时换个老师上来演示就可能翻车。
4.3 光照与背景对关键点的影响
MediaPipe 虽然鲁棒性不错,但强逆光、暗光、背景里有人形海报这些情况,关键点还是会飘。逆光时人体变成剪影,模型找不到关节细节,关键点会缩成一团。暗光下噪点多,检测置信度会掉。
解决办法不复杂:演示时保证正面光源,别背对窗户;背景尽量干净,别挂人体海报或者放穿衣镜。如果实在没法改环境,把model_complexity调到 2,大模型对困难场景的鲁棒性更好,代价是帧率下降。源码里如果有图像预处理模块,可以加一个直方图均衡化,对暗光场景有改善。
5. 避坑与排查:那些让源码跑不起来的常见问题
5.1 现象:运行报错module 'mediapipe' has no attribute 'solutions'
原因通常是安装的 mediapipe 版本不对,或者装了一个同名的假包。有些镜像源里的 mediapipe 是旧版本,API 结构不一样。解决方法是先卸载再指定版本重装:pip uninstall mediapipe,然后pip install mediapipe==0.10.9。装完在 Python 里import mediapipe打印一下版本号确认。
5.2 现象:摄像头画面卡在第一帧不动
原因多半是cv2.waitKey的延时参数设成了 0,或者没有正确释放资源。waitKey(0)会无限等待按键,视频流就卡住了。改成waitKey(1)让它在每帧之间只等 1 毫秒。另外确认cap.release()和cv2.destroyAllWindows()在循环结束后执行了,否则下次运行摄像头可能被占用。
5.3 现象:关键点画出来了但动作判定一直不触发
先检查坐标有没有做归一化到像素的转换。如果直接拿 0 到 1 的归一化坐标去算角度,结果会完全不对。再检查关键点索引有没有写错,左右肩的索引是 11 和 12,写反了动作逻辑就全乱。最后打印一下角度值,看是不是阈值设得太极端,导致正常动作也达不到。
5.4 现象:帧率低、画面延迟明显
按影响程度排序:model_complexity调到 0 能提升最明显;输入分辨率从 1280x720 降到 640x480 也有帮助;关掉smooth_landmarks能省一点计算;如果还不行,检查是不是在循环里重复创建了Pose对象,应该在外面创建一次,循环里只调process。
5.5 现象:换台电脑就跑不起来
最常见的原因是 Python 版本不一致,或者没装 Visual C++ 运行库。Windows 上 MediaPipe 依赖 VC++ 2019 以上的运行库,缺了会报 DLL 加载失败。另一个原因是显卡驱动太旧,虽然 MediaPipe 主要跑 CPU,但 OpenCV 的某些操作会调用 GPU 加速。把源码包里的requirements.txt带上,换机器先pip install -r requirements.txt,能省很多事。
6. 从能跑到能写进论文:动作扩展与效果验证的实操技巧
源码跑通只是第一步,毕业设计要的是「你做了什么」。最省力的扩展方式是在现有判定逻辑上加新动作。比如加一个「下蹲」判定,核心是算髋关节、膝关节、踝关节的角度,膝盖弯曲到 90 度左右算下蹲到位。加一个「挥手」判定,可以跟踪手腕在连续多帧内的横向位移,位移超过阈值且方向来回变化就算挥手。
# 下蹲判定示例 def is_squat(hip, knee, ankle): angle = calculate_angle(hip, knee, ankle) return angle < 100 # 膝盖弯曲小于 100 度 # 挥手判定:记录最近 10 帧手腕 x 坐标 wrist_history = [] def is_waving(wrist_x): wrist_history.append(wrist_x) if len(wrist_history) > 10: wrist_history.pop(0) if len(wrist_history) == 10: movement = max(wrist_history) - min(wrist_history) return movement > 0.15 # 归一化坐标下位移超过 0.15 return False验证效果不能只靠「我看着它动了」。论文里需要量化指标,最简单的做法是录一段包含目标动作和非目标动作的视频,人工标注每一帧的真实类别,然后跑代码统计准确率和召回率。源码里如果没有统计模块,自己加一个计数器,把判定结果和人工标注对比,算一个混淆矩阵。这个数据写进论文的实验章节,比单纯截图有说服力得多。
还有一个容易被忽略的点:把关键点数据存下来。每帧的 33 个关键点坐标存成 CSV,后面想换分类器(比如上 SVM 或者简单的神经网络)可以直接用这份数据训练,不用重新跑视频。我一般会在代码里加一个--save-landmarks开关,打开就把坐标写文件,关掉就正常演示。
从那以后我每次拿到类似的视觉项目,都强制自己先把数据落盘这一步加上,因为后期想换算法的时候,没有原始数据就只能重新采集,那个后悔药没地方买。希望这份源码能帮你把毕业设计的系统实现部分稳稳落地,把省下来的时间花在论文打磨上。
本文还有配套的精品资源,点击获取