☰
水下管道泄漏破损检测数据集:VOC转YOLO及YOLOv8训练
2026/10/1 23:29:41 网站建设 项目流程

简介:这是一份水下管道泄漏破损检测数据集,面向计算机视觉目标检测开发者和水下设施维护场景,提供Pascal VOC与YOLO两种主流标注格式,可直接用于训练和评测目标检测模型。压缩包内文件总数为2000,以xml标注文件为主,另含使用前必读.txt说明文件,整体大小约15.86MB;数据对应2069张水下管道图像,标注覆盖kebocoran(泄漏)、keretakan(破裂)两类缺陷,分别有1406框和1192框,总标注框2598个,全部由labelImg以矩形框完成。已有1269人学习下载。数据集标注规则清晰、格式完整,可帮助研究者免去繁琐的格式转换与标注整理工作,也适合作为水下缺陷检测、VOC/YOLO格式互通及模型训练调参的实战素材。

1. 水下管道泄漏破损检测数据集:把“VOC转YOLO”这一步从项目里删掉

水下管道泄漏破损检测数据集VOC+YOLO格式2069张2类别.7z,这个压缩包解决的是检测项目里最容易被低估的一环:数据格式对齐。做水下管网巡检、管道机器人视觉或市政排水管道状态评估的人通常不缺模型代码,缺的是能直接喂进YOLO训练脚本的标注。VOC的xml是绝对坐标,YOLO的txt是归一化中心点坐标,差一步换算,训练出来的框就会整体偏移。这个数据集把两边都备齐了,2069张图、泄漏和破损两个类别,解压后直接进yolov8训练自己的数据集,或者继续用VOC做迁移学习,都不需要再写转换脚本。适合正在找现成水下泄漏样本、又不确定标注边界是否可靠的工程师和学生。

2. 拆开压缩包:VOC与YOLO的字段映射和坐标换算

拿到这类数据集,第一件事不是急着训练,而是先确认压缩包里的标注是否真的和图片一一对应。水下图片噪声大、光照分布乱,转换脚本里任何一个想当然的字段都会在下游变成框偏移或漏检。这一章把解压、VOC字段读法、VOC转YOLO三件事一次讲清。

2.1 先解压:Linux下7z命令、目录预期与完整性校验

.7z格式在数据集分发里比zip更常见,因为水下原始图像纹理细节多,7z的压缩率通常比zip高一截,2049张图压下来能省不少流量。在Linux服务器上我一般直接用命令行解压,先测试再释放:

7z t pipe_leak_breakage_2069_2cls.7z 7z x pipe_leak_breakage_2069_2cls.7z -o./pipe_data

7z t是很多人会跳过的一步,但数据集的坑往往就在这:下载过程丢字节,解压到一半报CRC错误,你以为是密码或工具问题,实际上是文件本身坏了。7z x后面跟-o指定输出目录,不写-o时默认解压到当前目录,会把xml、txt、jpg全部摊在工作区里,后面训练时的路径要来回改,非常被动。如果是分卷压缩,命令写成7z x xxx.7z.001,7-Zip会自动读取后续分卷。

Windows下解压则尽量用官方7-Zip,Windows系统自带的“压缩文件夹”功能对7z的加密头和长文件名支持不完整,双击报错时先别怀疑密码。解压完成后,目录预期大致是两类标注并存:VOC/下是xml文件,YOLO/下是txt文件,两份标注描述同一批图片。如果只有其中一种,说明发布方把另一种格式当“赠送”选项,这时才需要跑转换脚本,后面2.3节会给出完整实现。

提示:解压后先执行find . -name "*.xml" | wc -l和find . -name "*.txt" | wc -l,两个数字应当相等且等于图片数量。这一步能在30秒内发现文件缺失或重复命名的严重问题。

2.2 VOC标注里最容易读错的三个字段:size、bndbox与object

VOC格式的核心是每个xml对应一张图片。解析xml时,新手最容易踩的坑是直接用bndbox里的xmin/xmax/ymin/ymax去做训练,却忘了这四个绝对坐标依赖size节点里的图像宽高。同一个标注框在1920x1080和640x360下语义完全不同,YOLO训练前又要把图缩放到imgsz,转换脚本一旦忽略size,输出的框就是百分比级的偏移。

