简介:本资源为面向YOLO系列目标检测算法的下水管道缺陷检测数据集,适用于市政管网巡检、工业设施维护等场景下的缺陷识别模型训练与验证,适合具备一定深度学习基础的目标检测学习者与工程人员使用。压缩包共2000个文件,约33.89MB,包含980个xml标注文件、980个txt标注文件、39张jpg图像及1个yaml配置文件,同时提供YOLO格式与VOC格式两种标签,分别存放于不同文件夹,文件名末尾标注部分类别名称,并附data.yaml可直接用于yolov5、yolov8、yolov9、yolov7、yolov10、yolo11等算法训练。数据集已划分完毕,覆盖关节偏移、障碍物、裂纹、带扣、洞、公用设施入侵、碎片等缺陷类别,标签坐标采用归一化中心点与宽高表示,便于直接加载训练与测试。目前已有417人学习下载,可为管道缺陷检测项目提供开箱即用的数据基础,帮助读者快速搭建实验流程、验证模型效果并开展对比研究。
1. 下水管道缺陷检测为什么值得用 YOLO 重做一遍
城市地下管网巡检过去靠人眼盯监控回放,一段两小时的巡检视频,师傅得逐帧暂停、截图、标注,一天下来眼睛发直还容易漏检。现在换成 YOLO 算法跑下水管道缺陷检测,980 张带标签图像、覆盖关节偏移、障碍物、裂纹、带扣、洞、公用设施入侵、碎片七类目标,这套数据集的价值不在于“图多”,而在于它把管道内窥镜那种畸变、低照度、反光、遮挡的恶劣成像条件都收进去了。你拿它训出来的模型,能直接部署到巡检机器人或边缘盒子上,边跑边出框,把“事后翻录像”变成“现场报警”。适合谁?做市政智慧化改造的算法工程师、想入门工业缺陷检测的学生、手里有管道CCTV检测视频但不知道怎么转成结构化数据的运维团队。这一章先把“为什么是YOLO、为什么是这七类缺陷”讲清楚,后面再动手。
管道缺陷检测和通用目标检测最大的区别是:缺陷没有固定形状。裂纹可能是一条细线,洞可能是一个不规则暗斑,碎片可能是成堆的杂物,关节偏移则是结构错位。用传统图像处理做阈值分割,换个管段、换种光照就翻车。YOLO 这类单阶段检测器把定位和分类揉在一个网络里,对不规则目标更鲁棒,而且推理速度快,适合视频流。980 张图像不算多,但七类缺陷分布相对均衡的话,做迁移学习足够跑出一个能用的基线。关键是标签质量——带标签意味着每张图都有对应的标注文件,省掉了最耗人力的环节。
2. 七类缺陷的标注逻辑与数据组织方式
2.1 为什么这七类缺陷不能混在一起标
关节偏移、障碍物、裂纹、带扣、洞、公用设施入侵、碎片,这七类在管道检测标准里对应不同的处置优先级。关节偏移是结构性错位,可能引发渗漏;障碍物和碎片是异物堵塞;裂纹和洞是管体损伤;带扣是接口松脱;公用设施入侵指非管道设施穿入。如果你把它们统一标成“缺陷”一个类,模型学到的特征会互相打架——裂纹的细长纹理和碎片的团块纹理完全不是一回事。常见做法是每类一个独立类别索引,标注时严格按定义走。我一般会先定一份标注手册,把每类的边界写清楚,比如“洞”要求面积大于多少像素、“碎片”要求与管壁有明显色差,避免不同人标出来的框尺度不一致。
数据组织上,980 张图像建议按 8:1:1 切分训练、验证、测试。如果某些类别样本极少,比如公用设施入侵可能只有几十张,那就不能随机切,要用分层抽样保证每个子集里都有这类样本。目录结构我习惯这样放:
dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml图像和标签文件名一一对应,标签用 YOLO 格式的 txt,每行class_id x_center y_center width height,坐标归一化到 0~1。这个格式是后续训练能不能跑通的前提,标错了后面全白搭。
2.2 从原始标注到 YOLO 格式的转换脚本
如果你拿到的标签是 VOC 的 XML 或者 LabelMe 的 JSON,得先转成 YOLO 格式。下面这个脚本处理 VOC 转 YOLO,顺带做类别映射:
import os import xml.etree.ElementTree as ET # 类别名到索引的映射,顺序要和 data.yaml 里一致 CLASS_MAP = { "joint_offset": 0, "obstacle": 1, "crack": 2, "buckle": 3, "hole": 4, "utility_intrusion": 5, "debris": 6 } def convert_voc_to_yolo(xml_dir, img_dir, out_dir): os.makedirs(out_dir, exist_ok=True) for xml_file in os.listdir(xml_dir): if not xml_file.endswith(".xml"): continue tree = ET.parse(os.path.join(xml_dir, xml_file)) root = tree.getroot() # 读取图像宽高,用于归一化 size = root.find("size") w = int(size.find("width").text) h = int(size.find("height").text) lines = [] for obj in root.findall("object"): name = obj.find("name").text.strip() if name not in CLASS_MAP: continue # 跳过未定义类别,避免索引错乱 cls_id = CLASS_MAP[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) # 归一化中心点和宽高 x_center = (xmin + xmax) / 2.0 / w y_center = (ymin + ymax) / 2.0 / h bw = (xmax - xmin) / w bh = (ymax - ymin) / h lines.append(f"{cls_id} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}") # 写同名 txt txt_name = os.path.splitext(xml_file)[0] + ".txt" with open(os.path.join(out_dir, txt_name), "w") as f: f.write("\n".join(lines)) if __name__ == "__main__": convert_voc_to_yolo("annotations/xml", "images", "labels/train")逻辑说明:先解析 XML 拿到图像宽高,再把每个目标框的左上右下坐标转成中心点加宽高的归一化形式。CLASS_MAP必须和data.yaml里的names顺序完全一致,否则训练时类别对不上,模型学出来的东西全是错的。参数上,x_center和y_center保留六位小数足够,YOLO 训练时对精度不敏感。如果遇到宽或高为 0 的框,直接跳过,那是标注错误。
2.3 data.yaml 的写法与路径陷阱
YOLO 训练靠data.yaml找数据,这个文件写错路径是新手最常见的翻车点。写法如下:
path: /home/user/dataset train: images/train val: images/val test: images/test nc: 7 names: - joint_offset - obstacle - crack - buckle - hole - utility_intrusion - debris注意path是数据集根目录,train和val是相对路径。如果你用绝对路径写train,换台机器就找不到。nc必须等于names的长度,多一个少一个都会在训练启动时报错。另外,标签目录默认和图像目录同级,YOLO 会自动把images替换成labels去找 txt,所以目录结构要按 2.1 那样摆。
3. 用 YOLOv8 在 980 张图上跑通训练的最小闭环
3.1 环境准备与预训练权重选择
训练前先把环境搭好。我一般用 conda 建一个干净环境,装 ultralytics 包:
conda create -n pipe_yolo python=3.10 -y conda activate pipe_yolo pip install ultralytics opencv-pythonultralytics 会自动装 PyTorch,但如果你有特定 CUDA 版本需求,建议先手动装对应版本的 torch 再装 ultralytics。预训练权重选yolov8s.pt或yolov8m.pt,980 张图用 s 就够了,m 容易过拟合。权重文件第一次运行会自动下载,放到当前目录。如果你在内网环境,提前把 pt 文件下好放进去。
3.2 训练命令与关键参数怎么设
最小训练命令就一行:
yolo detect train data=dataset/data.yaml model=yolov8s.pt epochs=150 imgsz=640 batch=16 patience=30参数说明:epochs=150是上限,实际靠patience=30早停,验证集 30 轮不提升就停,省时间。imgsz=640是输入分辨率,管道缺陷里裂纹很细,理论上用 1280 更好,但显存翻倍,980 张图用 640 先跑基线。batch=16看显存调,8G 显存跑 640 分辨率大概能到 16,不够就降到 8。学习率不用手动设,YOLO 默认用余弦退火加 warmup,对中小数据集够用。
训练过程中重点看mAP50和mAP50-95。管道缺陷检测里,mAP50 到 0.75 以上算能用,0.85 以上算不错。如果某个类别的 AP 一直很低,比如公用设施入侵,大概率是样本太少,得做数据增强或者单独补样本。
3.3 数据增强策略与管道场景的适配
YOLO 默认开了一堆增强,但管道图像有特殊性。默认的mosaic把四张图拼一起,对裂纹这种细长目标可能切断上下文,建议把mosaic概率从 1.0 降到 0.5。hsv_h、hsv_s、hsv_v可以保留,管道内窥镜光照变化大,色调抖动有帮助。flipud垂直翻转要慎用,管道图像上下有别,翻转后关节偏移的方向就反了,可能引入错误标签。我一般设flipud=0.0,fliplr=0.5。
yolo detect train data=dataset/data.yaml model=yolov8s.pt epochs=150 imgsz=640 batch=16 patience=30 mosaic=0.5 flipud=0.0 fliplr=0.5如果碎片和障碍物样本偏少,可以开copy_paste=0.3,把目标复制粘贴到其他图上,增加小目标出现频率。但复制粘贴要注意别把目标贴到管壁外面去,否则模型学到错误背景。
4. 训练完怎么验证模型真的能检出缺陷
4.1 验证集指标之外,必须做视频流测试
验证集 mAP 高不代表现场能用。管道巡检是视频流,单帧检测好不等于时序上稳定。训练完先跑yolo detect val看指标,然后拿一段没参与训练的巡检视频做推理:
yolo detect predict model=runs/detect/train/weights/best.pt source=test_video.mp4 save=True conf=0.4conf=0.4是置信度阈值,低于这个值的框不显示。管道缺陷检测里,漏检比误检代价高,所以阈值可以降到 0.25 先看召回,再根据误检情况往上调。推理结果会存成带框的视频,逐帧看有没有连续漏检的片段。
4.2 混淆矩阵与类别不平衡的排查
训练完 ultralytics 会在runs/detect/train/下生成混淆矩阵。重点看对角线,如果某一类经常被误判成背景,说明该类特征不明显或者样本太少。比如带扣和关节偏移在图像上可能都是接口处的异常,模型容易混。解决办法是在标注时把两者的区分特征写进手册,比如带扣强调“扣件松脱”,关节偏移强调“管口错位”,标注时严格按定义框。另一个办法是加类别权重,但 YOLO 不直接支持,得改损失函数,新手不建议一上来就动。
4.3 用测试集做一次盲测
验证集在训练时被用来调早停,多少有点信息泄露。真正可信的是测试集盲测。把best.pt在测试集上跑一遍:
yolo detect val model=runs/detect/train/weights/best.pt data=dataset/data.yaml split=test看测试集的 mAP 和验证集差多少,差 5 个点以内算正常,差太多说明过拟合。过拟合了就把模型换小一号,或者加增强、加数据。980 张图训 YOLOv8s,正常情况测试集 mAP50 在 0.78~0.88 之间,低于 0.7 就得回头查标签质量。
5. 避坑:下水管道缺陷检测训练里最容易翻车的五件事
现象:训练 loss 一直不降,mAP 在 0.1 附近晃。原因:标签路径不对,YOLO 找不到 txt,把所有框当背景学。或者data.yaml里nc和实际类别数不一致。 解决:先跑一遍yolo detect train看它打印的Scanning信息,确认找到多少张图、多少个标签。再用脚本抽查几张图的 txt,确认坐标在 0~1 之间。
现象:某些类别 AP 为 0,但训练集里明明有这类样本。原因:类别索引错位。标注时用的类别名和data.yaml里names的顺序不一致,比如标注里 crack 是 2,但 yaml 里 crack 排在第 3 位。 解决:把data.yaml的names和转换脚本里的CLASS_MAP逐行对齐,改完重新生成标签。
现象:模型在验证集上很好,一上视频就疯狂误检。原因:验证集和训练集同分布,但视频里有训练集没见过的光照或管段材质。管道内窥镜的自动曝光会让同一缺陷在不同帧里亮度差异巨大。 解决:训练时加强hsv_v抖动,范围开到 0.6;推理时用conf=0.5先压误检,再对连续多帧都检出的目标才报警,用时序滤波。
现象:裂纹这类细长目标总是检不全,框只盖住一半。原因:输入分辨率不够,640 下裂纹可能只占几个像素。或者标注时框太紧,没把裂纹两端包进去。 解决:把imgsz提到 1024 或 1280 重训,显存不够就降 batch。标注时框放宽 2~3 个像素,给模型一点容错。
现象:训练到一半显存爆了。原因:batch设太大,或者imgsz和batch组合超过显存。YOLO 默认开amp混合精度,但某些老卡不支持。 解决:先把batch降到 4 跑通,再逐步往上加。或者设amp=False关混合精度,显存占用会降但速度慢一点。
6. 把 980 张图的模型推到边缘设备上的两个实用技巧
训练出best.pt只是第一步,真正落地要把它塞进巡检机器人或边缘盒子。第一个技巧是导出 ONNX 或 TensorRT 做推理加速。YOLOv8 直接支持:
yolo export model=runs/detect/train/weights/best.pt format=onnx opset=12 simplify=Truesimplify=True会做图优化,去掉冗余算子。导出后在边缘设备上用 onnxruntime 加载,比 PyTorch 原生推理快 1.5~2 倍。如果设备是英伟达 Jetson 系列,直接导 TensorRT:
yolo export model=runs/detect/train/weights/best.pt format=engine half=True device=0half=True用 FP16 精度,速度再提一截,精度掉不到 1 个点。注意 TensorRT 引擎和具体设备绑定,换设备要重新导。
第二个技巧是滑动窗口推理处理高分辨率管道图。管道内窥镜原图可能是 1920x1080,直接缩到 640 会丢细节。我一般把原图切成 640x640 的块,块间重叠 128 像素,每块单独推理,再把框映射回原图坐标做 NMS 合并。这样小目标召回明显提升,代价是推理时间线性增加。如果边缘设备算力有限,可以只对模型置信度低的区域做二次切块推理,算力花在刀刃上。
最后说个血泪经验:别在训练集上追求完美指标。我见过有人把 mAP 刷到 0.95,结果现场一跑,关节偏移和带扣全混。后来把这两类的标注重新对齐定义,mAP 掉到 0.86,但现场可用性反而上来了。管道缺陷检测的终点不是指标,是巡检工人愿意用、敢信。希望帮到你。
本文还有配套的精品资源,点击获取