YOLOv8焊接面罩检测实战:三类目标标注、训练部署与避坑指南
发布时间:2026/9/28 3:53:34来源:尧图网络
简介基于YOLOv8的工地焊接面罩佩戴检测项目面向计算机视觉、人工智能及相关专业的毕业设计与课程设计场景可用于施工安全监控中的防护装备佩戴识别。资源完整收录源码、数据集、可视化界面与部署教程代码均已测试通过可直接运行验证。压缩包共8个文件包括3个Python脚本分别对应模型训练、可视化界面展示与视频检测3个模型权重文件涵盖预训练模型与训练产出另有2个说明文档用于环境配置与使用指引整体大小约15.91MB结构清晰紧凑。项目已有42人浏览学习。除基础检测功能外还支持输出核心指标曲线、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果及标签分布图便于答辩汇报与技术复盘配套的部署说明和README可帮助快速搭建环境适合需要完整落地项目的在校学生或初学者借鉴使用。1. 焊接面罩检测不是安全帽检测的换皮一个 YOLOv8 方案与三类样本问题很多工地安全帽检测项目已经跑得很成熟但你把同一套 YOLOv8 目标检测模型直接挪去检测焊接面罩十有八九会翻车——焊接面罩是全脸覆盖的弧形护具经常和安全帽叠戴遮挡关系复杂再加上电焊弧光的高亮背景普通安全帽模型的浅层特征根本扛不住。这套《基于 YOLOv8 的工地焊接面罩佩戴检测》资源就是针对这个专用场景做的带完整源码、可视化界面、标注好的数据集和部署教程简单部署就能跑拿来做毕业设计或课程设计很合适。适合人群是两类要做检测类毕设的学生以及想快速验证 yolo 落地的开发者。前者需要一条能走通的完整链路后者需要知道参数边界和踩坑点下面按落地顺序把这套东西拆开讲。2. YOLOv8 的检测思路与这套代码的类别设计为什么是“人-安全帽-面罩”三类2.1 先从主干说起anchor-free、解耦头与 C2f选 YOLOv8 而不是更早的 v5理由在结构上就写得很清楚。v5 还用 anchor 机制训练前要聚类算 anchor 尺寸换数据集就要重算这在毕设场景里是个隐形负担。v8 直接改成 anchor-free每个位置预测距离四条边的偏移省掉了 anchor 聚类这一步换数据集的成本低很多。对焊接面罩这种“类别少、样本量不大”的场景这个特性很实用。第二个关键是解耦头。v8 把分类和回归拆成两个分支分类分支专注“这是不是面罩”回归分支专注“框在什么位置”。焊接面罩是深色弧形表面安全帽是浅色硬壳两者在边缘处颜色容易混解耦头在分类分支上多分配了参数对这种“长得像”的类别区分度更好。C2f 结构则是在保证感受野的前提下把梯度回流做得更密小目标比如远处工人脸上的面罩特征不容易丢。选型上我的习惯是先用 yolov8n 或者 yolov8s 把链路跑通再决定要不要换大模型。焊接面罩检测不是遥感图那种动辄几千个小目标的场景画面里通常就几个人n 和 s 级别的精度差距很小但推理速度差出一大截。界面端要实时预览n 级别在普通显卡上能跑到 30ms 以内s 要 50ms 左右肉眼能感觉到差别。后面训练章节的参数表我会给出具体参考值。2.2 三类别的业务逻辑与标注策略这套资源把检测目标分成 person、helmet、welding_mask 三类不是随便分的。只分“戴没戴面罩”二分类在工程上是走不通的因为模型要知道“谁没戴”得先有人的位置再判断这个人头上有没有安全帽、脸上有没有面罩。所以类别设计是检出 person然后在 person 框范围内检查 helmet 和 welding_mask 的覆盖情况。这里有一个标注口径问题。焊接面罩戴好时覆盖整个面部这是正样本但工人经常把面罩翻起来架在安全帽上或者垂在胸前这时候面罩本体还在画面里要不要标我见过不少翻车案例就是把“挂在脖子上”的面罩也标成正样本模型学到的其实是“画面里有一块深色弧面”而不是“面罩覆盖了脸部”。正确做法是按“是否覆盖眼部到下颌区域”来定类别含义标注口径person作业人员完整人体框遮挡超过一半不标helmet安全帽帽子主体完整可见帽檐朝前才算戴好welding_mask焊接面罩必须覆盖眼部到下颌翻起、手持、挂在胸前都不算表格里这条“翻起不算”很重要。工地场景里工人确实常把面罩翻起来聊天、换焊条这时候人没在焊接作业严格说不算“违规佩戴”但如果数据里大量出现这种负样本模型会把“翻起状态”学成一条独立特征干扰正样本判断。更稳的做法是这类画面单独留出来当测试集不进训练集训练集里只保留“戴好”和“完全没戴”两种极端状态。2.3 代码目录结构与可视化界面工作流解压后你会看到一套标准的检测项目结构我按常见做法给你标一下每个文件是干什么的welding_mask_detect/ ├── dataset/ │ ├── images/ │ │ ├── train/ │ │ └── val/ │ └── labels/ │ ├── train/ │ └── val/ ├── weights/ │ └── best.pt ├── ui/ │ ├── main_window.py │ └── camera_thread.py ├── train.py ├── detect.py ├── welding.yaml └── requirements.txtdataset 是标准 YOLO 格式图和标注 txt 一一对应后面第三章详细讲格式weights 下放训练好的权重ui 目录是可视化界面主程序train.py、detect.py 分别是训练和推理入口。可视化界面主窗口的常见做法是启动时加载 weights/best.pt然后让你选输入源——单张图片、视频文件、USB 摄像头三选一。选完源就开始推理画面上实时叠加三个类别的框右上角统计当前画面人数和违规人数。界面里通常会放两个滑块一个是 confidence置信度阈值默认 0.5一个是 IoU/NMS 阈值默认 0.45。很多新手只调 confidence忽略了 NMS 阈值。焊接面罩戴好时几乎覆盖半张脸NMS 阈值设太高压不住重叠框一个面罩可能同时出两三个框设太低又把相邻两个人的框合并掉。我一般建议 confidence 在 0.35~0.5 之间调NMS 固定在 0.45 不动。这个包默认参数就是 0.5 和 0.45适合先用起来再按你现场摄像头距离微调。3. 环境准备与数据集格式训练前把数据对齐3.1 环境搭建CUDA、CPU 与依赖版本这套包的依赖就一个核心ultralytics。其它都是 PyTorch、OpenCV、PyQt5 这种常规件。我习惯先建独立 conda 环境不给系统 Python 添乱conda create -n yolo python3.9 -y conda activate yolo pip install ultralytics torch torchvisionpip 默认装的是 CPU 版 PyTorch如果机器有 N 卡训练前要换成 CUDA 版。常见做法是去 PyTorch 官网按 CUDA 版本生成安装命令比如 CUDA 11.8 就装 cu118 对应的包。注意先确认驱动支持哪个 CUDA 版本用nvidia-smi看右上角的 CUDA Version。初学者最容易在这一步踩坑装了 CPU 版后来回折腾重装其实一行命令就能解决。如果你只有 CPU 没显卡也不是不能跑。yolov8n 在纯 CPU 上训练 100 轮大约比 GPU 慢 5 到 8 倍几百张图的数据集咬咬牙能出结果。推理端完全没问题CPU 跑单张图 200ms 左右做毕设演示足够。网上搜“ubuntu20.04 搭建 yolov8 环境 cpu 版本”能看到一堆教程核心就是别装 CUDA 版 torch其它依赖一模一样。装完依赖后先跑一句验证python -c from ultralytics import YOLO; print(YOLO.__version__)能打印版本号说明环境通了。再跑model YOLO(yolov8n.yaml)能实例化说明网络结构文件能正常读取。这两步过了环境基本没有大问题。requirements.txt 里列的是固定版本号比如 ultralytics 8.x、PyQt5 5.15如果你装的是最新版导致语法报错优先按这个文件里的版本降级。3.2 数据集目录结构与 YOLO 格式转换这套资源自带完整数据集但到手后你大概率想换成自己拍的现场图。YOLO 格式的目录结构约定很死images 和 labels 两个大目录各自下分 train 和 val文件名前缀必须完全一致。比如IMG_001.jpg对应IMG_001.txt少一个、多一个都会在训练时报 warning。dataset/ ├── images/ │ ├── train/ # 放 8 成图片 │ └── val/ # 放 2 成图片 └── labels/ ├── train/ # 每张图对应一个同名 txt └── val/labels 的 txt 是纯文本每行一个目标格式固定为类别ID x_center y_center width height四个数值都归一化到 0~1。如果原始标注是 Labelme 的 JSON 格式需要先转成 YOLO。转换脚本的核心就是多边形坐标到归一化中心点的换算def labelme_to_yolo(json_path, img_w, img_h): 把 labelme 的 json 标注转成 yolo 一行数据 import json with open(json_path, encodingutf-8) as f: data json.load(f) lines [] for shape in data[shapes]: # labelme 存的是多边形顶点这里转成外接矩形 points shape[points] # [[x1,y1], [x2,y2], ...] xs [p[0] for p in points] ys [p[1] for p in points] x1, y1 min(xs), min(ys) x2, y2 max(xs), max(ys) w x2 - x1 h y2 - y1 # 归一化中心点坐标除以图片宽高 x_center (x1 w / 2) / img_w y_center (y1 h / 2) / img_h class_id shape[label] # 这里需要换成 0,1,2 的映射 lines.append(f{class_id} {x_center:.6f} {y_center:.6f} {w / img_w:.6f} {h / img_h:.6f}) return lines这段脚本有两点要留神。第一labelme 的 label 字段是字符串写成 yolov8 需要你手动建一个映射表比如{person: 0, helmet: 1, welding_mask: 2}第二如果标注是“矩形标签”而不是多边形points 只有两个角点xs/ys的写法同样成立因为 min 和 max 取的就是左上右下两个点。转换完成后检查一下 txt 里有没有969.68这种越界的数——物体贴在图片边缘时x_center 偶尔会到 1.0 以上训练时不报错但精度会莫名其妙掉。还有一个全局配置文件 welding.yaml它告诉 ultralytics 数据在哪、类别是什么path: dataset train: images/train val: images/val names: 0: person 1: helmet 2: welding_maskpath 建议写成相对于 yaml 文件所在目录的相对路径不要写绝对路径。因为你这个包可能在不同机器间拷贝绝对路径换个电脑就得改相对路径让训练命令更稳。names 的编号顺序必须和标注 txt 里的类别 ID 一致这条错位了模型会把安全帽当人而且不会报任何错误属于最容易排查半天的问题。3.3 类别不平衡与过曝样本的处理焊接面罩检测有个天然的数据问题person 类几乎每张图都有welding_mask 类可能只出现在一小半图里。类别不平衡会让模型往多数类偏移表现就是面罩的 recall 偏低、安全帽的框精度却很高。处理手段按性价比排序第一是亮度扰动。电焊弧光会让画面过曝训练集里如果没有这类样本模型一遇到亮背景就丢检测。你可以在数据增强里加大 brightness 参数或者在转换脚本里用 OpenCV 随机加一层亮度噪声。第二是翻转和随机裁剪。面罩戴在左脸和右脸本质上是对称的水平翻转能把样本量直接翻倍这是最没有副作用的增强。第三才是复制粘贴把过曝面罩的小图贴到正常画面上注意贴的图要跟着做透视变换否则模型学的是“方块图贴上去”的假特征。还有一个细节我处理这类小数据集时一定会在训练前做个数据体检# 统计每个类别在训练集里的样本数 grep -rh ^0 dataset/labels/train/ | wc -l # person 数量 grep -rh ^1 dataset/labels/train/ | wc -l # helmet 数量 grep -rh ^2 dataset/labels/train/ | wc -l # welding_mask 数量如果 welding_mask 数量连 person 的十分之一都不到别急着训练先回去补标注或加增强。这条习惯能省掉你后面调参的大把时间属于经验里最不值钱但最实用的一条。yolov8 的 mosaic 增强默认开着它会把四张图拼在一起训练对小数据集很有效但如果你的图大多是近距离单人作业mosaic 拼出来的图反而偏离真实分布。遇到这种情况我会把增强里的mosaic0.8降低到0.5或者直接在训练参数里关掉。4. 训练与评估从损失曲线判断模型能不能用4.1 训练命令与超参数怎么定数据准备齐了训练本身反而不是最难的部分。命令就一条yolo train modelyolov8n.pt datawelding.yaml \ epochs100 imgsz640 batch16 device0我逐参数说一下边界。modelyolov8n.pt用的是 COCO 预训练权重不是随机初始化如果你从零训练yolov8n.yaml100 轮大概率欠拟合毕设场景一定要用预训练。epochs在样本量几百张时设 100 足够ultralytics 默认开了早停patience20连续 20 轮验证集没提升就自动停所以你设 100 实际可能 50 轮结束。imgsz默认 640如果画面里人普遍很小比如摄像头装在塔吊上可以提到 960代价是显存占用按平方上涨。batch在 6G 显存的 GTX 1660 Ti 上yolov8n 配 batch 16 已经是上限再高会 OOM没有独显的话把device改成cpubatch 降到 8。训练过程中定期看runs/detect/train/目录下的train_batch*.jpg这是每个 batch 增强后的样例图。如果发现图像被 mosaic 拼得面目全非、目标的框画得不对说明标注转换那里就出问题了这时候停掉训练回去查数据别让模型带着错误数据硬学。训练结束后同一目录下会有confusion_matrix.png和results.png前者看类别互相误检的情况后者是损失曲线的走势。关于“yolov8 画损失函数曲线图”这个问题其实不用自己画ultralytics 每次训练完自动产出results.png包含 train/val 的 box_loss、cls_loss、dfl_loss 六条曲线。如果你拿到的源码里没有可视化模块也可以自己读results.csv用 matplotlib 画文件在训练输出目录下每行是一个 epoch 的指标。4.2 看哪些指标mAP、PR 曲线与损失曲线训练完第一步跑验证集yolo val modelruns/detect/train/weights/best.pt \ datawelding.yaml batch1输出里重点看三类指标mAP50、mAP50-95、precision/recall。mAP50 是 IoU 阈值 0.5 下的平均精度焊接面罩这种单一场景做到 0.85 以上就算合格mAP50-95 是你最终答辩报告里要写的指标它把 IoU 从 0.5 到 0.95 都过一遍数值会比 mAP50 低 10 到 20 个点这是正常现象。更关键的是分开看每类的 recall——列出类别明细那个表里能找到。面罩的 recall 如果低于 0.7说明漏检多后面我会讲一个调低置信度阈值的补救办法。损失曲线比单看 mAP 更早暴露问题。results.png里的 cls_loss 如果训练到最后还在明显下降说明模型没收敛加 epoch 或加大数据增强如果 val 的 box_loss 在中间某个 epoch 突然反弹但 train 的还在降这是过拟合信号不是参数问题而是数据增强不够或数据集太小。注意早期停断早停触发后别急着用last.pt除非你只想看结构效果否则一律用best.pt它是验证集 mAP 最高的那个权重。有一个“玄学”环节是精确率和召回率的取舍。安全帽场景里误报把安全帽阴影当安全帽影响不大人工复核成本低但漏报一个没戴面罩的工人在安全审查里就是事故。所以我实际部署时会把默认置信度从 0.5 降到 0.35用召回率换精确率界面里那个滑块留给使用者自己拉。4.3 模型导出从 PyTorch 权重到 ONNX/TorchScript可视化界面直接加载 best.pt 就能跑PyTorch 和界面在同一环境里不用导出。但你如果想让界面跑得更快或者把模型挪到没有 PyTorch 的环境就得导出成 ONNX 或 TorchScriptyolo export modelruns/detect/train/weights/best.pt \ formatonnx imgsz640 opset12ONNX 文件出来后在weights/下会多个 best.onnx。导出这一步经常翻车的是 opset 版本PyTorch 2.x 默认导出的 opset 比较高旧版 onnxruntime 加载会报算子不支持解决办法是把 opset 固定到 12 或者按你的 onnxruntime 版本往上加。TorchScript 的兼容性比 ONNX 好但文件大一点如果你的部署环境还是 Python 系直接用 TorchScript 更省事。导出完成后我习惯做一次“前后对比”分别用 pytorch 和 onnxruntime 跑同一张测试图比较两者输出的框坐标和置信度差值在 1e-3 以内算通过。这一步排查的不是模型精度而是预处理链路的一致性——很多边缘设备上推理结果偏移问题都不在网络本身而是输入图像的缩放和归一化跟训练时不一致。关于这一点第五章的避坑小节里还有更具体的现象描述。5. 部署与可视化界面避坑推理卡顿、中文乱码与摄像头掉线5.1 画面预览卡顿GPU 占用率却很低现象界面跑起来了但摄像头预览明显迟滞画面像幻灯片同时任务管理器里 GPU 占用不到 30%。原因最常见的是在界面主线程里直接跑推理。PyQt5 的界面事件循环和推理循环抢同一把锁推理占住线程界面就等它算完才刷新一帧。另一个原因是模型没真正跑到 GPU 上——有些机器上torch.cuda.is_available()返回 True但 ultralytics 默认 fallback 到 CPU需要手动指定设备。解决推理放到独立线程这是治本的办法。PyQt5 里常见的做法是写一个QThread子类重写run()方法放推理循环信号量把带框的帧传回主线程刷新。如果没有现成线程代码至少在推理前强制指定设备from ultralytics import YOLO model YOLO(weights/best.pt) model.to(cuda) # 没有显卡时改为 cpu5.2 界面中文乱码项目路径含中文加载失败现象界面标题和按钮全是方框代码拷贝到“桌面/焊接面罩项目”目录后加载权重一直报错找不到文件。原因PyQt5 默认字体在新版 Windows 上不包含中文字形需要手动指定字体而 ultralytics 底层用 OpenCV 读图OpenCV 的imread遇到中文路径直接返回空图片读不进来训练和推理都会静默失败。解决界面主函数里加一行字体设置项目路径强制用英文。字体设置是通用的不论代码原来是啥样加在QApplication初始化后面就生效from PyQt5.QtGui import QFont app.setFont(QFont(Microsoft YaHei, 10)) # Windows 用微软雅黑路径问题没有代码层面的解法只能物理上把文件夹改名。拿到任何 yolov8 项目的第一件事就是看路径里有没有中文有就重命名这是最省时间的习惯。5.3 摄像头打不开或运行中途掉线现象打开界面选摄像头预览区黑屏报Assertion camera open failed或者跑十几分钟后画面冻结必须重启界面才能恢复。原因cv2.VideoCapture(0)在 Windows 上默认用旧的 DSHOW 后端对 USB 摄像头兼容性差插着多个摄像头时还可能选错设备。运行中途掉线多是 USB 供电问题尤其是通过扩展坞接的摄像头供电波动会让采集线程死掉。解决打开摄像头时显式指定后端掉线后释放资源并等待几秒重连。代码里常见的写法是这样import cv2 import time def open_camera(index0): cap cv2.VideoCapture(index, cv2.CAP_DSHOW) # Windows 下用 DirectShow if not cap.isOpened(): time.sleep(2) cap cv2.VideoCapture(index, cv2.CAP_DSHOW) return capCAP_DSHOW是 Windows 专属参数Linux 上不要加这个用默认的CAP_V4L2。另外如果你只是测试用一个摄像头别同时开多个很多型号的 USB 摄像头芯片不允许同一时刻被两个进程占用界面和调试脚本同时开就会互相抢。5.4 ONNX 导出后检测框偏移现象PyTorch 推理好好的转成 ONNX 后用 onnxruntime 跑框的位置明显偏了或者类别标签对不上。原因训练时 ultralytics 内部做的是 letterbox 缩放保持比例多余部分填灰边导出 ONNX 后如果你手写预处理直接把图resize(640, 640)画面长宽比被拉伸了框自然也歪。另外一个原因是类别映射错位onnxruntime 的输出是原始索引你手动映射类别时顺序和 yaml 不一致。解决导出的 ONNX 配合 ultralytics 自带的预处理来推理不要自己重新造轮子。onnxruntime 推理时先做 letterbox拿到输出后把中心坐标除以缩放比例再减去 pad 偏移def letterbox(img, new_size640): h, w img.shape[:2] scale min(new_size / w, new_size / h) nw, nh int(w * scale), int(h * scale) resized cv2.resize(img, (nw, nh)) canvas np.full((new_size, new_size, 3), 114, dtypenp.uint8) x_off, y_off (new_size - nw) // 2, (new_size - nh) // 2 canvas[y_off:y_off nh, x_off:x_off nw] resized return canvas, scale, x_off, y_off坐标映射回来时x (pred_x - x_off) / scaley (pred_y - y_off) / scale。这个错误最隐蔽的地方在于——模型精度看起来没掉太多因为拉伸后的图和原图整体特征还在但你画框回原图时位置就是歪的。如果你手上是 RK3588 这类边缘板子预处理逻辑不一致是部署时翻车率最高的一个环节记住一个原则训练端和推理端必须共用同一套 letterbox 参数。6. 把模型用得更顺一个推理脚本与三类必测样本训练完模型界面也能跑了最后一步建议做一个脱离界面环境的“裸推理”验证。把模型从界面里剥出来单独测一方面能确认模型本身的好坏不受界面代码影响另一方面这个脚本可以直接改造成服务端接口。from ultralytics import YOLO model YOLO(weights/best.pt) results model.predict( sourcetest_arc.jpg, conf0.35, imgsz640, devicecuda ) boxes results[0].boxes names results[0].names for box in boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) print(f{names[cls_id]} conf{conf:.2f})脚本里的conf0.35是部署阈值跟训练时的指标无关只影响你这张图上“算不算检出”。测的时候固定用三类现场样本正常光线下的正面作业图、弧光过曝的焊接图、别人佩戴但翻起面罩的负样本图。这三类样本能区分出模型是真的学会了“覆盖面部”还是只记住了“画面里有深色弧形物体”。弧光过曝图如果漏检一般不是模型问题而是训练数据缺这类样本补几张进去做亮度增强就能解决负样本如果被误报成“已佩戴”说明标注口径里翻起状态没被排除掉要回头清理训练集标注。另外养成一个习惯每次训练完把results.csv的最后三行单独看一眼确认 val 损失没比 train 高出 30% 以上然后顺手记录下当时的超参数组合。我最早调的时候吃过“同一个模型白天跑出一个数、晚上重训又变一个数”的亏后来每次固定 seed 并且把训练命令存到train_cmd.txt里再对比不同版本就心里有数了。从那以后我拿到任何新数据集都强制先做一遍数据体检再决定训练策略而不是直接跑训练等结果。这套资源我放在文末了需要毕设、课程设计或者只是想跑通一条完整链路的话直接下载解压按这篇的顺序操作就行希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网