☰
YOLOv8姿态估计实战:八段锦动作评分系统从训练到部署
2026/10/11 11:57:07 网站建设 项目流程

简介:这是一套基于YOLOv8的八段锦动作识别与练习指导系统,面向计算机视觉、人工智能方向的高校学生及毕业设计开发者,可完成目标检测、动作分类与可视化交互演示。资源共含97个文件,以Python源码(70个py)为核心,配套预训练模型权重(pt)、配置文件(xml)、说明文档(txt)及演示视频(mp4),整体压缩包约24.21MB,结构覆盖模型训练、检测服务、可视化页面与部署指南。数据显示已有296人学习使用。内容不仅包含可运行的完整项目,还提供可视化界面设计、核心指标曲线、混淆矩阵、F1曲线等评估工具,便于答辩展示;部署说明与README指引清晰,简单配置即可运行,适合毕业设计、课程设计或初期项目立项演示,也适合新手学习YOLOv8实战流程。

1. 用 YOLOv8 给八段锦动作打分:这套毕设资源能省掉哪些事

YOLOv8 做目标检测不稀奇,但把它拆出 pose 分支做八段锦动作评估,还能在答辩现场直接跑起来,就是另一回事了。这个资源包我拆过一遍,里面不是孤零零的训练代码,而是从完整数据集、训练脚本、可视化界面到部署教程的一整套,属于那种解压后照着文档走,就能真实跑起来的关键点检测与动作指导系统。它解决的痛点是:体育类或计算机类毕设想做 AI 方向,又怕算法太偏被答辩老师问倒——基于人体姿态估计的动作规范性判断,既能讲出深度学习的原理,又能现场演示界面实时识别,算是个很稳的选题。适合做毕设、课设,以及想快速上手 YOLOv8-pose 的初学者。

2. 方案选型与资源拆解:为什么是 YOLOv8-pose,包里到底有什么

2.1 先对比一轮:姿态估计方案里为什么最后选了 YOLOv8

做动作评估,第一步是把人体关键点提取出来。常见的方案不止一个,我平时在项目里选型会先列一张对比表,把精度、速度、工程集成难度都摆出来再拍板。

方案关键点数量部署难度工程集成友好度选型倾向
OpenPose18 / 25 / 135高,依赖 Caffe 和复杂后处理一般,输出格式重,推理速度偏慢不选
MediaPipe33 点低,开箱即用生态闭环,关键点格式和训练流程不好接进自己的卷积管线不选
MoveNet17 点低,轻量速度快但相同分辨率下精度一般,没有统一训练接口不选
YOLOv8-pose17 点低,Ultralytics 一条命令训练能复用检测的训练、验证、导出链路,UI 集成也成熟选用

OpenPose 精度不错,但依赖链太长了,在毕设这种时间预算下,光配环境就能耗掉一周;MediaPipe 拿来做个 demo 很爽,可真要训练自己的动作数据集、调整关键点权重,就不那么顺手了。YOLOv8-pose 最大的优势是生态统一:同一个框架里做检测和关键点,训练时用yolo pose train,推理时直接读权重,后面接可视化界面也省事。所以这套资源选择它作为整个系统的主模型,符合这种项目的实际诉求——不是追求某个指标登顶,而是保证在“数据、训练、界面”这条完整链路里都跑得顺。

2.2 资源包目录拆解:源码、数据、界面各管哪一段

解压后建议先顺着目录走一遍,别急着跑命令。我拆完这个包之后整理的目录结构大概是这样的:

BajingYOLOv8/ ├── weights/ │ ├── yolov8n-pose.pt # 官方 COCO 预训练权重,做迁移学习起点 │ └── best.pt # 基于八段锦数据训练后的权重 ├── datasets/ │ └── pose/ │ ├── images/ │ │ ├── train/ │ │ └── val/ │ ├── labels/ │ │ ├── train/ │ │ └── val/ │ └── pose.yaml # 数据集配置文件 ├── deployment/ │ └── 部署教程.md # 环境配置、训练、界面运行的完整说明 ├── ui/ │ ├── main_window.py # 可视化界面主程序 │ └── pose_utils.py # 关键点后处理、画骨骼线、动作判分工具 ├── tools/ │ ├── preprocess.py # 标注整理与数据集划分 │ └── draw_curve.py # 画损失曲线和指标曲线 └── requirements.txt

weights里放了两份权重,yolov8n-pose.pt是 COCO 预训练模型,只做通用关键点识别;best.pt是这个数据集训练出来的产物,界面默认加载的应该是它。deployment/部署教程.md建议最先读,里面写清楚了从创建环境到启动界面的顺序,我后文讲的步骤和它基本一致,但会补充一些它没写透的参数细节。

