☰
安全帽检测数据集实战:YOLOv5格式转换与训练全流程
2026/10/1 19:51:51 网站建设 项目流程

简介:这份资源是面向深度学习与计算机视觉方向的 YOLOv5 头盔目标检测数据集,适合正在做安全帽佩戴识别、工地或厂区安全监控项目的开发者、学生与算法工程师使用,可解决目标检测训练中缺少标注样本的问题。压缩包共 160 个文件,以 80 个 jpg 图像与 80 个 xml 标注文件成对组成,整体约 2.86MB,xml 可直接转换为 YOLO 格式标签,便于快速接入训练流程。目前已有 482 人学习下载,具备一定参考热度。数据集覆盖多种头盔佩戴场景,图像与标注一一对应,读者可据此完成模型训练、验证与调优,也可用于课程设计、毕业设计或算法对比实验,帮助缩短数据采集与标注周期,把精力集中在模型结构与参数调优上。

1. 安全帽检测数据集:从一堆散图到 YOLOv5 可训练样本的落地路径

工地、电厂、矿区这类场景做视觉项目,绕不开的第一道坎就是安全帽佩戴检测。算法本身不复杂,YOLOv5 跑起来也就那几行命令,真正卡住进度的是数据——要么没有,要么标注格式不对,要么类别定义混乱。这份「用于 yolo5 头盔目标检测的数据集.zip」解决的就是这个前置问题:它把一批头盔/安全帽相关的图像素材打包好了,省去从零采集和初筛的时间。适合两类人:一是刚接触目标检测、想拿一个真实场景数据集跑通 YOLOv5 全流程的新手;二是手头有检测需求、需要快速验证模型可行性的工程人员。但要注意,拿到压缩包不等于能直接开训,中间还有格式转换、类别映射、数据清洗几步硬活,下面按实际落地顺序拆开讲。

2. 先搞清楚手里有什么:数据集结构解析与 YOLOv5 格式对齐

2.1 压缩包解压后的典型目录形态

拿到一个目标检测数据集压缩包,第一件事不是急着写训练脚本,而是把目录结构摸清楚。常见做法是解压后先tree或ls -R看一眼层级。这类头盔数据集通常有两种组织方式:一种是已经切好images/和labels/的 YOLO 格式,另一种是原始图片加一个annotations文件夹(可能是 VOC XML 或 COCO JSON)。从项目正文列出的文件名来看,图片命名是u=xxxx,xxxx&fm=253&fmt=auto&app=138&f=PNG.jpg这种带查询参数的格式,说明素材来源比较杂,大概率是网络采集后统一重命名的,标注文件需要单独确认。

# 解压后先看目录层级,别急着写代码 unzip 用于yolo5头盔目标检测的数据集.zip -d helmet_dataset cd helmet_dataset find . -maxdepth 2 -type d | sort # 统计图片数量,心里有个底 find . -name "*.jpg" -o -name "*.png" | wc -l # 看看有没有标注文件 find . -name "*.txt" -o -name "*.xml" -o -name "*.json" | head -20

这段命令的逻辑很直白:先解压到独立目录避免污染工作区,然后用find限制层级看目录骨架,再分别统计图片和标注文件。参数上-maxdepth 2是防止目录太深输出刷屏,head -20是先扫一眼标注文件类型,不用一次性全列出来。如果发现只有图片没有标注,那这个包可能只是素材集,需要自己标注或另找标注文件;如果标注是 XML 格式,就得走后面的转换流程。

2.2 YOLOv5 要求的标签格式与坐标归一化

YOLOv5 的标签格式是每个图片对应一个同名.txt文件,每行代表一个目标,格式为:

<class_id> <x_center> <y_center> <width> <height>

其中坐标全部是相对于图片宽高的归一化值,范围 0 到 1。这一点和 VOC 的xmin, ymin, xmax, ymax绝对坐标完全不同,也是新手最容易翻车的地方。归一化公式不复杂:

# 假设图片宽 w=1920,高 h=1080 # VOC 格式的框:xmin=400, ymin=300, xmax=700, ymax=600 w, h = 1920, 1080 xmin, ymin, xmax, ymax = 400, 300, 700, 600 x_center = (xmin + xmax) / 2.0 / w # (400+700)/2/1920 = 0.2865 y_center = (ymin + ymax) / 2.0 / h # (300+600)/2/1080 = 0.4167 width = (xmax - xmin) / w # (700-400)/1920 = 0.1563 height = (ymax - ymin) / h # (600-300)/1080 = 0.2778 print(f"0 {x_center:.4f} {y_center:.4f} {width:.4f} {height:.4f}") # 输出:0 0.2865 0.4167 0.1563 0.2778

