道路圆石墩检测数据集:VOC+YOLO双格式461图,目标检测训练实战
2026/9/16 4:14:25 网站建设 项目流程

简介:一套面向计算机视觉、智能交通与自动驾驶感知领域开发者和研究者的道路圆石墩检测数据集,主要解决道路圆石墩目标检测任务中训练样本不足、数据标注成本高的问题。压缩包共一千三百八十八个文件,包含四百六十二张JPG原图、四百六十二个VOC格式的XML标注文件以及四百六十四个YOLO格式的TXT标注文件,整体体积约二百一十五点七三MB。图片合计标注了一千七百九十八个球形路障目标框,全部使用labelImg绘制矩形框完成标注,标注信息准确合理,可直接用于YOLO、Faster R-CNN等常见目标检测模型的训练与评估。同时提供VOC与YOLO两种常用格式,省去转换成本,便于在不同算法框架间迁移试用。目前共有一百三十六人浏览学习,适合作为道路障碍物识别、模型效果验证与算法比对的实用基准数据。

1. 道路圆石墩检测数据集:461 张图、VOC+YOLO 双格式,目标检测的第一份燃料

道路巡检视频里,最容易漏看也最需要盯住的小目标就是圆石墩:它立在机非隔离带端头、人行道入口和桥墩四周,被车辆剐蹭移位后隐患很大,人工回放几十路监控成本实在太高,通常交给目标检测模型先筛一遍。标题里的「道路圆石墩检测数据集」就是这份差事的第一份燃料:461 张现场图、单一类别,同时打包了 VOC 的 XML 标注和 YOLO 的 TXT 标注,压缩在 7z 包里。

VOC + YOLO 双格式的意义在于省掉最脏的格式转换:可视化检查时读 XML,训练时读 TXT,两边还能互相校验。461 张属于典型小样本,但足够跑通「解压体检 → 格式校验 → 参数训练 → 增强验证」全流程。下文按这个顺序展开,适合道路养护方向的算法工程师、拿真实场景数据练手的入门开发者,以及要快速验证单类检测器的测试人员。

2. 拿到 .7z 后的第一件事:Linux 下解压、数据体检与标注完整性检查

2.1 为什么数据集分发偏爱 7z 压缩

目标检测数据集里 JPEG 图像占比极高,冗余度大,7z 的 LZMA2 算法在这类数据上通常比 zip 再小 30% 到 50%。所以公开下载的数据集、团队内部流转的标注包,越来越多直接以 .7z 分发,「linux解压7z文件」成了训练前置的固定环节。解压和训练基本都在 Linux 服务器上完成,第一步是确认 p7zip 工具链存在,很多精简安装的服务器默认没有这个命令。

# Debian/Ubuntu 系安装 sudo apt install p7zip-full # CentOS/RHEL 系安装 sudo yum install p7zip # 只列出压缩包内部结构,不实际解压 7z l 道路圆石墩检测数据集VOC+YOLO格式461张1类别.7z

7z l这一步值得养成习惯。它能在不落盘的情况下看到包内目录层级,确认有没有顶层文件夹、图片和标注怎么分放,避免解压后才发觉文件散落各处。正式解压用7z x,它会保留包内目录结构,是数据集场景下最安全的选择。

7z x 道路圆石墩检测数据集VOC+YOLO格式461张1类别.7z -o./road_bollard

参数说明:-o指定输出目录,注意-o与路径之间没有空格,这是 7z 命令里最容易写错的地方;不加-o就解压到当前目录。命令里的中文文件名最好用引号包起来,避免 shell 对空格或特殊字符的额外解释。解压后先看顶层布局,常见的有两种:一是 images/ 与 annotations/ 平级,annotations 下再分 VOC 与 YOLO 两个子目录;二是 XML 与 TXT 各一个目录并列。先看清楚再写脚本,比拿到哪份样例就照抄路径要省心。

提示:7z 报「cannot find archive」时,先怀疑下载完整性。用sha256sum 文件名.7z和发布方给出的校验值对比,比对不上就重新下载,不要反复解压浪费时间。

2.2 数据体检:图像、XML、TXT 数量与解码验证

解压完直接开训是常见的翻车姿势。单类小数据集最怕三类问题:图片解码失败、标注文件缺失、类别名跟预期不一致。461 张的体量没必要靠人眼抽查,脚本几十毫秒就能把所有文件过一遍。

# 数量对齐检查,三个数字都应等于 461 find images -type f -name "*.jpg" | wc -l find VOC -type f -name "*.xml" | wc -l find YOLO -type f -name "*.txt" | wc -l

三个数字一致只说明文件层面一一对应,还要确认图片能真正被解码。这点容易被忽略:部分从爬虫或批量转换流程里出来的 JPEG,系统预览能显示,但 cv2.imread 会返回 None,训练时轻则丢样本,重则 loss 在某一步跳变,排查成本很高。