xml里的关键结构大致长这样:

<annotation> <filename>pipe_00042.jpg</filename> <size> <width>1280</width> <height>720</height> </size> <object> <name>leak</name> <bndbox> <xmin>312</xmin> <ymin>240</ymin> <xmax>518</xmax> <ymax>331</ymax> </bndbox> </object> </annotation>

每张图有几个object节点就表示标注了几个目标。类别字段是name,这个数据集的2类一般命名为leak和break,但不同发布版本可能写成leakage或crack。训练前先用一条命令统计所有xml里出现过的类别名,不要拿着README里的类别说明想当然:

grep -h "<name>" VOC/*.xml | sort | uniq -c

这条命令同时能暴露出类别不平衡问题。如果leak占了90%以上,后面训练就需要针对break单独做增强或调loss权重,否则模型会对泄漏敏感、对破损迟钝。另一个常被忽略的点是filename字段:某些数据集的xml里写的图片文件名和实际文件名后缀不一致,比如xml写的是.jpg,盘里实际是.png,转换脚本按后缀去拼标签路径时会找不到对应文件。

2.3 VOC转YOLO的Python脚本:坐标归一化和类别映射的完整实现

YOLO的txt每行是class_id x_center y_center width height,五个值都必须归一化到0-1。转换逻辑本身不复杂,但两个细节很容易出错:一是bndbox四个值要先除以图片宽高,二是x_center是(xmin+xmax)/2再除以width,不是xmin除以width。下面这个脚本我用来处理多套VOC数据集,改一下CLASS_MAP就能复用:

import xml.etree.ElementTree as ET import os from pathlib import Path # 类别映射:顺序决定class_id,必须和训练时data.yaml的names一致 CLASS_MAP = {"leak": 0, "break": 1} def convert_voc_xml(xml_path, output_dir, img_width, img_height): tree = ET.parse(xml_path) root = tree.getroot() txt_name = Path(xml_path).stem + ".txt" lines = [] for obj in root.findall("object"): name = obj.find("name").text if name not in CLASS_MAP: print(f"警告: {xml_path.name} 含未定义类别 {name},已跳过") continue bndbox = obj.find("bndbox") xmin = float(bndbox.find("xmin").text) ymin = float(bndbox.find("ymin").text) xmax = float(bndbox.find("xmax").text) ymax = float(bndbox.find("ymax").text) # 归一化到[0,1],YOLO要求框坐标相对图片宽高 x_center = ((xmin + xmax) / 2) / img_width y_center = ((ymin + ymax) / 2) / img_height box_w = (xmax - xmin) / img_width box_h = (ymax - ymin) / img_height # 防止标注越界导致训练时警告,做一次夹紧 x_center = min(max(x_center, 0.0), 1.0) y_center = min(max(y_center, 0.0), 1.0) box_w = min(box_w, 1.0 - x_center) box_h = min(box_h, 1.0 - y_center) lines.append(f"{CLASS_MAP[name]} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}") if not lines: return 0 out_path = os.path.join(output_dir, txt_name) with open(out_path, "w") as f: f.write("\n".join(lines) + "\n") return len(lines) xml_root = "VOC" label_root = "YOLO/labels" os.makedirs(label_root, exist_ok=True) for xml_file in sorted(Path(xml_root).glob("*.xml")): tree = ET.parse(str(xml_file)) root = tree.getroot() # 推荐从xml的size节点取宽高,不用PIL读图 size_node = root.find("size") w = int(size_node.find("width").text) h = int(size_node.find("height").text) n = convert_voc_xml(str(xml_file), label_root, w, h) if n == 0: print(f"提示: {xml_file.name} 没有有效目标,检查类别名是否在CLASS_MAP中")

这段脚本的逻辑可以拆成三层看:外层遍历xml文件,中层遍历object节点,内层做坐标换算。最关键的参数是CLASS_MAP,它的字典顺序直接决定YOLO的class_id,训练时data.yaml里的names必须按相同顺序写,否则class_id=1会对应到错误的类别名。用(xmin+xmax)/2而不是xmin + box_w/2,数学上等价,但前者少一次计算,对于几千张图来说更稳。

还要说明的是,标题说“VOC+YOLO格式”意味着压缩包里大概率两套标注都已给出。这种情况下,这个脚本的价值不是必须跑一遍,而是用来做校验——随机抽5张图,把转换出的txt里的框画回原图,再和xml里的框比较IOU,但凡有一个框对不上,就要检查size字段和filename字段。水下图像经常被发布方做过去雾或裁剪,任何预处理都会改变原始尺寸,而xml里的size可能还停留在预处理前,这是唯一需要手工介入的地方。

3. 用YOLOv8训练自己的水下泄漏破损数据集:目录组织与参数修正

数据集准备到位后,接下来的问题就是怎么让训练不翻车。yolov8训练自己的数据集这件事,网上教程很多,但大多没讲清目录和数据yaml之间的配对规则。水下数据又有特殊性:目标小、对比度低、背景纹理杂,参数照搬COCO那套不一定合适。

3.1 目录组织:images和labels必须按train/val分好,data.yaml写对names

YOLOv8训练时要求的目录结构固定,常见做法是:

pipe_data/ ├── images/ │ ├── train/ │ ├── val/ ├── labels/ │ ├── train/ │ ├── val/ └── data.yaml

关键约束是:同一张图片的标注文件必须放在labels下的同名子目录里,后缀从.jpg换成.txt,主文件名不能变。如果一张图在images/train下,它的标签就得在labels/train下,目录层级必须一致。我一般用脚本划分而不是手动拖文件夹,方便复现:

import random import shutil from pathlib import Path random.seed(42) src_imgs = Path("pipe_data/images/all") src_labels = Path("pipe_data/labels/all") all_imgs = sorted(src_imgs.glob("*.jpg")) random.shuffle(all_imgs) val_num = int(len(all_imgs) * 0.2) # 8:2划分 def organize(img_path, split): dst_img_dir = Path(f"pipe_data/images/{split}") dst_lbl_dir = Path(f"pipe_data/labels/{split}") dst_img_dir.mkdir(parents=True, exist_ok=True) dst_lbl_dir.mkdir(parents=True, exist_ok=True) shutil.copy(img_path, dst_img_dir / img_path.name) # 标签文件和图片的主名必须一致 label_src = src_labels / (img_path.stem + ".txt") if label_src.exists(): shutil.copy(label_src, dst_lbl_dir / label_src.name) else: print(f"警告: {img_path.name} 找不到对应标签") for img in all_imgs[val_num:]: organize(img, "train") for img in all_imgs[:val_num]: organize(img, "val")

这段脚本固定的随机种子保证了每次划分结果一致,方便对比实验。脚本最后打印的警告非常关键——如果图片和标签文件主名对不上,训练时不会报错,只会导致标签参与率下降;比如200张图只找到150个标签,训练照样跑,但模型学到的类别分布是残缺的。

data.yaml的内容更直接:

train: pipe_data/images/train val: pipe_data/images/val nc: 2 names: ['leak', 'break']

nc必须与names列表长度一致,names的顺序就是类别索引的映射顺序。如果你在第2章的转换脚本里把leak设成class_id=0,那么这里的names列表也必须把leak放在第0位,否则模型训练过程中会把类别A的数据当成类别B去拟合,预测结果全乱。可以用一个简单方式验证:训练完随意挑两张val图片做预测,如果所有框都显示成同一个类别,大概率是names排序错了,而不是模型没收敛。

3.2 训练命令和三个必调的参数:batch、epochs、imgsz

数据组织好,训练命令本身很短。我通常用yolov8s.pt预训练权重起步,不用nano是因为水下小目标检测对特征表达能力有要求,s版本在精度和显存占用之间更平衡:

yolo detect train \ data=pipe_data/data.yaml \ model=yolov8s.pt \ epochs=200 \ batch=16 \ imgsz=640 \ project=./runs \ name=pipe_leak_v8s

第一次运行这条命令时会自动下载yolov8s.pt预训练权重,如果离线环境,需要手动下载权重放到当前目录,并把model=改成model=./yolov8s.pt。三个参数需要按实际情况调:

batch直接受显存限制。12G显存跑yolov8s和640分辨率,batch=16是安全的;如果显存只有8G,batch降到4会明显影响BatchNorm稳定性,这时优先把imgsz降到480,而不是硬扛batch=4。水下目标视野通常较窄,480分辨率并不会造成严重的精度损失。epochs我先给200,但配合早停观察loss曲线,一般110到150轮就收敛了,跑满200轮多半开始过拟合。imgsz默认640够用,原始图如果普遍是1920x1080的高分辨率,可以试试960,但显存占用接近翻倍,训练时间也明显拉长。

3.3 损失曲线怎么读:box_loss、cls_loss、dfl_loss哪一条先收敛

训练开始后,打开runs/pipe_leak_v8s/results.csv或直接看results.png。YOLOv8有三条核心loss:box_loss是边界框回归损失,cls_loss是分类损失,dfl_loss是分布焦点损失,它负责让框边缘更贴合目标。判断训练是否健康的标准是:三条loss在前20个epoch同步下降,只是下降幅度不同;如果某一条横盘超过30个epoch,就要回头检查数据。

box_loss高而cls_loss正常,通常意味着标注框本身有偏差——比如水下图片边缘弯曲导致真实管道轮廓和标注框不完全重合,模型怎么拟合都压不住回归误差。这时不要加训练轮数,而是检查标注框是否准确。cls_loss高而box_loss正常,则大概率是类别不平衡或两类目标外观太接近,早期能明显看到漏检集中在频次少的那一类。dfl_loss单独偏高时,我一般先检查是不是有大量小目标——dfl对小目标的边缘预测更敏感,如果数据集里泄漏点只有十几个像素,dfl_loss不降是正常的,可以尝试提升imgsz到960再看曲线。

提示:如果训练日志里出现NaN,优先怀疑batch太小和学习率太高,而不是网络结构。把batch调到16以上、学习率降到0.0005,这个数据集基本不会触发数值问题。

4. 水下数据集训练常见问题避坑指南:5条能省一周的排错记录

做数据集项目最浪费时间的就是排错。下面5条都是我在类似的水下检测任务里实际踩过的坑,按“现象、原因、解决”的方式记录,你大概率会遇到其中的一两条。

4.1 7z解压报错:密码正确却提示错误,问题多半不在密码

现象:执行7z x时报密码错误,或者Windows下双击压缩包解压到一半提示文件损坏。 原因:下载文件不完整,或者解压工具对7z加密头的兼容性有问题。还有一个常见现象是输出路径中包含空格或中文目录,部分终端环境下7z解析路径出错,给出误导性的密码错误信息。 解决:先执行7z t测试完整性,返回CRC Error就重新下载,不要反复试密码;路径全部改成纯英文数字;Windows下安装官方7-Zip后右键解压,不要用第三方压缩软件。这个问题和数据本身没关系,但会卡住你半天。

4.2 yolo训练中bn崩溃:loss突然变nan,问题定位到BatchNorm

现象:训练到某个epoch后loss变成nan,重启训练又在相近位置崩掉。 原因:batch过小时BatchNorm的均值和方差估计不稳,加上默认学习率对它来说偏高,BN统计量发散后loss直接爆炸。显存不足导致的batch=2、batch=4是这个问题的高发区。 解决:先把batch调到16,若显存不够就把imgsz降为480;再把学习率从默认的1e-2降到0.0005;如果还是nan,临时加上amp=False排除混合精度问题。用这个2069张的数据集,batch=16配合yolov8s在一个12G显卡上是可以跑完的,没有理由用batch=4硬撑。

4.3 类别不平衡:leak占绝大多数,break老被漏检

现象:训练完成后val集上break的recall明显低于leak,尤其在小目标上几乎检不到。 原因:水下破损磨损样本天然少于泄漏样本,统计标签分布经常能看到leak占了80%以上,break和它的差距会误导模型的分类边界。 解决:先统计两类频次,然后对break做离线增强——把break样本做亮度扰动、顺时针旋转15度、加高斯噪声,增强后的新图片同步生成对应txt标签。这一步不要去动leak的样本量,保持原始分布验证增强效果。如果离线增强后仍不均衡,评估指标改用macro mAP看少数类的平均表现。

4.4 yolo混淆矩阵总合不唯一:指标读法比数值更重要

现象:训练后生成的混淆矩阵,行求和和列求和都不等于100%,看起来“不对劲”。 原因:yolo的混淆矩阵不是单一归一化矩阵。按行归一化时每一行代表某个真实类别的召回率分布,按列归一化时每一列代表某个预测类别的精确率分布,两者无法同时满足行列和为1。此外background单独占一行一列,也会让数字看着不规整。 解决:读图前先确认坐标轴含义——行是Ground Truth、列是Predicted时,按行看召回率;想查某个类别的误检率就按列看。不要用“所有数字加起来是不是100%”来判断代码有没有bug,这本来就不是同一个归一化基准。

4.5 标注边界错位:xml里的size和真实图片不一致

现象:val集上mAP不低,但把模型放到实际水下视频里,检测框整体偏移,误差方向一致。 原因:VOC的xml里记录了图片尺寸,如果数据集发布方做过裁剪、去雾或缩放,但xml的size没有同步更新,转换出的YOLO坐标就带着系统性偏差。 解决:随机抽5张图,把xml里的bndbox画回原图,看框是否贴合目标。如果发现框全部偏右或偏上,直接用2.3节的脚本重新处理,并从预处理后的图片读取新尺寸。这个检查必须在训练前做,训练后再发现只能重新标注,代价最大。

5. 验证与进阶:从混淆矩阵到视频流实时检测

训练完别急着看mAP,先把val集的指标拆细。用yolo val拿到per-class AP后,我习惯额外盯漏检率而不是只盯mAP——水下泄漏检测漏掉一个点可能比误报十个更严重。把混淆矩阵按行归一化看recall,找出漏检集中在哪类目标的哪个尺寸区间。如果漏检集中在小目标,可以训练时开scale数据增强或者提高imgsz;如果集中在模糊帧,说明训练集缺少模糊样本,需要在数据层面补图而不是调参。

模型验证通过后,下一步是接实时视频流。水下管道机器人或固定点摄像头通常走RTSP协议,用YOLO的Python接口做流式推理非常直接:

from ultralytics import YOLO model = YOLO("runs/pipe_leak_v8s/weights/best.pt") source = "rtsp://user:pass@192.168.1.64:554/stream" results = model.predict( source=source, imgsz=640, conf=0.30, stream=True, max_det=50, ) for r in results: boxes = r.boxes.xyxy.cpu().numpy() # 检测框坐标 clss = r.boxes.cls.cpu().numpy() # 类别ID scores = r.boxes.conf.cpu().numpy() # 置信度 # 实际项目里在这里做连续帧逻辑:同一位置连续5帧出现才触发报警

stream=True表示开启生成器模式,逐帧处理而不是一次性加载整段视频,这对长时间值守很重要;conf=0.30是经验值,水下场景的置信度往往比陆地场景低一截,设太高会把真目标滤掉。每帧拿到boxes和clss后,连续帧逻辑要自己做——同一位置连续出现才报警,能过滤掉鱼和悬浮物在镜头前短暂遮挡造成的误报。

我自己在项目里的习惯是:任何数据集拿到手,先花10分钟把标签画回图上目检20张,再谈训练。这一步帮我躲过了至少三次格式错位和类别顺序颠倒的坑,比调任何超参都值得。这次这个水下管道泄漏破损检测数据集VOC+YOLO格式2069张2类别.7z,只要解压后你愿意先做一遍标签抽检,后面整个训练流程会很顺。希望帮到你。

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

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

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

立即咨询