安全帽检测YOLO实战:数据集标签格式转换与训练环境搭建指南

发布时间:2026/9/13 6:11:39
安全帽检测YOLO实战:数据集标签格式转换与训练环境搭建指南 简介YOLO安全帽手套检测数据集是一套真实场景的目标检测训练数据图片内容涵盖工地常见的安全帽与手套佩戴情况数据场景丰富适合计算机视觉初学者、算法工程师以及需要快速搭建安全检测方案的项目团队。压缩包共2000个文件其中1000个XML标签和991个TXT标签为主要标注文件另有HTML训练教程、Python划分脚本及YAML配置等辅助内容整体大小约50.13MB标注涵盖VOC、COCO、YOLO三种主流格式可灵活对接不同检测框架。目前已有544人学习/下载配套教程和脚本经过实际使用验证适合作为深度学习实战练习或安全检测项目的基础数据。随包附赠的训练教程从环境搭建、GPU驱动版本选择延伸到修改案例训练自定义数据集配合划分脚本可一键拆分训练集、验证集和测试集帮助用户从数据准备到模型训练形成完整闭环显著降低上手门槛。1. 为什么安全帽检测数据集值得自己动手跑一遍 YOLO工地现场的监控画面里安全帽和手套通常只占几十个像素光线从正午直射到夜间补光再加上人员遮挡和机位俯仰检测难度其实远高于公开的通用目标集。很多人在训 YOLO 时发现验证集 mAP 很高一上真实场景就掉点问题往往不在模型结构而在数据本身的分布和标注质量。这份安全帽手套检测数据集共 1000 张真实场景图片标注框质量高同图提供 VOC(xml)、COCO(json)、YOLO(txt) 三种格式的标签并附带训练集/验证集/测试集划分脚本和从 Ubuntu 安装、GPU 驱动到修改训练案例的完整教程。它适合要在安全生产领域做项目预研的工程师也适合毕设和课题需要自建小目标检测数据集的人。整篇文章围绕数据怎么组织、标签怎么转、划分怎么做、训练怎么跑展开每一步都能直接复现。2. 数据集结构与 VOC / COCO / YOLO 三种标签格式的衔接关系拿到资源后先别急着开训。它的目录组织方式决定了后面所有脚本怎么改三种标签格式之间的坐标换算关系也直接影响训练是否收敛。这一节把文件结构和格式转换逻辑拆开讲清楚。2.1 数据集目录结构与 1000 张图片的组织方式资源内图片和标签采用分目录存放不同格式的标签互不干扰。用tree看下来大致是这样helmet_glove_dataset/ ├── JPEGImages/ # 1000张原图jpg格式 ├── Annotations/ # VOC格式标签每张图对应一个xml ├── labels/ # YOLO格式标签每张图对应一个txt ├── annotations/ │ ├── instances_train.json # COCO 格式训练标签 │ └── instances_val.json # COCO 格式验证标签 └── ImageSets/ └── Main/ # train.txt / val.txt / trainval.txt这里有个容易忽略的细节labels下 YOLO 格式的 txt 文件名必须和 JPEGImages 里的图片名保持一致训练时 YOLO 系列框架会按图片路径自动寻找同名 txt。如果图片名带了中文或空格建议先统一改成000001.jpg这类纯数字命名否则后续在 Windows 和 Linux 之间搬运时大概率踩路径解析的坑。之所以同时提供三种格式是因为不同训练框架的入口不一样。YOLOv5 和 YOLOv8 原生读取 YOLO txt 格式mmdetection 更习惯 COCO json而 LabelImg 可视化核对时又得切回 VOC xml。数据集的作者把这三种格式都备好相当于省掉了自行转换的时间和出错的余地。2.2 三种格式的字段对照与坐标基准差异三种格式的核心差异在于框的表示方式。VOC xml 记录的是像素坐标系下的xmin, ymin, xmax, ymaxCOCO json 记录的是像素坐标的x, y, width, height其中 x、y 是框左上角坐标而 YOLO 的 txt 记录的是归一化到 0~1 之间的中心点坐标class x_center y_center width height。关键区别在于归一化YOLO 格式把坐标值除以图片宽高这样模型在任意输入尺寸下都能用同一个标签文件。格式位置基准框表示坐标范围典型应用VOC xml像素坐标系xmin, ymin, xmax, ymax0~W 或 0~HLabelImg 标注、Pascal VOC 系列COCO json像素坐标系x, y, width, height0~W 或 0~Hmmdetection、Detectron2YOLO txt归一化坐标class, x_center, y_center, w, h0~1YOLOv5、YOLOv8、Ultralytics 全系COCO 格式里还有一个容易看错的字段叫area它要求填写框面积。有些转换脚本图省事直接写width * height这在绝大多数情况没问题但如果样本里有带iscrowd1的群体标注面积计算方式就不一样了训练时某些框架会用 area 做小目标采样算错了会影响采样权重。这份数据集主要是单人单框的安全帽和手套标注没有 crowd 标签所以直接按标准公式即可。2.3 VOC 转 YOLO 的标准化写法如果后续想往数据集里补充图片用 LabelImg 标注完得到的是 xml再转成 YOLO txt 是绕不开的一步。常见做法是写一个脚本遍历 Annotations 目录做转换核心代码如下import xml.etree.ElementTree as ET classes [helmet, glove] # 顺序要和训练yaml中的names保持一致 def voc_to_yolo(xml_path, out_txt_path): tree ET.parse(xml_path) root tree.getroot() img_w float(root.find(size/width).text) img_h float(root.find(size/height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in classes: continue cls_id classes.index(name) box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 由像素坐标转为归一化中心点坐标宽高除以原图尺寸 x_center (xmin xmax) / 2 / img_w y_center (ymin ymax) / 2 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}) with open(out_txt_path, w, encodingutf-8) as f: f.write(\n.join(lines))这段代码的关键在于img_w和img_h必须取原图真实尺寸而不是标注框所在的分辨率。实际项目里常有人在这里直接把尺寸写死成 640结果模型训练时看到的坐标全偏了验证集 mAP 从一开始就不涨。另外class_id的取值顺序必须固定如果 yaml 里写names: [helmet, glove]那 helmet 就是 0glove 就是 1一旦后续换了顺序旧标签全部作废得重新生成。反方向的 YOLO 转 VOC 在可视化验证时用得多把中心点坐标乘回图片宽高再计算xmin x_center - w/2做裁剪显示时记得取整。转换输出的 txt 每行对应一个目标空标签文件留空即可不要写任何字符。3. 训练集 / 验证集 / 测试集拆分两个脚本的用法与边界资源里带的划分脚本是很多人容易忽视但实际最省力的部分。许多自制数据集项目到训练阶段才发现整套数据只有一个目录临时手写划分逻辑又容易出错比如图片复制过去了标签没跟上或者同一个场景的连续帧被拆到训练集和验证集里造成数据泄漏。这个资源里直接提供了两个脚本对应两种组织思路。3.1 为什么划分比例不是越偏越大越好划分脚本解决的问题很明确把原始图片和对应标签按比例复制到新目录让 YOLO 框架能识别训练集、验证集、测试集。划分比例本身要根据样本量定。1000 张的小数据集如果训练集占比太高验证集只剩几十张每个类别的 mAP 波动会非常大一个难样本就能让指标掉好几个点。参数推荐值适用场景train_ratio0.7~0.81000 张以下的小数据集val_ratio0.1~0.15常规训练调参验证test_ratio0.1~0.2需要最终泛化性评估时保留这个数据集还要额外考虑一个特性工地监控画面里同一段时间采集的图片背景高度相似如果随机划分时没有做随机化很可能连续几十张相似场景全被分到训练集验证集碰到的都是没见过的机位。所以脚本里必须先shuffle再切片而不是顺序切割。3.2 文件复制到新目录的划分脚本第一个脚本名为“训练集、验证集划分脚本图片标签划分写入新文件夹.py”它是按图片标签对复制到新文件夹的方式运行后会生成 images/train、images/val、labels/train、labels/val 这样的目录结构。核心实现逻辑如下import os import random import shutil random.seed(42) # 固定随机种子保证多次运行结果一致 def split_and_copy(src_img_dir, src_label_dir, out_dir, train_ratio0.8, val_ratio0.1, test_ratio0.1): img_names [f for f in os.listdir(src_img_dir) if f.endswith(.jpg)] random.shuffle(img_names) n len(img_names) n_train int(n * train_ratio) n_val int(n * val_ratio) parts { train: img_names[:n_train], val: img_names[n_train:n_train n_val], test: img_names[n_train n_val:] } for part, names in parts.items(): for img_name in names: base_name os.path.splitext(img_name)[0] src_img os.path.join(src_img_dir, img_name) src_label os.path.join(src_label_dir, base_name .txt) # 输出目录结构与YOLO要求的images/train、labels/train组织方式对齐 dst_img os.path.join(out_dir, images, part, img_name) dst_label os.path.join(out_dir, labels, part, base_name .txt) os.makedirs(os.path.dirname(dst_img), exist_okTrue) os.makedirs(os.path.dirname(dst_label), exist_okTrue) shutil.copy(src_img, dst_img) shutil.copy(src_label, dst_label)脚本里random.seed(42)这行值得单独说。不固定随机种子的话每次运行划分结果都不同训练前想复现上一个实验的数据分布会非常别扭。我在实际项目里吃过亏数据划分不一致导致两个版本模型的 mAP 无法公平对比最后排查半天才发现是随机种子没固定。另外脚本里shutil.copy复制的是文件和标签而不是移动原目录文件仍然保留运行多次不会破坏原始数据。测试集在这个脚本里的角色容易被误解。如果只跑 YOLO 训练其实训练和验证两个集合就够用测试集更多是给最终模型做一次性评估的不要用测试集去反复调参否则测试集本身也变成了训练监督信号的一部分失去泛化评估的意义。3.3 生成 ImageSets 下 txt 列表的拆分脚本第二个脚本“split_train_val 生成 ImageSets 下 txt 文件划分脚本.py”面向的则是 VOC 系训练流程。它不在目录层面复制数据而是在 ImageSets/Main 下生成train.txt、val.txt、test.txt和trainval.txt四个文本文件内容是不带扩展名的图片名列表。这种做法源自 VOC 数据集的习惯YOLO 早期版本在数据加载阶段会读取这些 txt 找到图片路径。import os import random random.seed(42) img_dir JPEGImages names [os.path.splitext(f)[0] for f in os.listdir(img_dir)] trainval names[:int(len(names) * 0.9)] test names[int(len(names) * 0.9):] train trainval[:int(len(trainval) * 0.89)] val trainval[int(len(trainval) * 0.89):] def write_txt(name_list, path): with open(path, w) as f: f.write(\n.join(name_list)) os.makedirs(ImageSets/Main, exist_okTrue) write_txt(train, ImageSets/Main/train.txt) write_txt(val, ImageSets/Main/val.txt) write_txt(test, ImageSets/Main/test.txt) write_txt(trainval, ImageSets/Main/trainval.txt)这里有个细节值得注意生成的 txt 中每行内容取决于框架读取时怎么拼接。YOLOv5 早期版本的 VOC 数据加载逻辑会拿 txt 里的名字拼上完整的JPEGImages路径所以 txt 只写文件名即可。现在主流的 Ultralytics YOLOv8 已经不再需要这种 txt 列表直接读数据集 yaml 里的目录结构。如果你用的是 YOLOv8这个脚本生成的 txt 文件仅作为归档或二次开发的辅助使用。提示无论用哪种划分方式划分完成后都要检查 labels 目录和 images 目录下的文件数量是否一一对应。常见问题是某些图片没有对应标签导致训练时找不到 txt 报错或者标签文件孤立无图可依。3.4 两种脚本的协作方式建议的流程是先跑第二个脚本生成列表确认划分比例符合预期再跑第一个脚本把对应文件复制到 YOLO 期望的 images/train、labels/train 目录结构里。实际上第二个脚本更适合做“先规划后执行”先拿到所有图片名的划分清单再按清单复制文件。顺序反过来容易造成两套划分结果不一致。这份资源的两个脚本刚好互补配合使用时注意两点第一随机种子在两个脚本里要统一第二两个脚本的划分比例最好保持一致避免列表归列表、文件归文件。4. YOLO 训练环境搭建GPU 驱动版本、CUDA 与 PyTorch 的选择资源里带了三份 html 教程分别是 Ubuntu 安装教程、YOLO 环境搭建和 YOLO 训练教程其中环境搭建部分重点讲了 GPU 显卡驱动版本的选择。这里把最关键的环节梳理出来重点回答新手最容易卡的“为什么环境装完运行不了”的问题。4.1 驱动版本、CUDA 和 PyTorch 三者怎么匹配GPU 驱动是底层CUDA 是并行计算框架PyTorch 是上层库三者版本必须形成一条兼容链。驱动版本低了CUDA 装不上CUDA 版本与 PyTorch 的编译版本不一致torch.cuda.is_available()会一直返回 False。启动训练前先确认驱动状态nvidia-smi输出里的右上角会显示 “CUDA Version: 12.4” 之类的字样这代表当前驱动支持的最高 CUDA 版本。只要这个数值不低于你要安装的 CUDA 版本驱动就是够用的。安装 CUDA 后查看实际版本nvcc --version如果nvidia-smi显示 12.x 但nvcc显示 11.x前者是驱动兼容的上限后者才是当前环境实际使用的运行时版本这套组合也能工作不必强行对齐。PyTorch 安装时直接用预编译的 cu118 或 cu121 wheel 包能省掉大量编译时间pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118安装后先用一行 Python 验证 GPU 是否真正可用python -c import torch; print(torch.cuda.is_available()); print(torch.cuda.get_device_name(0))输出第一行必须是 True。如果输出 False绝大多数情况是 PyTorch 误装了 CPU 版。排查时执行pip list | grep torch看 torch 版本号里有没有cu后缀没有就是装错了。这个坑在 Windows 上尤其常见因为 CPU 版 torch 体积小pip 默认解析时容易命中。4.2 YOLO 环境安装与训练前的目录确认环境装好后YOLO 主程序按教程里的方式克隆或解压到工作区。训练前需要确认数据集目录被正确放到工程可访问的位置。以 YOLOv5 为例训练入口文件是train.py数据配置入口是 datasets 下的 yaml 文件。把划分脚本生成的数据集整体复制到工程目录下目录结构应该满足helmet_dataset/ ├── images/ │ ├── train/ │ └── val/ ├── labels/ │ ├── train/ │ └── val/ └── data.yamldata.yaml在这里是承上启下的关键环节内容如下# helmet_glove.yaml path: /home/user/yolov5/helmet_dataset # 数据集的绝对路径 train: images/train val: images/val test: images/test nc: 2 # 类别数量 names: 0: helmet 1: glovepath建议写绝对路径。很多人训练时报错 “AssertionError: train: No labels in ...”就是因为用了相对路径而运行train.py时当前工作目录不在项目根目录导致框架找不到images/train。nc和names的顺序必须和之前 VOC 转 YOLO 时的 class 顺序完全一致这是整个训练配置里最容易被忽略的隐性约束。4.3 显卡信息与 batch size 的第一轮试探双卡或单卡机器的显存直接决定 batch size 上限。YOLOv5 默认训练配置里 batch size 是 16但那是基于 COCO 数据集的通用设置。对这个数据集输入图片是真实监控场景尺寸从几百到上千像素不等。训练时框架会自动做 letterbox 缩放所以输入尺寸统一设 640 即可。建议第一次训练用一个保守组合试水python train.py --data helmet_glove.yaml --weights yolov5s.pt --epochs 100 --batch-size 16 --imgsz 640如果显存只有 6G 或 8Gbatch size 减少到 8 或 4。判断标准很简单训练开始后每一步迭代耗时稳定且不出现 CUDA out of memory。这个参数会在训练 YAML 里写到实验记录中之后可以对比不同 batch size 下的收敛曲线。Ubuntu 环境下的显卡驱动安装同样在教程里有说明常见做法是通过 apt 直接安装推荐驱动sudo ubuntu-drivers autoinstall安装完成后重启再次执行nvidia-smi确认驱动生效。最后提醒一点如果是在虚拟机里跑 YOLO直接跳过 GPU 环节用 CPU 小 batch 训练做流程验证可以但不适合跑完整训练。5. 训练安全帽数据时最该调的三个参数与验证技巧模型跑起来之后真正的调参才刚开始。安全帽和手套检测场景里最常见的问题是两类目标尺度差异过大安全帽在画面里相对大手套常被身体遮挡且面积小导致小目标类别在损失函数里贡献不足。处理这类问题优先关注三个参数的联动关系。第一个是imgsz。训练分辨率从 640 提到 960小目标的 mAP 通常能涨 3~5 个点代价是显存占用和训练时间同步上升。1000 张图的数据集规模用 960 分辨率训练百轮仍在可接受范围内。第二个是conf-thres和iou-thres推理阈值训练完成后验证阶段不要直接用默认 0.25先把阈值提到 0.5 看误检率再降到 0.3 看漏检率在两个指标之间取平衡点。第三个是训练轮数epochs小数据集不用盲目上 300 轮100 轮以内基本能看到收敛趋势关键是观察 loss 曲线是否在最后 20 轮还在继续下降如果已经平坦提前停止即可。训练结束后验证一张现场照片python detect.py --weights runs/train/exp/weights/best.pt --source on_site_test.jpg --conf-thres 0.35 --iou-thres 0.5best.pt是训练过程中验证集 mAP 最高的权重文件区别于最后保存的last.pt。对这个小数据集来说last.pt可能已经过拟合best.pt才是真正可供部署使用的模型。把 confidence 阈值调低到 0.25 重新跑一遍对比两次输出的差异凡是没戴手套的手背区域模型都会给出低置信度框。这些低置信度框要保留后续可挑出来做人工复核作为扩充数据集的候选。真实工地上最有价值的数据恰恰是这些难负样本比随机再拍 1000 张通用场景更能提升泛化能力。最终固定阈值后导出 ONNX 或 TensorRT 模型时把验证好的参数固化到导出命令里避免部署环境与测试环境默认值不一致造成效果回退。本文还有配套的精品资源点击获取