尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

城市道路井盖破损丢失数据集:1377张VOC+YOLO双格式实战指南

城市道路井盖破损丢失数据集:1377张VOC+YOLO双格式实战指南 简介本资源为城市道路井盖破损与丢失检测数据集面向从事智慧城市、道路巡检及目标检测算法开发的工程师与研究者可用于训练和评估井盖异常状态识别模型。数据集共1377张jpg图片每张均配有对应的VOC格式xml标注与YOLO格式txt标注标注类别分为jg、jg_ds、jg_nd、jg_ps四类总标注框数达1722个其中jg类872个、jg_ps类623个另两类分别为177个和50个标注工具为labelImg。压缩包内文件总数2000个以1377个xml和623个txt为主整体约212.35MB目录结构清晰便于直接接入YOLO或VOC训练流程。目前已有426人学习下载适合需要快速获取井盖缺陷样本、开展模型训练与验证的读者参考使用。1. 城市道路井盖破损丢失数据集1377张VOCYOLO双格式到底能跑出什么城市道路巡检的算法团队常遇到一个尴尬公开数据集里井盖样本少得可怜自己标又费时费力。这个标题指向的是一份现成的目标检测数据集1377张图像VOC和YOLO两种标注格式并存覆盖4个类别专门针对井盖破损与丢失场景。它解决的不是“模型怎么搭”的问题而是“训练数据从哪来”的问题。适合两类人一是做市政巡检、智慧城管方向的产品团队需要快速验证井盖缺陷检测的可行性二是刚接触YOLO训练、想找一个真实场景数据集练手的工程师。1377张不算大但4类标注在垂直场景里已经够跑通一轮基线。下面从数据本身、格式转换、训练配置到踩坑按能复现的路径拆开讲。2. 井盖数据集的结构拆解与VOC到YOLO的格式对齐2.1 1377张4类别先搞清楚标注里到底有什么拿到一个VOCYOLO双格式的数据集第一件事不是急着训练而是把标注分布摸清楚。井盖破损丢失场景的4个类别常见划分是完好井盖、破损井盖、丢失井盖、井盖周边异常或类似定义。但不同来源的数据集类别命名可能不同必须自己核对。VOC格式的核心是每张图对应一个XML文件结构如下annotation folderimages/folder filenameroad_0001.jpg/filename size width1920/width height1080/height depth3/depth /size object namemanhole_broken/name bndbox xmin342/xmin ymin567/ymin xmax489/xmax ymax701/ymax /bndbox /object /annotationYOLO格式则是每张图对应一个txt文件每行一个目标0 0.432 0.587 0.153 0.124五个字段依次是类别索引、中心点x归一化坐标、中心点y归一化坐标、宽度归一化、高度归一化。注意YOLO用的是归一化后的中心点坐标不是左上角坐标这是新手最容易翻车的地方。先跑一段统计脚本确认类别分布和标注完整性import os import xml.etree.ElementTree as ET from collections import Counter voc_dir annotations/voc class_counter Counter() missing_xml [] for img_name in os.listdir(images): img_stem os.path.splitext(img_name)[0] xml_path os.path.join(voc_dir, img_stem .xml) if not os.path.exists(xml_path): missing_xml.append(img_name) continue tree ET.parse(xml_path) for obj in tree.findall(object): class_counter[obj.find(name).text] 1 print(类别分布:, class_counter) print(缺失标注的图片数:, len(missing_xml))这段脚本做两件事统计每个类别的目标数量以及找出没有对应XML的图片。如果某个类别只有几十个目标训练时大概率欠拟合需要考虑过采样或数据增强。缺失标注的图片必须从训练集中剔除否则YOLO训练时会直接报错或静默跳过。参数说明voc_dir指向VOC标注文件夹images指向原图文件夹。实际使用时路径按自己的目录结构调整。类别分布输出后如果发现“丢失井盖”类别样本极少这是正常现象——真实道路中丢失井盖本身就是小概率事件但恰恰是检测的重点。处理方式后面在避坑章节展开。2.2 VOC转YOLO转换脚本与四个边界坑双格式数据集虽然省去了自己标注的麻烦但VOC和YOLO的坐标体系不同如果数据集里的YOLO标注不是从VOC严格转换来的可能出现对不上的情况。稳妥做法是自己跑一遍转换确保两边一致。import xml.etree.ElementTree as ET import os # 类别映射必须与训练时的data.yaml一致 class_map { manhole_normal: 0, manhole_broken: 1, manhole_missing: 2, manhole_surround: 3 } def voc_to_yolo(xml_path, img_w, img_h): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(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) # 边界裁剪防止标注越界 xmin max(0, min(xmin, img_w)) xmax max(0, min(xmax, img_w)) ymin max(0, min(ymin, img_h)) ymax max(0, min(ymax, img_h)) # 转中心点归一化坐标 cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) return lines逻辑说明先做边界裁剪把坐标限制在图像范围内避免标注人员手误导致xmax超过图像宽度。然后按YOLO要求转成中心点归一化坐标。保留6位小数足够再多没必要。四个边界坑第一图像尺寸不一致。VOC的XML里记录了width和height但有些数据集这个字段是错的。稳妥做法是用PIL或OpenCV实际读取图像尺寸而不是信XML里的值。第二类别名大小写和空格。manhole_broken和Manhole_Broken在映射时会变成两个类转换前统一strip并转小写。第三空标注文件。有些图片没有任何目标VOC里没有object节点转换后应该生成一个空txt文件而不是不生成。YOLO训练时空txt表示“这张图没有目标”不生成会被当成缺失标注。第四坐标取整问题。VOC的坐标是整数转换后如果xmax等于xmin宽度为0这种无效框要过滤掉。转换完成后用以下脚本验证YOLO标注的可视化效果import cv2 def draw_yolo_bbox(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() if len(parts) ! 5: continue cls_id, cx, cy, bw, bh int(parts[0]), *map(float, parts[1:]) x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, class_names[cls_id], (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2) cv2.imwrite(vis_check.jpg, img)抽10到20张不同类别的图跑一遍可视化肉眼确认框的位置和类别都对。这一步花不了几分钟但能省掉训练几小时后发现标注错位的后悔药。3. 用YOLOv8跑通井盖检测从data.yaml到训练收敛3.1 data.yaml的路径陷阱与类别顺序YOLOv8训练依赖一个data.yaml文件结构如下path: /home/user/manhole_dataset train: images/train val: images/val nc: 4 names: 0: manhole_normal 1: manhole_broken 2: manhole_missing 3: manhole_surroundpath是数据集根目录train和val是相对于path的路径。常见翻车点把train写成绝对路径但path又设了值YOLO会做路径拼接导致找不到文件。要么全用相对路径要么path留空、train和val写绝对路径不要混用。nc是类别数names的索引必须和转换脚本里的class_map完全一致。如果转换时manhole_broken是1这里写成了0训练不会报错但推理时类别全错。这种玄学问题排查起来很痛苦建议转换后把class_map和data.yaml并排核对一遍。数据集划分比例1377张按8:1:1分训练集约1100张验证集约138张测试集约138张。如果某些类别样本少划分时要做分层采样保证验证集里每个类别都有出现。import os import random import shutil random.seed(42) img_dir images/all train_ratio, val_ratio 0.8, 0.1 all_imgs [f for f in os.listdir(img_dir) if f.endswith(.jpg)] random.shuffle(all_imgs) n len(all_imgs) train_imgs all_imgs[:int(n * train_ratio)] val_imgs all_imgs[int(n * train_ratio):int(n * (train_ratio val_ratio))] test_imgs all_imgs[int(n * (train_ratio val_ratio)):] for split, imgs in [(train, train_imgs), (val, val_imgs), (test, test_imgs)]: os.makedirs(fimages/{split}, exist_okTrue) os.makedirs(flabels/{split}, exist_okTrue) for img in imgs: shutil.copy(os.path.join(img_dir, img), fimages/{split}/{img}) label os.path.splitext(img)[0] .txt src_label os.path.join(labels/all, label) if os.path.exists(src_label): shutil.copy(src_label, flabels/{split}/{label}) else: open(flabels/{split}/{label}, w).close()这段脚本做随机划分并复制文件。random.seed(42)保证每次划分结果一致方便复现。空标注文件用open(..., w).close()创建确保每张图都有对应的txt。3.2 训练参数怎么设1377张图的batch size与学习率YOLOv8的训练命令yolo detect train \ datadata.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ lrf0.01 \ patience20 \ device0 \ projectruns/manhole \ nameexp1参数逐个说清楚modelyolov8n.pt选nano版本1377张图用nano足够跑出基线。如果显存充裕且追求精度可以换yolov8s.pt但训练时间翻倍。imgsz640是输入分辨率。井盖在道路图像中占比通常不大640能覆盖大部分场景。如果原图是1920x1080井盖只占几十个像素可以考虑imgsz960或1280但显存占用会明显上升。batch16在单卡12GB显存下比较稳。如果显存不够降到8或4同时把lr0按比例调小比如batch8时lr00.005。lr00.01是初始学习率lrf0.01是最终学习率系数实际最终学习率是lr0 * lrf 0.0001。这个余弦退火策略在100轮训练里比较稳。patience20表示20轮验证指标不提升就早停。1377张图通常30到50轮就能收敛设100轮是留余量。训练过程中重点看三个指标box_loss是否稳定下降、mAP50是否在上升、cls_loss是否震荡。如果box_loss下降但mAP不涨大概率是验证集标注有问题如果cls_loss震荡剧烈可能是类别不平衡导致。3.3 训练完看什么混淆矩阵与mAP的解读训练结束后runs/manhole/exp1/目录下会生成混淆矩阵、PR曲线和验证集预测图。混淆矩阵是判断类别混淆的关键工具。井盖检测场景中最常见的混淆是“破损井盖”和“丢失井盖”互相误判。原因在于两者视觉特征有重叠破损井盖可能只剩部分结构丢失井盖是一个空洞但在低分辨率或光照差的情况下模型难以区分。如果混淆矩阵显示这两类互相误判严重处理方式有三种增加这两类的训练样本、在数据增强中针对这两类做更强的亮度/对比度扰动、或者考虑把两类合并成一个“异常井盖”类再细分。mAP50达到0.7以上对于1377张图的基线来说算正常。如果低于0.5先检查标注质量再检查data.yaml的类别顺序最后才考虑换模型或调参。很多新手一上来就调学习率实际上八成问题出在数据上。4. 井盖数据集训练的避坑与排查记录4.1 类别极度不平衡丢失井盖只有几十个目标怎么办现象训练后模型对“丢失井盖”的召回率极低几乎检测不到。原因1377张图中丢失井盖的目标数可能只有50到80个而完好井盖有上千个。YOLO的损失函数对各类别是加权平均的少数类被多数类淹没。解决第一在数据增强中针对少数类做复制粘贴增强把丢失井盖的目标裁剪出来随机粘贴到其他道路图像上生成额外训练样本。第二调整损失函数中各类别的权重YOLOv8支持通过cls_pw参数设置类别权重但更直接的方式是在数据集层面做过采样。第三如果少数类实在太少考虑先用全部数据训练一个二分类模型正常 vs 异常再在异常类里细分。4.2 验证集mAP高但实际推理漏检查一下图像尺寸现象验证集mAP50有0.75但拿实际道路视频跑推理漏检严重。原因验证集图像和实际推理图像的尺寸分布不同。如果验证集都是1920x1080而实际推理时输入是1280x720YOLO会做letterbox缩放小目标进一步缩小导致漏检。解决训练时的imgsz要贴近实际部署时的输入尺寸。如果部署端是1080p训练就用imgsz1080或至少960。另外验证集要包含不同尺寸的图像不要全是同一分辨率。4.3 训练loss正常但mAP为0类别索引对不上现象训练过程中box_loss和cls_loss都在下降但验证时mAP始终为0。原因data.yaml里的names顺序和YOLO标注文件里的类别索引不一致。比如标注里0是manhole_broken但data.yaml里0写成了manhole_normal。模型学到的预测和验证时的类别匹配全错。解决写一个校验脚本读取data.yaml的names再统计所有YOLO标注文件里出现的类别索引确认两者范围一致。这个检查花30秒能省几小时排查。4.4 显存溢出batch size和imgsz的取舍现象训练启动后报CUDA out of memory。原因batch和imgsz的乘积决定了显存占用。1377张图用imgsz640, batch16在8GB显存上可能溢出。解决优先降batch从16降到8或4。如果降batch后训练不稳定再考虑降imgsz到512。不要同时降两个否则训练动态会变差。另外YOLOv8支持ampTrue混合精度训练默认开启能省约30%显存。4.5 数据集中混入非道路图像训练后的模型在道路上表现差现象模型在验证集上表现正常但在实际道路场景中误检率高。原因数据集里可能混入了非道路场景的井盖图像比如小区、厂区、人行道。这些图像的背景分布和城市道路差异大模型学到了无关特征。解决训练前用CLIP或简单的图像分类模型过滤一遍把明显不是城市道路的图像剔除。如果不想引入额外模型可以人工抽检100张看背景是否以道路为主。1377张抽检100张10分钟能完成。5. 把1377张用到极致小数据集的增强策略与推理调优1377张在目标检测里算小数据集但井盖场景的视觉变化相对有限用对增强策略能显著提升泛化。我一般会开以下几组增强HSV色域扰动hsv_h0.015, hsv_s0.7, hsv_v0.4模拟不同光照和天气随机翻转flipud0.5, fliplr0.5井盖没有固定方向随机缩放scale0.5让模型适应不同距离的井盖Mosaic增强mosaic1.0YOLOv8默认开启把4张图拼成一张对小数据集特别有效。但Mosaic有一个副作用训练后期如果一直开着模型对单张图的真实分布拟合会变差。YOLOv8默认在最后10轮关闭Mosaic这个策略保留即可。推理阶段的调优同样重要。conf阈值默认0.25井盖检测场景建议调到0.35到0.4减少误检。iou阈值默认0.7如果井盖密集调到0.5到0.6避免重叠框被过度抑制。如果部署端算力有限可以用yolo export导出ONNX或TensorRT推理速度能提升2到3倍。最后说一个我自己的习惯每次训练完把验证集里漏检和误检的图单独挑出来按类别归类看是标注问题还是模型问题。1377张的验证集只有138张挑一遍用不了20分钟但下一轮训练的数据修正方向就清楚了。小数据集的核心竞争力不在模型结构而在你对这1377张图的理解深度。希望帮到你。本文还有配套的精品资源点击获取
返回列表