简介:这份资源是面向计算机、人工智能、自动化等专业学生与教师的YOLOv8五禽戏动作识别完整项目,可直接用于毕业设计、课程设计或大作业。项目基于YOLOv8目标检测框架,实现五禽戏动作的识别与可视化展示,包含训练脚本、推理检测、可视化界面与部署说明,部署简单、操作门槛低,适合具备一定Python基础的学习者进阶实践。压缩包共97个文件,约24.21MB,以70个py源码文件为核心,辅以4个pt模型权重、5个xml配置、12个pyc缓存及txt说明文档等,覆盖模型训练、检测推理与界面交互等模块。已有71人学习下载。读者可获得一套经过运行验证的完整方案,包括数据集、可视化页面、部署教程,以及核心指标曲线、混淆矩阵、F1分数曲线、精确率-召回率曲线和验证集预测结果等分析图表,便于快速复现实验、理解检测流程并在此基础上修改扩展功能。
1. 五禽戏动作识别为什么值得用 YOLOv8 做一遍
健身气功五禽戏只有虎、鹿、熊、猿、鸟五套动作,但每一套里又有若干定式,比如虎举、虎扑、鹿抵、鹿奔、熊运、熊晃、猿提、猿摘、鸟伸、鸟飞。做教学评估、比赛打分或者康复训练记录时,靠人眼逐帧看视频既慢又容易疲劳,动作是否到位、定式是否标准,很难给出稳定一致的判断。把这件事交给视觉模型,核心诉求其实很朴素:给一段手机拍的视频,能自动切出每一式,并判断当前属于哪一类动作。
YOLOv8 在这里不是拿来直接做分类的,而是先做人体检测,再在人体框上做姿态或动作分类,或者干脆把动作类别当成检测目标训练。标题里提到的源码、完整数据集、可视化界面、部署教程,本质是把「数据标注—训练—推理—界面」这条链路打包好,让毕设或课程设计能快速跑起来。适合谁?适合有 Python 基础、想做一个能演示、能写进论文、能在本地或服务器上跑通的学生和初级工程师。不适合指望开箱即用、完全不碰命令行的人。
2. 五禽戏数据集怎么准备:从视频到 YOLO 标注
2.1 数据采集与类别定义
五禽戏动作识别最容易翻车的地方不是模型,而是数据。网上能找到的五禽戏视频大多是完整套路演练,镜头角度、背景、服装、光照差异极大。如果直接拿这些视频抽帧训练,模型学到的很可能是「背景 + 服装」而不是动作本身。我一般会先明确类别体系:是按五禽分五大类,还是按具体定式分十几类。毕设级别建议先做五类,即虎、鹿、熊、猿、鸟,每类至少 300 到 500 张有效帧,总样本量控制在 2000 到 3000 张,这样在单卡 8G 显存上也能训得动。
采集时尽量保证每个类别有 3 到 5 个不同演练者、2 到 3 种背景、正面和侧面两个机位。视频抽帧不要按固定间隔一刀切,动作缓慢时相邻帧几乎一样,动作快时又容易漏掉关键姿态。常见做法是用 OpenCV 先做帧间差分,把变化明显的帧留下来,再人工筛选。下面这段脚本就是按帧间差异抽帧的最小实现。
import cv2 import os def extract_keyframes(video_path, out_dir, diff_thresh=18, min_gap=8): os.makedirs(out_dir, exist_ok=True) cap = cv2.VideoCapture(video_path) prev_gray = None saved = 0 idx = 0 last_save = -min_gap while True: ret, frame = cap.read() if not ret: break gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) gray = cv2.GaussianBlur(gray, (5, 5), 0) if prev_gray is not None: diff = cv2.absdiff(gray, prev_gray) score = diff.mean() # 差异超过阈值且距离上次保存超过 min_gap 帧才保存 if score > diff_thresh and idx - last_save >= min_gap: cv2.imwrite(os.path.join(out_dir, f"frame_{idx:05d}.jpg"), frame) saved += 1 last_save = idx prev_gray = gray idx += 1 cap.release() print(f"saved {saved} frames from {video_path}") extract_keyframes("hu_01.mp4", "raw/hu")逻辑说明:diff_thresh控制灵敏度,值越小保留帧越多,五禽戏这种慢动作建议设在 15 到 25 之间;min_gap防止连续保存几乎相同的帧,一般取 5 到 10。跑完以后一定要人工过一遍,把模糊、遮挡、只有半个身子的帧删掉,否则后面标注和训练都会受影响。
2.2 用 Labelme 标注再转 YOLO 格式
标注工具用 Labelme 还是 LabelImg 都行,关键是框要贴紧人体,不要框到背景里的器械或其他人。五禽戏动作识别如果做的是「人体检测 + 动作分类」,标注时只需要画人体框,类别名写成hu、lu、xiong、yuan、niao。如果做的是「动作定式检测」,那就要把每一式单独标,比如hu_ju、hu_pu,类别数会涨到十几个,标注成本明显上升。毕设建议先用五类跑通。
Labelme 保存的是 JSON,YOLOv8 要的是每张图对应一个 txt,格式为class_id x_center y_center width height,全部归一化到 0 到 1。转换脚本如下。
import json import os classes = ["hu", "lu", "xiong", "yuan", "niao"] cls2id = {c: i for i, c in enumerate(classes)} def labelme_to_yolo(json_dir, out_dir): os.makedirs(out_dir, exist_ok=True) for name in os.listdir(json_dir): if not name.endswith(".json"): continue with open(os.path.join(json_dir, name), "r", encoding="utf-8") as f: data = json.load(f) img_w = data["imageWidth"] img_h = data["imageHeight"] lines = [] for shape in data["shapes"]: label = shape["label"] if label not in cls2id: continue pts = shape["points"] xs = [p[0] for p in pts] ys = [p[1] for p in pts] x1, x2 = min(xs), max(xs) y1, y2 = min(ys), max(ys) # 归一化并转成 YOLO 的 center 格式 xc = (x1 + x2) / 2.0 / img_w yc = (y1 + y2) / 2.0 / img_h w = (x2 - x1) / img_w h = (y2 - y1) / img_h lines.append(f"{cls2id[label]} {xc:.6f} {yc:.6f} {w:.6f} {h:.6f}") txt_name = os.path.splitext(name)[0] + ".txt" with open(os.path.join(out_dir, txt_name), "w") as f: f.write("\n".join(lines)) labelme_to_yolo("labels_json", "labels_txt")参数说明:classes的顺序必须和后面训练时 data.yaml 里的 names 完全一致,否则类别会错位。归一化时用imageWidth和imageHeight,不要用自己以为的尺寸。转换完随便抽几张用可视化脚本画框检查,确认框的位置和类别都对。
2.3 数据集划分与 data.yaml
YOLOv8 要求目录结构是 images/train、images/val、labels/train、labels/val。按 8:2 划分,如果样本少可以 7:3。注意同一个视频抽出来的帧不能同时出现在训练集和验证集里,否则验证指标会虚高,这是血泪经验。正确做法是按视频源划分,同一个视频的帧只进一个集合。
# 目录结构示例 dataset/ images/ train/ val/ labels/ train/ val/ data.yamldata.yaml 内容如下,路径写绝对路径最稳,避免工作目录变化导致找不到数据。
path: /home/user/wuqinxi/dataset train: images/train val: images/val nc: 5 names: ["hu", "lu", "xiong", "yuan", "niao"]3. YOLOv8 训练五禽戏动作识别模型的参数怎么设
3.1 环境配置与模型选择
环境配置是新手第一道坎。Ubuntu 20.04 上装 CPU 版本最简单,一条命令就能跑通推理,但训练会非常慢。有 NVIDIA 显卡的话建议装 CUDA 版本的 PyTorch,GTX 1660 Ti 这种 6G 显存的卡跑 YOLOv8n 或 YOLOv8s 是够的,batch 设 8 或 16。安装顺序是先装 PyTorch 再装 ultralytics,不要反过来。
# CPU 版本,适合先跑通流程 pip install torch torchvision --index-url https://download.pytorch.org/whl/cpu pip install ultralytics opencv-python labelme # 验证环境 yolo checksyolo checks会打印 PyTorch 版本、CUDA 是否可用、设备信息。如果显示 CUDA 不可用但你有显卡,多半是 PyTorch 装成了 CPU 版,重装对应 CUDA 版本的 torch 即可。模型选择上,YOLOv8n 最快,适合毕设演示;YOLOv8s 精度略高,训练时间翻倍。五禽戏这种类别少、姿态差异大的任务,n 和 s 的差距不会特别大,先用 n 跑通再考虑换 s。
3.2 训练命令与关键参数含义
训练入口就一条命令,但参数决定成败。下面是我常用的配置。
yolo detect train \ data=/home/user/wuqinxi/dataset/data.yaml \ model=yolov8n.pt \ epochs=150 \ imgsz=640 \ batch=16 \ lr0=0.01 \ lrf=0.01 \ patience=30 \ device=0 \ project=wuqinxi_runs \ name=exp1参数逐个说:epochs=150是上限,实际会在 patience 触发时早停;imgsz=640是输入尺寸,显存不够就降到 416 或 320;batch=16在 6G 显存上跑 640 可能爆,爆了就改 8;lr0是初始学习率,0.01 是默认值,数据量小可以降到 0.005;lrf是最终学习率比例,控制余弦退火终点;patience=30表示 30 轮验证指标不提升就停,省时间。device=0指定第一块 GPU,CPU 训练写device=cpu。
训练过程中重点看三个指标:box_loss 是否稳定下降、mAP50 是否上升、cls_loss 是否震荡。如果 box_loss 下降但 mAP 不涨,多半是验证集和训练集分布差异太大,检查是不是同一个视频的帧泄漏了。如果 cls_loss 一直很高,可能是类别不平衡,虎和鹿的样本数差太多,需要补数据或加类别权重。
3.3 训练结果解读与模型导出
训练完在wuqinxi_runs/exp1/weights/下会有best.pt和last.pt。best.pt 是验证指标最好的权重,部署用这个。结果目录里还有results.png和confusion_matrix.png,前者画损失和 mAP 曲线,后者看类别混淆。五禽戏里熊和猿的动作如果混淆严重,说明这两类的姿态特征在检测框层面区分度不够,可以考虑加关键点分支或者换更大的模型。
导出成 ONNX 方便后续部署到不同平台。
yolo export model=wuqinxi_runs/exp1/weights/best.pt format=onnx imgsz=640导出后可以用 onnxruntime 做推理验证,确认导出前后结果一致。如果要做 RK3588 这类板端部署,还需要进一步转 RKNN,那是另一条链路,毕设阶段先用 PyTorch 权重跑通界面就够了。
4. 可视化界面怎么做:从推理脚本到可演示系统
4.1 推理脚本:图片、视频、摄像头三合一
界面之前先有一个稳定的推理函数,输入是帧,输出是带框和类别标签的帧。这样无论后面用 PyQt、Gradio 还是 Web 都能复用。
from ultralytics import YOLO import cv2 model = YOLO("wuqinxi_runs/exp1/weights/best.pt") names = model.names def infer_frame(frame, conf=0.4): results = model.predict(frame, conf=conf, verbose=False) for r in results: for box in r.boxes: x1, y1, x2, y2 = map(int, box.xyxy[0]) cls_id = int(box.cls[0]) score = float(box.conf[0]) label = f"{names[cls_id]} {score:.2f}" cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(frame, label, (x1, y1 - 8), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) return frameconf=0.4是置信度阈值,演示时如果框太多可以调到 0.5,如果漏检多就降到 0.3。verbose=False关掉每帧日志,否则控制台会刷屏。这个函数对图片、视频帧、摄像头帧都适用,区别只在读取方式。
4.2 用 Gradio 快速搭一个可交互界面
毕设演示最省事的方案是 Gradio,几十行就能做出上传图片、上传视频、实时摄像头三个标签页。不需要前端知识,浏览器打开就能用。
import gradio as gr import cv2 import numpy as np from infer import infer_frame def image_ui(img): # Gradio 传入的是 RGB,OpenCV 要 BGR frame = cv2.cvtColor(img, cv2.COLOR_RGB2BGR) out = infer_frame(frame) return cv2.cvtColor(out, cv2.COLOR_BGR2RGB) def video_ui(video_path): cap = cv2.VideoCapture(video_path) fps = cap.get(cv2.CAP_PROP_FPS) w = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH)) h = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT)) out_path = "output.mp4" writer = cv2.VideoWriter(out_path, cv2.VideoWriter_fourcc(*"mp4v"), fps, (w, h)) while True: ret, frame = cap.read() if not ret: break writer.write(infer_frame(frame)) cap.release() writer.release() return out_path with gr.Blocks() as demo: gr.Markdown("五禽戏动作识别演示") with gr.Tab("图片"): img_in = gr.Image() img_out = gr.Image() img_in.change(image_ui, img_in, img_out) with gr.Tab("视频"): vid_in = gr.Video() vid_out = gr.Video() vid_in.change(video_ui, vid_in, vid_out) demo.launch(server_name="0.0.0.0", server_port=7860)逻辑说明:Gradio 的 Image 组件默认给 RGB,OpenCV 处理要 BGR,所以进出都要转一次,这是新手最容易忽略的颜色错乱问题。视频处理是逐帧读、逐帧写,输出用 mp4v 编码,浏览器能直接播。server_name="0.0.0.0"让局域网内其他设备也能访问,答辩时用手机拍一段直接传上去演示很方便。
4.3 界面演示时的性能与体验细节
CPU 推理一帧 640 尺寸大概 100 到 300 毫秒,视频会明显卡顿。演示前把视频分辨率降到 720p 以下,或者抽帧处理后再合成。GPU 推理能到 20 到 50 毫秒一帧,基本流畅。界面上加一个置信度滑块让老师自己调,比固定阈值更有互动感。另外准备几张典型测试图,万一现场网络或摄像头出问题,用图片标签页也能完成演示。
5. 避坑与排查:五禽戏动作识别最常见的五个翻车点
5.1 验证集指标很高但实际演示一塌糊涂
现象:训练日志里 mAP50 到 0.9 以上,但拿新视频一跑,框乱飞或者类别全错。原因:训练集和验证集来自同一批视频的相邻帧,模型记住了背景和人物,没有学到动作本质。解决:按视频源划分数据集,验证集用完全没参与训练的视频抽帧,重新训练后再看指标,通常会掉到 0.6 到 0.75,这才是真实水平。
5.2 类别混淆严重,熊和猿分不开
现象:混淆矩阵里熊和猿互相错分,虎和鹿也有少量混淆。原因:检测框只框人体,而熊运和猿提在人体外接框层面姿态差异不大,模型只能靠背景和服装猜。解决:要么增加关键点分支,用姿态特征辅助分类;要么把检测框换成更细的定式标注,让每一式单独成类;最省事的办法是补数据,专门拍熊和猿的对比样本,让模型看到更多区分性帧。
5.3 训练 loss 不下降或变成 nan
现象:开始几轮 loss 正常,突然变 nan 或者一直不降。原因:学习率太大、batch 太小导致梯度不稳,或者标注文件里有宽高为 0 的框。解决:先把 lr0 降到 0.001 试,batch 调到 8 或 16;然后检查 labels 里有没有0 0 0 0 0这种空框,写个脚本扫一遍,把宽高小于 0.001 的行删掉。数据里如果有损坏图片也要清掉,YOLOv8 遇到坏图可能直接报错或产生异常梯度。
5.4 部署到 CPU 环境后推理慢到无法演示
现象:GPU 上跑得好好的,换到只有 CPU 的笔记本或服务器上,视频处理卡成幻灯片。原因:PyTorch CPU 推理没有做优化,默认线程数也可能没吃满。解决:导出 ONNX 用 onnxruntime 推理,速度通常能提升 2 到 3 倍;设置torch.set_num_threads(8)吃满 CPU 核心;输入尺寸从 640 降到 416;视频演示改成抽帧或降分辨率。如果还不行,就只做图片演示,视频用预处理好的一段结果播放。
5.5 界面传视频后输出没有声音或无法播放
现象:Gradio 视频标签页上传后处理完,输出视频浏览器打不开或者没声音。原因:OpenCV 的 VideoWriter 只写视频流,不处理音频;mp4v 编码在某些浏览器上兼容性一般。解决:用 ffmpeg 把原视频音频合并到输出视频上,命令是ffmpeg -i output.mp4 -i input.mp4 -c copy -map 0:v:0 -map 1:a:0 final.mp4;编码换成avc1或直接用 ffmpeg 重编码。演示前一定在目标浏览器上试一遍,别到答辩现场才发现播不了。
6. 把五禽戏识别做扎实的一个进阶习惯
如果只满足于「能跑起来」,上面五章已经够了。但如果你想让这个系统在答辩时经得起追问,或者真的拿去做教学辅助,我建议养成一个习惯:每次训练完,不要只看 mAP,而是把验证集里分错的样本单独导出来看。YOLOv8 的val模式可以保存预测结果,用save_json=True导出 COCO 格式的预测,再写个小脚本对比标注,把 FP 和 FN 的图片路径列出来。这一步花不了多少时间,但能让你清楚知道模型到底错在哪。
具体做法是训练后跑一次验证并保存预测:
yolo detect val \ model=wuqinxi_runs/exp1/weights/best.pt \ data=/home/user/wuqinxi/dataset/data.yaml \ save_json=True \ project=wuqinxi_runs \ name=val_check然后在val_check目录里找到预测 JSON,和验证集标注做比对。下面这个脚本按类别统计漏检和误检数量,输出一个简单的表格。
import json from collections import defaultdict def load_gt(label_dir, img_list): gt = defaultdict(list) for img in img_list: txt = img.replace("images", "labels").replace(".jpg", ".txt") with open(txt) as f: for line in f: c, x, y, w, h = line.split() gt[img].append(int(c)) return gt def compare(pred_json, gt): with open(pred_json) as f: preds = json.load(f) stat = defaultdict(lambda: {"gt": 0, "pred": 0, "miss": 0}) for item in preds: img = item["image_id"] for ann in item.get("annotations", []): stat[ann["category_id"]]["pred"] += 1 for img, labels in gt.items(): for c in labels: stat[c]["gt"] += 1 for c, s in stat.items(): s["miss"] = max(0, s["gt"] - s["pred"]) return stat这个统计不追求严格匹配 IoU,只是给你一个方向:哪一类的漏检最多,就补哪一类的数据;哪一类的误检最多,就去看那些误检图是不是背景干扰太强。我自己的习惯是每训完一版就把错例图存到一个文件夹,命名带上类别和错误类型,攒够几十张就集中分析一次。五禽戏这个任务,动作慢、类间差异小,靠调参能提升的空间有限,真正拉开差距的是数据质量和错例分析。希望这个思路能帮到你,少走一些我当年踩过的弯路。
本文还有配套的精品资源,点击获取