ARTICLE DETAIL

资讯详情

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

危化品运输车辆VOC+YOLO数据集详解与目标检测训练实践

危化品运输车辆VOC+YOLO数据集详解与目标检测训练实践 简介这是面向目标检测任务的高质量图像数据集聚焦危化品运输车辆以油罐车为主的真实场景标注内容对应2007张现场图片包含2211个类别为dangercar的目标矩形框适合用于训练YOLO、SSD、Faster R-CNN等常见检测模型也可作为安监、交通、物流领域的算法验证与教学素材。压缩包共2000个文件以1999个XML标注文件为主另附1个TXT说明文本整体约116.56MB采用LabelImg工具统一画框标注格式规范。目前已有691人学习/下载可直接用于迁移学习、模型评估或数据增强实验节省人工采集与标注成本同时需注意数据集只保证标注准确合理不对训练后的模型精度作任何承诺。1. 危化品运输车辆数据集一份能直接喂给 YOLO 的 VOC 格式标注包做危险品运输监管相关项目时最头疼的往往不是模型选型而是训练数据。公开数据集里自然场景车辆不少但带“危化品运输”标识的罐车、厢式货车样本少且分散标注格式还五花八门。这份 2007 张、单类别危化品运输车辆的 VOCYOLO 双格式数据集省掉了我自己爬图、清理、标注的一大半时间。它适合的目标很明确做安监场景下车辆检测、道路运输车辆识别、或者智慧园区车辆道闸分类的开发者。你拿到手不需要转格式VOC 用于训练前可视化校验YOLO 格式直接喂给 darknet 或 yolov5 系项目如果要做微调目录里已经按 ImageNet 风格分好了 train/val连划分脚本都省了。下面这篇笔记我把目录结构、标注内容、训练前的验证步骤和最容易翻车的几个坑一次说清。2. 把 2007 张图拆开看VOC 和 YOLO 两种格式的目录差异与标签对应关系2.1 VOC 格式的目录树JPEGImages、Annotations 和 ImageSets 缺一不可拿到 zip 解压后第一步不是急着开训练而是确认目录结构是否完整。VOC 格式的检测数据集固定由三个目录支撑JPEGImages/放原始图片Annotations/放 XML 标注ImageSets/Main/放划分好的 train.txt、val.txt 和 trainval.txt。这份数据集里三者都在而且图片名和 XML 名严格一一对应。unzip 危化品运输车辆数据集VOCYOLO格式2007张1类别.zip -d hazardous_vehicle cd hazardous_vehicle # 假设解压后是 VOC2007 风格的目录 find . -maxdepth 2 -type d | sort我一般会先用find把目录层级打出来确认没有套娃式的多级嵌套——有些打包者会把数据集再包一层带日期的外层目录训练脚本里路径拼接就很容易出错。目录结构正常后再看三个关键统计ls JPEGImages/ | wc -l # 应该等于 2007 ls Annotations/ | wc -l # 应该等于 2007 wc -l ImageSets/Main/*.txt # 三个 txt 的行数之和应覆盖全部样本逻辑说明JPEGImages的数量等于Annotations数量是 VOC 格式的基本盘只要出现不一致后面训练时一定会报FileNotFoundError或者读取到空标签。ImageSets/Main下的 txt 每行只写图片文件名不含扩展名trainval.txt 通常占 50%train.txt 再从 trainval 里取一部分val.txt 是剩下的这是 VOC2007 的默认划分逻辑。如果你后续要跑 SSD 或者更早的 detectron 版本它们会直接读这些 txt 做样本列表所以划分文件的完整性直接决定训练能否启动。2.2 读一条 XML 标注bndbox 坐标、name 标签和 difficult 标记的含义VOC 的 XML 标注格式并不复杂但要训练前确认类别名和坐标范围是否符合预期。我习惯用xmllint或者一段短 Python 脚本提取关键字段。import xml.etree.ElementTree as ET tree ET.parse(Annotations/000001.xml) root tree.getroot() # 打印图片尺寸和第一个目标框 size root.find(size) print(width:, size.find(width).text, height:, size.find(height).text) for obj in root.findall(object): name obj.find(name).text difficult obj.find(difficult).text bndbox obj.find(bndbox) xmin bndbox.find(xmin).text ymin bndbox.find(ymin).text xmax bndbox.find(xmax).text ymax bndbox.find(ymax).text print(name, difficult, xmin, ymin, xmax, ymax)参数说明xmin/ymin/xmax/ymax是左上角和右下角的像素坐标基于原图分辨率不需要归一化。difficult为 1 的框表示目标特别模糊或遮挡严重VOC 在计算 mAP 时会默认忽略这些难例但如果你的场景里危化品车辆经常被栏杆、树影遮挡建议把 difficult 为 1 的样本也参与训练别让模型只学“干净”的框。类别名这里固定是单一的比如hazmat_vehicle或者dangerous_goods_vehicle具体以你解压后的 XML 为准——但要注意这个 name 值必须和 YOLO 格式的类别映射表一致否则转换脚本会把所有框标成错位类别。2.3 YOLO 格式标签txt 里的五个数字究竟怎么对应原图坐标YOLO 格式的标签是归一化的每个 txt 文件和一张图片同名放在labels/目录下。每一行代表一个目标框五个数字依次是class_id x_center y_center width height其中x_center/y_center/width/height全部除以了图片宽高值域在 0 到 1 之间。这份数据集既然同时提供 VOC 和 YOLO 格式那就一定要检查两种格式的标注内容是否一致——常见做法是写一段对照脚本随机抽几张图把 XML 里的 bndbox 转成归一化坐标再和同名的 txt 比对。import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, w, h): tree ET.parse(xml_path) root tree.getroot() boxes [] for obj in root.findall(object): b obj.find(bndbox) xmin float(b.find(xmin).text) ymin float(b.find(ymin).text) xmax float(b.find(xmax).text) ymax float(b.find(ymax).text) # 归一化并转为中心点宽高 x_center ((xmin xmax) / 2) / w y_center ((ymin ymax) / 2) / h bw (xmax - xmin) / w bh (ymax - ymin) / h boxes.append((0, x_center, y_center, bw, bh)) return boxes # 以图片 000001.jpg 为例 w, h 1920, 1080 voc_boxes voc_to_yolo(Annotations/000001.xml, w, h) with open(labels/000001.txt) as f: yolo_lines [list(map(float, line.strip().split())) for line in f if line.strip()] for vb, yb in zip(voc_boxes, yolo_lines): diff [abs(a-b) for a, b in zip(vb, yb)] print(max diff:, max(diff))常见做法是让max diff小于1e-6超过这个量级就说明转换或打包过程有精度损失。这里要特别提一个玄学问题YOLO 格式的坐标是 float部分数据集打包时为了省空间做了截断比如只保留 6 位小数对检测任务影响不大但如果截断到 3 位框的像素误差可能到几十个像素训练出来的模型边界框会明显偏大或偏小。遇到这种情况直接用 VOC 格式重新转一遍 YOLO 是最稳妥的后悔药。3. 从解压到训练数据校验、类别文件配置与 YOLOv5/v8 训练入口3.1 全量校验图片完整性损坏 JPEG 是训练中断的头号元凶2007 张图里只要有 1 张损坏训练跑到一半就可能崩掉尤其是 mosaic 增强随机拼图时损坏图片会让 dataloader 直接抛异常。我拿到数据集后第一件事不是看标注而是先验证图片能不能被完整解码。用 OpenCV 逐张读一遍最直接。import cv2 import os img_dir JPEGImages/ bad_images [] for fname in sorted(os.listdir(img_dir)): path os.path.join(img_dir, fname) img cv2.imread(path) if img is None: bad_images.append(fname) else: # 顺便确认尺寸是否和 XML 里 size 字段一致 h, w img.shape[:2] # 这里可以对比 XML 的 width/height不一致要记下来 if h 32 or w 32: print(too small:, fname, w, h) print(bad count:, len(bad_images))cv2.imread返回None说明文件头损坏或解码失败这类图片直接移出数据集。我一般还会顺手过滤掉分辨率小于 32x32 的图——虽然这个数据集正常不会有但 yolov5 的增强管线对极小图做随机缩放时容易产生空标签属于隐性问题。图片数量少的时候这一步跑完不到一分钟但能避免训练半天后死在验证集上的尴尬。3.2 写 data.yaml路径、类别数、类别名三个字段最容易写错YOLO 系框架训练时需要一个数据集描述文件通常叫data.yaml。关键字段是train、val、nc和names。这份数据集是单类别nc: 1names列表里只放一个名字。train: hazardous_vehicle/images/train val: hazardous_vehicle/images/val nc: 1 names: [hazmat_vehicle]路径写法这里有个大坑yolov5 和 yolov8 对train字段的解析逻辑略有不同。yolov5 的create_dataloader接受的是图片目录框架会自动找同级的labels目录yolov8 也是如此但要求目录结构必须是images/train和labels/train成对出现。如果你解压后发现train.txt里写的是旧路径比如打包者本机的绝对路径一定要改成相对当前项目根的路径或者干脆重建 train.txt——绝对路径跨机器必炸。我习惯把数据集放到和项目同级的目录data.yaml 里直接用../hazardous_vehicle/images/train这样项目整体迁移时不用改配置文件。3.3 训练前跑一次验证用val.py或detect.py确认 dataloader 正常不要一上来就train.py。先把验证流程跑通能提前暴露 80% 的格式问题。以 yolov5 为例python val.py --data hazardous_vehicle.yaml --weights yolov5s.pt --batch-size 16如果看到All 2007 images loaded且没有警告说明图片和标签的对应关系没问题。常见做法是只跑 100 张图做冒烟测试把--batch-size调小、加--max-det限制这样几秒就能出结果。这一步能发现的问题包括标签里有超出图片边界的框、类别 id 超出了nc范围、某张图完全没标签导致 loss 为 NaN。参数说明--weights可以先用官方预训练权重yolov5s.pt它会在首次运行时自动下载如果你的网络环境不方便下载就随便指定一个随机初始化的权重文件跳过加载。跑通的标志是终端输出里出现mAP0.5和mAP0.5:0.95两行指标值哪怕很低也没关系因为预训练权重没见过危化品车辆。这一步真正要的是“能跑完前向”而不是“精度高”。4. 避坑与常见问题标注错位、路径写死、类别混淆和样本不均衡4.1 现象训练时 loss 正常下降但验证集 mAP 一直是 0原因图片与标签文件没有对齐模型看到的是别的图片的标注。这个问题在双格式数据集中尤其隐蔽——如果打包时图片经过旋转或缩放处理但标注没有同步变换就会出现这种“训练正常、验证全错”的假象。解决不要信目录结构直接随机抽 20 张图把 YOLO 格式的框画回图上人工看。import cv2 def draw_yolo_boxes(img_path, label_path, class_names): img cv2.imread(img_path) h, w img.shape[:2] with open(label_path) as f: for line in f: parts line.strip().split() cls, xc, yc, bw, bh map(float, parts) x1 int((xc - bw/2) * w) y1 int((yc - bh/2) * h) x2 int((xc bw/2) * w) y2 int((yc bh/2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(img, class_names[int(cls)], (x1, y1-5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 1) return img # 实际使用时替换成你的图片和标签路径 img draw_yolo_boxes(images/train/000001.jpg, labels/train/000001.txt, [hazmat_vehicle]) cv2.imwrite(check_000001.jpg, img)框如果明显偏离车体说明标签和图没对应上。这时不要尝试修标注直接放弃 YOLO 格式从 VOC XML 重新转一套。4.2 现象训练时出现IndexError: list index out of range原因data.yaml里的nc设置和标签文件里的class_id不一致。比如 XML 里类别名有两个转 YOLO 时把第二个类映射到了 id1而 yaml 里nc1读取标签时报错。解决全量扫描所有 txt 标签统计出现过的 class id 最大值。cat labels/train/*.txt labels/val/*.txt | awk {print $1} | sort -n | uniq如果输出里出现1说明这个单类别数据集里混入了不该有的类别。常见做法是把 id0 的行直接过滤掉或者回到 XML 确认原始类别名——有时候是hazmat_vehicle和hazmat_truck两个名但一个含义转格式时没做归一化。4.3 现象训练集 mAP 很高但实际视频流里检测不到车原因数据分布单一——2007 张图如果全来自白天、晴天、高速公路模型学到的其实是“那种环境下的车”而不是“危化品运输车”。这份数据集作为基础是可用的但工程落地前必须做数据增强和场景补采。解决先用 yolov5 的--augment参数跑一轮看提升幅度如果仍不够把白天样本随机调亮度、加高斯噪声、随机水平翻转扩到 6000 张再训。危化品车辆检测的关键特征是罐体形状、黄色/橙色警示色和车顶危险品标识这些特征对光照变化较敏感增强策略要重点覆盖亮度扰动和色彩抖动。4.4 现象验证时大量漏检尤其是画面远处的小目标原因原始图片如果大量是 1920x1080 的远视角目标车辆可能只有几十个像素。yolov5s 的输入是 640x640小目标下采样后特征很弱。解决训练时调高输入尺寸比如--img 1280。代价是显存占用接近翻倍V100 上勉强能跑如果只有 2080Ti就用--img 960做折中。另外考虑把默认的 P2 检测头打开yolov5 的--hyp里调anchor相关参数或者换成 yolov8 的 P2 模型变体。这属于调优环节不是数据集的锅但新手经常误以为标注有问题实际是小目标策略没跟上。5. 进阶用法把这份数据集变成你的专属检测器的两种路径5.1 路径一增量学习——用自己的场景图扩充原数据集原数据集 2007 张只够打底。我一般会把这份数据当作预训练的先验然后采集自己园区/路口的监控截图 500 到 1000 张用训练好的模型做伪标注人工修正后混入原数据集一起训练。具体做法是先用这份数据训练 100 轮得到一个粗糙模型然后用它对场景视频抽帧做批量预测把置信度高于 0.6 的框存成伪标签低于 0.6 的框跳过。人工抽检一部分后把伪标签样本和原始数据按 3:7 混合再训练 50 轮。这么做的好处是模型已经认识了危化品车辆的通用特征新场景只需要学“你的相机角度下它长什么样”收敛速度明显快于从零训练。# 伪标注阶段示例yolov5 detect 模式输出标签 python detect.py --weights runs/train/exp/weights/best.pt \ --source new_scene/ --save-txt --save-conf \ --project pseudo_labels/ --exist-ok--save-txt会把预测框写为 YOLO 格式 txt--save-conf额外把置信度写为第六个数字。后续清洗时如果不需要置信度用脚本把前五位截出来即可。5.2 路径二验证增强——用 mAP 变化曲线判断数据集质量边界判断一份数据集值不值得继续投入核心指标是 mAP 和 PR 曲线。训练结束后用val.py导出 PR 曲线重点看召回率Recall在置信度阈值下降时能否快速爬升。危化品运输车属于“漏报代价远高于误报”的场景宁可多框几个普通货车让人工二次确认也不能漏掉真正的危险品车。所以我会特意压低置信度阈值部署一般设到 0.25 而不是默认的 0.45。验证时对比 0.25 和 0.45 两个阈值下的召回率差如果差距超过 15%说明模型对目标特征的区分度不够需要回到数据层面补样本而不是调阈值硬扛。从上一次用这份数据集做项目之后我养成了一个习惯任何数据集下载完第一步先跑完整性和标签对齐校验再谈训练。这两步花不了 20 分钟但能避免整个调参周期白费。希望这份笔记帮你在同样的路上少走一段。本文还有配套的精品资源点击获取
返回列表