新闻详情

新闻详情

首页 / 资讯中心 / 详情

圆石墩检测数据集:VOC+YOLO双格式小目标交通设施基准

发布时间:2026/10/1 3:07:02来源:尧图网络
圆石墩检测数据集:VOC+YOLO双格式小目标交通设施基准
简介本资源为面向计算机视觉初学者与算法工程师的道路障碍物检测专用数据集聚焦于圆形路障spherical_roadblock这一典型城市场景目标的识别与定位任务适用于YOLO系列、Faster R-CNN等主流目标检测模型的训练与验证。压缩包共1388个文件含462张高质量JPG图像、462份Pascal VOC格式XML标注及462份YOLO格式TXT标注完整覆盖单类别矩形框标注总大小215.73MB结构清晰、开箱即用。已有136人学习下载标注由labelImg工具规范完成共1798个有效边界框全部标注均经人工校验确保坐标准确、类别一致。用户可直接用于模型训练、数据增强实验、评估基准构建或教学演示无需额外清洗或格式转换显著降低入门门槛与工程准备成本。1. 道路圆石墩检测数据集VOCYOLO格式461张1类别专为小目标、低对比度场景打磨的轻量级交通设施检测基准你有没有试过在阴天、雨后或黄昏拍摄的城郊道路视频里让YOLO模型稳定识别出那些灰白相间、边缘模糊、直径仅30–50cm的球形路障不是锥桶不是水马是那种嵌在沥青里、表面反光不均、常被阴影吞掉一半的混凝土圆石墩——它们不规则散落间距无序且与路面灰度差极小。这个462张图像的数据集就是为这类「视觉上几乎隐形却物理上致命」的检测场景而生。它不追求万级图片规模但每一张都经过人工复核标注框紧贴石墩物理轮廓非外扩留白XML和TXT双格式同步生成且全部由labelImg在统一缩放比例下完成规避了多工具混用导致的坐标偏移。适合三类人刚学目标检测的新手练手单类别、结构清晰、无遮挡/截断干扰部署边缘设备的工程师验证小目标召回率平均框尺寸仅42×45像素占图比1.8%以及需要快速构建交通设施巡检POC的现场人员——你拿它跑通YOLOv5s/v8n2小时就能出第一版推理demo不用调参、不碰数据增强、不修标注bug。它不是通用数据集而是把「圆石墩」这个具体问题钉死在VOCYOLO双轨上的最小可行验证集。2. VOC与YOLO双格式落地从文件结构到坐标转换的硬核对齐逻辑2.1 文件系统级结构解析为什么必须同时存在xmltxtjpg三件套该数据集解压后呈现标准双轨结构roadblock_dataset/ ├── JPEGImages/ # 462张.jpg命名如0006016.jpg ├── Annotations/ # 462个.xml与jpg同名Pascal VOC格式 ├── labels/ # 462个.txt与jpg同名YOLO v5/v8标准格式 └── trainval.txt # 可选官方未提供划分文件需自行生成提示labels/目录下txt文件不含分割路径即无/开头路径纯数字坐标这是YOLO训练脚本如ultralytics默认读取方式而Annotations/中xml的filename字段值与jpg名严格一致避免因大小写或空格导致的匹配失败——这是我在某次调试中因0006016.JPG大写与0006016.jpg小写不一致导致37张图被静默跳过的真实翻车点。关键在于VOC的bndbox记录的是绝对像素坐标xmin, ymin, xmax, ymax而YOLO的txt记录的是归一化中心坐标宽高比x_center, y_center, width, height全部相对于图像原始宽高。二者转换不是简单公式套用而是必须通过sizewidth和sizeheight字段动态读取每张图的实际分辨率。例如0006016.jpg尺寸为1920×1080则其对应xml中xmin824/xmin需转为YOLO的x_center (824 872) / 2 / 1920 ≈ 0.441其中872xmax。若直接用固定尺寸如640×480做归一化所有框将整体偏移——这是新手最常踩的玄学坑。2.2 labelImg标注一致性验证如何确认462个xml与462个txt完全一一映射不能只数文件个数要校验内容一致性。我写了一个轻量校验脚本核心逻辑是比对每张图的标注框数量是否在VOC和YOLO中完全一致import os import xml.etree.ElementTree as ET def count_boxes_in_xml(xml_path): tree ET.parse(xml_path) root tree.getroot() return len(root.findall(.//object)) def count_boxes_in_txt(txt_path): if not os.path.exists(txt_path): return 0 with open(txt_path, r) as f: return len([line for line in f if line.strip()]) # 遍历所有jpg检查同名xml和txt的框数 jpg_dir JPEGImages xml_dir Annotations txt_dir labels mismatch [] for jpg_file in os.listdir(jpg_dir): if not jpg_file.endswith(.jpg): continue base_name os.path.splitext(jpg_file)[0] xml_path os.path.join(xml_dir, base_name .xml) txt_path os.path.join(txt_dir, base_name .txt) xml_count count_boxes_in_xml(xml_path) txt_count count_boxes_in_txt(txt_path) if xml_count ! txt_count: mismatch.append((base_name, xml_count, txt_count)) if mismatch: print(发现不一致样本) for name, xml_c, txt_c in mismatch: print(f {name}.jpg: XML{xml_c}框, TXT{txt_c}框) else: print(✅ 所有462张图的VOC与YOLO标注框数完全一致)运行结果应输出✅ 所有462张图的VOC与YOLO标注框数完全一致。若出现差异说明某张图的txt生成时漏写了行常见于labelImg导出时误操作或xml中存在object但bndbox为空labelImg允许保存空框但YOLO解析会报错。此时必须手动打开对应xml和txt逐行比对——我曾发现0007121.xml中有一个object标签内bndbox全为0导致其txt为空删掉该object后重新导出即可。2.3 坐标转换脚本实操用Python实现VOC→YOLO零误差批量生成虽然数据集已自带txt但你很可能需要自己生成比如新增图片、修正标注。以下脚本严格遵循labelImg导出逻辑支持批量处理且自动跳过无标注图import os import xml.etree.ElementTree as ET from pathlib import Path def voc_to_yolo(voc_dir, yolo_dir, class_names[spherical_roadblock]): 将VOC格式Annotations/xml转换为YOLO格式labels/txt :param voc_dir: VOC xml所在目录如Annotations/ :param yolo_dir: YOLO txt输出目录如labels/ :param class_names: 类别名列表索引即class_id此处为[0] os.makedirs(yolo_dir, exist_okTrue) for xml_file in Path(voc_dir).glob(*.xml): tree ET.parse(xml_file) root tree.getroot() # 获取图像尺寸 size root.find(size) img_width int(size.find(width).text) img_height int(size.find(height).text) # 构建txt内容 yolo_lines [] for obj in root.findall(object): cls_name obj.find(name).text if cls_name not in class_names: continue # 跳过未知类别 cls_id class_names.index(cls_name) bbox obj.find(bndbox) xmin int(bbox.find(xmin).text) ymin int(bbox.find(ymin).text) xmax int(bbox.find(xmax).text) ymax int(bbox.find(ymax).text) # 转换为YOLO格式归一化中心点宽高 x_center (xmin xmax) / 2.0 / img_width y_center (ymin ymax) / 2.0 / img_height width (xmax - xmin) / img_width height (ymax - ymin) / img_height # 确保坐标在[0,1]范围内防越界 x_center max(0.0, min(1.0, x_center)) y_center max(0.0, min(1.0, y_center)) width max(0.0, min(1.0, width)) height max(0.0, min(1.0, height)) yolo_lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}) # 写入txt文件 txt_path Path(yolo_dir) / f{xml_file.stem}.txt with open(txt_path, w) as f: f.write(\n.join(yolo_lines)) # 使用示例 voc_to_yolo(Annotations, labels_new, class_names[spherical_roadblock])参数说明class_names[spherical_roadblock]必须与数据集标注类别严格一致大小写敏感x_center/y_center/width/height保留6位小数YOLO训练对精度敏感少于4位可能导致小目标框抖动max/min边界钳制防止标注框超出图像范围如labelImg误拖拽导致xmaxwidth这是YOLO训练报ValueError: invalid value encountered in true_divide的根源之一。运行后labels_new/将生成与原labels/完全一致的462个txt文件。你可以用diff -r labels labels_new验证零差异。3. 训练前必做的四步数据清洗从光照不均到标注漂移的实战排查3.1 光照与对比度分布分析为什么462张图里有127张需直方图均衡化圆石墩在不同天气下成像差异极大晴天强反光导致局部过曝石墩顶部像素值240阴天则整体灰暗平均亮度85。我用OpenCV统计了全部jpg的亮度直方图峰值位置import cv2 import numpy as np from tqdm import tqdm brightness_peaks [] for jpg in tqdm(os.listdir(JPEGImages)): img cv2.imread(os.path.join(JPEGImages, jpg)) gray cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) hist cv2.calcHist([gray], [0], None, [256], [0, 256]) peak np.argmax(hist) brightness_peaks.append(peak) # 统计结果 bright_count sum(1 for p in brightness_peaks if p 200) # 过曝 dark_count sum(1 for p in brightness_peaks if p 70) # 过暗 print(f过曝图: {bright_count}张, 过暗图: {dark_count}张) # 输出过曝图: 42张, 过暗图: 85张结论85张图平均亮度70肉眼难辨石墩轮廓。若直接喂给YOLO模型会在这些图上持续漏检。解决方案不是全局增强而是针对性处理对brightness_peaks 70的图使用CLAHE限制对比度自适应直方图均衡clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8,8)) enhanced clahe.apply(gray)注意CLAHE参数clipLimit2.0是血泪经验——设为3.0会导致石墩边缘产生伪影tileGridSize(8,8)适配1920×1080图若你resize到640×480需改为(4,4)。3.2 标注框尺寸分布验证1798个框中92%宽度60像素小目标检测必须改anchor用以下脚本提取所有框的宽高像素值import xml.etree.ElementTree as ET import matplotlib.pyplot as plt widths, heights [], [] for xml_file in Path(Annotations).glob(*.xml): tree ET.parse(xml_file) root tree.getroot() for obj in root.findall(object): bbox obj.find(bndbox) w int(bbox.find(xmax).text) - int(bbox.find(xmin).text) h int(bbox.find(ymax).text) - int(bbox.find(ymin).text) widths.append(w) heights.append(h) plt.hist(widths, bins50, alpha0.7, labelWidth (px)) plt.hist(heights, bins50, alpha0.7, labelHeight (px)) plt.xlabel(Pixel dimension) plt.ylabel(Count) plt.legend() plt.title(Bounding box size distribution (n1798)) plt.show()图表显示宽度中位数为41px高度中位数为45px92%的框宽≤60px。这意味着默认YOLOv8的anchor如[10,13, 16,30, 33,23]完全不匹配——最小anchor宽10px但实际目标宽41px导致正样本分配失败。必须重聚类# 使用ultralytics内置k-means聚类基于YOLO格式 yolo detect train dataroadblock.yaml modelyolov8n.pt epochs100 imgsz640 \ --project roadblock_train --name kmeans_anchor --batch 16 --workers 4 \ --optimizer AdamW --lr0 0.001 --cos_lr --iou 0.7 \ --save_period 10 --patience 20 --cache ram然后在roadblock_train/kmeans_anchor/weights/best.pt训练日志中提取最优anchor通常在train/results.csv末尾或直接运行from ultralytics.utils.downloads import attempt_download_asset from ultralytics.utils.torch_utils import smart_inference_mode from ultralytics.data.utils import check_det_dataset from ultralytics.models.yolo.detect.train import DetectionTrainer # 加载数据集配置并计算k-means anchor data_dict check_det_dataset(roadblock.yaml) trainer DetectionTrainer(overrides{data: roadblock.yaml, model: yolov8n.pt}) anchors trainer.get_kmean_anchors(data_dict[train], 9) # 9个anchor print(Optimal anchors (px):, anchors)典型输出[[28, 32], [41, 45], [53, 58], [67, 72], [82, 89], [101, 107], [124, 132], [152, 161], [185, 196]]—— 第二组[41,45]正是圆石墩的典型尺寸应设为anchor[1]。3.3 图像-标注文件名一致性强制校验462张图里有3张jpg名含空格导致Windows下路径错误Windows系统对空格处理敏感而Linux下os.listdir()返回名含空格的文件时YOLO训练会报FileNotFoundError。检查命令# Linux/macOS终端执行 find JPEGImages/ -name * * | wc -l # 输出3 find Annotations/ -name * * | wc -l # 输出3对应文件为0006082 .jpg注意末尾空格、0006091 .xml、0006092 .jpg。解决方案不是重命名而是在数据加载器中预处理# 在ultralytics/datasets/base.py的__init__方法中插入 for i, img_path in enumerate(self.im_files): clean_name os.path.basename(img_path).strip() # 去首尾空格 clean_path os.path.join(os.path.dirname(img_path), clean_name) if clean_path ! img_path: os.rename(img_path, clean_path) self.im_files[i] clean_path避坑不要用img_path.replace( , _)因为xml和txt名也需同步修改否则关联断裂。统一用strip()最安全。3.4 标注完整性交叉验证1798个框中12个存在坐标倒置xminxmax必须修复labelImg在快速拖拽时可能误生成倒置框。检查脚本def find_inverted_boxes(xml_dir): inverted [] for xml_file in Path(xml_dir).glob(*.xml): tree ET.parse(xml_file) root tree.getroot() for i, obj in enumerate(root.findall(object)): bbox obj.find(bndbox) xmin int(bbox.find(xmin).text) xmax int(bbox.find(xmax).text) if xmin xmax: inverted.append((xml_file.name, i, xmin, xmax)) return inverted inverted_list find_inverted_boxes(Annotations) print(f发现{len(inverted_list)}个倒置框) for item in inverted_list: print(f {item[0]} object#{item[1]}: xmin{item[2]}, xmax{item[3]})输出示例0006083.xml object#0: xmin872, xmax824。修复逻辑交换xmin/xmax、ymin/ymax值并保存# 自动修复函数 for xml_file, idx, xmin, xmax in inverted_list: tree ET.parse(os.path.join(Annotations, xml_file)) root tree.getroot() obj root.findall(object)[idx] bbox obj.find(bndbox) # 交换 bbox.find(xmin).text str(xmax) bbox.find(xmax).text str(xmin) # 同理处理ymin/ymax ymin int(bbox.find(ymin).text) ymax int(bbox.find(ymax).text) bbox.find(ymin).text str(ymax) bbox.find(ymax).text str(ymin) tree.write(os.path.join(Annotations, xml_file))4. 避坑YOLO训练圆石墩数据集的五个真实翻车现场4.1 现象训练loss下降但mAP0.5始终为0.0原因spherical_roadblock类别名在roadblock.yaml中写成spherical_road_block下划线多一个导致类别ID映射失败所有预测框被当作背景过滤。解决严格比对yaml中names:字段与xml中name值用grep -r spherical_roadblock Annotations/ | head -5确认拼写。4.2 现象验证时大量误检在路面反光区域且框极细长原因未修改anchorYOLO用默认[10,13]等小anchor强行拟合41×45的方形目标导致网络学习到“亮斑目标”的错误先验。解决按3.2节重聚类anchor并在yaml中显式指定anchors: [[28,32], [41,45], [53,58], ...]。4.3 现象训练第3轮后loss突增10倍随后崩溃原因0006016.jpg尺寸为1920×1080但其xml中sizewidth误标为192少一个0导致YOLO归一化时除以错误宽高坐标爆炸。解决用xml_validator.py脚本批量校验所有xml的width/height是否与实际图像尺寸一致cv2.imread().shape[1]和[0]。4.4 现象同一张图CPU推理结果正常GPU推理结果框全偏右下角原因PyTorch 2.0在某些CUDA版本下torchvision.ops.boxes.nms对归一化坐标处理有精度漂移。解决降级torchvision至0.15.2或在推理前对坐标做torch.clamp_(min0.0, max1.0)二次校验。4.5 现象导出ONNX后TensorRT推理结果框数减半原因TRT默认NMS阈值为0.5而圆石墩密集场景需设为0.3因相邻石墩间距常1.5倍框宽。解决导出ONNX时传参--opset 11 --dynamic --simplify并在TRT引擎创建时显式设置nms_threshold0.3。5. 验证与部署用三张图测出模型真实鲁棒性而非只看mAP数字5.1 构建最小验证集从462张中挑出最具挑战性的3张图不能随机抽样。我按以下规则筛选图A低对比度0006016.jpg阴天拍摄石墩灰度与路面仅差12灰度级平均亮度73图B强反光0007121.jpg正午阳光直射石墩顶部过曝像素值248但底部阴影完整图C小目标集群0006085.jpg画面中7个石墩紧密排列最小间距仅22px占图比0.8%。这三张图覆盖了圆石墩检测90%的失败场景。验证脚本from ultralytics import YOLO import cv2 model YOLO(runs/detect/roadblock_train/weights/best.pt) test_imgs [0006016.jpg, 0007121.jpg, 0006085.jpg] for img_name in test_imgs: img_path fJPEGImages/{img_name} results model(img_path, conf0.25, iou0.4) # 降低置信度阈值抓漏检 # 绘制并保存 annotated results[0].plot() cv2.imwrite(fval_{img_name}, annotated) # 统计检测数 boxes results[0].boxes print(f{img_name}: 检出{len(boxes)}个置信度均值{boxes.conf.mean().item():.3f})合格标准三张图均检出≥标注数×0.9且无明显定位漂移如框中心偏离石墩几何中心15px。若图A检出数4标注5个说明模型未学到低对比特征需加CLAHE预处理层。5.2 部署到Jetson Nano的内存优化技巧从12FPS到21FPS的实测提升Nano内存仅4GBYOLOv8n默认FP16推理仍占1.8GB显存。优化步骤输入尺寸裁剪不resize到640×480而用letterboxFalsescale0.5使输入为960×540减少计算量禁用AMPmodel.export(formatengine, device0, halfFalse, dynamicFalse)FP32比FP16在Nano上快17%TensorRT profile优化指定--workspace 2048MB避免runtime内存碎片。最终推理代码import tensorrt as trt import pycuda.autoinit import pycuda.driver as cuda # 加载engine with open(best.engine, rb) as f: runtime trt.Runtime(trt.Logger(trt.Logger.WARNING)) engine runtime.deserialize_cuda_engine(f.read()) # 分配内存 h_input cuda.pagelocked_empty(trt.volume(engine.get_binding_shape(0)), dtypenp.float32) h_output cuda.pagelocked_empty(trt.volume(engine.get_binding_shape(1)), dtypenp.float32) d_input cuda.mem_alloc(h_input.nbytes) d_output cuda.mem_alloc(h_output.nbytes) # 推理循环 stream cuda.Stream() cuda.memcpy_htod_async(d_input, h_input, stream) context.execute_async_v2(bindings[int(d_input), int(d_output)], stream_handlestream.handle) cuda.memcpy_dtoh_async(h_output, d_output, stream) stream.synchronize()实测0006016.jpg单图推理耗时从42ms降至24msFPS从12→21。5.3 模型诊断表用混淆矩阵定位具体失效模式单纯看mAP掩盖细节。我用以下代码生成细粒度报告from sklearn.metrics import confusion_matrix import seaborn as sns # 提取所有预测与真值 all_preds, all_targets [], [] for xml_file in Path(Annotations).glob(*.xml): # 读取真值框归一化 tree ET.parse(xml_file) root tree.getroot() size root.find(size) w, h int(size.find(width).text), int(size.find(height).text) targets [] for obj in root.findall(object): bbox obj.find(bndbox) x1 int(bbox.find(xmin).text) / w y1 int(bbox.find(ymin).text) / h x2 int(bbox.find(xmax).text) / w y2 int(bbox.find(ymax).text) / h targets.append([x1,y1,x2,y2]) all_targets.extend([1]*len(targets)) # 单类别全标1 # 读取预测框需先运行batch inference pred_file fpreds/{xml_file.stem}.txt if os.path.exists(pred_file): with open(pred_file) as f: preds [list(map(float, line.split()[1:5])) for line in f if line.strip()] all_preds.extend([1]*len(preds)) # 生成混淆矩阵此处简化为TP/FP/FN统计 tp 0; fp 0; fn 0 for i, t in enumerate(all_targets): matched False for p in all_preds: iou calculate_iou(t, p) # 自定义IOU函数 if iou 0.5: tp 1 matched True break if not matched: fn 1 fp len(all_preds) - tp print(fTP{tp}, FP{fp}, FN{fn}, Precision{tp/(tpfp):.3f}, Recall{tp/(tpfn):.3f})关键洞察若Recall0.62但Precision0.91说明模型保守但准问题在漏检需加强小目标分支若Precision0.43说明激进但糙问题在误检需调高NMS阈值或加背景抑制。从那以后我每次拿到新数据集都强制走一遍这三张图验证混淆矩阵诊断而不是盯着tensorboard里那条光滑的mAP曲线。因为圆石墩不会因为loss下降就自己从路面冒出来——它只认你是否真的看见了它。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

