ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

YOLO安全帽手套检测:三套标签格式与训练数据集全解析

YOLO安全帽手套检测:三套标签格式与训练数据集全解析 简介YOLO安全帽手套检测数据集整合了1000张真实场景图片面向目标检测初学者与安全施工场景应用开发者可直接用于YOLO系列模型训练与效果验证。包内包含2000个文件其中1000个xml标注、991个txt标签配合少量Python划分脚本、YAML配置及HTML训练教程分别提供VOC、COCO、YOLO三种格式标签便于切换不同检测框架。资源包整体约50.13MB文件按功能分类存放目录结构较清晰。数据集使用LabelImg标注标注质量高场景丰富。另附训练集/验证集/测试集划分脚本以及环境搭建和训练教程HTML读者可按需求自行划分数据并快速启动训练。已有544人学习下载适合作为YOLO安全帽佩戴检测、手套识别等项目的入门数据集与教学素材。1. 想快速跑通YOLO安全帽手套检测先解决标签格式这一关工地上每天有成百上千人在来回走动单靠监控室肉眼确认谁没戴安全帽、没戴手套本身就是件会漏掉的事。很多做智慧工地的人第一反应是“用YOLO训练一个检测模型”但真正动手时才发现模型不难跑难的是没有一份能直接给训练器吃的数据——要么图片乱要么标签格式对不上。名为“YOLO安全帽手套检测数据集”的这份资源把1000张图片、三套标签VOC、COCO、YOLO和一个划分脚本打包在了一起附带训练教程。它解决的核心问题不是“给你一个训练好的模型”而是“让你从零把训练流程跑通”。新人可以照着它的目录结构和教程完成第一次训练熟手也能拿它当数据格式校验的参考基准。别小看这1000张图安全帽和手套的形态差异足够大用它验证训练链路完全够用。2. 三套标签同框VOC、COCO、YOLO 的本质区别与选择逻辑2.1 先打开文件看结构XML、JSON、TXT 标注长什么样拿到数据包后第一件事不是训练而是先认识标签文件长什么样。因为三套格式描述了同一批框但存储方式完全不同混着用就会出问题。VOC 格式的文件后缀是.xml每个图片对应一个同名 XML核心信息保存在object标签里。一个安全帽框看到的是类似这样的内容annotation filenameimage_0001.jpg/filename size width1920/width height1080/height depth3/depth /size object namesafety_helmet/name difficult0/difficult bndbox xmin412/xmin ymin233/ymin xmax508/xmax ymax321/ymax /bndbox /object object nameglove/name difficult0/difficult bndbox xmin860/xmin ymin701/ymin xmax1010/xmax ymax842/ymax /bndbox /object /annotation这里框的坐标是绝对像素值xmin/ymin/xmax/ymax一眼能看出物体在图中的位置适合人读但不适合直接喂给 YOLO。这就是为什么需要 COCO 和 YOLO 格式共存。COCO 格式把所有标注写进一个大的 JSON 文件里结构是三层images存图片信息和 IDannotations存每个框的坐标和类别categories存类别列表。它的坐标不是四点而是[x, y, width, height]也就是左上角坐标加框的宽高。用 Python 看这个文件最直观import json with open(annotations/instances_train.json, r) as f: data json.load(f) # 看类别表 print(data[categories]) # 看第一张图的信息 print(data[images][0]) # 看第一个标注框 print(data[annotations][0])这段代码读的是 COCO 标准 JSON 结构。如果打印出的annotations[0]里category_id和bbox都存在说明文件是完整的。这里的bbox是[x, y, w, h]而x, y是左上角坐标千万别和 VOC 的顺序混淆。YOLO 格式则是最“省事”的一种每个图片对应一个同名.txt文件一行一个目标每行只有五个数字类别ID、中心点 x、中心点 y、宽度、高度。注意后四个值全部做了归一化范围是 0 到 1。例如0 0.2396 0.2565 0.0500 0.0815 1 0.4870 0.7144 0.0781 0.1306第一行的第一个数字0表示安全帽第二行的1表示手套。后面四个数分别是中心点坐标和框宽高都除以了图片的原图宽高。这种格式几乎不需要解析训练时直接读文本是 YOLO 系列训练器最友好的一类标签。2.2 训练时到底选哪套格式选 YOLO但为什么还要留另外两套打开这三套文件后很多人会陷入选择困难既然 YOLO 格式最直接那 VOC 和 COCO 是不是多余不完全是。选择取决于你用哪个训练框架。如果你用的是 Ultralytics YOLOv8 或 YOLOv5标签路径写的是images/train和labels/train训练器会按规则到labels目录找同名.txt文件。这条路最稳数据包里 YOLO 后缀的标签就是给你干这个用的。如果你后续要改用 Detectron2 或 MMDetection这套框架的默认输入往往是 COCO JSON 或 VOC XML。比如 MMDetection 的 CocoDataset你给它一个instances_train.json就能跑而 VOC 数据则适合用VOCDataset直接加载。数据包里保留三套格式相当于同一份标注给了三次选择权换框架时不必重新标注这是这套数据集最大的价值。我一般会建议第一次训练的人直接走 YOLO 标签因为省去 JSON 转码的麻烦。但要用对 YOLO 标签得先确认两点一是.txt文件名必须和.jpg文件名完全同名包括前缀零二是类别索引必须和训练时的data.yaml对齐。数据包里如果默认把0设为安全帽、1设为手套那训练配置里也要保持同样顺序。这份“对应关系”才是跨格式转换时最常翻车的地方后面避坑章再细说。3. 划分脚本拆解训练/验证/测试的比例分配与文件关联3.1 划分脚本首先得干什么保持图片和标签同步防止样本泄露数据包既然带了划分脚本说明一个意思你不能把1000张图全拿去训练。深度学习训练必须有验证集和测试集。验证集用来在训练过程中监控模型状态决定什么时候停止测试集是最后验收用的“考卷”模型在训练时没见过它分数才真实。划分脚本的首要任务是保证“图片被切走时标签也被一起切走”。听起来是废话但手工去分目录时最容易犯的错就是只复制了images/train漏掉了labels/train或者两边文件名对不上。其次要保证的是“同场景不泄露”如果数据集中有同一批工人的连续帧照片这些图片不能一部分进训练集、一部分进验证集否则验证集分数虚高。判断方法很朴素——看图片文件名前缀同一前缀的自己尽量归到同一边。数据包里的划分脚本常见做法是扫描images目录下的所有图片按设定比例随机打散后把文件名分成三组再按分组名生成对应的标签目录。如果你在本地打开脚本调试注意看它有没有随机种子参数没有的话每次划分结果都不一样复现训练效果会很难受。3.2 等价的划分脚本实现随机种子、比例、双目录同步不管数据包里给的脚本长什么样建议你在本地保留一份自己能完全掌控的划分脚本。下面这个是我习惯用的最小实现它同时处理images和labels并且日志会打印每个集合的图片数和标签缺失情况import os import random import shutil from pathlib import Path random.seed(42) # 随机种子固定保证多次运行结果一致 src_images Path(datasets/images) src_labels Path(datasets/labels) dst Path(datasets/split) train_ratio 0.7 val_ratio 0.2 # test 占比由 1 - train_ratio - val_ratio 得到 for split_name in [train, val, test]: for sub in [images, labels]: (dst / split_name / sub).mkdir(parentsTrue, exist_okTrue) for img_path in src_images.glob(*.jpg): label_path src_labels / (img_path.stem .txt) if not label_path.exists(): print(f[WARNING] 标签缺失: {label_path.name}) continue r random.random() if r train_ratio: split_name train elif r train_ratio val_ratio: split_name val else: split_name test shutil.copy2(img_path, dst / split_name / images / img_path.name) shutil.copy2(label_path, dst / split_name / labels / label_path.name) print(划分完成)这段脚本的逻辑是把images下的每个.jpg文件作为主索引找到同名.txt标签然后按随机数落入训练集、验证集或测试集。它好在哪第一标签缺失直接跳过并打印警告防止脏数据混进训练第二random.seed(42)让结果可复现你在不同机器上跑也能得到完全相同的划分结果。参数上train_ratio0.7, val_ratio0.2意味着测试集自动占到 0.1也就是 1000 张图片里约 100 张做测试。如果你的数据量更小比如不到 500 张我一般会把train_ratio调到 0.8给训练集更多样本。脚本只复制文件而不移动原文件这是一层后悔药。原目录被搞乱了随时可以直接删掉split重新划分。比起在原目录上原地挪文件复制方式更安全。3.3 三个参数我建议这样调train占比、随机种子、是否按场景分组划分脚本里最关键的参数不是比例而是“随机分配的粒度”。默认做法是对单张图片做随机这对正常情况够用。但如果这套数据集本身存在同一场景连续帧光随机就可能导致验证集里混进训练集的“近亲”。怎么判断有没有这种问题把划分结果打印出来看train/images和val/images的文件名前缀是否有重复。文件名往往是按拍摄过程编号的比如site1_0321.jpg、site1_0322.jpg。一旦发现同一个前缀既出现在训练集又出现在验证集必须改成按前缀分组再划分groups {} for img_path in src_images.glob(*.jpg): prefix img_path.name.split(_)[0] # 取场景前缀 groups.setdefault(prefix, []).append(img_path) for prefix, imgs in groups.items(): r random.random() # 整个场景组一起分配不拆开这段代码先把同一场景前缀的图片归为一组再按组分配保证同一个场景的照片不会跨集合。这是我在做过几次训练后总结出来的经验这种分组划分会让验证集分数稍微“难看”但更贴近真实部署环境。你宁可训练时看到低一点的 mAP也别被虚高的指标骗了。4. 用这套数据跑通训练从Anaconda环境到第一版权重4.1 目录结构固定成YOLO习惯避免“No labels found”在启动训练之前先解决目录结构。Ultralytics 默认按图片目录找标签目录它有一套自己的推断规则。最简单的方式是把数据目录摆成它认识的样子datasets/ ├── data.yaml ├── images/ │ ├── train/ │ ├── val/ │ └── test/ └── labels/ ├── train/ ├── val/ └── test/images和labels在同一个父目录下训练器会自动把images/train中的xxx.jpg对应到labels/train中的xxx.txt。如果把标签放在别的位置或者文件层级不平齐启动训练时就会出现一行醒目的警告WARNING: no labels found in .../labels/train这行警告几乎总是目录问题而不是数据本身的问题。看到它第一反应是去确认 labels 目录是否存在、文件名是否和 images 完全同名而不是怀疑标签文件写坏了。4.2 数据配置文件data.yaml两个类别却容易写错的一行环境配置是个简单但容易卡住的一步。我常用的做法是在 Anaconda 里新建一个独立环境避免把 TensorFlow、PyTorch 老版本搅在一起。命令如下conda create -n yolo python3.10 -y conda activate yolo pip install ultralytics这里用python3.10主要是兼容性和稳定性好新版 Ultralytics 对这个版本支持比较稳。装完库之后把数据配置文件写出来内容是 YOLO 训练的“连接器”它告诉模型你的类别是什么path: /absolute/path/to/datasets train: images/train val: images/val test: images/test nc: 2 names: 0: safety_helmet 1: glovenc是类别数量names的索引顺序必须和 YOLO 标签文件里的第一个数字严格对应。数据标注时如果否把安全帽设为0、手套设为1这里就必须保持一致。很多训练出来检测结果全部错乱都是因为顺序没对齐模型本身一点问题都没有。4.3 启动训练与日志观察哪些参数值得赌、哪些是玄学环境就绪后启动训练一行命令就能跑yolo detect train datadata.yaml modelyolov8m.pt epochs200 imgsz640 batch16 device0展开说明几个关键参数。modelyolov8m.pt表示从预训练权重开始训练这里选了中等体量的 m 版本比 n 更准比 l 更快。数据量只有 1000 张用 m 已经是上限再大就容易过拟合训练时间也白白浪费。imgsz640是最常见的默认尺寸这套数据集的原始分辨率如果高于 1280用 640 训练等于隐式降采样速度换精度的权衡新手可以先保持默认。device0是使用第一块 GPU没有 GPU 就改成devicecpu但训练时间会明显变长1000 张图建议仍想办法用 GPU。启动之后不要盯着进度条发呆重点观察每轮 Epoch 输出的三行损失值box_loss、cls_loss、dfl_loss。三条曲线在正常训练里应当整体下降哪怕有波动趋势必须向下。如果cls_loss突然跳到nan说明标签里混进了非法数值最常见的来源是 YOLO 标注的归一化坐标里出现了大于 1 的数字。等第一轮训练跑完看尾部表格里的mAP50(B)和mAP50-95(B)。对安全帽和手套这种大目标检测任务mAP50 能做到 0.8 以上才算可用。如果只有 0.3 或者更低优先怀疑数据而不是调参。参数调整这件事真正值得动手调的是batch和epochs其它很多调法在 1000 张的小数据集上收益约等于玄学。训练的本质是让损失下降日志里的损失变化比任何花哨的参数都诚实。5. 踩坑记录五个让人想删项目的暗坑与补救5.1 训练启动就报“No labels found”原因却是标签文件尺寸为 0现象数据集路径参数全对labels 目录非空训练器却始终打印no labels found。原因部分.txt标签文件是空文件0 字节训练器在读取时认为它没有标注目标于是视为不存在。这种情况往往发生在标注环节漏掉了某些图片但转换脚本仍然为每张图片生成了同名标签。解决训练前先写一个快速过滤脚本把空标签连同对应的图片一起清掉保证每张训练图至少有一个有效目标。5.2 训练完成后 mAP 很高但检测时把所有安全帽都识别成手套现象训练日志漂亮mAP50 达到 0.9但单独跑测试图片时安全帽和手套的类别标签互相换位。原因类别 ID 顺序不一致。数据集转换时把安全帽标成了类别 1、手套标成了类别 0而data.yaml里把 0 定义成了安全帽训练器学会的映射关系与你的预期翻转了。解决这个坑最隐蔽模型并没有错错的是配置。最稳妥的办法是随机挑三张图用可视化脚本在图上画出真实框和类别名和原图对比一眼就能看出映射对不对。5.3 换了一台电脑重新训练结果和上次完全不同现象同样数据、同样参数两次训练结果差异明显上一版训练到 150 轮 mAP50 是 0.85这次到 150 轮只有 0.78。原因划分脚本没有固定随机种子两次划分出的训练集和验证集不一样。测试集也变了指标自然没法复现。解决在你的划分脚本里固定random.seed()并把种子值写进训练日志。这个细节一开始不处理后面做实验对比时全部做废。5.4 loss 在中段反弹一次后持续上升最终变成 nan现象训练到第 40 轮左右cls_loss突然从 0.2 跳到 2.0再往后直接变成nan。原因学习率过大叠加数据里有异常标注框比如某个 YOLO 标签归一化坐标写成了1.85远远超出图片边界导致梯度爆炸。解决先清洗标签数据把所有坐标限制在 0~1 范围的标签抽出来检查。然后调低学习率Ultralytics 里可以指定lr00.0001比默认值低一个数量级。数据干净了这个现象多半不会再出现。5.5 labelimg 打完标后训练器总报越界错误检查坐标却没问题现象用 labelimg 手动打标导出 YOLO 格式打开文件看坐标都是 0 到 1 之间的小数但训练器仍然提示某些框的宽高为 0。原因labelimg 导出时如果误把某个目标框拖成了一个点宽度或高度会被记录为 0归一化后仍然是 0训练器计算损失时对 sqrt 或 log 操作就会异常。解决数据清洗时过滤掉w 0 or h 0的框。这个踩坑概率不高但只要标了几百张图必然会遇到一次。6. 一个立刻能做的验证技巧批量测试集可视化与置信度门限调整训练拿到第一版权重后不要急着部署先在测试集上做一次全量检查和可视化。最好的验证方式不是只看汇总指标而是把每个检测结果画出来存成图人眼扫一遍比看 mAP 数字更能发现问题。下面这个脚本遍历测试集对每张图跑一次预测并把置信度低于设定阈值的框过滤掉最后输出一张带安全帽和手套颜色区分的可视化图from ultralytics import YOLO import cv2 import glob model YOLO(runs/detect/train/weights/best.pt) threshold 0.4 # 置信度门限低于这个值的检测结果直接丢弃 output_dir test_visual/ for img_path in glob.glob(datasets/split/test/images/*.jpg): results model.predict(img_path, confthreshold, imgsz640) boxes results[0].boxes for box in boxes: x1, y1, x2, y2 map(int, box.xyxy[0].tolist()) cls_id int(box.cls[0]) conf float(box.conf[0]) label f{model.names[cls_id]} {conf:.2f} color (0, 255, 0) if cls_id 0 else (0, 165, 255) cv2.rectangle(results[0].orig_img, (x1, y1), (x2, y2), color, 2) cv2.putText(results[0].orig_img, label, (x1, y1 - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.7, color, 2) out_name img_path.replace(/, _) cv2.imwrite(output_dir out_name, results[0].orig_img) print(可视化完成)这里confthreshold直接传进predict方法相当于调整推理时的置信度门限这是部署前最常用到的参数之一。门限设为 0.4 的意思是凡是模型只有四成把握的判断全部不显示。门限设得越高误检越少但漏检也会变多。你在真实监控画面里如果发现手套经常抓不到可以把门限降到 0.25如果发现误检烦人就往上调到 0.55。小数据集训练出的模型门限一般落在 0.3 到 0.5 之间比较平衡以可视化结果为准不必死磕。跑完后把输出目录里的图按“工人正确佩戴”“未戴安全帽”“手套颜色与背景接近”三类各看几张你会很快发现数据集的盲区在哪里。有些图安全帽颜色鲜亮检测很稳有的场景手套是白色、背景也是白色框就会糊在一起。我自己的习惯是每次换数据集后都拿一张正面照、一张侧光照、一张仰拍图做快速体检同时调整置信度门限直到三张图都能稳住关键框再谈进一步部署。这步看着不起眼实际为后续省了大量无谓的调参时间。训练这事数据和验证比模型结构更值得花时间。希望这篇笔记能帮你把分坑踩在前面顺利跑出第一版可用的检测权重。本文还有配套的精品资源点击获取
返回列表