这里的关键参数是w和h,必须用每张图片自己的实际尺寸,不能统一用一个值。常见错误是批量转换时读了一张图的尺寸就套用到所有图上,结果标签全部偏移。另外class_id从 0 开始编号,如果数据集里头盔和安全帽分成两类,需要提前定义好类别映射表,比如{0: 'helmet', 1: 'head'},这个映射关系要同时写进data.yaml和转换脚本里,两边不一致训练时不会报错但精度会莫名其妙地低。

2.3 类别定义与 data.yaml 配置

YOLOv5 训练需要一个data.yaml文件来描述数据集路径和类别信息。头盔检测场景通常分两类:戴头盔(helmet)和未戴头盔(head),也有只检测头盔一类的。具体几类要看标注文件里的class_id分布,用脚本统计一下最稳妥:

import os from collections import Counter label_dir = "helmet_dataset/labels" counter = Counter() for txt_file in os.listdir(label_dir): if not txt_file.endswith(".txt"): continue with open(os.path.join(label_dir, txt_file), "r") as f: for line in f: cls_id = int(line.strip().split()[0]) counter[cls_id] += 1 print("类别分布:", dict(counter)) # 典型输出:{0: 3200, 1: 1800} 说明有两类

统计完类别数后,data.yaml按下面这样写:

# data.yaml path: ./helmet_dataset train: images/train val: images/val nc: 2 names: ['helmet', 'head']

nc是类别数量,names的顺序必须和class_id一一对应。如果统计出来只有一类,nc改成 1,names只留一个。这里有个容易忽略的点:path用相对路径时,训练脚本的工作目录要对,否则 YOLOv5 找不到图片。我一般直接用绝对路径,省得后面排查半天发现是路径问题。

3. 从原始标注到 YOLOv5 训练集:转换脚本与数据划分实操

3.1 VOC XML 转 YOLO txt 的完整脚本

如果解压后发现标注是 XML 格式,需要先转成 YOLO 的 txt。下面这个脚本处理了图片尺寸读取、坐标归一化和类别映射,可以直接改路径用:

import os import xml.etree.ElementTree as ET from PIL import Image # 类别映射,根据实际标注文件里的 name 调整 CLASS_MAP = {"helmet": 0, "head": 1, "person": 0} def convert_annotation(xml_path, img_dir, out_dir): tree = ET.parse(xml_path) root = tree.getroot() # 从 XML 里拿图片文件名 filename = root.find("filename").text img_path = os.path.join(img_dir, filename) if not os.path.exists(img_path): print(f"图片缺失:{img_path}") return # 读取图片真实宽高 with Image.open(img_path) as img: w, h = img.size lines = [] for obj in root.iter("object"): cls_name = obj.find("name").text.strip() if cls_name not in CLASS_MAP: continue cls_id = CLASS_MAP[cls_name] bbox = obj.find("bndbox") xmin = float(bbox.find("xmin").text) ymin = float(bbox.find("ymin").text) xmax = float(bbox.find("xmax").text) ymax = float(bbox.find("ymax").text) # 归一化 x_center = (xmin + xmax) / 2.0 / w y_center = (ymin + ymax) / 2.0 / h bw = (xmax - xmin) / w bh = (ymax - ymin) / h lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}") # 写同名 txt out_name = os.path.splitext(filename)[0] + ".txt" with open(os.path.join(out_dir, out_name), "w") as f: f.write("\n".join(lines)) # 批量执行 xml_dir = "helmet_dataset/annotations" img_dir = "helmet_dataset/images" out_dir = "helmet_dataset/labels" os.makedirs(out_dir, exist_ok=True) for xml_file in os.listdir(xml_dir): if xml_file.endswith(".xml"): convert_annotation(os.path.join(xml_dir, xml_file), img_dir, out_dir)

逻辑上分四步:解析 XML 拿到图片名和框坐标,用 PIL 读图片真实尺寸,按公式归一化,写同名 txt。参数上CLASS_MAP要根据实际标注里的name字段调整,如果标注里写的是中文「头盔」,映射表里就得写{"头盔": 0}。:.6f保留六位小数是 YOLOv5 官方推荐的精度,太少会有坐标误差,太多没必要。跑完后抽查几个 txt 文件,确认坐标都在 0 到 1 之间,如果出现大于 1 的值说明图片尺寸读错了。

3.2 训练集/验证集划分与目录组织

YOLOv5 默认要求images/train、images/val、labels/train、labels/val这样的结构。划分比例一般 8:2 或 9:1,数据量少的时候验证集至少留几十张,否则评估指标波动很大。下面脚本按比例随机划分并复制文件:

import os import shutil import random random.seed(42) # 固定随机种子,保证可复现 img_dir = "helmet_dataset/images" label_dir = "helmet_dataset/labels" base_out = "helmet_dataset" # 收集所有有对应标签的图片 pairs = [] for img_name in os.listdir(img_dir): if not img_name.lower().endswith((".jpg", ".png", ".jpeg")): continue stem = os.path.splitext(img_name)[0] label_name = stem + ".txt" if os.path.exists(os.path.join(label_dir, label_name)): pairs.append((img_name, label_name)) random.shuffle(pairs) split_idx = int(len(pairs) * 0.8) train_pairs = pairs[:split_idx] val_pairs = pairs[split_idx:] for subset, data in [("train", train_pairs), ("val", val_pairs)]: img_out = os.path.join(base_out, "images", subset) lbl_out = os.path.join(base_out, "labels", subset) os.makedirs(img_out, exist_ok=True) os.makedirs(lbl_out, exist_ok=True) for img_name, label_name in data: shutil.copy(os.path.join(img_dir, img_name), os.path.join(img_out, img_name)) shutil.copy(os.path.join(label_dir, label_name), os.path.join(lbl_out, label_name)) print(f"训练集 {len(train_pairs)} 对,验证集 {len(val_pairs)} 对")

random.seed(42)是为了每次划分结果一致,方便复现实验。split_idx按 0.8 切分,如果数据量少于 500 张,建议改成 0.9 留更多训练数据。复制而不是移动,是为了保留原始文件,后面如果发现划分有问题还能重新来。跑完后检查images/train和labels/train的文件数量是否一致,不一致说明有图片没有对应标签,训练时 YOLOv5 会跳过这些图但不会报错,容易导致实际训练数据比预期少。

3.3 用 YOLOv5 官方脚本做标签校验

YOLOv5 仓库里自带一个utils/dataset.py或训练启动时的标签检查逻辑,但更直接的方式是用官方提供的check_labels思路自己扫一遍。常见问题是标签文件里有空行、坐标越界、类别 id 超出nc范围。下面这段脚本快速排查:

import os label_dir = "helmet_dataset/labels/train" nc = 2 # 和 data.yaml 保持一致 issues = [] for txt_file in os.listdir(label_dir): if not txt_file.endswith(".txt"): continue path = os.path.join(label_dir, txt_file) with open(path, "r") as f: for line_no, line in enumerate(f, 1): parts = line.strip().split() if len(parts) != 5: issues.append(f"{txt_file}:{line_no} 字段数不对") continue cls_id = int(parts[0]) coords = [float(x) for x in parts[1:]] if cls_id >= nc: issues.append(f"{txt_file}:{line_no} 类别id越界 {cls_id}") if any(c < 0 or c > 1 for c in coords): issues.append(f"{txt_file}:{line_no} 坐标越界 {coords}") print(f"发现 {len(issues)} 个问题") for i in issues[:10]: print(i)

这段脚本检查三类高频问题:字段数不是 5、类别 id 超过nc、坐标不在 0 到 1 之间。发现坐标越界通常是转换时图片尺寸读错,或者标注本身有问题。类别 id 越界多半是CLASS_MAP和data.yaml的names对不上。跑完没问题再开始训练,比训练到一半发现 loss 不降要省时间。

4. 避坑与排查:头盔数据集训练前必须过的五道关

4.1 图片能打开但训练报「corrupt image」

现象是训练启动后日志里出现corrupt JPEG或image cannot be decoded,但手动双击图片能正常预览。原因是部分图片虽然扩展名是.jpg,实际编码可能是 PNG 或 WebP,PIL 和 OpenCV 读取时行为不一致。从项目正文的文件名看,有fmt=PNG和fmt=JPEG混在一起,这种情况概率不低。解决办法是用脚本统一转成标准 JPEG:

from PIL import Image import os img_dir = "helmet_dataset/images/train" for name in os.listdir(img_dir): path = os.path.join(img_dir, name) try: with Image.open(path) as img: rgb = img.convert("RGB") rgb.save(path, "JPEG", quality=95) except Exception as e: print(f"处理失败 {name}: {e}")

convert("RGB")是去掉 alpha 通道,quality=95是平衡质量和体积。转完后重新跑一遍标签校验,因为图片尺寸可能因为重新编码有微小变化,但通常不影响归一化坐标。

4.2 标签文件和图片文件名不匹配