tools/preprocess.py是容易被忽略的一环。YOLOv8 的 pose 标注不是常见的 JSON 或 XML,而是每个 txt 文件一行对应一个目标:类别、框的四个值,再加上 17 个关键点的坐标和可见性。这个脚本做的事情就是把原始标注转成这种格式,并按比例切分训练集和验证集。如果你拿到的数据集已经是 YOLO 格式,这步可以跳过,但建议还是跑一遍,确认数据划分是随机的、没有混入顺序性偏差。

2.3 先跑通最简推理:确认权重和关键点输出是对的

在碰界面之前,我习惯先用一段最朴素的脚本验证模型能不能推理,这样能把“模型问题”和“界面问题”隔离开。下面这段代码是包的常见用法,直接基于 Ultralytics 的 Python API 写:

from ultralytics import YOLO model = YOLO("weights/best.pt") results = model.predict( source="datasets/pose/images/val/0001.jpg", # 换成你手上的任意图片或视频 conf=0.5, # 关键点置信度阈值,低于它的点视为不可信 device="0", # "0" 是 GPU,CPU 环境改成 "cpu" save=True # 把标注结果保存到 runs/pose/predict ) keypoints = results[0].keypoints.data # (B, 17, 3) 形状 print(keypoints)

results[0].keypoints.data的形状是(B, 17, 3),B 是检测到的人数,17 是关键点数量,3 对应(x, y, visible)。visible 值为 2 表示标注可见、1 表示遮挡、0 表示该点在画面中不存在,界面判分时要先筛掉 low visible 的点,不然算角度会把动作判断带偏。跑通这段之后,就可以确定权重文件、推理环境和关键点输出都没问题,接下来所有操作都建立在“模型可用”这个前提上。

3. 环境与数据准备:按部署教程跑起来之前的三个前提

3.1 conda 环境与 torch 版本匹配

YOLOv8 的环境配置,热搜里常年有人问,原因在于 torch 装不对,后面全白搭。我建议按下面顺序来,每一行都值得看清楚再执行:

conda create -n bajing python=3.9 -y conda activate bajing pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121 pip install ultralytics

先装 torch 再装 ultralytics,这个顺序是有讲究的。Ultralytics 在上层,它对 torch 版本有要求,如果先把 ultralytics 装好再补 torch,pip 可能会因为依赖冲突把 torch 重新装一遍,白等半天。cu121对应 CUDA 12.1,如果你的显卡驱动版本较老,可以换成cu118,具体以nvidia-smi里看到的驱动支持为准——这一块经常被形容为玄学,但本质是驱动、CUDA、torch 三者要匹配,不是随机问题。

CPU 环境也能跑,torch那行用默认源安装就行,但不建议用 CPU 训练,速度慢到怀疑人生。如果是 GTX 1660 Ti 这类 6G 显存的卡,训练时设batch=8、imgsz=640是跑得动的,后面训练一章会细说。装完环境记得验证一下import torch; torch.cuda.is_available()是否为 True,这一步 10 秒钟,能避免后面所有 CUDA 相关的报错。

3.2 数据集目录与 pose.yaml 的正确写法

数据集目录结构在 2.2 已经列过,这里重点说pose.yaml。YOLOv8 训练时靠这个文件定位数据,路径写错是最常见的翻车点,而且报错信息不太直接,常以AssertionError: train dataset not found这类形式出现。

path: datasets/pose # 数据集根目录,相对当前工作目录 train: images/train # 训练图片目录 val: images/val # 验证图片目录 kpt_shape: [17, 3] # 17 个关键点,每个点保存 (x, y, visibility) names: 0: bajinji # 本数据集只有一个类别

path用相对路径还是绝对路径?如果报路径找不到,直接改成/你的绝对路径/datasets/pose,大部分项目用绝对路径能少生一肚子气。kpt_shape这里要特别留意:[17, 3]表示 17 个点、每个点 3 个值。如果你用的是自定义关键点格式,改动这里的同时,界面端读关键点的代码也得同步改,否则会出现第 5 章要讲的“数量不匹配”问题。

对应的 labels 文件是纯文本,每行表示一个人体目标:class_id x_center y_center width height开头,后面跟 17 个关键点的(x, y, visible),也就是一行一共 1 + 4 + 17×3 = 56 个数。坐标全部归一化到 0~1,写的时候要注意别把像素坐标直接丢进去,那是检测和关键点训练失败的高频原因。

3.3 训练前的预处理:把原始标注转成 YOLO 格式

这个包里的tools/preprocess.py就是干这件事的。原始标注可能是从标注工具导出的 JSON,也可能是别人打包好的 XML,脚本负责统一转成 YOLO pose 的 txt,并完成训练集/验证集的随机划分。

python tools/preprocess.py \ --src-dir datasets/raw \ --out-dir datasets/pose \ --val-ratio 0.2

--src-dir填原始数据所在目录,--val-ratio 0.2表示留 20% 做验证集。执行后脚本会生成 n 个 txt 标注文件,同时打印出每个类别的目标数量。这里要核对一个数:类别数量必须是 1,也就是只有bajinji。如果打印出来显示有噪音类别,说明原始标注里有空标注或错误标签,需要先清理,不然训练一个多类别模型出来,界面按单类别去画骨骼线就会错乱。

跑完预处理,再打开pose.yaml确认 train/val 路径和生成的images、labels目录能对上,然后就可以进入训练环节了。

4. 训练自己的关键点模型:命令、参数与损失曲线判断

4.1 训练命令与关键参数说明

训练是整套资源里最耗时的环节,也是值得反复调整的环节。命令本身不复杂,复杂的是参数怎么配合你的硬件和数据量。

yolo pose train \ data=datasets/pose/pose.yaml \ model=yolov8n-pose.pt \ epochs=120 \ imgsz=640 \ batch=8 \ patience=20 \ device=0

逐个说参数怎么理解。model=yolov8n-pose.pt是从 COCO 预训练权重开始微调,比从头训练收敛快得多;如果显存只有 4G,可以换yolov8n-pose.yaml且配imgsz=480,精度会掉一些,但训练时显存占用小很多。epochs=120在 pose 任务里够用了,前提是patience=20生效——它表示连续 20 个 epoch 验证损失没改善就提前停止。这个机制是防过拟合的,不要随手关掉。

batch=8在 6G 显存卡上是个安全值。如果报 CUDA out of memory,优先降到 4,而不是去换更小的模型,因为显存不够影响的只是 batch-size,强行调小 imgsz 反而会让关键点定位精度下降。device=0指定第一张 GPU,建议启动前用nvidia-smi看一眼是不是已经有进程占了显存。

4.2 看损失曲线判断训练状态:什么时候该停

训练跑起来之后,别干等着,Ultralytics 会在runs/pose/train/下生成results.csv,里面记录了每个 epoch 的 box loss、pose loss、cls loss 和验证集指标。用这个包自带的tools/draw_curve.py,或者直接自己画,我一般这样写:

import pandas as pd import matplotlib.pyplot as plt df = pd.read_csv("runs/pose/train/results.csv") # 注意列名自带空格,取列时按实际 CSV 为准 for col in ["train/box_loss", "train/pose_loss", "val/pose_loss"]: plt.plot(df[col], label=col.strip()) plt.xlabel("epoch") plt.ylabel("loss") plt.legend() plt.savefig("loss_curve.png", dpi=200)

重点看val/pose_loss,也就是验证集上的关键点损失。曲线在前几十个 epoch 快速下降,然后趋平,这是正常节奏。如果验证损失出现明显回升而训练损失还在降,就是过拟合信号,patience=20应该已经触发早停;没触发的话,说明曲线在抖,可以再等几个 epoch,也可以直接停掉,用当前验证指标最好的权重。

这里顺带回应一下“yolov8 画损失函数曲线图”的常见困惑:很多人开了训练就干等,跑完了也不看曲线,直接拿last.pt用。关键点任务里,最低验证损失对应的不一定是最 后一个 epoch,所以best.pt和last.pt要分清——界面默认加载的是best.pt,你用last.pt替换训练出来的新权重时,得先确认这一点。

4.3 验证指标与权重选择

训练结束后,跑一次显式验证,看看权重在验证集上的真实表现:

yolo pose val \ model=weights/best.pt \ data=datasets/pose/pose.yaml

输出里会给出mAP50-95、pose AP等指标。对小规模数据集,mAP50-95在 0.8 以上就可以接受,关键点定位误差需要结合可视化的骨骼叠加来判断——打开runs/pose/val/下保存的预测图片,看骨骼线和原图人体对齐程度,这比单看一个数字更有说服力。如果发现多数图片里脚跟、膝盖位置偏差明显,优先去检查 labels 的标注质量,而不是堆 epoch。

5. 避坑记录:界面与推理部署时最容易翻车的五个点

5.1 训练或推理时报 CUDA out of memory

现象:命令跑起来没几秒就报torch.cuda.OutOfMemoryError,进程直接退出。

原因:imgsz 或 batch 超出显存容量,也可能是别的程序占了显存。

解决:先降 batch 到 4 或 2,再考虑降低 imgsz 到 480。顺序不能反过来,因为关键点任务对输入分辨率更敏感。如果还不行,检查nvidia-smi看显存占用是否被其他进程吃掉了;训练前通过CUDA_VISIBLE_DEVICES=0锁定单卡,能避免多卡环境下的显存冲突。

5.2 界面运行时摄像头画面黑屏或卡死

现象:界面能打开,但视频区域一直黑,或者几秒才刷一帧,点了关闭也没反应。

原因:最常见的是界面主线程里直接循环调用cap.read()和model.predict(),推理耗时把 UI 事件循环堵死了。摄像头被占用时还会读到空帧但不会报错。

解决:把视频读取和模型推理移到单独线程,主线程只负责显示。读帧前必须先做cap.isOpened()检查,读出来是空帧就跳过这一轮;摄像头索引不对时,测试cv2.VideoCapture(1)而不是盯着 0 不放。这个坑在运行界面代码时出现频率最高,部署教程里如果没提多线程,你大概率会撞上。

5.3 界面文字显示成方块或乱码

现象:窗口标题、动作名称显示为“□□□□”。

原因:OpenCV 的cv2.putText不支持中文,默认渲染不出汉字,这在界面里显示“左右开弓似射雕”这类动作名时尤其明显。

解决:两个办法。一是在界面里全部用英文标签,开发成本最低;二是在画面上用 Pillow 把中文先画到透明图层,再叠加到帧上,效果自然,但需要额外引入 PIL 并处理字体文件路径。毕设答辩时画面上的文字要能看清,方块字非常减分。

5.4 关键点索引与模型输出不对齐

现象:界面能跑,画出来的骨骼线位置错乱,比如肘关节连到了肩膀。

原因:模型输出是 17 点,但界面代码里写死了自己的一套关键点顺序,和 COCO 约定的顺序(鼻子、双眼、双耳、双肩…)不同。你训练的时候改了类别数或关键点数量,界面端没跟着改,就会出现这种静默错误。

解决:训练后先打印model.model.yaml里的kpt_shape,确认和界面读取代码一致;同时对照 COCO 关键点索引表,把界面里每个关节的连线顺序对一遍。这个错不报异常,全靠肉眼排查,是最耗人的一类坑。

5.5 模型推理结果正常但界面一直没输出提示

现象:摄像头上人体的骨骼线画出来了,但没有动作判分文字,或者分数恒为 0。

原因:判分逻辑依赖的关键点可见性(visible)筛选,把大部分点都过滤掉了;或者界面代码读的是 0.5 版本之前的关键点坐标格式,没适配新的可见性值。

解决:先输出原始关键点数据,手动检查 visible 分布,合理阈值一般设在 0.5。别把visible == 2才视为有效,那样遮挡帧就会全部判为无效,分数当然恒为 0。判分函数里加一条日志,输出当前参与计算的关键点数量,比盯着分数猜要快得多。

6. 可视化界面的判分套路:从关键点到动作规范分数

6.1 用余弦定理算关节角:判分的关键一步

八段锦动作规范与否,落到代码层面其实就是几个关键角度是否落在合理区间。界面里pose_utils.py的核心函数,本质是用三点算夹角,以肘关节角度为例,传入肩膀、肘部、手腕三个点的坐标,取肘部为夹角顶点:

import math def calc_angle(a, b, c): # a: 肩, b: 肘, c: 腕,b 是夹角顶点 ab = (a[0] - b[0], a[1] - b[1]) cb = (c[0] - b[0], c[1] - b[1]) dot = ab[0] * cb[0] + ab[1] * cb[1] dist_ab = math.hypot(ab[0], ab[1]) dist_cb = math.hypot(cb[0], cb[1]) if dist_ab == 0 or dist_cb == 0: return 0.0 cos_val = max(-1.0, min(1.0, dot / (dist_ab * dist_cb))) return math.degrees(math.acos(cos_val))

拿到角度后,界面里会跟一组预设阈值比对,输出“偏低/到位/偏高”的提示。阈值通常在代码顶部以字典形式集中定义,换个动作式样只改字典值,不用动判分逻辑。这是整个系统最值得讲给答辩老师听的部分——把姿态问题转化成可量化的角度判定。

6.2 一个可持续运行的实时主循环

界面主程序的视频处理部分,哪怕引用了线程,核心循环也是同样的结构:读帧、推理、算角度、写提示。简化后就长这样:

while cap.isOpened(): ret, frame = cap.read() if not ret: continue results = model.predict(frame, verbose=False)[0] kpts = results.keypoints.data.cpu().numpy() # 对每个目标:筛可见点 -> 算关节角 -> 比对阈值 -> 拼提示文字 frame = draw_pose(frame, kpts, thresholds) cv2.imshow("Bajing Judge", frame) if cv2.waitKey(1) & 0xFF == ord("q"): break

注意verbose=False,不然推理信息会刷屏,界面性能也会被日志拖慢。从那以后我每次拿到一套带界面的 YOLO 工程包,都会先跑一遍不带界面的推理脚本,确认模型输出形状和关键点顺序没问题,再去碰 UI 代码——这个顺序帮我省掉了大量无意义的排错时间,希望帮到你。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询