基于MediaPipe Holistic的八段锦动作识别:从关键点提取到92%分类实战

发布时间:2026/10/11 13:03:08

基于MediaPipe Holistic的八段锦动作识别:从关键点提取到92%分类实战 简介这份资源面向计算机视觉与体育健康交叉方向的开发者、学生及八段锦教学研究者提供一套基于MediaPipeHolistic的智能辅助训练系统实现方案用于解决无指导者在场时动作识别与评估的问题。压缩包共10个文件约13.87MB包含Python主程序、JSON配置、Markdown说明文档、字体文件及依赖清单等覆盖从环境搭建到动作分析的核心环节。系统可实时检测33个身体关键点与42个手部关键点并基于自建测试数据集对八段锦8个标准动作进行识别准确率达92%同时支持练习历史记录与动作评分反馈。资源中附有说明文件与项目代码便于读者快速理解关键点检测、动作判定与界面交互的实现细节也可作为计算机视觉在传统健身场景落地的学习范例。目前已有142人学习下载。1. 八段锦动作识别这套源码到底能不能直接跑起来健身气功八段锦看着慢真要用计算机视觉去判对错麻烦程度一点不比健身操低——手部翻掌、旋腕、握拳这些细节33 个身体关键点根本盖不住。这套资源的核心思路是用 MediaPipe Holistic 把身体姿态和手部关键点一起抽出来再对 8 个标准动作做分类自建测试集上给出的识别准确率是 92%。它解决的不是能不能检测到人这种入门问题而是动作做没做到位、属于哪一式的细粒度识别。适合两类人一类是计算机视觉课程设计或大作业想找个完整闭环项目的学生另一类是做人机交互、康复训练、体育教学辅助的从业者想拿现成管线改造成自己的动作评估系统。资源包里是完整源码加自建数据集不是只有推理脚本的半成品这一点决定了它能不能被真正复现。2. MediaPipe Holistic 关键点提取3342 个点是怎么落到代码里的2.1 为什么选 Holistic 而不是 Pose 或 Hands 单独用八段锦的判定难点在于上下同判。以双手托天理三焦为例判定它是否标准既要看肩肘腕的抬举角度又要看手指是否并拢上托、掌心朝向是否到位。MediaPipe Pose 只给 33 个身体关键点手部细节全靠猜MediaPipe Hands 单独跑只能拿到 21 个点且需要自己处理双手检测和左右手分配。Holistic 把 Face Mesh、Pose、Hands 三个子模型串成一条管线一次前向就能同时输出身体 33 点、单手 21 点双手共 42 点以及面部 468 点。对八段锦这种躯干定式 手型定细节的任务Holistic 是省事且够用的选择。代价也要说清楚Holistic 的推理开销明显高于单独 Pose在 CPU 上跑 720p 视频大概 1525 FPSGPU 上能到 60 FPS 以上。如果你的场景是实时摄像头交互建议降到 480p 输入或者只对关键帧做 Holistic、中间帧用轻量 Pose 插值。这套源码默认走的是视频文件离线处理所以没有做这个优化你如果要改成实时得自己补。2.2 关键点提取的完整代码与参数下面这段是提取逻辑的核心我按源码结构重写并加了注释参数含义逐条说明import cv2 import mediapipe as mp import numpy as np mp_holistic mp.solutions.holistic def extract_keypoints(video_path, target_fps15): cap cv2.VideoCapture(video_path) src_fps cap.get(cv2.CAP_PROP_FPS) # 抽帧间隔源视频 30fps 时每 2 帧取 1 帧降到 15fps 减少冗余 step max(1, int(round(src_fps / target_fps))) # Holistic 关键参数 with mp_holistic.Holistic( static_image_modeFalse, # 视频流用 False复用上一帧做跟踪更快更稳 model_complexity1, # 0/1/21 是精度与速度的平衡点 smooth_landmarksTrue, # 开启平滑抑制关键点抖动 min_detection_confidence0.5, # 首帧检测阈值 min_tracking_confidence0.5 # 跟踪置信度低于此值重新检测 ) as holistic: frames, labels [], [] idx 0 while cap.isOpened(): ret, frame cap.read() if not ret: break if idx % step 0: rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) rgb.flags.writeable False # 只读避免 MediaPipe 内部拷贝 res holistic.process(rgb) # 身体 33 点缺失时补 0保证特征维度固定 pose np.array([[p.x, p.y, p.z, p.visibility] for p in res.pose_landmarks.landmark]) \ if res.pose_landmarks else np.zeros((33, 4)) # 左右手各 21 点共 42 点 lh np.array([[p.x, p.y, p.z] for p in res.left_hand_landmarks.landmark]) \ if res.left_hand_landmarks else np.zeros((21, 3)) rh np.array([[p.x, p.y, p.z] for p in res.right_hand_landmarks.landmark]) \ if res.right_hand_landmarks else np.zeros((21, 3)) feat np.concatenate([pose.flatten(), lh.flatten(), rh.flatten()]) frames.append(feat) idx 1 cap.release() return np.array(frames) # 形状 (T, 33*4 21*3 21*3) (T, 258)逻辑说明static_image_modeFalse是视频场景的关键它让 MediaPipe 在帧间做跟踪而不是每帧重新检测速度和稳定性都更好。model_complexity1是默认档如果你发现手部关键点频繁丢失可以调到 2但帧率会掉三成左右。smooth_landmarksTrue对八段锦这种慢动作特别有用能明显减少关键点在小范围内的抖动代价是快速动作时会有轻微延迟。参数说明min_detection_confidence和min_tracking_confidence都设 0.5 是通用起点。如果视频里人物离镜头远、手部区域小检测置信度会偏低可以降到 0.30.4但误检会增多如果背景干净、人物占画面大可以提到 0.60.7 减少误检。target_fps15是我建议的抽帧目标八段锦动作慢15fps 足够描述一个完整动作周期原始 30fps 直接喂进去只会让特征序列翻倍、训练变慢。2.3 特征拼接与归一化别让坐标尺度坑了你上面拼出来的 258 维特征里x、y 是归一化到 [0,1] 的图像坐标z 是相对深度以髋部为原点量级和 x 接近visibility 是 [0,1] 的可见性。直接把这些拼起来送进分类器有个隐患不同视频里人物站位不同x、y 的绝对值会漂移。常见做法是以髋部中点Pose 的 23、24 号点为原点做平移归一化再按肩宽做尺度归一化。源码里如果没做这一步你自己补上识别率通常能再涨几个点。def normalize(feat): pose feat[:132].reshape(33, 4) hip (pose[23, :2] pose[24, :2]) / 2.0 shoulder_w np.linalg.norm(pose[11, :2] - pose[12, :2]) 1e-6 pose[:, :2] (pose[:, :2] - hip) / shoulder_w return np.concatenate([pose.flatten(), feat[132:]])这段归一化对八段锦尤其重要因为八段锦有大量原地转身、重心移动的动作不归一化的话同一个动作在不同站位下特征差异会大到让分类器翻车。3. 8 个动作的分类管线从特征序列到 92% 准确率3.1 时序建模选型为什么不是简单帧分类八段锦 8 个动作里摇头摆尾去心火和两手攀足固肾腰都有明显的前俯后仰单帧看姿态可能相似必须靠时序上下文区分。所以这套管线不能做成每帧独立分类再投票而要做序列建模。常见做法有三条路LSTM/GRU 直接吃特征序列、1D-CNN 做时序卷积、或者 Transformer。这套源码走的是轻量路线用滑动窗口切序列 分类头兼顾了训练成本和可复现性。滑动窗口的切法直接决定样本质量。窗口太短一个动作被切成好几段标签对不上窗口太长一个窗口里混了两个动作模型学不明白。八段锦单个动作完整做一遍大约 48 秒按 15fps 算就是 60120 帧。我一般把窗口设成 90 帧、步长 30 帧这样每个动作能切出 24 个样本且相邻窗口有重叠增加样本量。def make_windows(seq, label, win90, stride30): X, y [], [] for start in range(0, len(seq) - win 1, stride): X.append(seq[start:start win]) y.append(label) return np.array(X), np.array(y)参数说明win90对应 6 秒覆盖绝大多数八段锦单式stride30是 2 秒重叠保证动作过渡段也能被采到。如果你的视频帧率不是 15fps这两个值要按比例换算否则窗口覆盖的物理时长就变了这是新手最容易忽略的坑。3.2 分类模型搭建与训练参数模型部分用 Keras 搭一个轻量时序网络就够了不需要上大模型from tensorflow.keras import layers, models def build_model(win90, feat_dim258, n_class8): inp layers.Input(shape(win, feat_dim)) x layers.Conv1D(64, 5, paddingsame, activationrelu)(inp) x layers.MaxPooling1D(2)(x) x layers.Conv1D(128, 3, paddingsame, activationrelu)(x) x layers.GlobalAveragePooling1D()(x) x layers.Dropout(0.4)(x) x layers.Dense(64, activationrelu)(x) out layers.Dense(n_class, activationsoftmax)(x) model models.Model(inp, out) model.compile(optimizeradam, losssparse_categorical_crossentropy, metrics[accuracy]) return model逻辑说明两层 1D 卷积负责提取局部时序模式比如手腕翻转的短时变化GlobalAveragePooling 把时间维压掉避免全连接层参数爆炸。Dropout 0.4 是针对小数据集的防过拟合手段自建数据集样本量通常不大这个值别调太低。训练参数建议batch_size 设 1632epochs 先跑 80配合 EarlyStoppingpatience15防止过拟合。学习率用默认 1e-3 起步如果 loss 震荡明显降到 5e-4。数据划分一定要按人划分而不是按窗口划分——同一个人做的同一个动作切出的多个窗口如果同时进了训练集和测试集准确率会虚高这是 92% 这个数字能不能信的关键。我见过太多项目在这里翻车测试集里混了训练集同源样本报出来的准确率没有任何参考价值。3.3 自建数据集的采集与标注规范这套资源带的是自建测试数据集采集时要注意几点每个动作至少 3 个不同人各做 5 遍以上机位固定正面或 45 度斜前背景尽量干净。标注按动作段标即记录每个动作的起止帧和类别而不是逐帧标。如果只有整段视频没有分段标注可以用动作间的停顿作为切分点八段锦每式之间通常有短暂定式这是天然的切分信号。数据增强方面时序数据能做的增强有限常见的是加轻微高斯噪声、时间轴随机缩放0.91.1 倍、以及左右镜像。镜像要注意八段锦有些动作左右不对称镜像后标签可能失效用之前先确认你的动作定义是否对称。4. 避坑与排查这套管线最容易出问题的五个地方4.1 手部关键点整段丢失现象跑完提取脚本发现左手或右手特征全是 0或者大段为 0。原因通常是手部区域太小、被身体遮挡或者min_detection_confidence设太高。解决先把置信度降到 0.3 试如果还不行检查输入分辨率——手部在画面里占的像素太少时MediaPipe 的手掌检测器直接失效。把视频缩放到 720p 以上再跑或者对上半身做裁剪后再送 Holistic。4.2 准确率虚高但实际用不了现象训练时验证集 95%换一段新视频测试就掉到 60%。原因几乎都是数据泄漏——同一个人、同一段视频切出的窗口被分到了训练和验证两边。解决按视频文件或按人做 GroupShuffleSplit确保同一个人的数据只出现在一边。这个坑我在多个动作识别项目里都踩过血泪经验是划分数据前先按人分组再划分。4.3 帧率不一致导致窗口错位现象训练用 15fps 抽帧推理时忘了抽帧直接喂 30fps 视频识别结果乱跳。原因窗口长度是按帧数定义的帧率变了窗口覆盖的物理时长就变了。解决把抽帧逻辑封装成统一入口训练和推理都走同一个函数别在两处各写一遍。4.4 归一化遗漏导致跨机位失效现象固定机位测试正常换个机位或换个人站远一点就识别错。原因没做髋部原点平移和肩宽尺度归一化坐标绝对值漂移。解决把 2.3 节的归一化函数接在提取之后训练和推理都要走。这一步加上后跨机位鲁棒性通常有明显改善。4.5 动作过渡段被误分类现象两个动作之间的过渡帧被分成了第三个动作。原因滑动窗口切到了过渡段且训练时过渡段样本被标成了相邻动作之一。解决在标注阶段把过渡段单独标成其他类或者用动作起止点做硬切分只取动作主体段做训练。八段锦动作之间衔接平滑这个坑比健身操更明显。5. 进阶玩法把 92% 再往上推的几个具体技巧先说验证方法。想确认这套管线在你自己的数据上到底行不行别只看一个总准确率要出混淆矩阵。八段锦里调理脾胃须单举和双手托天理三焦都有上肢上举是最容易混的一对摇头摆尾去心火和两手攀足固肾腰都有躯干前倾也容易混。看混淆矩阵能直接告诉你模型到底在哪两式之间犯迷糊比一个笼统的 92% 有用得多。from sklearn.metrics import confusion_matrix, classification_report import seaborn as sns import matplotlib.pyplot as plt y_pred model.predict(X_test).argmax(axis1) cm confusion_matrix(y_test, y_pred) sns.heatmap(cm, annotTrue, fmtd, cmapBlues) plt.xlabel(Predicted); plt.ylabel(True) plt.show() print(classification_report(y_test, y_pred, digits3))拿到混淆矩阵后针对性补数据比盲目加样本有效得多。哪两式混得多就专门补这两式的区分性样本尤其是过渡段和定式保持段。第二个技巧是特征层面的增强。258 维原始坐标里其实很多维度对分类贡献很小比如面部相关的点这套管线没用但 Pose 里的 visibility 维度信息量也有限。可以算一下每个维度的方差或互信息把低贡献维度砍掉特征降到 150 维左右训练更快且过拟合风险更低。我一般会保留所有关节坐标但把 visibility 单独做阈值处理而不是当连续特征喂进去。第三个技巧是推理阶段的时序平滑。模型逐窗口输出类别概率后别直接取 argmax用滑动平均或维特比解码把概率序列平滑一下能消掉大部分单窗口的抖动误判。八段锦动作持续时间长平滑窗口设 35 个窗口比较合适太大会把动作切换点也抹平。最后一个习惯每次改完特征或模型固定用同一段留出视频跑一遍端到端记录混淆矩阵和每类 F1而不是只看训练日志里的 accuracy。从那以后我每次做动作识别项目都强制走一遍按人划分 混淆矩阵 留出视频端到端这三步缺一步都不敢说模型能用。这套八段锦源码的骨架是完整的真正决定它在你手里能不能落地的是数据划分和归一化这两个不起眼但致命的细节。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/11 13:03:08