import cv2, glob bad = [] for p in glob.glob('images/*.jpg'): img = cv2.imread(p) if img is None: bad.append(p) print('不可解码图片数量:', len(bad)) for p in bad: print(p)

这段逻辑很直白:逐个路径用 cv2.imread 读图,返回 None 就记录路径。跑完后最好顺手统计图像宽高分布,道路圆石墩数据经常混了不同摄像头的画面,1920x1080 与 1280x720 并存很常见。知道尺寸分布再决定训练时的 imgsz,比盲目套 640 更合理。

2.3 按 YOLO 生态标准整理目录并划分训练验证集

体检通过后,把数据整理成 yolov8、yolov5 通用读取的目录结构:train 和 val 两个集合,各自包含 images 和 labels 子目录。这个动作对应「yolov8训练自己的数据集」和「yolo目标检测流程」的公共前提。划分比例常见做法是 8:2,固定随机种子保证可复现。

import glob, os, shutil from sklearn.model_selection import train_test_split imgs = sorted(glob.glob('images/*.jpg')) train_imgs, val_imgs = train_test_split( imgs, test_size=0.2, random_state=42) def organize(img, split): stem = os.path.basename(img)[:-4] dst_img = f'dataset/{split}/images/{stem}.jpg' dst_txt = f'dataset/{split}/labels/{stem}.txt' os.makedirs(os.path.dirname(dst_img), exist_ok=True) shutil.copy(img, dst_img) shutil.copy(f'YOLO/{stem}.txt', dst_txt) for img in train_imgs: organize(img, 'train') for img in val_imgs: organize(img, 'val') print('train 图片数:', len(train_imgs)) print('val 图片数:', len(val_imgs))

train_test_split 默认按 8:2 切分,random_state 固定为 42 保证多次运行结果一致,对复现实验、对比消融结果很重要。这里用 shutil.copy 而不是符号链接,因为数据量小,复制不占空间,而且训练阶段的任何意外都不会改到原始文件。划分完 train 应为 369 张、val 为 92 张,对不上就回头看文件命名是否带中文或空格,这类文件名在部分框架里兼容性差,建议统一重命名为 seq_0001.jpg 这种纯 ASCII 格式。

3. VOC 与 YOLO 双格式的坐标换算逻辑与一致性校验

3.1 VOC 的 XML 里存的是像素坐标

VOC 格式的标注是一个 XML 文件,文件与图片同名,扩展名 .xml。根节点是 annotation,核心信息在 size 和 object 两个子节点里。size 记录图片宽度、高度和通道数,object 描述目标类别和位置,bndbox 里的 xmin、ymin、xmax、ymax 是像素级绝对坐标。圆石墩数据集只有一类,object 通常只有一个,但少数图里一个画面出现多个石墩时,object 节点会重复出现。

<annotation> <size> <width>1920</width> <height>1080</height> <depth>3</depth> </size> <object> <name>round_pier</name> <bndbox> <xmin>412</xmin> <ymin>356</ymin> <xmax>518</xmax> <ymax>489</ymax> </bndbox> </object> </annotation>

这里 name 就是类别名,单类数据集通常叫 round_pier 或 bollard,训练前要跟 data.yaml 里的 names 对齐。bndbox 四个值是整数像素坐标,左上角 (412, 356),右下角 (518, 489),框宽 106、高 133,这些数值严格依赖图片本身的宽高,换一张尺寸的图就失效。VOC 格式的可读性好,LabelImg 标注后默认输出这种结构,很多可视化调试工具直接解析 XML,这也是它到现在仍是数据集交付标配的原因。

3.2 YOLO 的 TXT 里存的是归一化坐标

YOLO 的 txt 每行一个目标,格式固定为 class_id center_x center_y width height。后四个值都是相对于图片宽高的比例,范围 0 到 1。同一个框在 YOLO 格式里写成一行:

0 0.242187 0.391204 0.055208 0.123148

对照上面的 XML:中心点 x = (412+518)/2/1920 = 0.242187,中心点 y = (356+489)/2/1080 = 0.391204,框宽 = (518-412)/1920 = 0.055208,框高 = (489-356)/1080 = 0.123148。一个容易忽略的细节是 YOLO 的 txt 里不携带图片尺寸信息,单独看一个 txt 文件无法还原像素坐标,这正是双格式并存的实际价值:XML 保留绝对几何,TXT 方便训练时快速读取。

3.3 双格式换算公式与一致性校验脚本