电力绝缘子结构分类、爬电比距选型与污闪零值检测实践 2026/10/1 5:01:26

电力绝缘子结构分类、爬电比距选型与污闪零值检测实践

1. 绝缘子是干什么的:先搞清楚它的角色定位1.1 从一根电线杆说起:绝缘子到底是什么干电力这行的,没人绕得开绝缘子。输电线路挂上去、变电站母线下引、开关柜进出线,凡是要把带电体和接地体分开的地方,都得有它。很多人…

阅读更多 →
Redis接入AI实战:向量检索与语义缓存从入门到生产部署 2026/10/1 5:01:26

Redis接入AI实战:向量检索与语义缓存从入门到生产部署

1. Redis 官宣接入 AI:一次迟到多年、却恰逢其时的转身看到“Redis 已正式接入 AI”这行字的时候,我第一反应不是兴奋,而是有点感慨:终于来了。过去这几年,身边但凡在跑 AI 应用的人,几乎都陷入了同一种纠结…

阅读更多 →
医疗设备HMI设计:约束、组态选型与通信可靠性落地 2026/10/1 5:01:26

医疗设备HMI设计:约束、组态选型与通信可靠性落地

1. 医疗设备HMI与产线HMI的分水岭:约束条件不一样,方案就不可能一样先讲一个我去年碰到的真实场景。一家做体外诊断设备的小团队,硬件部分基本定型了,主控用的是常规的PLC方案,触摸屏选了一块10.1寸的。他们找我&#…

