简介这套基于YOLOv8的八段锦练习指导系统面向计算机相关专业学生及毕设、课设、大作业场景解决传统健身动作难以客观评估的问题可完成动作识别与练习指导的端到端流程。包内整合源码、完整数据集、可视化界面与部署说明共97个文件以Python脚本70个py、预编译缓存12个pyc、模型权重4个pt、配置文件5个xml及说明文档为主整体仅24.21MB结构紧凑易于部署。除核心检测功能外还提供可视化页面与演示视频可生成核心指标曲线、混淆矩阵、F1分数曲线、精确率-召回率曲线及验证集预测结果等训练分析图表便于答辩展示与效果验证。项目代码均经过运行测试并附带README说明既适合初学者学习进阶也可直接作为毕业设计或课程设计的基础项目使用。目前已有295人浏览学习属于即下即用、完整度较高的实践资源。1. 基于YOLOv8的八段锦练习指导系统它到底在解决什么问题设想这样一个毕设场景你需要一套能对着摄像头识别八段锦动作、给用户打分纠正、还能做计数和结果展示的系统而且要从零开始攒数据集、训练模型、再写一个看得过去的界面。市面上关于YOLOv8的教学几乎都在讲“训练自己的目标检测数据集”但八段锦指导这种需求本质上不是“找到人”就够了而是要把“人做得对不对”变成可量化的判断。这个基于YOLOv8的八段锦练习指导系统走的是YOLOv8-pose关键点检测加规则判别的路线先用模型把人体17个关键点定出来再结合关节角度、肢体比例和时序逻辑去判断每一式动作达标没有。适合毕设、课程设计也适合想快速验证动作识别产品的开发者。最反直觉的地方在于训练模型往往不是最耗时的环节真正把人卡住的是数据集的坐标系、关键点标注规范以及推理结果如何在可视化界面里不畸变地画出来。2. 选YOLOv8做八段锦指导不是它最潮而是它够省事2.1 YOLOv8与OpenPose、MediaPipe的对比落地场景先说什么八段锦指导需要的是人体姿态估计很多人第一反应是OpenPose或MediaPipe。这类专门做姿态估计的框架确实开箱即用MediaPipe甚至不需要训练直接就能给出33个关键点。但毕设和课设要求的是“有自己的模型、有自己的数据集、能讲清楚训练过程”MediaPipe那种预训练方案不容易体现工作量。OpenPose的部署太重依赖一堆库CPU推理在普通笔记本上经常卡到不可用。YOLOv8-pose 是目标检测模型YOLOv8的同一个框架里带出来的关键点版本好处在于训练、验证、导出、部署全在一个库内完成不需要额外处理检测和姿态两套模型的拼接逻辑。从工程角度看YOLOv8-pose一次推理同时输出人体框和17个关键点拿到结果后可以直接在界面上绘制这对“练习指导系统”这种需要考虑交互反馈的场景来说是最少依赖的路径。选型不是看谁精度最高而是看谁能在你的电脑上跑起来。YOLOv8n-pose 模型只有十几MB的权重COCO预训练权重在公开环境下就能下载用普通CPU也能做推理测试。我一般直接用 ultralytics 这个库它把数据集加载、数据增强、训练、导出ONNX、TensorRT这几步全包了。相比自己写姿态估计的训练脚本出错率低很多。2.2 系统内部怎么分工检测、关键点、规则判断三层八段锦指导系统对外看起来是一个界面但内部一定是分层设计的。我见过的漂亮方案都遵循下面这个结构先检测人体区域再提取关键点最后做动作规则判断。不是把动作分类直接交给模型去输出而是让模型只做它擅长的事也就是回归出关键点坐标。第一层人体检测。YOLOv8-pose的输出里其实已经包含了人体框相当于检测和姿态估计是联合的不需要像OpenPose那样先跑检测再跑关键点。第二层关键点提取。模型输出17个COCO格式关键点每个点有x、y坐标和一个可见性置信度。第三层规则判断。根据关节之间的角度、距离判断当前动作是否到位。把动作判断从模型里摘出来的好处非常明显。八段锦八式动作每一式的标准都不一样如果让模型直接输出“当前是第几式”你得为每一个动作类别准备大量视频帧和标签而且不同人的动作速度不一样分类模型很容易在过渡动作上误判。用关键点加规则你的“数据集”就只需要保证关键点检测足够准动作判断逻辑可以在代码里反复调整阈值甚至用户改了评分标准都不用重新训练模型。2.3 从关键点到动作判断拿“攒拳怒目增气力”举个例子八段锦的八式里很多动作的判别都能用几个关键角度表达。以“攒拳怒目增气力”为例这一式里有“握拳收至腰间”和“出拳向前”两个明显状态。判断时最常用的是肘关节角度和肩关节位置关系。假设模型输出的关键点编号按COCO顺序左肩是5左肘是6左腕是7那么我们可以算三个点构成的角度。import math def calc_angle(a, b, c): # a, b, c 是 (x, y) 坐标b 是角点 ang math.degrees( math.atan2(c[1] - b[1], c[0] - b[0]) - math.atan2(a[1] - b[1], a[0] - b[0]) ) return abs(ang) if ang 180 else 360 - abs(ang) # 假设 frame_width, frame_height 用于还原坐标 # kpts 是从模型输出的归一化关键点 def is_punch_straight(kpts): shoulder (int(kpts[5][0] * frame_width), int(kpts[5][1] * frame_height)) elbow (int(kpts[6][0] * frame_width), int(kpts[6][1] * frame_height)) wrist (int(kpts[7][0] * frame_width), int(kpts[7][1] * frame_height)) elbow_angle calc_angle(shoulder, elbow, wrist) # 出拳时肘关节角度接近180度 return elbow_angle 160这套逻辑最值钱的地方在于你不需要为“出拳”这个动作单独攒几千张图片去训分类器。只要关键点检测准了规则判断是透明且可解释的。做毕设答辩时评委问“你这个逻辑怎么来的”你可以直接指着手上的关节说角度阈值比拿出黑匣子神经网络解释要有说服力。2.4 为什么不是姿态分类而是“关键点规则”很多初学者会把八段锦的每一式当作一个目标检测类别让YOLOv8直接识别“这是第几式”这其实是走弯路。八段锦是连续过渡的动作帧与帧之间没有明确边界同一式在不同人身上速率差异也大。目标检测模型可以识别“人拿着篮球”但很难稳定识别“人正在做五劳七伤往后瞧的途中”。关键点加规则的好处是每个时刻你都能拿到一个可计算的姿态描述无论动作做到一半还是完全到位规则逻辑都能给出一个“完成度”。当用户动作不标准时你可以精准回答是哪一条没达到比如“左脚没有外撇”“手臂没有完全上举”。这些输出天然适合做指导系统的提示文案。3. 八段锦数据集从标注到训练格式坐标系不能想当然3.1 YOLOv8-pose 的数据格式到底长什么样YOLOv8-pose 训练用的标签不是一个txt一组坐标这么简单。每一行的结构是类别编号、框中心x、框中心y、框宽、框高然后是17个关键点的x、y、可见性。所有坐标都是相对于图片宽高的归一化数值范围在0到1之间。这里最容易被忽略的是可见性标志很多标注工具默认导出的是0或1但YOLOv8训练时关键点缺失通常用0表示标注但遮挡的用1正常标注的用2。我在处理自己的八段锦数据集时把被身体遮挡的另一侧手臂关键点标成1模型反而学得更稳因为那些点虽然看不到但位置仍然隐含在身体姿态里。0 0.5000 0.2150 0.6010 0.3800 0.5010 0.1230 2 0.5020 0.1310 2 0.5120 0.1510 2 ...上面这个示例里第一个0代表类别编号我们只有一个类别“person”紧跟其后的四个数是人体的目标框中心xy和宽高从第七个数开始每三个数为一组关键点。每组前两个是x和y归一化坐标最后一个是该关键点的可见性标志。这个格式如果手工写特别容易出错一个点错位后面的关键点全部对不上。所以我建议永远用脚本转换别在Excel里人工编辑。3.2 用LabelMe标注关键点点标注与框标注要分开处理采集八段锦训练数据时常见做法是录制多个人做八段锦的视频按帧抽取图片。图片不需要每帧都抽每秒取2到3帧就够动作相近的帧太多会让模型过拟合。我一般把视频抽帧得到的图片放到 dataset/images 目录然后用LabelMe逐张标注。LabelMe里新建一个label用“Create Point”来标关键点而不是用矩形框。需要特别注意LabelMe的JSON里点标注的坐标是像素坐标类别名称出现在label字段里。转换脚本要做两件事把标注点放进person检测框同时算出框的坐标。import json import os def labelme_to_yolo_pose(json_path, img_w, img_h, out_txt_path): with open(json_path, r, encodingutf-8) as f: data json.load(f) shapes data[shapes] keypoints {} # 第一步收集所有point类型的标注 for shape in shapes: if shape[shape_type] point: label shape[label] x, y shape[points][0] keypoints[label] (x, y) # 第二步根据人体关键点计算目标框 xs [p[0] for p in keypoints.values()] ys [p[1] for p in keypoints.values()] x_min, x_max min(xs), max(xs) y_min, y_max min(ys), max(ys) # 给框加一点边距避免关键点贴边影响归一化 margin 20 x_min max(0, x_min - margin) y_min max(0, y_min - margin) x_max min(img_w, x_max margin) y_max min(img_h, y_max margin) box_w x_max - x_min box_h y_max - y_min box_cx x_min box_w / 2 box_cy y_min box_h / 2 lines [] # 按照COCO顺序输出关键点缺失点补0 coco_order [nose, left_eye, right_eye, left_ear, right_ear, left_shoulder, right_shoulder, left_elbow, right_elbow, left_wrist, right_wrist, left_hip, right_hip, left_knee, right_knee, left_ankle, right_ankle] line [0, f{box_cx / img_w:.6f}, f{box_cy / img_h:.6f}, f{box_w / img_w:.6f}, f{box_h / img_h:.6f}] for part in coco_order: if part in keypoints: kx, ky keypoints[part] line.append(f{kx / img_w:.6f}) line.append(f{ky / img_h:.6f}) line.append(2) # 正常标注 else: line.append(0.000000) line.append(0.000000) line.append(0) with open(out_txt_path, w, encodingutf-8) as f: f.write( .join(line) \n)这个转换脚本有几个值得留意的边界。第一标注点如果都在画面外计算出的框会变成负数所以标注时要保证主要关键点在画面内。第二COCO顺序里的左右是图像视角的左右也就是标注时看到的左侧对应COCO的left。别把左右肩弄反否则后面画骨骼图会很奇怪。第三关键点缺失时填0和0可见性填0但训练时这些点的loss会被忽略不会造成惩罚。3.3 数据集划分与增强不是越多越好要按动作片段切八段锦数据集不能简单随机划分。如果同一段视频中的连续帧一部分进了训练集、一部分进了验证集验证结果会虚高因为相邻帧几乎一样。我都是按视频片段切先按“人-动作式”建文件夹比如 person_01_wushi、person_02_shuangshou再把整个片段的数据全部归到训练集或验证集里。否则最后答辩演示时容易翻车。增强方面ultralytics训练时默认会做Mosaic、随机平移和缩放这些对目标检测有效但对关键点任务要小心。Mosaic把四张图拼在一起时关键点坐标也跟着变这没问题但注意图片里的人可能被截断很多关键点会被裁到图外。我一般在训练时关闭Mosaic或者把mosaic调低到0.2只保留左右翻转、轻微亮度和对比度变化。左右翻转需要同时把关键点左右对调ultralytics会自动处理基于num_kpts的映射不用自己写但你说给“指导系统”用左右反转会导致“左”和“右”动作颠倒所以我自己的八段锦模型是禁用hsv和翻转的。具体设置为# dataset.yaml path: ./datasets/baduanjin train: images/train val: images/val names: 0: person kpt_shape: [17, 3]如果你用ultralyticskpt_shape在模型定义里已经存在数据yaml里只需要指定路径和类别名。额外要提的是八段锦动作中经常出现侧面角度比如“左右开弓似射雕”需要侧身打开手臂如果训练数据只有正面模型看到侧面躯干的关键点会混乱。最有效的扩充办法不是图像增强而是多角度采集哪怕一个人做动作正面、侧面、斜45度各录一遍模型鲁棒性都会有明显提升。3.4 标注一致性比标注数量更影响精度八段锦动作有起式和收式很多关键点在快速运动时是模糊的。标注最容易出的问题是前一帧把左肘标在关节窝后一帧标在小臂中段模型会认为肘关节在来回跳动。我的习惯是每帧都放大到原尺寸200%再标而且人眼对骨骼关节的视觉中心有偏差最好让同一个人完成所有标注不要多人分工标同一个数据集。标注完一个视频片段后我会随机抽20帧做“重标注检查”重新标一次看两次坐标偏差。偏差超过15个像素的说明这帧动作模糊直接删除不要留到训练里。模糊样本带来的噪声会让验证集准确率掉5%以上但训练损失看着还挺正常。4. 环境搭建与训练Ubuntu 20.04 也能跑但别跳过这些细节4.1 CPU版Ultralytics环境先跑通推理再谈训练很多课程设计机器没有独立显卡标题里也经常出现“ubuntu20.04搭建yolov8环境cpu版本”这种检索词。我的建议是CPU环境完全可以用来学习和做界面但训练最好去云平台或者用GPU。训练和推理是两个不同量级的消耗。在Ubuntu 20.04上搭建CPU版本很简单先装Python虚拟环境再装ultralytics就够了。# 在项目目录下创建虚拟环境 cd baduanjin_project python3 -m venv venv source venv/bin/activate # 安装CPU版本的PyTorch不要装默认的GPU版 pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu # 安装ultralytics和onnxruntime pip install ultralytics onnxruntime pyside6这里有一个容易翻车的点如果直接pip install ultralytics它会顺带拉一个与当前环境匹配的PyTorch版本如果是GPU机器可能装一个很大且和CUDA不匹配的包。CPU机器上明确指定--index-url .../whl/cpu能省掉将近2GB的下载量。安装完成后先用官方预训练模型跑一次推理验证环境。yolo predict modelyolov8n-pose.pt source./data/sample.jpg第一次运行会下载权重到当前目录或缓存目录。如果网络不稳定可以手动把权重文件放到项目根目录下然后引用本地路径。看到输出结果里包含17个关键点坐标说明环境OK。4.2 训练自己的八段锦关键点模型参数选型和命令解释训练命令看起来短但里面的参数组合决定了几小时后模型的成败。我用的是YOLOv8n-pose作为预训练底座因为模型小、CPU也能做实时推理如果追求更高精度可以换成YOLOv8s-pose但推理速度会慢约一半。八段锦指导系统最终要在界面里实时显示用户不会愿意等半秒才看到骨骼线。# 训练关键点模型 yolo pose train \ data./dataset/baduanjin.yaml \ modelyolov8n-pose.pt \ epochs100 \ imgsz640 \ batch8 \ lr00.01 \ lrf0.01 \ optimizerAdamW \ device0 \ project./runs/train \ namebaduanjin_pose参数说明imgsz640是训练输入分辨率八段锦关键点集中在躯干分辨率太低会丢失小关节信息batch在显存不足时要调小如果是CPU训练甚至只能设为1-2lr0是初始学习率用预训练权重时不必从0.001开始保持0.01通常没问题optimizerAdamW比默认的SGD收敛更稳定尤其关键点回归这种多目标任务。值得专门说的是device0如果你机器上没有NVIDIA GPU这里改成devicecpu但训练时间会非常难熬100轮可能跑几十个小时。所以哪怕你的最终部署目标是CPU训练阶段我还是强烈建议用一个免费GPU云平台或本地GPU电脑跑。4.3 训练过程中的损失曲线怎么看何时停和何时加数据训练时每隔一个epoch会输出一行loss但真正要看的是三个东西train/box_loss、train/pose_loss和val/pose_loss。其中val/pose_loss是判断模型是否过拟合的关键。通常前20轮训练损失掉得很快验证损失也同步下降30轮之后验证损失会是锯齿状这时候不要慌继续观察。如果验证损失连续20轮没有下降反而训练损失还在继续降那就是过拟合了。我一般设patience20让ultralytics在验证指标不提升20轮后自动停止。# 恢复训练和早停都在同一命令里控制 yolo pose train \ data./dataset/baduanjin.yaml \ model./runs/train/baduanjin_pose/weights/last.pt \ epochs80 \ resumeTrue \ patience20训练完成后模型最好的是runs/train/baduanjin_pose/weights/best.pt而不是last.pt。很多人直接拿last.pt去导出最终部署的模型精度反而低于best.pt。另一点八段锦的关键点分类类别只有“person”这一类如果训练日志里出现cls_loss居高不下通常是误把关键点类别也做了多分类训练检查一下数据yaml里names是否写对。4.4 导出ONNX界面端引用的最佳格式训练完成后下一站就是导出ONNX。ONNX是可视化界面部署时最通用的中间格式PySide6的界面里可以直接用onnxruntime加载不需要在界面环境里再装PyTorch和ultralytics。导出命令如下会生成best.onnx和对应的metadata.yaml。yolo export model./runs/train/baduanjin_pose/weights/best.pt formatonnx opset12 imgsz640 dynamicFalse simplifyTrue导出后可以用Netron打开ONNX文件检查输出张量的形状。YOLOv8-pose的ONNX输出通常是1x56x8400或类似结构8400对应640分辨率下所有anchor的数量56是人体框4维加关键点51维再加类别数。如果dynamicFalse那么输入必须是固定尺寸640x640界面端做预处理时要等比缩放并填充灰边否则推理结果会偏。simplifyTrue会做计算图简化减少算子数量CPU推理能快一点。5. 部署与可视化界面中的常见问题与排查5.1 现象模型在训练集上很好一到摄像头视频里就歪原因通常是推理时的图像预处理和训练时不一致。YOLOv8训练时会做letterbox把图片等比缩放到640x640不足部分用灰色填充。但自己在PySide6界面里用OpenCV读摄像头帧后如果直接resize到640x640宽高比被拉伸关键点坐标也跟着变形。解决用ultralytics库提供的LetterBox类或者手工按比例缩放并填充到方形画布。import cv2 import numpy as np def letterbox(img, new_shape(640, 640), color(114, 114, 114)): shape img.shape[:2] # height, width r min(new_shape[0] / shape[0], new_shape[1] / shape[1]) new_unpad (int(round(shape[1] * r)), int(round(shape[0] * r))) dw (new_shape[1] - new_unpad[0]) / 2 dh (new_shape[0] - new_unpad[1]) / 2 if shape[::-1] ! new_unpad: img cv2.resize(img, new_unpad, interpolationcv2.INTER_LINEAR) top, bottom int(round(dh - 0.1)), int(round(dh 0.1)) left, right int(round(dw - 0.1)), int(round(dw 0.1)) img cv2.copyMakeBorder(img, top, bottom, left, right, cv2.BORDER_CONSTANT, valuecolor) return img推理之后得到的坐标是letterbox后图像上的坐标要画回原图必须把填充的边去掉、除以缩放比例。这一步没做对画出来的骨骼线会整体偏移尤其人站在画面偏左偏右时偏移更明显。5.2 现象CPU推理速度只有2到3帧每秒界面明显卡顿原因每个摄像头帧都做一次640x640全尺寸推理而且界面主线程里同时处理视频读取和模型推断。解决有两步。第一步调小输入尺寸YOLOv8n-pose在320x320输入下关键点精度损失有限但推理时间能砍一半以上。第二步把推理放到单独线程主线程只负责显示否则PySide6界面会假死。如果是录播视频还可以隔帧推理比如每处理一帧跳一帧显示上一帧的关键点结果人的视觉基本感知不到延迟。# 界面推理线程伪代码 import threading import queue class PoseThread(threading.Thread): def __init__(self, session, frame_queue, result_queue): super().__init__() self.session session self.frame_queue frame_queue self.result_queue result_queue def run(self): while True: frame self.frame_queue.get() # letterbox, normalize, 推理, 后处理 # result_queue.put((draw_frame, keypoints))界面卡顿还有一个隐藏原因OpenCV的cap.read()和PySide6的QImage转换之间用了过多的cv2.cvtColor这些操作在Python里是同步的每帧都会阻塞UI。正确做法是先将BGR转RGB后写进QImage并且只在检测到新结果时才更新QLabel。5.3 现象左右肩关键点经常互换导致动作判断错误原因有两个一是数据标注时左右反了二是训练数据里正面和背面样本不平衡。八段锦很多动作需要转身回头比如“五劳七伤往后瞧”背对镜头时模型看到的是用户的背面它输出的“左肩”其实是画面里的左肩但用户自己的左右已经和画面左右互换。如果想判断动作是否标准结论会错。解决方法是在规则判断阶段不直接依赖左右关键点而是依据肩髋连线方向判断人体朝向。如果肩髋连线距离比肩宽大很多说明用户侧身或转身此时暂停该帧的左右侧动作判断直到人体回到正面。这个“姿态置信度”逻辑简单实用能避免大量误报。def is_front_face(kpts, frame_w, frame_h): left_shoulder kpts[5] * [frame_w, frame_h] right_shoulder kpts[6] * [frame_w, frame_h] left_hip kpts[11] * [frame_w, frame_h] right_hip kpts[12] * [frame_w, frame_h] shoulder_w np.linalg.norm(left_shoulder - right_shoulder) hip_w np.linalg.norm(left_hip - right_hip) # 正常站立肩宽和髋宽接近若肩髋连线中间距离过大说明侧身 center_diff np.linalg.norm( (left_shoulder right_shoulder) / 2 - (left_hip right_hip) / 2 ) return center_diff shoulder_w * 0.35.4 现象Qt界面中绘制的骨骼点位置比画面滞后一截原因摄像头采集和模型推理的时间戳没有对齐再加上queue里积压了太多待处理帧。常见做法是队里最多保留一帧新帧来了直接替换清空这样永远显示最新帧。代码里用queue.Queue(maxsize1)在put之前先get掉旧帧。如果发现显示画面和骨骼错位明显说明你用了多帧队列必须在推理线程里丢弃旧帧。try: self.frame_queue.put_nowait(frame) except queue.Full: # 丢旧帧只保留最新帧 try: self.frame_queue.get_nowait() except queue.Empty: pass self.frame_queue.put_nowait(frame)5.5 现象模型对某一式动作识别得差比如“两手攀足固肾腰”总提示不合格原因这一式涉及弯腰和手触脚关键点在弯腰时容易被躯干遮挡尤其髋关节和膝关节角度变化大。排查时先看可视化界面里骨骼线是否正确如果骨骼线在弯曲时乱跳说明是数据问题需要补充弯腰姿态的标注数据。如果骨骼线稳定那就是规则阈值太苛刻。两手攀足的“达标”定义不要只看“手能不能碰到脚”而是看“髋关节角度变化是否超过某个阈值”因为不同人的柔韧性差异极大。用相对角度而不是绝对坐标作为判断依据是八段锦指导系统里最实用的调参经验。比如弯腰时躯干角度定义为肩中点-髋中点连线与垂直方向的角度差只要超过60度就算“有弯腰动作”而不是要求手触到地面。6. 进阶把练习指导做得更像产品——评分、时序平滑与复盘报表做到这里系统已经能识别关键点、给出动作是否达标但八段锦练习指导还有一个体验层面的功能给出可读的动作得分和阶段反馈。最后这个环节我用的是一个清屏时序逻辑把“连续帧的抖动”变成“稳定动作状态”。具体做法是保留最近15帧的判断结果只有某一种状态连续出现超过5帧才锁定同时给每个动作状态打一个基础分再根据关键点角度偏离程度扣分。比如“双手托天理三焦”的上举阶段肩膀到手腕的连线应接近垂直偏离超过10度扣5分超过20度再扣5分。from collections import deque STATE_WINDOW 15 THRESHOLD 5 class ActionStateMachine: def __init__(self): self.buffer deque(maxlenSTATE_WINDOW) self.current_action None def update(self, state): self.buffer.append(state) if len(self.buffer) THRESHOLD: return self.current_action # 只在窗口内出现最多的状态超过阈值时才切换 count sum(1 for s in self.buffer if s state) if count THRESHOLD and state ! self.current_action: self.current_action state self.buffer.clear() return self.current_action状态机的好处是动作切换的瞬间不会因为一两帧的抖动就乱报。我做过的最有用的一次复盘是用户做一个完整的八段锦套路系统记录每一式每个阶段进入和离开的时间戳最后生成一张表格。这正好发挥可视化界面的价值左侧播放带骨骼线的回放视频右侧显示每一式“动作名称、进入时刻、离开时刻、完成度、主要问题”。完成度是阶段角度判断的比例加权主要问题是角度偏差最大的关键点名称。这个报表非常受答辩老师欢迎因为它直观展示了系统的工程完整性。复盘功能里我会把每帧的关键点坐标以CSV形式记录而不是只存视频。CSV一行17个关键点坐标文件不大但可以做离线分析比如画出这15秒内肘关节角度的变化曲线精确看出动作在第几帧发生变形。这个技巧让八段锦指导系统从“检测模型界面”升级成“有数据分析能力的小产品”也算是我做过这类系统后最想保留的习惯——所有判断都要留下可追溯的数据而不是让用户看完一个得分就没了。这个方向在毕设里可以单独抽出来作为创新点工作量不大但很有说服力。希望这个从数据集到界面排查的完整套路帮到你。本文还有配套的精品资源点击获取