两套格式的换算公式很固定。设图片宽为 W、高为 H,则中心点 x 为 (xmin + xmax) / 2 / W,中心点 y 为 (ymin + ymax) / 2 / H,框宽为 (xmax - xmin) / W,框高为 (ymax - ymin) / H。反向换算把比例乘回去再取整即可。训练前做一次双向一致性校验成本很低,却能拦住数据发布或拷贝阶段引入的错误,比如归一化时漏除以图宽、类别 id 从 1 开始而不是 0。两套格式的差异可以归纳成一张表:

对比项VOC / XMLYOLO / TXT
坐标基准像素绝对值归一化比例
数值类型整数浮点(0~1)
图片尺寸信息size 节点自带不携带
单目标存储XML 多行标签一行 5 个数字
解析方式ElementTree / lxml按空格 split

校验脚本以 VOC 作为基准,逐图读取 XML 的 bndbox,换算成 YOLO 坐标后与 txt 里的值逐项对比:

import glob, os, xml.etree.ElementTree as ET def voc_to_yolo(xml_path): root = ET.parse(xml_path).getroot() W = int(root.find('size/width').text) H = int(root.find('size/height').text) boxes = [] for obj in root.findall('object'): bb = obj.find('bndbox') xmin = float(bb.find('xmin').text) ymin = float(bb.find('ymin').text) xmax = float(bb.find('xmax').text) ymax = float(bb.find('ymax').text) boxes.append(((xmin + xmax) / 2 / W, (ymin + ymax) / 2 / H, (xmax - xmin) / W, (ymax - ymin) / H)) return boxes for xml_path in sorted(glob.glob('VOC/*.xml')): stem = os.path.splitext(os.path.basename(xml_path))[0] txt_path = f'YOLO/{stem}.txt' if not os.path.exists(txt_path): print('缺失对应 txt:', stem) continue voc_boxes = voc_to_yolo(xml_path) txt_lines = [] with open(txt_path) as f: for line in f: txt_lines.append(list(map(float, line.strip().split()))) if len(voc_boxes) != len(txt_lines): print('目标数量不一致:', stem) continue for vb, tb in zip(voc_boxes, txt_lines): err = max(abs(a - b) for a, b in zip(vb, tb[1:])) if err > 1e-3: print(f'坐标偏差过大: {stem}, err={err:.5f}')

这段脚本输出三类异常:缺 txt、目标数量不一致、坐标偏差过大。findall('object') 用循环处理同图多目标,比只取第一个更可靠。tb[1:] 跳过类别 id,只比较四个坐标值。误差阈值我一般取 1e-3,浮点计算本身有微小舍入差,超过这个量级基本就是有人手工改过标注。461 对文件对完如果没有任何输出,说明两套格式可信,可以进训练环节。

4. 用 YOLO 数据训练圆石墩检测器:data.yaml、训练命令与参数边界

4.1 data.yaml 的写法与类别对齐

YOLO 生态统一通过 data.yaml 描述数据集路径和类别定义。高频踩坑点是:配置文件里的 names 顺序必须和 txt 里的 class_id 一一对应。单类数据集 class_id 只有 0,names 列表只放一个元素。

# data.yaml path: /data/road_bollard/dataset train: train/images val: val/images nc: 1 names: ['round_pier']

path 是数据集根目录的绝对路径,train 和 val 写相对于 path 的子路径,这是 ultralytics 的推荐写法,绝对路径可以避免切换工作目录后找不到数据。nc 为类别数,单类就写 1。names 只在可视化推理和导出时影响显示名,不参与 loss 计算,但如果 txt 里的 class_id 写成 1 而这里只声明了 1 个类别,训练时索引越界直接报错,所以核对 txt 第一列的实际取值也是体检的一部分。

注意:报「No labels found in ...」时先检查 data.yaml 的 path 是不是绝对路径,其次检查 labels 子目录是否存在,最后检查 txt 里是不是有空文件。空文件会让训练器认为这张图没有标注,静默跳过该样本。

4.2 最小训练命令与直观解释

目录整理好、data.yaml 写好之后,训练命令短到可以一行完成。常见选择是 yolov8 系列,生态和文档最成熟,社区里问「yolo第几代了」时,大多数回答仍然建议至少先跑通 v8 再谈新版本,因为标注格式、配置方式在 v8、v11 以及更新版本之间是兼容的,这套 TXT 可以直接喂进去。

yolo detect train \ data=data.yaml \ model=yolov8n.pt \ epochs=100 imgsz=640 batch=16 \ name=bollard_run1

逐项说明:model=yolov8n.pt使用 nano 尺寸预训练权重,461 张小数据集从 nano 起步最划算,显存占用低且收敛快;imgsz=640是训练分辨率,如果你的图片主要是 1920x1080,可以提到 800 或 832 换取小目标召回,但训练时间会同步上升;batch=16在 12GB 显存上比较稳,显存紧张就降到 8。习惯用 yolov5 的话,命令换成python train.py --data data.yaml --weights yolov5nu.pt --img 640 --batch 16 --epochs 100即可,TXT 标注完全通用。

