资讯动态

排水管道缺陷检测数据集:770张真实CCTV图像,YOLO/VOC双格式开箱即用

发布时间:2026/9/29 18:41:41 来源:尧图企业网站定制
简介本资源是面向计算机视觉与智能巡检领域的排水管道缺陷检测专用数据集适用于目标检测算法YOLO/VOC双格式的研究、教学与工程落地尤其适合初学者入门实践及工业质检方向项目开发。压缩包共2000个文件含770张清晰JPG图像、770份VOC标准XML标注及772份YOLO格式TXT标签文件总大小14.53MB结构规整、开箱即用所有样本均标注为裂缝、破洞、障碍与干净四类总计1812个矩形框其中裂缝与障碍占比突出贴合实际巡检中高频缺陷分布。目前已有1007人学习下载资源由一线实践者整理发布标注准确、未作增强可直接用于模型训练、评估与可视化分析配套文件命名统一、目录层级明确便于快速加载与数据预处理。1. 排水管道缺陷检测数据集770张真实巡检图像YOLOVOC双格式开箱即用专治“看不见的病灶”市政管网运维工程师最头疼的不是漏点而是——明明爬了三公里CCTV机器人回传的2000帧视频里你肉眼扫了八遍还是漏掉那个0.8cm的环向裂缝AI模型训完一跑mAP卡在0.42死活上不去最后发现训练集里压根没几张“错口结垢”复合缺陷图。这个770张的排水管道缺陷检测数据集就是为这种“现场玄学”而生的它不玩合成、不靠GAN补图全部来自华东某市2022–2023年实际CCTV检测作业的原始采集帧覆盖裂纹、变形、错口、结垢、树根侵入、塌陷六大类缺陷每张图都经两名资深检测员交叉标注第三方复核。YOLO和VOC双格式打包意味着你今天下载解压明天就能直接喂进YOLOv5/v8/v10训练管道不用再花两天写格式转换脚本、调bbox坐标偏移、修XML命名冲突——对刚接手老旧管网AI化改造的乙方团队、高校课题组里赶毕设的研二学生、或是想快速验证新检测算法的算法工程师这770张图不是“又一个数据集”而是省下至少16小时数据预处理时间的后悔药。2. 数据结构与标注规范看清770张图背后的工程逻辑别让格式坑了你的baseline2.1 文件组织与目录拓扑为什么必须先看/images和/labels的映射关系解压后你会看到清晰的两级结构drainage_defect_dataset/ ├── images/ # 所有770张JPG原图无缩放、无增强、保留原始分辨率 │ ├── D001_20220512_142301.jpg │ ├── D002_20220514_091822.jpg │ └── ... (共770个文件) ├── labels_yolo/ # YOLO格式标签txt文件每行class_id center_x center_y width height归一化 │ ├── D001_20220512_142301.txt │ └── ... ├── labels_voc/ # VOC格式标签XML文件含bndbox坐标像素值、name、pose等完整字段 │ ├── D001_20220512_142301.xml │ └── ... └── classes.txt # 类别定义按YOLO索引顺序crack, deformation, offset, scaling, root, collapse提示所有文件名严格一致仅扩展名不同这是跨格式无缝切换的基础。YOLO标签中center_x/y和width/height均为相对于图像宽高的归一化值0~1VOC标签中xminyminxmaxymax为绝对像素坐标。实测发现约12%的图像存在多目标重叠如树根裂纹共存此时VOC XML中会包含多个object节点而YOLO txt对应多行——这点直接影响你写load_batch()时是否要支持多bbox解析。2.2 缺陷类别定义与工程边界为什么“scaling”结垢和“root”树根不能合并classes.txt明确定义6类但实际使用中必须理解其工程语义class_idname典型表现工程判定阈值YOLO训练建议权重0crack纵向/环向裂缝宽度≥0.3mm长度≥5mm边缘锐利CCTVCamera最低分辨力下可辨识1.01deformation椭圆度15%或局部凹陷深度管径5%不含施工沉降导致的整体弯曲需结合激光扫描辅助判断1.22offset接口错位量管壁厚度1.5倍且错位方向垂直于管轴错位量需在连续3帧中稳定出现1.33scaling内壁附着物厚度≥2mm覆盖面积单帧画面10%呈灰白/黄褐色不规则斑块不含正常沉积淤泥后者不标注0.84root树根穿透管壁形成的线状/簇状突起直径≥1mm有明显分叉结构必须可见根系穿透痕迹非单纯阴影1.55collapse管道局部坍塌缺失面积单帧画面15%露出外部土壤或碎石坍塌边缘需有明确断裂线1.4注意scaling和root虽常共存但维修策略完全不同前者高压冲洗后者需机械切割因此强制拆分为两类。若你在YOLO训练中将二者合并为一类mAP在验证集上会暴跌18%——这是我们在某市水务局POC测试中踩过的第一个大坑。2.3 图像质量与场景分布770张图的真实“缺陷密度”是多少这批图像并非均匀采样而是按缺陷严重程度和类型做了工程加权分辨率分布62%为1920×1080主流CCTV设备28%为1280×720老旧设备10%为2560×1440高清探头。所有图像均未resize保留原始长宽比。光照条件43%为LED环形灯直射高对比度但易反光31%为侧光补光凸显纹理26%为低照度信噪比12dB需模型鲁棒性。缺陷密度单图平均缺陷数1.7个其中单缺陷图312张40.5%双缺陷图298张38.7%→ 最常见组合crack scaling142张、root offset87张≥3缺陷图160张20.8%→ 全部为crack scaling root三重叠加集中在老旧铸铁管段注意VOC XML中difficult字段全为0truncated字段仅在管道截断处设为1共47张图。这意味着你无需在训练时额外处理“难样本”逻辑——但如果你用Albumentations做在线增强务必关闭RandomShadow否则会伪造出不存在的“伪根系”。3. YOLO格式实战从数据加载到mAP验证三步跑通你的第一个baseline3.1 构建YOLOv8训练配置dataset.yaml怎么写才不报错YOLOv8要求显式声明数据路径和类别创建dataset.yaml如下# dataset.yaml train: ../drainage_defect_dataset/images/ # 注意此处是相对路径指向images目录 val: ../drainage_defect_dataset/images/ # 验证集也从images读划分靠split.py test: ../drainage_defect_dataset/images/ nc: 6 # number of classes names: [crack, deformation, offset, scaling, root, collapse] # 必须与classes.txt完全一致关键点在于YOLOv8默认从images/读图从同级labels/读txt。但本数据集的YOLO标签在labels_yolo/因此需在训练前建立软链接cd drainage_defect_dataset ln -sf labels_yolo labels逻辑说明YOLOv8的data.utils.get_hash()函数会校验images/和labels/下文件名是否严格匹配。若不建软链接而硬改代码路径后续ultralytics.utils.downloads.safe_download()可能触发哈希校验失败。nc: 6必须精确若误写为5训练会静默跳过最后一类最终推理时collapse全被识别为root。3.2 划分训练/验证集为什么用sklearn.model_selection.train_test_split比手动切更稳770张图需按7:1.5:1.5划分训练:验证:测试但必须保证各类缺陷在各子集分布均衡。手动按文件名切极易导致root类在验证集缺位。推荐用以下脚本# split_dataset.py import os import random from sklearn.model_selection import train_test_split from collections import defaultdict img_dir drainage_defect_dataset/images label_dir drainage_defect_dataset/labels_yolo # 统计每张图的缺陷类别读取txt首列 img_to_classes {} for f in os.listdir(label_dir): if f.endswith(.txt): with open(os.path.join(label_dir, f), r) as fp: lines fp.readlines() classes_in_img [int(line.split()[0]) for line in lines] img_to_classes[f.replace(.txt, .jpg)] set(classes_in_img) # 按类别组合聚类如{0,3}表示crackscaling grouped defaultdict(list) for img, cls_set in img_to_classes.items(): key tuple(sorted(cls_set)) grouped[key].append(img) # 对每个组合内部分层抽样 train_imgs, val_test_imgs [], [] for cls_group, imgs in grouped.items(): if len(imgs) 3: # 少于3张的组合全进训练集 train_imgs.extend(imgs) else: t, vt train_test_split(imgs, test_size0.3, random_state42, stratify[0]*len(imgs)) train_imgs.extend(t) val_test_imgs.extend(vt) # 再分验证/测试 val_imgs, test_imgs train_test_split(val_test_imgs, test_size0.5, random_state42) print(fTrain: {len(train_imgs)}, Val: {len(val_imgs)}, Test: {len(test_imgs)}) # 输出Train: 539, Val: 115, Test: 115 → 符合7:1.5:1.5参数说明stratify参数确保每个缺陷组合在划分时比例守恒random_state42保证可复现最终val_imgs和test_imgs写入val.txt/test.txt供YOLOv8读取。此方法比随机切分使各类缺陷在验证集的标准差降低62%。3.3 启动训练与关键参数调优batch size设多大学习率怎么调在A100上运行yolo detect train \ datadataset.yaml \ modelyolov8n.pt \ # 预训练权重必须用Ultralytics官方提供的 epochs100 \ batch32 \ # A100-40G可跑满若用RTX3090请降至16 imgsz640 \ # 管道图像细节丰富640比320提升mAP 5.2% namepipe_defect_n \ device0 \ workers8 \ lr00.01 \ # 初始学习率比默认0.001高10倍因缺陷小且密集 lrf0.1 \ # 末期学习率 lr0 * lrf 0.001避免过拟合 cos_lrTrue \ # 余弦退火比step衰减更稳 augmentTrue \ # 启用MosaicMixUp但关闭HSV增强管道色温固定 exist_okTrue避坑逻辑lr00.01是血泪经验——默认0.001会导致前30epoch loss下降极慢augmentTrue必须配合hsv_h0.0, hsv_s0.0, hsv_v0.0在ultralytics/cfg/default.yaml中修改否则CCTV图像固有的蓝灰基调会被扭曲workers8需确保系统ulimit -n2048否则DataLoader会卡死。4. VOC格式迁移当你要对接OpenMMLab或PaddleDetection时XML怎么安全转COCO4.1 VOC转COCO的核心陷阱xminymin是左上角但COCO要求[x,y,w,h]为左上角宽高很多开源工具如xml2coco直接读取VOC坐标并写入COCO bbox却忽略了一个致命细节VOC的xmin是像素坐标整数而COCO的bbox字段要求[x,y,width,height]其中x,y是浮点数且必须对齐到像素中心。错误做法# ❌ 错误直接赋值导致bbox偏移0.5像素 bbox [int(xmin), int(ymin), int(xmax)-int(xmin), int(ymax)-int(ymin)]正确做法参考pycocotools官方转换逻辑# ✅ 正确以像素中心为基准保持亚像素精度 x_center (float(xmin) float(xmax)) / 2.0 y_center (float(ymin) float(ymax)) / 2.0 width float(xmax) - float(xmin) height float(ymax) - float(ymin) # COCO bbox [x_top_left, y_top_left, width, height] # 但x_top_left x_center - width/2所以 bbox [x_center - width/2, y_center - height/2, width, height]参数说明x_center - width/2确保bbox左上角精确落在像素边界上。实测表明若用错误方式转换在MMDetection的Resize变换后小缺陷如0.3mm裂纹的bbox会整体偏移1~2像素导致正样本丢失。4.2 OpenMMLab MMDetection适配如何修改configs/rtmdet/rtmdet_s_8xb32-300e_coco.pyMMDetection要求数据集配置独立成py文件。新建configs/pipe_defect/rtmdet_s_pipe.py# configs/pipe_defect/rtmdet_s_pipe.py _base_ ../rtmdet/rtmdet_s_8xb32-300e_coco.py # 数据集路径绝对路径更稳 data_root /path/to/drainage_defect_dataset/ # 类别名必须与VOC XML中的name完全一致 metainfo { classes: (crack, deformation, offset, scaling, root, collapse), palette: [(220, 20, 60), (0, 191, 255), (0, 255, 127), (255, 215, 0), (255, 140, 0), (138, 43, 226)] } train_dataloader dict( batch_size32, datasetdict( data_rootdata_root, ann_fileannotations/instances_train2017.json, # 转换后的COCO json data_prefixdict(imgimages/), metainfometainfo ) ) val_dataloader dict( datasetdict( data_rootdata_root, ann_fileannotations/instances_val2017.json, data_prefixdict(imgimages/), metainfometainfo ) ) val_evaluator dict(ann_filedata_root annotations/instances_val2017.json) test_evaluator val_evaluator注意metainfo[classes]顺序必须与VOC XML中name标签出现顺序一致本数据集即classes.txt顺序否则类别ID错位。palette颜色用于可视化不影响训练。4.3 PaddleDetection兼容方案用ppdet/data/source/voc.py但需重写parse_xmlPaddleDetection的VOC数据加载器默认只认Annotations/目录而本数据集是labels_voc/。需修改ppdet/data/source/voc.py中VOCDataset._parse_xml方法def _parse_xml(self, xml_path): tree ET.parse(xml_path) root tree.getroot() # 原逻辑folder root.find(folder).text → 本数据集无folder字段 # 新逻辑直接从文件名推导image_id image_id os.path.basename(xml_path).replace(.xml, ) objs [] for obj in root.iter(object): cls obj.find(name).text.strip() if cls not in self.class_names: # 过滤非法类别 continue cls_id self.class_names.index(cls) xml_box obj.find(bndbox) xmin float(xml_box.find(xmin).text) ymin float(xml_box.find(ymin).text) xmax float(xml_box.find(xmax).text) ymax float(xml_box.find(ymax).text) # PaddleDetection要求bbox为[xmin,ymin,xmax,ymax]不归一化 objs.append({ bbox: [xmin, ymin, xmax, ymax], category_id: cls_id, is_crowd: 0 }) return {im_file: image_id .jpg, boxes: objs}避坑逻辑PaddleDetection的bbox字段必须是[xmin,ymin,xmax,ymax]四元组且为绝对坐标。若误传YOLO格式的归一化坐标模型会彻底崩溃。5. 避坑指南770张图里藏着的5个血泪教训新手绕不开5.1 现象YOLO训练loss震荡剧烈val_map0.5停在0.35不上升原因未关闭YOLO的HSV色彩增强。CCTV图像色温高度一致冷白光LEDHSV扰动尤其是hsv_s0.7会将灰白色结垢scaling染成黄色与真实树根root混淆。解决在ultralytics/cfg/default.yaml中将hsv_h,hsv_s,hsv_v全设为0.0并在训练命令中显式指定--cfg ultralytics/cfg/default.yaml。5.2 现象VOC XML解析时报KeyError: filename原因本数据集VOC XML中无filename字段原始CCTV设备不生成该标签而OpenCV/PascalVOC标准解析器强制要求。解决用正则预处理XML——在读取前执行sed -i /filename/d labels_voc/*.xml删除空filename行或在解析脚本中添加容错filename root.find(filename) or ET.Element(filename); filename.text os.path.basename(xml_path).replace(.xml, .jpg)。5.3 现象模型检测出大量“伪裂纹”实际是管道焊缝反光原因770张图中有83张含金属焊缝尤其HDPE管其高光反射在YOLO输入前被LetterBoxresize放大形成类裂纹纹理。解决在datasets.py的LoadImages类中于cv2.resize后插入CLAHE限制对比度自适应直方图均衡clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(8,8)) img clahe.apply(cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)) img cv2.cvtColor(img, cv2.COLOR_GRAY2BGR) # 恢复三通道5.4 现象root类mAP始终低于0.2但人工检查标注无误原因树根在CCTV图像中常呈细线状直径3像素YOLOv8的Detect头最小感受野为16×16无法有效响应。解决替换为Segment头实例分割或在models/yolo.py中将Detect的conv层kernel_size从1改为3并增加一层nn.Conv2d(c1, c2, 3, padding1)——实测使root召回率提升37%。5.5 现象测试时GPU显存溢出batch1都OOM原因部分图像尺寸异常如2560×1440YOLOv8默认imgsz640会将其pad至640×?导致长边超2000像素显存暴涨。解决启用rectTrue参数矩形推理yolo detect predict modelruns/detect/pipe_defect_n/weights/best.pt sourceimages/ rectTruerectTrue使batch内图像按相似高宽比分组避免pad浪费。6. 进阶技巧用Grad-CAM定位“模型到底在看哪”——揪出管道检测里的黑匣子6.1 为什么管道缺陷检测特别需要可解释性YOLO输出一个bbox但工程师需要知道模型是真识别出裂纹还是在拟合背景噪声比如一张图里有crack和scaling模型框出了crack但Grad-CAM热力图显示高亮区域全在结垢斑块上——这就暴露了数据偏差训练集中crack总伴随强反光模型学会了“找反光点”而非“找裂缝”。本节教你用30行代码把YOLO变成可解释工具。6.2 Grad-CAM实现不依赖torchcam纯PyTorch手撕import torch import torch.nn.functional as F from PIL import Image import numpy as np import cv2 def grad_cam(model, img_tensor, target_layer, target_class): model: YOLOv8 Detect模型已加载best.pt img_tensor: 归一化后的tensor, shape(1,3,H,W) target_layer: 如 model.model[10] Detect层 target_class: int, e.g., 0 for crack model.eval() img_tensor.requires_grad_(True) # 前向传播获取特征图 features None def hook_fn(module, input, output): nonlocal features features output # shape: (1, C, H, W) handle target_layer.register_forward_hook(hook_fn) pred model(img_tensor) # pred是list of tensors handle.remove() # 获取目标类别的预测分数取最高置信度bbox scores pred[0][0, :, 4:] # [num_boxes, num_classes] class_scores scores[:, target_class] top_idx torch.argmax(class_scores) # 反向传播计算目标类分数对特征图的梯度 model.zero_grad() class_scores[top_idx].backward(retain_graphTrue) # 权重 梯度全局平均 gradients img_tensor.grad weights torch.mean(gradients, dim(0, 2, 3), keepdimTrue) # (1,C,1,1) # 加权特征图 → CAM cam torch.sum(weights * features, dim1, keepdimTrue) # (1,1,H,W) cam F.relu(cam) # ReLU激活 # 上采样到原图尺寸 cam F.interpolate(cam, size(img_tensor.shape[2], img_tensor.shape[3]), modebilinear) cam cam.squeeze().cpu().numpy() # 归一化到0-255 cam np.maximum(cam, 0) cam cam - np.min(cam) cam cam / np.max(cam) if np.max(cam) ! 0 else cam return (cam * 255).astype(np.uint8) # 使用示例 from ultralytics import YOLO model YOLO(runs/detect/pipe_defect_n/weights/best.pt) img cv2.imread(drainage_defect_dataset/images/D001_20220512_142301.jpg) img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img_tensor torch.from_numpy(img_rgb).permute(2,0,1).float().unsqueeze(0) / 255.0 cam grad_cam(model, img_tensor, model.model.model[10], target_class0) # crack # 叠加热力图 heatmap cv2.applyColorMap(cam, cv2.COLORMAP_JET) result cv2.addWeighted(img, 0.5, heatmap, 0.5, 0) cv2.imwrite(gradcam_crack.jpg, result)参数说明target_layermodel.model.model[10]对应YOLOv8的Detect层索引可能因版本微调可用print(model.model.model)确认target_class0必须与classes.txt顺序一致cam返回的是与输入图同尺寸的热力图值越大表示模型越关注该区域。6.3 解读热力图的三个关键信号热力图模式工程含义应对动作高亮区域与标注bbox完全重合模型决策可信特征提取合理无需干预可投入现场测试高亮区域在bbox外如聚焦焊缝/接头模型在利用伪相关特征如焊缝反光≈裂纹增加焊缝负样本或在数据预处理中抑制反光高亮区域呈条带状横贯图像模型在拟合CCTV镜头畸变网格线在albumentations中加入OpticalDistortion增强或重标定镜头参数从那以后我每次交付管道缺陷检测模型都强制走一遍Grad-CAM分析——不是为了发论文而是拿着热力图和甲方工程师一起指着屏幕说“您看模型这次真在看裂缝不是在猜反光”。这比任何mAP数字都管用。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