AI UI设计工具有哪些?开发交付前先分清UI图、设计稿和前端代码

很多人聊“AI生成UI”,说的其实不是同一种东西。有人指的是一张UI图,方便讨论方向;有人要的是能继续改的设计稿;还有人想直接拿到能跑的前端代码。这三样交付出去,结果可差得远着呢。设计师看着UI图很满意,…

2026/10/11 13:03:08

参考文献中DOI如何正确书写?要不要带https://doi.org前缀?

先给急着出结果的读者一个结论:不存在一个放之四海而皆准的固定答案,但绝大多数正式场景下,带上https://doi.org/前缀更稳妥。这是我在审稿、投稿和给团队做培训时被问得最多的问题之一。同一条文献,A 作者在参考文献里只写10.101…

2026/10/11 12:58:08

PaddleDetection人脸检测与情绪识别双阶段实战指南

简介:本资源是一套基于百度飞桨PaddleDetection框架的人脸检测与情绪识别一体化模型实现方案,面向计算机视觉初学者、AI开发者及高校科研人员,解决多场景下人脸定位与表情分类的工程落地问题,适用于智能安防、人机交互、情感计算等…

2026/10/11 17:38:27

SpringBoot+微信小程序点餐系统实战:从架构到支付回调避坑指南

如果你最近在调研“小程序点餐系统”这类题目,大概率会看到一堆千篇一律的项目骨架:用户登录、商品列表、下单、支付,没了。但真正到了答辩或者上线阶段,才会发现购物车并发、库存扣减、微信支付回调、小程序体验版配置这些才是拉…

2026/10/11 17:38:27

Python+Django员工管理系统开发全流程:从数据库设计到部署实践

做完整的企业员工管理系统,用 Python Django 其实是不少人会走的一条路。标题写着“源码数据库文档”,乍一看像是卖课搞培训的套路,但我自己从头到尾把这类系统从零搭过一遍之后,反而觉得这套组合挺适合拿来当练手项目的。它不是…

2026/10/11 17:38:27

基于Python+Django的企业员工管理系统设计与部署实战

企业员工管理系统这类项目,可以说是 Python/Django 开发者绕不开的“练手标配”。但说实话,能真正把它做得完整、能交付、能跑在生产环境的并不多。最近我刚完成了一套基于 Python Django 的企业员工管理系统,从源码、数据库脚本到配套文档都…

2026/10/11 17:38:27

手写C语言Pascal编译器:词法语法语义全流程实现

简介:本资源是一份面向高校计算机专业本科生的编译原理课程设计报告,聚焦Pascal子集编译器的完整实现方案,助力学生系统掌握词法分析、语法分析、语义分析、中间代码生成等核心编译技术。报告由北京邮电大学五人团队协作完成,内容…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/11 0:02:13

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/11 0:02:13

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/11 0:02:13

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/11 0:02:13

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