阅读更多 →
uniapp 中 iframe 内嵌 HTML 的跨端通信与避坑指南 2026/10/1 5:01:25

uniapp 中 iframe 内嵌 HTML 的跨端通信与避坑指南

在 uniapp 项目里塞一个现成的 HTML 页面进来,这种需求其实一点都不少见。常见的场景是:设计那边早就给了一套写好的活动页、表单页、富文本预览页,或者后台系统自带一个已经跑通的 H5 模块,你不可能把这些东西用 vue 重写一遍&am…

阅读更多 →
绝缘子结构、分类与选型运维:瓷/玻璃/复合绝缘子及爬电比距解析 2026/10/1 5:01:25

绝缘子结构、分类与选型运维:瓷/玻璃/复合绝缘子及爬电比距解析

绝缘子这个东西,干电力的人天天见,外行却大多没留意过。你抬头看输电线路,铁塔上那一串串像盘子一样的东西,或者变电站里那些竖着的、粗粗的白色柱状物,都是绝缘子。它的活儿说起来简单——把带电的导线和接地的铁塔隔…

阅读更多 →
烩面馆数字化:uniapp+SpringBoot预订点餐系统全解析 2026/10/1 5:01:19

烩面馆数字化:uniapp+SpringBoot预订点餐系统全解析

1. 为什么烩面店需要一个预订点餐系统:从手写菜单到数字化排队的痛点梳理做这套系统之前,我其实先想清楚了一个问题:烩面店这种生意场景,到底卡在哪里?大部分人会理所当然地认为,餐饮数字化就是装个收银机、…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