现象是训练时提示No labels found或者某张图被跳过。原因是图片名里带u=2855313472,3725098243&fm=253这种特殊字符,转换脚本生成 txt 时可能因为编码或截断导致文件名不一致。解决方法是统一重命名图片和标签为纯数字或 UUID:

import os import uuid img_dir = "helmet_dataset/images/train" lbl_dir = "helmet_dataset/labels/train" for img_name in os.listdir(img_dir): stem, ext = os.path.splitext(img_name) new_stem = uuid.uuid4().hex[:12] # 重命名图片 os.rename(os.path.join(img_dir, img_name), os.path.join(img_dir, new_stem + ext)) # 重命名对应标签 old_lbl = os.path.join(lbl_dir, stem + ".txt") if os.path.exists(old_lbl): os.rename(old_lbl, os.path.join(lbl_dir, new_stem + ".txt"))

重命名后图片和标签仍然一一对应,但去掉了特殊字符,避免路径解析问题。注意这个操作不可逆,建议先备份原始文件。

4.3 类别不均衡导致模型只学一类

现象是训练完模型对「戴头盔」检测很好,但「未戴头盔」几乎检不出。原因是两类样本数量差距大,比如 helmet 有 3000 个框,head 只有 500 个。解决办法有两个方向:一是对少数类做过采样,在划分训练集时重复复制少数类图片;二是用 YOLOv5 的--weights加载预训练权重,让模型从小样本里也能学到特征。我一般先用预训练权重跑一版看效果,如果少数类召回率还是低,再做过采样。

4.4 验证集 mAP 高但实际场景漏检

现象是训练日志里 mAP@0.5 到了 0.85,但拿工地实拍图测试时漏检严重。原因是数据集里的图片可能场景单一,比如都是白天、正面、清晰的头盔,而实际场景有逆光、遮挡、小目标。解决办法是在验证集里刻意加入困难样本,或者用--img-size增大输入分辨率,让远处的小头盔有更多像素。YOLOv5 默认 640,可以试 960 或 1280,但显存占用会明显上升。

4.5 训练中断后恢复时数据加载变慢

现象是--resume恢复训练后每个 epoch 时间比之前长很多。原因是 YOLOv5 的缓存机制在恢复时可能重新扫描数据集,如果图片数量多且磁盘慢,就会卡在数据加载。解决办法是训练前加--cache ram或--cache disk,把图片缓存起来。内存够就用ram,不够用disk。这个参数在第一次训练时加上,恢复时也能受益。

5. 训练启动与效果验证:从命令行到实际推理的闭环

5.1 YOLOv5 训练命令与关键参数

数据准备好之后,训练本身反而简单。假设 YOLOv5 仓库已经克隆到本地,data.yaml放在helmet_dataset目录下:

python train.py \ --img 640 \ --batch 16 \ --epochs 100 \ --data helmet_dataset/data.yaml \ --weights yolov5s.pt \ --cache ram \ --name helmet_exp

--img 640是输入分辨率,头盔检测如果目标偏小可以调到 960。--batch 16看显存,8G 显存跑 640 分辨率一般能到 16,不够就降到 8。--epochs 100是上限,实际看 mAP 曲线早停。--weights yolov5s.pt加载官方预训练权重,小数据集上比从头训效果好很多。--cache ram把图片缓存到内存,加快 epoch 速度。--name是实验名,结果存在runs/train/helmet_exp下。

5.2 用验证集跑推理看实际效果

训练完拿验证集图片跑一遍推理,直观看看漏检和误检:

python detect.py \ --weights runs/train/helmet_exp/weights/best.pt \ --source helmet_dataset/images/val \ --img 640 \ --conf 0.4 \ --save-txt \ --name helmet_val

--conf 0.4是置信度阈值,默认 0.25 会出很多低置信框,头盔场景调到 0.4 到 0.5 比较合适。--save-txt会把检测结果存成 txt,方便和标注对比算指标。结果图在runs/detect/helmet_val下,重点看几类情况:远处小头盔有没有检到、遮挡情况下有没有漏、背景里类似头盔的圆形物体有没有误检。如果误检多,提高--conf;如果漏检多,降低--conf或者增大--img。

5.3 一个容易忽略的验证习惯

我每次训练完不会只看 mAP 数字,而是随机抽 20 张验证集图片,把检测结果和原图并排看一遍。这一步花不了几分钟,但能发现指标看不出的问题,比如框偏大偏小、类别标反、密集场景框重叠。从那以后我每次拿到新数据集训练完,都强制走一遍这个抽检流程,比单纯信 mAP 靠谱得多。希望这份数据集和上面的流程能帮你把安全帽检测项目快速跑起来。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询