
简介这是一份基于YOLOv8的游泳动作识别系统完整项目资源源码来自个人毕业设计全部代码已测试运行成功可直接用于计算机视觉、人工智能等相关专业的毕业设计、课程设计或大作业。资源包共97个文件以Python源码70个py为主涵盖模型训练、检测服务、可视化页面等模块另含PyTorch权重文件pt、配置文件xml、说明文档txt及演示视频mp4整体大小24.21MB轻量易部署。系统提供可视化操作界面能一键生成核心指标曲线、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果及标签分布图便于展示模型性能。配套完整数据集与详细部署教程下载后按README指引即可快速运行也可以在此基础上二次开发实现其他功能。目前已有40人学习下载适合需要快速落地YOLOv8项目的学生与开发者。1. 基于YOLOv8的游泳动作识别系统泳池边的教练一节课要盯十几个学员划水频率、换气节奏、转身时机全靠肉眼漏判和误判几乎是必然。把YOLOv8接到泳池监控上对视频流逐帧检测人体位置并输出当前泳姿类别和动作阶段这个方案的工程量其实比想象中低——它绕开了OpenPose那种姿态估计路线把问题简化为单帧检测每一帧里人是什么姿态就贴什么动作标签。识别结果直观、答辩时容易讲清楚精度和召回率也适合用mAP量化。整套系统的核心环节只有三个带泳姿标签的数据集、YOLOv8的训练与调参、一个能跑起来看效果的可视化界面。这套路径也适合刚接触目标检测的工程师拿真实场景练手比单纯跑一遍COCO预训练权重有价值得多。2. 为什么选YOLOv8做游泳动作识别模型结构与识别思路2.1 YOLOv8网络结构中的C2f模块特征提取与梯度流动很多人一上来就找YOLOv8的网络结构图然后被C2f、SPPF、Anchor-Free这些名词劝退。做游泳动作识别最需要理解的就两个设计C2f解决了细粒度特征提取得不够的问题Anchor-Free解决了泳姿检测框长宽比极端的问题。C2f是YOLOv8相对YOLOv5最核心的结构变化。它把上一层的特征图通过两个1x1卷积做通道分离一部分直接走捷径另一部分经过若干个Bottleneck后再拼回去。这样梯度回传路径变短深层网络不容易梯度消失特征提取层加深的同时参数量不爆炸。对游泳动作识别来说这意味着手臂入水、腿部打水这些在画面里只占几十个像素的细节在前向传播中能保留更多有效特征。# C2f的核心逻辑源自ultralytics实现的简化示意 import torch.nn as nn class Bottleneck(nn.Module): def __init__(self, c1, c2, shortcutTrue, g1, k(1, 1), e0.5): super().__init__() c_ int(c2 * e) self.cv1 nn.Conv2d(c1, c_, 1, 1) self.cv2 nn.Conv2d(c_, c2, k[1], 1, paddingk[1] // 2, groupsg) self.add shortcut and c1 c2 def forward(self, x): return x self.cv2(self.cv1(x)) if self.add else self.cv2(self.cv1(x))这段代码的关键在 forward 里的x 也就是残差连接。shortcut 打开时输入特征直接加到输出上即使网络裁掉部分中间变换也不会掉精度这正是 C2f 能堆叠更多层而不过拟合的原因。用两个1x1卷积做通道变化是因为1x1卷积计算量极小降维—提特征—升维的性价比远高于直接用3x3卷积做全通道变换。YOLOv8在检测头上也改成了Anchor-Free每个特征图位置直接回归到物体中心点的距离不再预设anchor框。这个改动对游泳动作识别有实际意义因为游泳时人体在画面里的长宽比可能在0.2到4之间浮动预设anchor网格很难覆盖这种极端分布。Anchor-Free直接绕开锚框设计长条形身体、团缩的蛙泳姿态都能统一回归出来。2.2 动作识别不是动作分类检测框、泳姿标签与时序处理常见误区是把游泳动作识别做成游泳动作分类——用一个大模型对整张图输出一个类别。这在泳池场景里完全不可用因为画面里通常有多个人泳姿可能不同且人体在画面中的占比随时变化。YOLOv8给出的方案是输出N个检测框每个框带一个类别标签和置信度。那么动作阶段和检测框怎么映射最实用的做法是让类别标签直接描述动作阶段而不是只写自由泳蛙泳。我一般建议按下面的体系打标签类别ID标签覆盖的动作场景0freestyle_arm_up自由泳手臂空中移臂1freestyle_catch自由泳手臂入水抓水2breaststroke_glide蛙泳滑行阶段3breaststroke_kick蛙泳蹬腿阶段4backstroke仰泳整体姿态5butterfly蝶泳整体姿态6idle踩水、站立等非泳姿状态按这个标签体系打框训练模型天然就是个逐帧动作阶段识别器。这里有个副产品问题相邻帧的标签会抖动比如蛙泳的 glide 和 kick 边界帧检测结果可能来回跳。常见做法是在后处理里加滑动窗口投票把连续5帧的检测结果做众数平滑再作为最终输出。为什么不直接做关键点检测OpenPose那种思路要输出17个身体关键点再额外用一层网络把关键点序列映射到泳姿类别中途任何一个关键点丢失都会拖垮整体判断。泳池场景里人小、水花遮挡多、池壁反光频繁关键点漏检率远高于目标检测框漏检率。所以用YOLOv8直接输出动作类别在工程上更稳也更适合单人完成毕设代码的量级。2.3 yolov8环境配置从裸机到可用的最小命令环境配置是这类项目卡人最多的一步Windows上尤其要兼顾显卡驱动和PyTorch的CUDA版本匹配。按下面的顺序装出错率最低conda create -n swim_yolo python3.10 -y conda activate swim_yolo pip install ultralytics8.3.0 torch torchvision --index-url https://download.pytorch.org/whl/cu121先建独立Python环境再一起装ultralytics和torch避免pip轮子之间的依赖打架。装完验证一下CUDA是否真的可用python -c import torch; print(torch.cuda.is_available(), torch.cuda.get_device_name(0))打印True RTX 3060说明GPU版本通了。输出False基本只有两种原因一是torch装成了CPU版需要按cu121或cu118的源重装二是显卡驱动太老版本低于525的尽早更新。CPU环境不是不能跑但YOLOv8s在1080p视频上推理只有3-5 FPS做实时识别基本不可用实训项目建议优先解决GPU环境。GTX 1660 Ti这个级别的卡跑YOLOv8s训练561张图、100个epoch大约需要4到6小时属于完全可接受的范畴。3. 游泳动作数据集准备标注格式、数据增强与质量检查3.1 数据集结构与YOLO标注格式游泳相关的目标检测没有现成可用的公共数据集。COCO里有person类但没有泳姿细分KITTI和DOTA来自自动驾驶和遥感场景POI偏行人检测中文场景文字数据集更是完全不沾边。这个项目的数据集基本靠自建从游泳比赛录像、训练视频里抽帧再按2.2的标签表手工标注。YOLO格式是目标检测数据集里最不折腾的格式之一。每张训练图片对应一个同名txt文件放在labels目录下文件里每行代表一个目标class_id x_center y_center width height注意x_center、y_center、width、height全部是相对图片宽高的归一化数值值域0到1。这个细节是最容易踩的坑一旦把像素坐标直接写进txt训练时loss会一路涨mAP基本为零。一个合法的数据集目录结构如下dataset/ ├── images/ │ ├── train/ │ │ ├── swim_001.jpg │ │ └── ... │ └── val/ │ ├── swim_002.jpg │ └── ... ├── labels/ │ ├── train/ │ │ ├── swim_001.txt │ │ └── ... │ └── val/ │ ├── swim_002.txt │ └── ... └── data.yamldata.yaml里写路径、类别数和类别名path: dataset train: images/train val: images/val nc: 7 names: [freestyle_arm_up, freestyle_catch, breaststroke_glide, breaststroke_kick, backstroke, butterfly, idle]训练集和验证集的划分有个省力的技巧按时间窗口切分而不是随机切分。把一段完整比赛视频按1:4:1切成测试、训练、验证三段利用连续帧之间的相似性让同一动作在多个样本里出现相当于变相扩充数据量。随机切分会让相邻帧同时出现在两边评估结果虚高。3.2 用albumentations做针对性数据增强标注完基础数据后用albumentations增强比直接改YOLOv8内置增强参数更好控制。下面这套配置对游泳场景有明确的针对性import albumentations as A transform A.Compose([ A.HorizontalFlip(p0.5), A.RandomBrightnessContrast(brightness_limit0.2, contrast_limit0.2, p0.6), A.MotionBlur(blur_limit5, p0.3), A.Affine(scale(0.8, 1.2), translate_percent0.05, rotate(-10, 10), p0.5), ])水平翻转对游泳动作天然成立左右手动作镜像后类别不变等于直接翻倍数据量。MotionBlur模拟运动相机或监控快速移动产生的拖影让模型见过模糊样本后推理时遇到岸边监控画质才不会退化。旋转角度控制在±10度以内超过15度会引入泳池外区域干扰。各项增强的适配原因可以这样归纳增强手段建议参数适配原因HorizontalFlipp0.5左右手动作对称镜像后标签不变MotionBlurblur_limit5模拟监控拖影与运动模糊RandomBrightnessContrast0.2 / 0.2泳池反光、不同时段光照差异Affine rotate±10度拍摄视角轻微偏转另外ultralytics训练时默认开启mosaic增强拼接4张图生成新样本。不要在训练脚本里关掉它mosaic对游泳这种目标尺度变化大的场景帮助明显唯一要注意的是训练最后10轮需关闭这个下章会细说。3.3 标注质量检查与样本不平衡处理标注质量直接决定训练上限。训练前跑一遍检查脚本看三类问题类别ID是否越界、归一化坐标是否越界、长宽比是否异常。python check_labels.py --data datasetcheck_labels.py 的核心逻辑import os, sys from pathlib import Path def check_labels(label_dir, nc): for txt in Path(label_dir).rglob(*.txt): for line in txt.read_text().strip().splitlines(): cid, x, y, w, h map(float, line.split()) assert cid nc, f类别越界: {txt} {cid} assert 0 x 1 and 0 y 1, f中心点越界: {txt} assert 0 w 1 and 0 h 1, f长宽越界: {txt} w{w} h{h} if w / h 3 or h / w 3: print(f提示极端长宽比 {txt} {w:.2f}/{h:.2f}请复核)长宽比极端不一定是错误游泳时人体横向展开的情况很多但标注人整体的框长宽比在0.3到3之间比较正常。极端值经常是手滑或框没拉全。检查完还要看类别样本数分布如果breaststroke_kick的框只有自由泳的十分之一训练后这个类别的AP会显著偏低。这类不平衡不用急着删数据把低频类别的图片在数据集里复制2到3份再训练就能缓解多数类主导梯度方向的问题。4. 用YOLOv8训练自己的数据集命令、参数与调优4.1 训练命令与train脚本数据准备妥当后训练本身在ultralytics里相当简洁。命令行一条直接跑yolo train datadataset/data.yaml modelyolov8s.pt epochs100 imgsz640 batch16 device0 patience20这里选yolov8s而不是yolov8n是因为游泳动作的细粒度特征需要稍宽一点的backbonen在池边监控的中距离场景下容易漏检。选yolov8m也可以但8G显存以下的卡训练吃力推理速度也下降课程设计不建议直接上m。用Python脚本训练更方便存配置和复现from ultralytics import YOLO model YOLO(yolov8s.pt) model.train( datadataset/data.yaml, epochs100, imgsz640, batch16, device0, patience20, lr00.01, lrf0.01, close_mosaic10, cos_lrTrue, projectruns/swim_train, nameexp1 )yolov8s.pt这个预训练权重会从GitHub自动下载网络不稳定时提前手动下载并放到当前目录命令行里model参数改成yolov8s.pt的本地路径即可。预训练权重的价值在于模型已经见过大量通用目标特征迁移到泳姿识别上50个epoch就能达到直接从头训练100个epoch的效果。4.2 关键训练参数表与close_mosaic技巧参数推荐值对动作识别的影响imgsz640提高到1280能提升小目标召回但显存和时间翻倍batch168G显存上限16G显存可开到32lr00.01用预训练权重不需要更大学习率patience20验证集20轮不涨就早停防过拟合close_mosaic10最后10轮关闭mosaic对齐真实分布cos_lrTrue余弦退火让后期收敛更稳定close_mosaic 常被忽略。mosaic增强虽然在训练中段有效但拼接图的统计分布和真实泳池画面差距较大如果一直开着到最后验证集loss会偏高最终 mAP 也看着偏低。ultralytics 8.0 之后支持 close_mosaic训练收尾阶段自动切回普通增强一般能带来1到2个点的mAP提升。训练期间无需人工干预但有一点要注意如果loss在某几个epoch出现nan九成是学习率过高或混合精度在非NVIDIA设备上的兼容问题。先试ampFalse仍不行就把batch减半。这条对YOLOv8在部分AMD或老NVIDIA显卡上训练尤其常见。4.3 从损失函数曲线和验证指标判断训练质量训练结束后看两个文件runs/swim_train/exp1/results.csv和weights/。判读方法一句话概括train/box_loss一路下降、cls_loss在40轮左右放缓、val/box_loss不掉头上涨就是良性训练。可以用pandas把损失函数曲线图画出来方便答辩展示import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/swim_train/exp1/results.csv) df[[epoch, train/box_loss, val/box_loss]].plot(xepoch) plt.savefig(loss_curve.png)曲线图上如果val/box_loss在第60轮后持续上升而train/box_loss还在降就是过拟合信号。此时最有效的操作不是调早停而是回到数据增强里把翻转、亮度变化的概率各降0.1因为泳姿数据量普遍小过拟合几乎都来自增强强度不足。验证集指标的完整评估用yolo val modelruns/swim_train/exp1/weights/best.pt datadataset/data.yaml输出会包含每类的Precision、Recall、mAP50和mAP50-95。mAP50-95是COCO协议下的主指标游泳动作识别因为帧间相似度高mAP50-95到0.6以上就足够应付演示。如果某一类AP明显低于均值比如breaststroke_kick总被错分成breaststroke_glide回3.3检查类别样本数大概率是不平衡问题。确认无误后后面所有推理都用weights/best.pt这个权重是按验证集mAP保存的最优模型。5. YOLOv8部署与游泳动作可视化界面5.1 用torchscript导出模型训练验证做完先把best.pt导出成更适合部署的TorchScript格式yolo export modelruns/swim_train/exp1/weights/best.pt formattorchscript导出后得到best.torchscript加载方式与pt类似但内部计算图被固化推理开销更小在CPU上通常也有10%左右的提速。如果部署环境连PyTorch都不想装可以继续导出ONNX但可视化界面里用torchscript足够没必要多引入转换问题。5.2 用Gradio或PySide6搭可视化界面毕设验收常见的两套界面方案Gradio适合快速演示十几行代码搞定浏览器打开即用import gradio as gr from ultralytics import YOLO model YOLO(runs/swim_train/exp1/weights/best.pt) def detect_image(img): results model.predict(img, conf0.35, iou0.5, imgsz640) return results[0].plot()[:, :, ::-1] gr.Interface(fndetect_image, inputsimage, outputsimage, title游泳动作识别系统).launch()conf0.35比默认0.25严格因为泳池背景杂乱、水花干扰多太低的置信度阈值会引入大量误检。把inputs换成webcam就能直接调摄像头做实时识别。要满足桌面应用的验收要求我一般用PySide6加载视频并实时绘制检测框import sys import cv2 from PySide6.QtWidgets import QApplication, QLabel, QVBoxLayout, QWidget from PySide6.QtGui import QImage, QPixmap from ultralytics import YOLO class SwimDetector(QWidget): def __init__(self): super().__init__() self.model YOLO(best.pt) self.cap cv2.VideoCapture(test_swim.mp4) self.label QLabel() layout QVBoxLayout(self) layout.addWidget(self.label) self.timer self.startTimer(0) def timerEvent(self, _): ret, frame self.cap.read() if not ret: return results self.model(frame, conf0.35, iou0.5) frame results[0].plot() rgb cv2.cvtColor(frame, cv2.COLOR_BGR2RGB) h, w, ch rgb.shape self.label.setPixmap(QPixmap.fromImage( QImage(rgb.data, w, h, ch * w, QImage.Format_RGB888))) if __name__ __main__: app QApplication(sys.argv) win SwimDetector() win.show() sys.exit(app.exec())self.startTimer(0)表示事件循环空闲就跑一次timerEvent实际帧率由推理耗时决定把0改成16就是强制约10帧播放节奏但推理跟不上的话画面会丢帧这两个值的取舍以最终流畅度为准。5.3 部署阶段容易踩的3个坑部署时最容易出问题的三个点按优先级说。第一GPU显存占用不等于模型在工作。用nvidia-smi看显存被占满但检测结果全为空先把conf降到0.15试一遍仍为空就换一张训练集里的图片做单图推理确认模型本身有没有输出排除图片输入通道顺序问题。第二用TorchScript做推理时输入要做预处理。直接拿cv2读出的BGR帧喂进去颜色通道和归一化全错。至少要做BGR转RGB、转float32、除以255这三步。第三多泳道场景下NMS参数要放开。训练和推理的iou阈值保持0.5比较稳妥设到0.6以上会把相邻泳道的人合并成一个框动作类别直接跟着乱跳。这三个点按顺序查界面基本能稳定跑完整个演示流程。本文还有配套的精品资源点击获取