4.3 关键参数表与调整边界

小样本数据集的参数调节优先级和 COCO 大模型不一样,epochs、patience、imgsz 这三个最值得花时间,其余保持默认即可。常用参数边界整理成一张表:

参数建议值边界与说明
epochs100~200461 张单类,100 轮已能观察趋势,超过 200 轮收益递减
patience30验证集指标连续 30 轮不提升则早停,防止过拟合
imgsz640 / 832必须能被 32 整除,这是多数 YOLO 版本的下采样硬约束
batch8 / 16显存不足报 CUDA OOM 时优先降 batch,不要先降 imgsz
lr00.01(预训练)随机初始化从头训练要降到 0.001,否则前几轮 loss 爆炸
cacheTrue461 张图整体缓存进内存,首轮训练速度提升明显

逐条解释边界:epochs 对单类小数据很容易在 60 轮左右进入平台期,设太高浪费算力,patience 就是用来兜底的;imgsz 与原始图宽高比例差异太大会导致拉伸变形,选值前先看 2.2 节统计的尺寸分布;batch 和显存的关系最直接,OOM 报错会指明哪一层分配失败,此时直接减 batch 不要犹豫;lr0 是很多人忽视的一项,用预训练权重沿用 0.01 没问题,换成随机初始化还不降学习率,第一轮 loss 可能直接变成 NaN。

4.4 训练过程中看什么:损失函数的下落曲线

训练时终端每轮会打印 box_loss、cls_loss、dfl_loss 三个损失值。对单类检测器,cls_loss 会很快降到很低,因为分类任务只有一正一负,真正要盯的是 box_loss 和 dfl_loss,它们反映框回归质量。判断依据有三条:三者整体下降并在 patience 窗口内波动,说明模型在学习;box_loss 下降但验证指标不动,说明过拟合早于收敛,优先增强数据而不是加 epoch;loss 出现突然尖峰,先回看是不是混入了解码失败的坏图,而不是急着调学习率。

# 训练结束后查看指标记录文件 ls runs/detect/bollard_run1/ head -3 runs/detect/bollard_run1/results.csv

results.csv 里记录了每轮的三种 loss、precision、recall、mAP50 和 mAP50-95,用 pandas 读出来画两条曲线,能直观看到收敛节点和过拟合起点。对 461 张的小数据集,mAP50 达到 0.9 以上是正常水平,mAP50-95 更多反映标注框质量,不必追求极致。

5. 461 张图不够用时的增强边界与漏检定位

5.1 在线增强参数怎么给

小样本场景下,ultralytics 的在线增强默认开启,但默认参数是为 COCO 这种大而全的数据设计的,对道路圆石墩要主动收敛。圆石墩是立在地面的物体,不会倒置,flipud 必须关掉;水平翻转 flip 保持 0.5。光照才是这条数据的主要变化维度,把 hsv_h 提到 0.02、hsv_s 提到 0.7,模拟早晚和阴晴的变化。

yolo detect train \ data=data.yaml model=yolov8n.pt \ epochs=100 imgsz=640 batch=16 \ flipud=0.0 hsv_h=0.02 hsv_s=0.7 \ scale=0.3 translate=0.1

scale 给到 0.3 用来模拟不同拍摄距离下石墩的大小变化,translate 0.1 模拟目标出现在画面边缘的情况。mosaic 保持默认开启,对小数据集帮助很大,它把四张图拼成一张,相当于变相扩充了上下文多样性,也能缓解单类目标分布单一的问题。

5.2 用混淆矩阵定位漏检而不是只看 mAP

单类检测最容易出现的情况是 mAP50 很高,但现场跑起来偏偏漏掉远处的小石墩。要定位这类问题,训练结束后看运行目录下的 confusion_matrix.png 和 PR 曲线。混淆矩阵里重点关注 background 列,如果石墩被预测成背景的比例明显偏高,说明置信度阈值设置不合理,或者远距离小目标特征不足。

# 用 best.pt 对验证集做推理,输出带框结果图 yolo detect predict \ model=runs/detect/bollard_run1/weights/best.pt \ source=dataset/val/images save=True

predict 后会在 runs/detect/predict 下生成带预测框的图片,逐个翻这些图比盯指标更直接。漏检的图如果几乎都集中在远景小尺寸石墩,就去检查训练集里小目标占比:统计 txt 中框宽高占图宽高的比例分布,低于 0.05 的小框如果数量明显偏少,模型天然偏向大目标。这时更有效的做法是对远距离样本做离线裁剪增强,把远处石墩裁出来作为附加训练样本,再重新划分训练验证集,而不是只调置信度阈值。

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

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

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

立即咨询