尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

基于YOLOv8的实验室防护服穿戴检测系统:从数据集训练到界面部署

基于YOLOv8的实验室防护服穿戴检测系统:从数据集训练到界面部署 简介面向计算机视觉与人工智能方向的学习者尤其适合计算机、人工智能、自动化等专业的在校学生用于毕业设计、课程设计或项目初期演示。该方案基于YOLOv8实现实验室防护服穿戴规范检测从数据集到训练、推理、可视化展示形成完整闭环。资源包含训练与推理全流程源码、可交互的可视化界面、整理好的标注数据集以及部署说明文档代码经过个人毕设场景测试运行成功能够稳定生成核心指标曲线、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果及标签分布图等图表帮助快速形成答辩所需的过程性实验材料。压缩包共8个文件主要涵盖3个Python脚本、3个模型权重文件含已训练好的best.pt和2个说明文档整体约15.91MB体积精简目录结构清晰按README即可完成环境配置与运行。目前已有47人学习下载适合对目标检测感兴趣、需要快速落地YOLO项目并产出可视化成果的初学者或进阶者。1. 实验室防护服穿戴检测为什么YOLOv8能把这个毕设做成“可落地”的项目实验室安全员每天要盯好几路摄像头检查防护服、护目镜、口罩有没有按规范穿戴。基于YOLOv8的实验室防护服穿戴规范检测就是用目标检测把这件重复劳动自动化一个摄像头画面进来先找到人再检查这个人身上有没有穿防护服、戴护目镜漏了就在界面上标红并记录。标题里同时带了源码、可视化界面、完整数据集和部署教程意味着你拿到的不是一篇纯理论论文而是一个能直接跑起来、用于毕设或课程设计的工程包。适合两类人想快速复现一个完整系统交差的学生和想把这个方向做成安全巡检原型的入门工程师。接下来的内容我会按“任务拆解→环境与数据→训练调参→界面部署→踩坑修复”的顺序把这个项目从头到尾走一遍并且给出可以直接照抄的命令和代码。2. 任务拆解与模型选型把“穿戴规范”翻译成YOLOv8能学的类别2.1 穿戴检测到底检测什么类别设计决定后面的逻辑代码很多人拿到这类项目的第一反应是训练一个“违规检测器”直接标注“穿了防护服”和“没穿防护服”两类。这个思路在样本极度充足时能跑通但实验室场景下很容易翻车不同角度下“没穿”的画面差异太大正面拍到的“没穿”和侧面拍到的“没穿”完全是两种样子数据稍微不平衡模型就会倾向于把所有人判成“穿戴规范”。更常见的做法是拆成多类别检测把“人”和“防护装备”分开标。我一般会设置四类person、lab_coat、goggles、mask有需要再加 safety_hat。这样训练出的模型只回答“画面里有没有这些东西”至于“这个人穿得规不规范”由后置的合规判断逻辑去算。逻辑非常直接检测到一个人但这个人所在的框内没有匹配到 lab_coat就判定违规。这种做法的好处是类别边界清晰标注工作量也小每个类别都是一个独立目标不会因为姿态变化让整个框的语义崩掉。类别设计直接决定了后面可视化界面里的判断代码怎么写。如果一上来就标“违规/正常”二分类界面里就只能显示一个判决结果没法告诉安全员“到底是没穿防护服还是没戴护目镜”。拆成四类之后违规原因可以被拆成一条一条界面左侧列一个清单谁没穿谁没戴一目了然。2.2 为什么选YOLOv8而不是Faster R-CNN和YOLOv5选型这件事毕设和真实项目是两套逻辑。真实项目要看精度、算力成本和部署平台的综合账但毕设工程包最看重的是“我能不能在两周内做完、答辩时能不能稳定演示”。YOLOv8在这条路上几乎是性价比最高的选择。相比Faster R-CNNYOLOv8的部署成本低得多。一个最小的推理脚本只有几行不需要单独写RPN和ROI相关的后处理而且YOLOv8的head是解耦结构分类和回归分支分开在小目标、遮挡场景下不容易把类别和位置互相牵制。实验室的摄像头画面通常是固定机位、近距离拍摄防护服和护目镜都属于中等大小目标这个场景正好落在YOLOv8的优势区间。和YOLOv5比YOLOv8的标签分配策略更省心。YOLOv5用静态的anchor分配数据里目标大小分布比较极端时得手动算anchorYOLOv8用TaskAlignedAssigner训练过程会自动匹配正样本少一次肉眼挑anchor的玄学环节。对于自定义数据集这个“少一个调参步骤”就是实打实的省时间。型号选择上不要盲目上最大模型。实验室桌面机大多是GTX 1660 Ti、RTX 2060这个级别的显卡我给的参考如下模型参数量级显存占用参考适用场景yolov8n约3M2G以内核显或老显卡追求快速跑通yolov8s约11M3G左右桌面机默认选择精度和速度平衡yolov8m约25M5G左右6G以上显存数据量也较多时再用对几百张自定义数据的穿戴检测来说yolov8s是起点不是终点。先拿s把流程跑通如果显卡报警再降级到n这个顺序最省心。2.3 先检测人再检测装备一条不会“漏报”的合规判断规则穿戴规范检测的核心逻辑不是“检测到违规框”而是“人存在但装备缺失”。这句话写进代码之后整个系统才谈得上可用。拿一个最简的伪代码说清楚这个规则def check_compliance(person_boxes, equip_boxes, conf_thres0.25): violations [] for person in person_boxes: has_coat any( is_inside(equip, person) for equip in equip_boxes.get(lab_coat, []) ) if not has_coat: violations.append({ person: person, reason: missing_lab_coat, confidence: person.conf }) return violations这段代码做的事遍历每个检测到的人check这个人框内有没有防护服is_inside判断装备框的中心点是否落在人的框内这是穿戴检测里最常用的匹配方式。参数conf_thres控制判定门槛默认0.25实际上我会建议在界面里做成滑条让用户自己调。理由很简单安全场景宁可多报几个“疑似漏穿”也不能漏掉一个真违规。置信度调低会让误报变多但误报的代价远小于漏报。这套逻辑也解释了为什么类别设计不能图省事。如果模型只输出“违规”和“正常”两类这段check_compliance根本没有存在空间而把检测目标拆成人、防护服、护目镜之后判断代码和报警记录都能分门别类写清楚。3. 环境配置与数据集制作先让YOLOv8在本地跑通再标出自己的防护服样本3.1 YOLOv8环境配置conda、Python和CUDA版本的匹配关系每次看到有人卡在环境上浪费两三天我都觉得亏。YOLOv8的环境配置本身不复杂复杂的是PyTorch和CUDA的版本关系。不管你手里的包是谁整理的依赖清单里一定写着ultralytics和torch装这两样之前先把三件事定下来Python版本、CUDA版本、显卡驱动支持的最高CUDA。我的做法是先建独立环境不和系统Python混在一起省得后面装其他包冲突。装PyTorch前先跑一次nvidia-smi看右上角的CUDA Version。注意那行数字表示驱动支持的最高CUDA版本不是系统里已经装的CUDA工具包。PyTorch的CUDA版本只要不高于这个数字就能用11.8是目前兼容性最好的选择。conda create -n ppe python3.10 -y conda activate ppe pip install ultralytics pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118参数说明Python 3.10是ultralytics在各版本下最省心的解释器3.12偶尔会遇到numpy和opencv的兼容问题没必要赌。--index-url指定PyTorch官方源下载慢就把这段去掉用默认PyPI源装CPU版训练再换CUDA版。装完之后用yolo predict modelyolov8n.pt测一次能出结果就说明环境通了一半。环境配置的另一个坑是网络。国内机器直接下载ultralytics的预训练权重经常很慢建议提前把 yolov8n.pt、yolov8s.pt 下载好放进项目目录训练时用本地路径引用不依赖自动下载。这属于“简单部署即可运行”的工程包里最常见的隐藏依赖拿到手先检查weights目录下有没有对应文件没有就自己补上。3.2 数据集目录规范与YOLO标注格式从LabelImg开始训练YOLOv8的自定义数据集目录结构是约定俗成的我们的数据集dataset目录按如下结构组织mkdir -p dataset/{all,train,val,test}/{images,labels}all目录放全部原始图片和标注文件train、val、test是后面脚本自动划分出来的。每个子目录下images放图片labels放同名txt标注。YOLO格式的标签文件长这样每行一个目标0 0.523 0.441 0.235 0.412 1 0.512 0.386 0.180 0.115第一列是类别编号从0开始对应data.yaml里names列表的下标。后面四个数字是归一化后的中心点x、中心点y、宽度w、高度h取值范围都是0到1由标注工具自动算好。如果这四列的值算出来超过1或者小于0就说明标注框出界了这种标签要直接删掉重标。标注工具我习惯用LabelImgpip install labelImg之后启动按W画框按D切下一张按CtrlS保存。注意保存格式要选YOLO工具会为每张图生成同名txt。针对穿戴检测标注时有个原则护目镜这类小目标宁可框得稍微紧一点也不要框进额头和头发防护服要框全身从肩膀到鞋尖这样才能和“人”的框有足够的重叠区域供后面的判断逻辑使用。3.3 数据划分与标签校验一个脚本同时干两件事标注完的图片不能直接开训YOLOv8对数据集的整洁度要求很高。我吃过的最大教训是标注文件里的类别编号从1开始写训练时所有指标全部为零排错排了三小时。下面这个Python脚本能在划分数据集的同时把空标签和越界编号一并揪出来import random import shutil from pathlib import Path random.seed(42) root Path(dataset) imgs sorted((root / all / images).glob(*.jpg)) random.shuffle(imgs) for split in [train, val, test]: (root / split / images).mkdir(parentsTrue, exist_okTrue) (root / split / labels).mkdir(parentsTrue, exist_okTrue) nc 4 # 改成data.yaml里的实际类别数 issues [] for i, img in enumerate(imgs): label_file root / all / labels / (img.stem .txt) if not label_file.exists() or label_file.stat().st_size 0: issues.append(f{img.name}: 标签缺失或空文件) continue cls_ids [int(line.split()[0]) for line in label_file.read_text().splitlines() if line.strip()] if max(cls_ids) nc: issues.append(f{img.name}: 类别编号越界最大编号 {max(cls_ids)}) continue split train if i 0.8 * len(imgs) else val if i 0.9 * len(imgs) else test shutil.copy(img, root / split / images / img.name) shutil.copy(label_file, root / split / labels / label_file.name) print(问题文件:, issues if issues else 无)这段脚本做的事情有三件按8:1:1比例切分数据、跳过空标签和越界标签、把干净的图片和标注复制到对应目录。参数nc必须和data.yaml里写的类别数一致不一致时脚本会明确报出问题文件名和越界编号。random.seed(42)保证每次运行得到相同的划分结果答辩时如果反复训练至少数据分布是可控的。跑完这段脚本后train/val/test三个目录里都有图片和txtdata.yaml里的path字段写绝对路径train写相对路径如train/images。这一步做扎实了训练阶段翻车的概率直接降一半。4. 训练自己的穿戴检测数据集命令、超参与损失曲线判读4.1 训练命令与关键超参第一次跑不要全用默认值YOLOv8的训练命令看起来简单但很多人直接跑默认参数小数据集上很容易过拟合或者不收敛。基于自定义穿戴数据集我常用的命令是这样yolo detect train \ data/home/user/ppe/dataset/data.yaml \ modelyolov8s.pt \ epochs100 imgsz640 batch8 \ optimizerAdamW lr00.001 \ patience20 ampTrue \ projectruns/detect nameppe参数含义如下表这几项是我每次必调的参数推荐值为什么这么设epochs100几百张数据跑100轮足够再多容易把背景纹理一起背下来imgsz640摄像头原图多为1080p640是效果和显存的折中点batch86G显存从8开始OOM就降到4不要硬扛optimizerAdamW小数据集下比SGD收敛更利索SGD要花时间调momentum和lrlr00.001默认0.01对自定义数据偏大loss容易震荡patience20连续20轮val指标不升就提前停省时间ampTrue混合精度能省一半显存遇到nan再关掉训练时长按硬件说yolov8s在GTX 1660 Ti上100轮通常在一个半小时左右yolov8n能压到半小时以内。这个量级完全拖得起多跑几组实验。我一般会跑两个版本一个n模型用来快速验证数据有没有问题一个s模型用来出最终结果而不是一上来就挂在s模型上熬时间。这里有一个很多人忽略的点训练前先看一眼weights目录里有没有yolov8s.pt。YOLOv8的迁移学习依赖官方预训练权重如果本地没有会自动下载。工程包搬运到新电脑时经常漏掉这个文件训练命令就会一直卡在下载阶段。有就把它放在当前目录下命令里直接写modelyolov8s.pt即可。4.2 训练过程看什么recall比mAP50更能反映漏检训练跑起来之后终端会持续输出每个epoch的指标。那个滚动刷屏的过程很多人只是看着并不知道真正该盯哪几个数字。穿戴检测这个场景我最先看的是metrics/recall其次才是metrics/mAP50。原因很直接安全检测任务里漏检的代价远高于误检recall代表“所有真实目标里被找回的比例”recall低就意味着有人没穿防护服系统却根本没标出来。mAP50-95低、mAP50正常这个组合在这个项目里不用太焦虑。穿戴装备的图像边界比较规则mAP50已经能反映实际效果mAP50-95是在不同IoU阈值下求平均对边框像素级贴合要求更高护目镜这类小目标天然不占便宜。答辩时如果被问到就按“我们更关注漏检率所以以recall和mAP50为主要优化目标”来回应。训练过程中真正需要留意的信号有两个一是val/box_loss在epoch 20之后还在持续上升这是过拟合的典型信号说明数据集多样性不够二是recall在第60轮之后纹丝不动说明模型容量或数据量到了瓶颈这时候加训练轮数没有意义回去补数据更实在。每轮跑完best.pt都会被保存到runs/detect/ppe/weights目录这个文件就是后面部署和可视化界面要用的核心产物。4.3 画损失函数曲线从results.csv到一张答辩能用的图训练结束后runs/detect/ppe/下会生成一个results.csv里面按epoch记录了所有训练和验证指标。这个文件本身已经是结构化数据但答辩时直接贴表格太难看我习惯用matplotlib画成图保存为一张平滑的曲线图放进论文附录import pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/detect/ppe/results.csv) df.columns [c.strip() for c in df.columns] # 列名带有行尾空格必须清理 fig, ax1 plt.subplots(figsize(10, 6)) ax1.plot(df[epoch], df[train/box_loss], labeltrain box_loss, colorblue) ax1.plot(df[epoch], df[val/box_loss], labelval box_loss, colororange) ax1.set_xlabel(epoch) ax1.set_ylabel(box_loss) ax2 ax1.twinx() ax2.plot(df[epoch], df[metrics/mAP50], labelmAP50, colorgreen) ax2.set_ylabel(mAP50) plt.legend(locupper left) plt.savefig(loss_curve.png, dpi300)代码里的twinx()双y轴曲线是关键因为box_loss的量级和mAP50完全不在一个尺度画在一张单y轴图上loss曲线会把mAP压成一条紧贴横轴的直线。dpi300是为了放进论文不失真。看这张图时最健康的形态是loss下降、mAP50上升两者趋势相反但都平滑如果loss和mAP50一起往下掉先检查是不是label标反了。5. 排查记录五个最容易让这个项目翻车的坑这个项目真正消耗时间的不是训练而是训练之后一连串让人摸不着头脑的报错。以下五条是我认为在这个特定项目上出现频率最高的坑每一条我都按现象、原因、解决的顺序写清楚。5.1 CUDA out of memory问题不一定在显卡现象训练跑到第几个step就崩报错信息是RuntimeError: CUDA out of memory。原因绝大多数情况下不是显卡太差而是batch、imgsz和模型尺寸三个参数叠加超过显存容量。GTX 1660 Ti这种6G卡跑yolov8m、imgsz640、batch16必崩但同样的卡跑yolov8s、batch8完全能跑。解决先把batch降到4imgsz保持640如果还崩就换yolov8n。不要一上来就缩imgsz穿戴装备是小目标imgsz降到416会让防护服的框变得模糊精度掉得很快。降batch对训练效果的影响远小于降imgsz。5.2 val指标全为0标签编号是从0开始的现象训练正常跑完终端输出的mAP、precision全为0loss看起来也平得像一条直线。原因最典型的是标签文件里类别编号写成了1、2、3而data.yaml里nc3最大合法编号是2。编号越界后YOLOv8在计算损失时会把所有样本当成无效目标处理指标自然全为零。解决用前面3.3的校验脚本跑一遍它会直接报出哪些文件越界、越到了多少。出问题的文件在LabelImg里重新打开把class改成从0开始的编号重新保存后再训练。这个错误肉眼极难发现因为图片上看框的位置完全正确。5.3 mAP50很高现场视频却一路漏检现象验证集效果不错mAP50有0.9但把摄像头对准实验室真实画面防护服和护目镜频繁漏检尤其是侧身和背对镜头的画面。原因训练集和现场画面的分布不一致。很多人拍数据集时喜欢站在正前方模型学到的其实是“正面的防护服长什么样”现场摄像头大多是斜上方俯拍角度一变模型就认不出来。解决从现场摄像头直接截取一批真实画面加进训练集这是最有效的手段比换模型、调参数都管用。同时把界面的置信度阈值从0.25降到0.15让模型“宁可多找几个疑似目标”再结合2.3里的合规判断逻辑做二次过滤。实测下来这套组合能把现场漏检压到可接受范围。5.4 界面推理卡成PPT不要在UI线程里跑YOLO现象打开可视化界面后摄像头画面的刷新像幻灯片一样拖动窗口就显示“未响应”点关闭按钮要等好几秒。原因界面的主线程被推理循环占住了。PySide6的UI刷新和推理放在同一个线程里推理一次几百毫秒期间UI完全没法响应事件。这个是界面开发里最经典的错误。解决把推理放进QThread工作线程推理结果通过信号传回主线程刷新画面。给一个最小骨架from PySide6.QtCore import QThread, Signal class InferThread(QThread): frame_ready Signal(object) def __init__(self, model_path, conf): super().__init__() self.model_path model_path self.conf conf self.model None def run(self): from ultralytics import YOLO self.model YOLO(self.model_path) while True: frame get_frame_from_camera() result self.model.predict(frame, confself.conf, imgsz640, verboseFalse) self.frame_ready.emit(result) def set_conf(self, value): self.conf valueSignal(object)把推理结果发回主线程主线程里连接这个信号只做画框和文字更新不做任何推理。set_conf方法留出来给界面滑条调用这样不用重启程序就能调整置信度。这个骨架能解决95%的界面卡顿问题。5.5 loss变成nan先降学习率再关混合精度现象训练到某个epochloss突然变成nan之后所有指标全部归零怎么等都恢复不了。原因可能性有三按出现频率排学习率太大、数据里有损坏图片、混合精度在某些显卡上有浮点溢出。前两个最常见第三个在一些老款N卡上出现过。解决先把lr0从0.001降到0.0005再不行就在训练命令里加ampFalse。同时用一个脚本对图片做一遍解码测试凡是cv2读不出来的图片全部移出数据集。养成一个习惯每跑一组实验把runs/detect/ppe/weights/best.pt复制出来以ppe_s_epoch100_conf015.pt这种方式命名保存这就是后悔药。后面改参数改坏了随时能退回上一个效果可用的权重。6. 部署与验收的收尾技巧从best.pt到能演示的可视化界面权重训练完之后别急着打开可视化界面。我先在命令行把权重压一遍确认模型本身没问题再往界面里接yolo val modelbest.pt datadataset/data.yaml yolo predict modelbest.pt sourcetest_room.jpg conf0.25 saveTrueyolo val输出的是最终指标报告yolo predict则会把推理结果的图片保存下来。打开那张图看一眼如果框的位置和类别都对才允许自己进入界面开发环节。这个习惯能帮你把“模型问题”和“界面问题”完全隔开。给可视化界面留一个置信度滑条这个小改动非常加分。在PySide6里这样接from PySide6.QtCore import Qt from PySide6.QtWidgets import QSlider conf_slider QSlider(Qt.Horizontal) conf_slider.setRange(10, 90) conf_slider.setValue(25) conf_slider.valueChanged.connect(lambda v: infer_thread.set_conf(v / 100))滑条范围是10到90对应置信度0.10到0.90。答辩演示时现场灯光和训练环境不同固定阈值很可能出问题有滑条在手就能当场调给老师看这比任何解释都有说服力。最后一个验收技巧分三步准备一段没有参与训练的实验实拍视频当作盲测集记录全片漏检次数统计每帧推理耗时作为“系统性能”数据写进报告把违规画面自动截图存盘做成一条违规时间线。我当时做类似项目时的教训是时间和精力不要全花在界面美化上答辩老师更关心漏检率、推理速度和违规记录界面干净能用远比花哨重要。如果一个工程包能让你把训练、界面、部署和踩坑都在一周内走通那这个方向就值得投入希望帮到你。本文还有配套的精品资源点击获取
返回列表