ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于YOLOv8的工地焊接面罩佩戴检测实战指南

基于YOLOv8的工地焊接面罩佩戴检测实战指南 简介面向毕业设计、课程设计及深度学习入门学习者这是一套基于YOLOv8的工地焊接面罩佩戴检测完整项目聚焦建筑工地安全施工场景下的目标检测问题。压缩包共8个文件结构清晰3个Python脚本分别覆盖模型训练、视频检测与可视化界面操作3个预训练权重文件yolov8n.pt、best.pt等可直接加载2个txt文档包含部署说明与项目说明整体大小仅15.91MB在常见GPU环境下简单配置即可运行。源码已经过测试训练阶段可自动生成核心指标曲线图、混淆矩阵、F1分数曲线、精确率-召回率曲线、验证集预测结果与标签分布图从模型评估到结果展示形成完整闭环同时可视化界面支持对图像、视频等输入进行直观检测特别适合毕设答辩现场演示。目前已有42人下载学习对于需要快速获得可运行深度学习项目或完成类似检测任务的在校学生这套资源具有拿来即用的实用价值。1. 工地焊接面罩佩戴检测选YOLOv8比你想的省事也比你想的挑数据在工地安全帽检测已经成为课题红海之后焊接面罩佩戴检测是这两三年真正值得做的方向。面罩和普通安全帽是两种完全不同的视觉目标它遮挡大半张脸只在眼部留一道窄观察窗而且焊接时飞溅的火花、防护玻璃的反光会让模型在明暗交替里丢目标。YOLOv8能在这个场景里成为主流是因为它在小目标检测、训练收敛速度和部署自由度上都有现成的成熟配方从闭源数据集做格式检查、Labelme标注、转YOLO格式、训练、导出ONNX再到Windows上用PyQt5做一个可视化界面半天就能跑出第一个像样的mAP。这篇笔记适合手头有源码但改不明白、或者打算从零自己撸一版的人。2. 面罩检测选型与数据集准备把“完整数据集”这块地基盘明白2.1 为什么是YOLOv8而不是Faster R-CNN或SSD焊接面罩检测的目标特征非常明确它通常覆盖在工人面部分为手持式和头戴式两种反光镜片是画面里的强高光区域。选模型看三点推理速度、小目标召回率、交付生态。快餐式结论是Faster R-CNN精度高但交付慢SSD快但小目标漏检多YOLOv8在两者之间取了一个平衡点。Faster R-CNN的两阶段设计确实准RPN先提候选框再分类回归但训练要维护RPN和ROI Head两个阶段调anchor、调NMS参数很耗时。我自己在工地场景试过一次一张1080P图片在GPU上推理几百毫秒做实时视频监控很吃力更别说部署到边缘盒子上。SSD用VGG16当backbone的年代已经过去它的anchor是预设的对远景里只有十几像素的小目标召回很差。焊接面罩的尺寸变化很大近景占半张画面远景只有十几个像素点固定anchor策略在这样一个尺度跨度很大的场景里非常吃亏。YOLOv8走anchor-free路线配合C2f结构和P3、P4、P5三层多尺度预测对小目标的召回能力比前代强不少。而且Ultralytics官方库把训练、验证、导出全做成了命令行工具数据集结构开箱即用不用自己写DataLoader。这对毕设和课程设计来说太关键了时间都花在业务逻辑上而不是造轮子。模型推理速度小目标召回交付难度部署生态Faster R-CNN慢中高一般SSD快低中一般YOLOv8快高低丰富上面的对比表可以当答辩时的选型依据。单纯讲精度Faster R-CNN在部分公开数据集上确实不输YOLOv8但毕设不是只比一个指标还要比“能不能按时交”。YOLOv8从数据到界面的链路最短这是它成为这类项目默认选择的核心原因。2.2 拿到数据集第一步检查格式而不是直接训练标题写着“完整数据集”但完整不代表和你手里的训练脚本适配。常见的情况有三种只有JPEGImages和VOC XML没有YOLO需要的txt标签有人用Labelme标了多边形但类别名和代码里写的不一致标签文件里混着空的txt一张图里没有目标。所以拿到数据集先做三件事第一统计图片数量用脚本把每张图的标注框数量打出来看看有没有全是0标注的文件。第二确认类别名。多数项目只有两类戴面罩的工人和没戴面罩的工人英文名可能是welding_mask、person也可能是mask_positive、mask_negative。这种细节不一致会让训练出来的模型什么都学到。第三对比图片尺寸和txt里的归一化坐标是否合理。如果出现大于1的坐标值说明转换脚本写错了或者txt不是YOLO格式而是别的格式。如果原始数据是Labelme的json格式需要转换成YOLO txt。我一般会写这样一个脚本import os import json classes {welding_mask: 0, person: 1} def labelme_json_2_yolo(json_path, out_dir): with open(json_path, r, encodingutf-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 classes: continue pts shape[points] x_s [p[0] for p in pts] y_s [p[1] for p in pts] x_min, x_max min(x_s), max(x_s) y_min, y_max min(y_s), max(y_s) cx ((x_min x_max) / 2) / img_w cy ((y_min y_max) / 2) / img_h w (x_max - x_min) / img_w h (y_max - y_min) / img_h lines.append(f{classes[label]} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) out_txt os.path.join(out_dir, os.path.basename(json_path).replace(.json, .txt)) with open(out_txt, w, encodingutf-8) as f: f.write(\n.join(lines))这段脚本的核心逻辑是把多边形的外接矩形算出来再归一化到0到1之间。保留6位小数是标准做法避免浮点坐标抖动。labels字典的键必须和json里的label完全一致我之前吃过亏标注员写的是“weld_mask”脚本里写成“welding_mask”等于所有目标都被过滤掉了训练出来的模型检测什么都为空。转换完之后还要做一次反向检查随机挑几张图把txt里的坐标画回去肉眼看框是否贴合目标。这一步不是多余坐标多一个小数点错位目标框就会跑偏而模型在训练时对这类噪声非常敏感。2.3 数据集划分train/val/test不能有同源帧很多“完整数据集”的目录里只有images和labels两个平铺文件夹没有划分。这时候不要直接训练先自己划分。dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/对应的dataset/data.yaml这样写path: /home/qc/dataset train: images/train val: images/val test: images/test nc: 2 names: [welding_mask, person]path建议写绝对路径。Ultralytics在训练时会拼接path和train如果写成相对路径换机器后大概率报目录不存在。划分时有一个隐藏很深的坑来自同一段监控视频的连续帧如果简单地按时间顺序切成train和val模型其实见过这些帧的“邻居”验证集mAP会虚高。实际部署到工地新摄像头时掉点会非常严重。划分前先对图片做感知哈希去重或者至少把视频抽帧的时间间隔错开确保同一场景的帧只出现在一个集合里。如果数据集总量不足三百张常规做法是先扩充。翻转、随机裁剪、HSV色彩抖动都有帮助尤其要把面罩反光区域的亮度变化做足这样模型才不会把强反光和正常镜片当成两种东西。3. 从零跑通YOLOv8面罩训练环境、命令和参数的一次性交代3.1 用conda装出可复现的训练环境网上很多环境教程写得很复杂又是编译又是换源实际普通项目用不上。我通常只做三步conda create -n yolo python3.10 conda activate yolo pip install ultralytics如果机器没有独立显卡或者显卡太老装不上CUDA就装CPU版PyTorchpip install torch torchvision --index-url https://download.pytorch.org/whl/cpu注意这里指定CPU版本的wheel包避免pip自动拉下带CUDA的包。装了带CUDA的PyTorch但机器上没有对应驱动运行时直接报TFH或者找不到libcudart。装完验证一下python -c import ultralytics; print(ultralytics.__version__)这一步能过滤掉绝大多数环境问题。版本号不一致在YOLOv8的早期版本里很容易踩坑老版本的detect命令参数和新版本不兼容比如save_txt、save_conf这些参数在不同小版本里默认值改过。3.2 训练命令yolov8n还是yolov8m只看数据集规模面罩检测不是一个复杂视觉任务没有细到需要识别面罩上的焊缝型号所以模型规模不用太大。数据集在500张以下用yolov8n500到2000张用yolov8s或yolov8m再往上有条件就上yolov8l。训练命令如下yolo detect train datadataset/data.yaml modelyolov8n.pt epochs30 imgsz640 batch8 device0model传递的是一个预训练权重这就是迁移学习的入口。Ultralytics会保留COCO上学到的通用特征只把最后一层分类头替换成自己的类别数训练起来收敛很快。参数详细说明epochs设30到50就够。焊接面罩检测数据量小训练超过50轮会开始过拟合验证集mAP不见涨训练集loss却一直掉。batch设置取决于显存。8G显存跑imgsz640时batch最大6到86G显存的GTX1660Ti建议batch4。device0表示用第一张显卡没有GPU就改成cpu。如果预训练权重和类别数对不上比如data.yaml里写nc2但yolov8n.pt是从COCO80类迁移的会不会报错正常情况不会Ultralytics会自适应替换head层但日志里会有一行warning。强迫症想从零训练可以改用yolov8n.yaml作为model参数yolo detect train datadataset/data.yaml modelyolov8n.yaml epochs50 imgsz640这样是从随机权重开始训练收敛会慢很多需要更多epoch才能到达相同精度一般不建议。3.3 训练完看什么results.png和损失函数曲线训练结束后在runs/detect/train目录下会生成results.png里面包含了train/val的box_loss、cls_loss、dfl_loss以及mAP曲线。很多人只看mAP最后停在多少我建议先看loss曲线。如果val_loss在后期上升而train_loss还在下降就是过拟合需要停止训练或者加数据增强。用训练好的best.pt对单张图片做推理from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) results model.predict(test_imgs/worker_01.jpg, conf0.35, saveTrue)conf是置信度阈值默认0.25面罩检测建议调到0.35到0.5。工地上误报比漏报更让人厌烦反光的防护玻璃和白色安全帽容易互相误判调高阈值能少很多红色报警框。saveTrue会把标注框画在图上存到runs/detect/predict目录。想直观理解网络结构可以把best.pt导出成ONNX再用Netron打开看每一层的输出尺寸。命令行导出的方式yolo export modelruns/detect/train/weights/best.pt formatonnx dynamicTruedynamicTrue允许输入尺寸动态变化后面部署到不同分辨率的视频源时不用重新导出。4. 把检测模型做成可视化界面PyQt5、推理线程与部署方式4.1 界面功能拆解什么样的界面适合毕设和真实工地标题里的“可视化界面”是这套项目的加分项也是答辩时最容易展示的部分。一个够用的面罩检测界面包含4个区域左侧画面显示区右侧是检测结果列表底部有打开图片、打开摄像头、开始检测三个按钮再加一个置信度阈值滑块。统计栏显示检测总人数、未佩戴人数和报警状态。技术栈选PyQt5不选Tkinter和OpenCV自带的高GUI原因是PyQt5的布局控件美观对视频流的刷新也友好。OpenCV的highgui窗口在连续刷新时不可控做不了多控件交互。4.2 推理线程和UI分离避免界面卡死的核心代码新手最容易犯的错误是把推理写在按钮的回调函数里。这样点一次检测界面主线程被模型推理卡住窗口变白屏拖动窗口也没反应在Windows上还可能出现“未响应”。正确做法是单独开一个QThread负责检测用信号把结果回传到UI线程刷新画面。import cv2 import numpy as np from PyQt5.QtCore import QThread, pyqtSignal from ultralytics import YOLO class DetectThread(QThread): frame_ready pyqtSignal(np.ndarray, list) def __init__(self, model_path, source0): super().__init__() self.model YOLO(model_path) self.capture cv2.VideoCapture(source) self.running True self.conf 0.4 def run(self): while self.running: ret, frame self.capture.read() if not ret: break result self.model.predict(frame, confself.conf, verboseFalse)[0] boxes result.boxes.xyxy.cpu().numpy() cls_ids result.boxes.cls.cpu().numpy() plotted result.plot() self.frame_ready.emit(plotted, cls_ids.tolist()) def stop(self): self.running False self.capture.release()关键点有两个摄像头读取和模型推理都放在run方法里不在主线程执行result.plot()返回的是带标注框的BGR图片和cv2.VideoCapture读出来的通道顺序一致可以直接交给QImage显示。不要在这里用RGB转换会多一次无谓的开销。界面上放一个QSlider控制置信度阈值UI线程只更新self.conf的值运行中的线程下一帧就会生效不需要重启。busy脑回路想的是每次拖动阈值就重启线程完全没必要。4.3 佩戴判断逻辑不是画一个框就完事的模型只负责输出“这个框是welding_mask还是person”但业务要判断“这位工人有没有戴面罩”。这里需要一点目标配对逻辑。常见做法是把person框和welding_mask框做匹配计算两框的交并比IoU如果同一帧里存在一个welding_mask框与某个person框的IoU大于0.3就认为这个人戴了面罩否则标记为未佩戴并报警。这个阈值0.3是经验值。面罩紧贴人脸框之间交叠面积很高IoU一般在0.6以上如果阈值设太低比如0.1隔壁工友戴的面罩会被误判成当前工人佩戴导致漏报。4.4 部署到边缘设备rk3588和ONNX的转换路径在工厂实地部署经常要把模型放到RK3588这类边缘盒子上。流程上先导出ONNXyolo export modelbest.pt formatonnx opset12 imgsz640然后再用rknn-toolkit2把ONNX转换成rknn格式。转换中有两个注意点RKNPU对某些算子支持不全YOLOv8的DFL模块结构需要转换脚本里做特殊处理直接转成rknn后输出维度是错的固定imgsz640导出动态尺寸在RK3588上容易崩显存。如果你只是做毕业设计跑到这一步就够了不必真的去购买RK3588开发板但答辩的时候说得出“模型可以导出ONNX部署到边缘端支持摄像头RTSP流接入”比单纯演示界面效果好得多。5. 焊接面罩检测避坑5个翻车现场与对应的后悔药5.1 训练时类别不匹配模型从头学到尾现象训练日志里出现“WARNING, using inherited class names”之类的提示训练过程不报错但推理结果一直输出0号类别或者识别到的面罩框全部落在背景上。原因data.yaml里nc写了和类别数量对不上的数字或者names列表顺序和模型预训练权重的类别顺序不一致。YOLOv8在加载预训练权重时会尽量保留能匹配的层匹配不上的随机初始化这时候如果旧版本库没有正确处理nc的差异分类头就会乱。解决先打开data.yaml确认nc和names一一对应再训练。不要直接copy网上的data.yaml改个路径就完事。保险做法是先执行验证看数据加载yolo detect val datadataset/data.yaml modelruns/detect/train/weights/best.ptval能正常跑通说明数据标签基本没有格式问题了。5.2 GTX1660Ti训练直接OOM现象训练刚开始屏幕输出RuntimeError: CUDA out of memory后面跟了一串Tried to allocate 128.00 MiB。原因6G显存跑yolov8s默认batch8imgsz640显存不够。解决把batch降到4imgsz保持640。如果还想压用yolov8n模型并开启gradient checkpointing。实际上6G显存跑yolov8n、batch4、imgsz640大概占5G左右能跑完。别去设batch2虽然能训练但BN层统计不稳定模型精度可能受影响。5.3 远距离面罩完全漏检现象近景识别正常两米以外的工人戴没戴面罩完全判断不了要么没框要么框在人的胳膊上。原因训练数据里缺少小目标样本。大部分数据集从网上下载或者自己拍的近距离照片小目标占比不到5%模型没有见过足够多的“小面罩”学不到对应特征。解决给训练集添加小目标。做法有两种一是把大图缩小成小图再贴到背景上模拟远景二是直接从监控视频里抽全景帧手工标注远处工人。imgsz从640提到1280也有帮助但训练速度会慢很多。提升imgsz前先确认显存撑得住。5.4 推理时中文路径直接闪退现象界面能正常打开点选图片后程序崩溃命令行反馈找不到文件或者检测结果一直为空。原因OpenCV的imread不支持中文路径Windows下最常见的坑。数据集放在“D:\课题资料\数据集\标注图片”这种路径下图片读进来就是None模型无图可推。解决不用imread改用numpy读二进制再解码。import numpy as np import cv2 def imread_chinese(path): data np.fromfile(path, dtypenp.uint8) return cv2.imdecode(data, cv2.IMREAD_COLOR)我一般在项目入口处直接写死这个读取函数所有图片路径都走它省得后面哪天路径里混进中文又翻车。5.5 可视化界面点了开始检测就白屏现象界面按钮一点窗口卡住转动圆圈几分钟后恢复或者Windows提示“程序未响应”。监控视频源时尤其严重。原因把模型推理直接放在按钮的clicked信号槽函数里推理是同步阻塞操作。视频流每帧推理十几毫秒到几十毫秒但在UI线程里累积起来界面响应就会被拖垮。解决用上一章写好的QThread线程方案。主线程只负责发信号、收信号、刷新画面模型推理和摄像头读取全部挪到线程里。这算是最基本的多线程编程但对毕设来说这一条代码设计的细节往往直接决定演示环节顺不顺利。6. 进阶技巧用置信度阈值调优和难例挖掘让面罩检测真正能用模型训练完成只是起点真正拿到工地场景里用还有一个很重要的步骤调报警策略。我自己的习惯是把置信度阈值调高到0.5同时做一个报警确认机制同一帧里连续3次检测到未佩戴才触发报警。面罩在强光反射下偶尔会被模型漏掉一帧如果每帧都报警工地上几分钟就会产生大量误报焊工不会再当回事。难例挖掘也值得做。把验证集里预测错误的图专门收集出来人工看一眼错在哪里。最容易出错的样本集中在两类戴着墨镜的工人被识别为戴了面罩以及手持面罩正在摘下的动作被识别为未佩戴。第一类可以通过加数据集去解决第二类其实可以当成业务规则处理——检测对方的身体姿态再综合判断。这些工作不需要重新训练模型但对最终演示效果影响很大。还有一个值得投入的小技巧把检测结果实时写入SQLite记录检测时间、佩戴状态和截图路径。毕业设计的演示环节里评委问“系统有没有数据记录功能”时这个细节会很加分。用代码实现也不复杂在检测线程里拿到结果后执行一条INSERT语句就行。我自己的一个教训是不要迷信网上所谓的高mAP模型。别人数据集里的“工地”和真实的工地不是一回事光照、粉尘、遮挡情况都不一样。真正靠谱的办法是把公开数据集当成起点自己补拍一段现场环境的视频抽帧标上几十张图重新训练。这个补训练的过程才是整个项目里让你能讲清楚“为什么这个模型在我这里有效”的关键。这篇笔记把YOLOv8焊接面罩检测从选型、数据准备、训练参数、界面设计到部署方案都过了一遍。环境配置、代码路径、阈值设定这些细节都是我实际跑过之后的经验按着这个顺序去做半天时间应该能跑通第一个可用版本。如果中途卡在某个报错上回头看第五部分的排查思路大概率能找到对应的后悔药。希望帮到你。本文还有配套的精品资源点击获取
返回列表