十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

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

YOLOV9安全帽与反光背心检测:数据集构建与训练全流程指南

YOLOV9安全帽与反光背心检测:数据集构建与训练全流程指南 简介面向建筑工地、工厂车间等需要强制个人防护装备PPE的作业场景这份数据集已对安全帽、安全服与反光背心完成 2000 多张图像的 YOLOv9 格式标注可直接用于安全穿戴检测模型的训练与评估也可迁移到其他目标检测算法。压缩包共 2000 个文件其中 1955 个 txt 文件为 YOLO 格式标注结果44 张 jpg 为现场图像样本1 个 yaml 定义类别与数据集配置整体大小约 193.07MBtxt 标注可直接被多数检测框架读取。全部图像已完成自动定向并统一调整为 1280x720 黑边尺寸省去二次预处理流程用户拿到后无需额外转换可直接用于 YOLOv9 等主流框架的训练、验证与迭代优化。已有 855 人下载学习适合视觉算法工程师、安防系统开发者及科研人员快速获取经过规范化整理的高质量 PPE 检测数据支撑安全帽佩戴、反光背心穿着识别等真实项目落地。1. 安全帽与反光背心检测一套 YOLOV9 标注数据集与训练全流程工地安全巡检里最烦的不是算法选型而是数据。我拆的这套资源正好踩在要害上2000 多张真实场景下拍摄并完成标记的安全帽与反光背心图片统一做了自动定向和 1280x720 的适合黑边缩放文件命名带着清晰的 Roboflow 导出痕迹直接能喂给 YOLOV9 训练。它解决的是「从零攒数据 标数据」这段最苦的活——对做施工安全、智慧工地、安监视频分析的人来说拿到手不用再对着几千张监控截图一框一框点鼠标。新手可以跟着把训练流程跑通熟手则能直接拿这套数据做二次清洗、补类别或迁移到自己采集的视频流上。别急着下先弄清楚里面的文件组织、标注格式和预处理约定否则训练时大概率会在坐标映射上栽跟头。2. 数据集长什么样从文件名反推预处理链路拿到压缩包先别解压完就跑花十分钟把文件名读一遍信息量很大。这套资源的图片命名基本是File2_000023_jpg.rf.fbefa24622c889fa13170af5c95ba82a.jpg这样的格式中间那段.rf.加一长串哈希是 Roboflow 导出的典型标记说明原始素材经过平台级预处理后才打包。摘要里写得很清楚自动定向已应用缩放方式是「适合黑边」目标分辨率 1280x720。2.1.rf.文件命名的含义与影响.rf.是 Roboflow 的硬编码标识后面那串字符是图片在平台上的唯一 ID跟内容无关但它的存在暴露了三件事第一这份数据不是手工整理到文件夹里的而是通过 Roboflow 的 pipeline 统一处理过第二标注文件大概率与图片同名只是扩展名从.jpg变成了.txt放在 labels 目录下第三数据集的 train/valid/test 划分也是平台生成的随机种子固定自己重新划分时会遇到和原始划分不一致的问题。文件名里还藏着原始来源的线索person_cam_3__2023-05-01_13-14-18_jpg.rf.明显是摄像头按时间戳截帧的产物说明数据里有相当一部分来自固定机位的监控视频抽帧Recording-2024-06-11-200314-Trim_000042这种则是本地录屏或录像切片后导出的帧。这对训练有个直接影响——同一段视频抽出来的连续帧高度相似如果划分 train/valid 时不够小心验证集里就会出现大量和训练集几乎一样的画面mAP 虚高得离谱。2.2 自动定向被忽视的 EXIF 旋转隐患摘要里「自动定向已应用」这条很多人在训练时根本不看但恰恰是它最容易埋雷。手机或摄像头拍出来的 JPG 会写入 EXIF 方向信息有的照片实际是竖着拍的但像素数据在文件里是横着存的读取时靠 EXIF 标记来旋转显示。如果标注是在旋转后的画面上做的而训练脚本读图时没有执行同样的旋转就会出现「标注框全偏了」的翻车现场。Roboflow 的自动定向会把这张图真正重写为旋转后的像素并同步旋转标注框。这套资源已经把这一步做完了但你拿到手后如果再用 OpenCV 的cv2.imread()二次处理要注意 OpenCV 默认不读 EXIF 方向直接用是没问题的——因为图片已经被平台修正过了。真正的坑在你自己补数据时新加的图片如果没做方向归一化和这套数据混训模型会莫名对某些角度的目标漏检。2.3 1280x720 黑边缩放适合模式到底做了什么「适合黑边」在 Roboflow 里对应的是 letterbox 缩放即保持原始宽高比缩放到 1280x720多余部分用灰边通常是 114, 114, 114填充。这么做的目的是把不同长宽比的图片统一到固定尺寸同时不让目标发生形变。相比「拉伸填充」直接改变宽高比、导致框的坐标跟着变形letterbox 是检测任务里更稳妥的选择。我建议你打开一张图确认一下左右或上下是否有灰边有就说明预处理符合预期。后面训练 YOLOV9 时模型的输入尺寸要设为 1280而不是 640 或其他值——如果设成 640等于把已经 letterbox 过的图再缩一遍相当于双重缩放小目标的特征会进一步丢失。这一点在第 4 章训练参数里还会细说先心里有数。3. 标注内容与类别规范安全帽和反光背心怎么定义判断一份检测数据集能不能用标得专不专业比数量更重要。这套资源标的是「安全帽」和「安全服反光背心」两类但从文件名覆盖的场景看白天户外、夜晚灯光、监控广角画面都有涉及意味着标注策略不是简单画框里面有不少细节约束。3.1 YOLO 格式的 txt 标注文件怎么写每张 JPG 对应的标注是一个同名.txt文件每行代表一个目标格式是class_id cx cy w h五个值归一化到 0~1 之间。例如0 0.5234 0.3012 0.2128 0.1876 1 0.7156 0.4421 0.0963 0.5233第一列是类别 id0 代表安全帽1 代表反光背心具体映射关系要看同目录的data.yaml或classes.txt后面四个数是中心点 x、中心点 y、框宽 w、框高 h全部除以图片宽度和高度做了归一化。YOLO 系列训练时会按图片实际尺寸把这些值还原成像素坐标去算 IoU所以归一化必须基于预处理后的图片尺寸也就是 1280x720而不是原始拍摄分辨率。拿到数据后我建议先抽三五个 txt手工把归一化坐标换算回像素再去原图上框出来比对一遍。换算公式是px cx * 1280、py cy * 720、w_px w * 1280、h_px h * 720。如果框和实际目标贴合度差得离谱说明这份标注可能不是针对预处理后图片做的要么自己重新导出要么果断放弃。3.2 安全帽标注的两个边界顶部视角与遮挡安全帽检测有个行业共识正上方俯拍时帽顶是一圈圆形或椭圆形侧面视角则是一个半弧。同一顶帽子在不同机位下外观差异极大标注时需要统一规则——是标「可见的帽子部分」还是标「头部的完整范围」我从文件名里的person_cam_3这类监控截帧推测这套数据的标注大概率遵循前者即只画帽子实际露出的像素区域。这意味着模型学到的是「帽子的外观特征」而不是「人头位置」换个摄像头角度可能就失效。这带来的实操建议是如果目标场景是固定机位直接拿来训练没问题如果要用在移动巡检或不同工地最好自己补一批目标机位视角的样本再 fine-tune。另外安全帽被身体遮挡一半、手里拿着帽子、帽子挂在腰间这几类样本标注框会很小且语义模糊训练时很容易被当作背景忽略后面第 5 章我会给出针对性的过滤策略。3.3 反光背心的「看不见问题」白天和夜晚是两个类别反光背心是这套数据里最有意思的类别。白天自然光下它是普通的荧光黄或荧光绿布料特征是颜色饱和度高和周围灰蒙蒙的工地环境区分明显到了夜晚或隧道里光线不足布料本身几乎不可见只有在车灯或手电照射下反光条才会亮起来呈现银白色高亮条纹。这两类视觉特征差异巨大如果标注时没有把两种状态都覆盖模型在切换时段时性能会断崖式下跌。从文件名看数据里包含了Recording-2024-05-17-232902这种晚间录像说明原始采集有夜间的意识。但标注质量如何需要你亲手验证——白天样本的反光背心框是否覆盖了整件衣服、还是只框了反光条夜间样本人工标注时如果截图太暗背心区域几乎和背景融为一体标注员很容易漏标。建议你抽查夜间图片的标注密度如果发现大量「有人但没背心框」的情况说明这套数据对夜间场景支持不足得自己补标一批再训。3.4 类别不平衡与共现关系安全帽和反光背心在实际场景里高度共现——一个合规的工人两样都穿戴。但这不等于两类样本数量均衡。监控画面里安全帽通常比反光背心更显眼标注员也更倾向于先标帽子再找背心所以数据集的类别分布很可能存在倾斜。训练前先跑个统计脚本数一数每类有多少个实例做到心里有数import os from collections import Counter label_dir labels/train counter Counter() total_files 0 for fname in os.listdir(label_dir): if not fname.endswith(.txt): continue total_files 1 with open(os.path.join(label_dir, fname), r) as f: for line in f: cls_id int(line.strip().split()[0]) counter[cls_id] 1 print(f标注文件数: {total_files}) print(f各类别实例数: {dict(counter)}) print(f类别比例: {counter[0] / (counter[1] 1e-6):.2f})这段逻辑是遍历训练集所有 txt统计每个类别出现的总次数和比例。如果安全帽和背心的比例超过两倍训练时就要考虑给少数类提高 loss 权重或者用数据增强把少数类的样本复制几份否则模型会对多数类过拟合、对少数类欠拟合。YOLOV9 的--cls参数可以调整分类损失的权重一般我会把少数类权重设到 1.2~1.5这个数值没必要用理论推导跑一轮验证集 mAP 看趋势再微调就行。4. 用 YOLOV9 训练环境、配置与完整命令数据看明白了标注格式确认无误接下来就是真正的训练环节。YOLOV9 是 2024 年初由台湾学者王建尧团队开源的目标检测框架核心贡献是用可编程梯度信息PGI和广义高效层聚合网络GELAN缓解了深度网络中的信息瓶颈问题在保证推理速度的同时把检测精度提了一截。相比 YOLOV5 和 YOLOV8它在遮挡目标和小目标上的表现更稳定这也是这类安全穿戴检测场景选它的核心理由。4.1 环境准备与依赖安装YOLOV9 官方仓库基于 PyTorch 实现依赖项不难装。用 conda 建一个干净环境能省掉后续一堆版本冲突的麻烦conda create -n yolov9 python3.10 -y conda activate yolov9 pip install torch2.0.1 torchvision0.15.1 --index-url https://download.pytorch.org/whl/cu118 git clone https://github.com/WongKinYiu/yolov9.git cd yolov9 pip install -r requirements.txt先解释环境选择Python 3.10 是目前 YOLOV9 社区用下来兼容性最稳的版本PyTorch 2.0.1 对应 CUDA 11.8如果你是 30 系或 40 系 N 卡这套组合基本不会出幺蛾子。如果你的 CUDA 版本更高比如 12.1把cu118换成cu121即可。在 clone 官方仓库之前先确认本机显卡驱动版本和 nvcc 版本命令是nvidia-smi和nvcc --version两者决定你要装的 torch 版本这一步省了后面一定后悔。4.2 数据集目录结构与 data.yaml 编写YOLOV9 仓库本身不带数据管理工具它默认你手动组织好数据集再引用。把下载的图片和标注按下面结构放好dataset/ ├── images/ │ ├── train/ │ ├── valid/ │ └── test/ ├── labels/ │ ├── train/ │ ├── valid/ │ └── test/ └── data.yamltrain 和 valid 目录下放对应的图片和 txt图片和同名 txt 必须在各自的子目录里保持相同文件名YOLOV9 训练时通过替换扩展名来定位标注文件。这套资源如果下载后已经带了train/valid/test的划分直接用如果没有划分就得自己按 8:1:1 的比例随机切cd dataset python -c import os, random, shutil from collections import defaultdict imgs [f for f in os.listdir(images) if f.endswith(.jpg)] random.seed(42) random.shuffle(imgs) n_train int(len(imgs) * 0.8) n_valid int(len(imgs) * 0.1) for split, split_imgs in [(train, imgs[:n_train]), (valid, imgs[n_train:n_trainn_valid]), (test, imgs[n_trainn_valid:])]: os.makedirs(fimages/{split}, exist_okTrue) os.makedirs(flabels/{split}, exist_okTrue) for img in split_imgs: shutil.move(fimages/{img}, fimages/{split}/{img}) label img.replace(.jpg, .txt) if os.path.exists(flabels/{label}): shutil.move(flabels/{label}, flabels/{split}/{label}) 这段脚本做的是把 images 目录下的 jpg 随机打乱按 8:1:1 划分到 train/valid/test 子目录对应的 txt 标注同步搬移。随机种子固定为 42保证每次执行结果一致这是可复现性的关键。划完后检查一下 labels 目录里还有没有孤立文件如果有说明原数据里存在「有标注没图片」或「有图片没标注」的脏数据这种样本在训练时会导致崩溃或静默跳过建议直接删除。data.yaml 的内容很简单train: dataset/images/train val: dataset/images/valid test: dataset/images/test nc: 2 names: [hard_hat, safety_vest]nc是类别数names按顺序列出类别名。这一个文件必须保证类别顺序和标注 txt 里的 class_id 一一对应顺序错了模型就把安全帽当背心学了整个训练白给。4.3 训练命令与参数说明YOLOV9 提供train_dual.py双分支结构对应带辅助分支的原始架构和train.py单分支简化版两个入口。双分支训练得更稳、精度更高但显存开销大单分支显存占用低、速度更快适合小数据量快速迭代。这套数据规模不大我建议直接用train_dual.py跑满 100 轮cd yolov9 python train_dual.py \ --workers 8 \ --device 0 \ --batch 8 \ --data /path/to/dataset/data.yaml \ --img 1280 \ --cfg models/detect/yolov9-c.yaml \ --weights yolov9-c.pt \ --name safety_helmet_vest \ --hyp hyp.scratch-high.yaml \ --min-items 0 \ --epochs 100参数逐个说--workers是数据加载线程数8 表示用 8 个子进程并行读图如果你的 CPU 核数少或磁盘是机械硬盘降到 4否则 CPU 会成为瓶颈GPU 一直在等数据利用率上不去--batch 8是批次大小在 1280 分辨率下显存 11GB 左右的显卡如 RTX 2080Ti/3080基本是上限如果出现 CUDA out of memory 报错优先把它降到 4--img 1280必须和数据集预处理尺寸一致这是前文反复强调的点模型配置里的图像输入就这样定死了。--cfg指定模型结构yolov9-c.yaml是基础版yolov9-e.yaml是增强版后者参数更多精度略高但推理更慢。你的数据量只有 2000 多张用-c足够上-e很容易过拟合。--weights yolov9-c.pt表示用官方在 COCO 上预训练好的权重作为起点而不是从零训练——迁移学习在数据量小的时候能明显加速收敛同时减少欠拟合风险。--hyp hyp.scratch-high.yaml选择增强力度较大的超参数配置对 mAP 有稳定提升。--min-items 0用于过滤目标数过少的图片设为 0 表示不过滤保留所有样本。4.4 训练过程中的判断标准训练启动后终端会打印每个 epoch 的 loss 和 mAP0.5 等指标。很多人盯着 loss 看半天不知道好坏我的习惯是只看 mAP0.5 和 mAP0.5:0.95 这两个值它们在 validation 阶段更新。如果训练到第 50 轮 mAP0.5 还没超过 0.85大概率是标注有问题或训练参数没配对别硬等 100 轮跑完再检查。训练结束后runs/train/safety_helmet_vest/下会生成best.pt和last.pt。best.pt是验证集 mAP 最高时的权重last.pt是最后一轮的权重部署时无脑用best.pt。测试一下推理效果import torch from models.experimental import attempt_load from utils.dataloaders import LoadImages model attempt_load(runs/train/safety_helmet_vest/weights/best.pt, devicecuda) dataset LoadImages(test_images/) for path, img, im0s, _ in dataset: img torch.from_numpy(img).to(cuda) img img.float() / 255.0 if img.ndimension() 3: img img.unsqueeze(0) pred model(img, augmentFalse)[0] # 后续解析 pred 的检测框和置信度这段逻辑是加载训练好的权重对测试图片做前向推理img是经过 letterbox 预处理的张量pred里是原始的预测结果包含目标框坐标、置信度和类别概率。augmentFalse关闭测试时增强保证推理速度生产环境也推荐这个设置。如果你只是想快速看效果直接用仓库自带的detect.py更省事python detect.py --weights runs/train/safety_helmet_vest/weights/best.pt --source test_images/ --img 1280detect.py会把结果画框保存到runs/detect/目录下并且自动处理 letterbox 反向映射把框画回原始图片坐标不需要手工转换是最直观的验证方式。5. 数据与训练避坑五条血泪经验训完几轮你就会发现安全帽和反光背心检测的坑往往不在模型结构而在数据集和预处理细节。以下五条每一条都是我自己在类似项目里踩出来的真实记录按「现象 → 原因 → 解决」写清楚你遇到问题时可以逐条对照。5.1 训练 mAP 很高但实际视频检测稀烂现象训练集和验证集上的 mAP0.5 超过 0.9一放到真实视频里漏检和误检满地都是模型仿佛换了个脑子。原因数据划分时没有按「同一来源」切分。前面提到这套数据里有大量来自同一段视频的连续帧Roboflow 的随机划分把这些相似帧同时放进了 train 和 valid等于把答案提前给了模型验证集 mAP 虚高实际场景的泛化能力根本没被测量。解决自己重新划分数据划分前先按文件名前缀分组把同一来源比如同一个Recording-前缀或同一个摄像头编号的图片归到一个组然后以组为单位划分 train/valid保证验证集里的画面来源训练时完全没见过。划分脚本在前面代码基础上把imgs列表先按前缀分组再 shuffle 即可。5.2 夜间反光背心大面积漏检现象白天测试正常一到黄昏或夜间视频背心类别 mAP 直接掉到 0.3 以下安全帽倒是还凑合。原因夜间反光背心的视觉特征和白天的荧光布料差异太大如果原始数据里夜间样本占比低模型学到的「背心特征」几乎全是白天的样子遇到夜间亮度低、反光条高亮的画面自然识别不出来。解决给夜间样本单独加权最简单的做法是在训练时用--hyp里的mosaic和mixup增强把白天背心样本和夜间背景图混合模拟出背心在弱光下的样子。更彻底的办法是从原始视频里按时间段比如每天 18:00~6:00抽帧补标把夜间样本量补到总样本的 30% 以上再重新训练。5.3 安全帽戴在头上但模型报「未佩戴」现象侧面角度、光线强烈或逆光时模型把安全帽漏掉尤其是深色安全帽。原因标注框里混入大量“人头加帽子”的连带区域模型学到的是「头部整体轮廓」而不是「帽子本体」。逆光时头部轮廓变暗目标特征被背景吞掉检测自然失败。反光背心这类大目标没这个问题但安全帽本来就是小目标特征少对标注精度的要求更高。解决训练前清洗标注框——对面积小于图片总面积 1% 的框单独抽查如果发现大量框的中心点不在帽顶而在人头中部说明标注不严谨。条件允许的话自己用 LabelImg 或 Roboflow 重新框一批边界紧贴帽缘的严格标注替换掉模糊的框。注意安全帽被手拿在身侧或放在桌面上的样本这类「帽子但没戴在头上」的目标如果标注进数据集模型会把「持有帽子」也判为「已佩戴」语义上就错了要么单独建一个类别要么直接删掉。5.4 CUDA out of memorybatch 调到 2 也照样崩现象1280 分辨率下--batch 8报显存溢出改成 2 还是溢出让人怀疑是不是显卡坏了。原因YOLOV9 的双分支结构在train_dual.py下显存开销极大1280 输入时特征图尺寸翻倍即使 batch 很小也可能超过显存。另外--workers 8会预加载多批数据到内存再转 GPU多进程本身就占显存缓冲进一步推高峰值占用。解决先用nvidia-smi看当前显存占用关闭其他进程把--workers降到 4 或 2换单分支train.py入口显存占用直接少一半左右如果还不够把--img从 1280 降到 960代价是精度略有损失。最终方案是开启梯度累积把 batch 设为 2同时把有效迭代次数补回来训练效果等价但显存友好得多。5.5 推理时检测框位置整体偏移像被平移过现象detect.py跑出来的结果框上下偏移目标明明在画面中间偏左框却在同高度靠右的位置。原因这是最经典的 letterbox 坐标映射错误——训练时输入做了黑边填充推理时输入图片没有做同样的 letterbox 预处理或者--img尺寸设得和训练不一致模型看到的坐标参考系不同输出框自然就偏了。解决用官方detect.py时别改预处理参数它内部自带了 letterbox 逻辑自己写推理脚本时必须先用letterbox()函数把输入图处理到和训练一致的尺寸推理完再把框坐标按黑边偏移量减回去。我的习惯是推理脚本里强制写死img_size1280并且在读取图片后第一行就调用check_img_size校验宁可程序报错也不要静默跑偏。6. 验证模型可信度mAP 之外你必须跑的两项测试best.pt训练出来后验证集上的 mAP 只是个起点。安全穿戴检测是安监场景漏检一个没戴帽子的人可能就意味着一次安全事故所以必须做两项额外的验证置信度阈值曲线分析和真实场景压力测试。置信度阈值曲线用训练好的模型对验证集跑一遍统计不同置信度阈值下的精确率和召回率画出 P-R 曲线。YOLOV9 训练日志里自带了PR_curve.png和F1_curve.png看这两个图比看 mAP 更有用——它们能告诉你阈值设在 0.5 还是 0.7 时漏检和误检怎么平衡。安监场景通常更怕漏检所以我会把默认阈值降到 0.35让模型「宁可多框也不放过」代价是误报多了一些但误报还能靠后端逻辑二次过滤漏检没法补救。真实场景压力测试是拿模型跑一段完全没参与训练的视频流最好是半天连续监控画面白天和夜晚各一段。看完检测结果后我最在意三件事一是安全帽从侧面小角度出现时能不能持续检测到二是工人背对摄像头时反光背心的检出率三是两个人擦肩而过、目标短暂重叠时框是否稳定。这三类情况在标准数据集里往往占比很少而真实工地里天天发生。测试完我会顺手把明显漏检的帧抽出来按 5.2 的办法补进数据集做增量训练——这也是数据从 2000 张滚到更多的一条自然路径。最后一个进阶习惯把best.pt转成 ONNX 格式方便后续部署。YOLOV9 仓库自带export.py脚本一条命令搞定python export.py --weights runs/train/safety_helmet_vest/weights/best.pt --img 1280 --batch 1 --include onnx转完之后用onnxruntime在 CPU 上跑一遍推理验证一下数值和 PyTorch 版本相差多少——通常有 1e-3 级别的浮点差异这是正常的。从那以后我每次拿到 YOLOV9 模型都会强制走一遍「验证集 mAP → P-R 曲线 → 真实视频压力测试 → ONNX 数值对齐」这套流程四步走完才敢往现场部署。这套流程帮我挡掉了至少三次「训练好好的上线就翻车」的尴尬局面希望也能帮到你。本文还有配套的精品资源点击获取
返回列表