新闻详情

新闻详情

首页 / 资讯中心 / 详情

基于YOLOv8的下水道缺陷检测数据集与训练实践

发布时间:2026/9/26 11:02:02来源:尧图网络
基于YOLOv8的下水道缺陷检测数据集与训练实践
简介一套面向下水管道缺陷检测的YOLO格式数据集专门为使用YOLOv5/v7/v8/v9/v10/v11等系列算法的目标检测任务设计。数据覆盖关节偏移、障碍物、裂纹、带扣、洞、公用设施入侵、碎片等多类典型缺陷适用于市政管道巡检、智慧水务与工业视觉场景帮助研究者与工程师快速启动训练与验证。包体共2000个文件压缩后约33.89MB。内含980个xml与980个txt标注文件分别对应VOC格式和YOLO格式另附39张图像与1个data.yaml配置文件。图像标注采用标准YOLO格式的类别、中心点、宽高相对坐标配合预设的数据集划分与配置可直接对接主流YOLO训练框架无需额外整理。目前已有417人学习适合需要真实场景缺陷样本、希望减少数据标注成本并快速验证模型效果的读者。压缩包目录结构清晰标注文件命名规范拿到后即可直接开展训练、测试与结果分析是进行管道缺陷检测算法实验与工程落地的实用数据基础。1. 下水道缺陷检测980张标注图要解决的核心矛盾管道CCTV检测车跑一圈回来视频素材动辄几十个G切帧后的有效画面里真正有缺陷的往往不超过三分之一。我见过太多团队卡在同一个环节算法没开始调先被标注拖了两周好不容易标注完类别口径又不统一返工更痛苦。这套下水管道缺陷检测数据集一共980张带标签图像覆盖七类最常见的管道缺陷——关节偏移、障碍物、裂纹、带扣、洞、公用设施入侵、碎片。标签按YOLO格式组织下载解压后可以直接接进YOLOv5或YOLOv8训练不需要做格式转换。它适合的是已经被数据卡住的人想快速验证YOLO在下水管道缺陷检测上能不能落地想给甲方搭一个可演示的算法demo或者做毕业设计和横向课题时需要一个能复现的基线数据集。2. 七类缺陷标签体系类目定义、YOLO格式与质检脚本这套数据集的价值一半在图像另一半在标签口径。下水管道缺陷分类在工程上是有讲究的七个类别对应的是CCTV管道检测里最常见的缺陷类型关节偏移和带扣属于接口类缺陷裂纹和洞属于结构破坏类缺陷障碍物、碎片、公用设施入侵属于管道功能受阻类缺陷。类别定义清楚了训练出来的模型才有工程意义否则只是“框了一堆东西”而已。2.1 七类缺陷长什么样哪两类最容易混淆先把七类缺陷的视觉特征和容易混淆点说清楚。我后面标注新数据时会直接把下面这张表打印出来贴屏幕上。类别视觉特征最容易混的类关节偏移两节管接口错位接口处张开或台阶状凸起带扣障碍物管道内径被沉积物、树根、大块杂物侵占碎片裂纹管壁线状裂缝可长可短有时带分支光照阴影带扣接口处的钢带、套环松动翘起或脱落关节偏移洞管壁局部缺失边缘清晰周围常有渗漏泥渍大面积裂纹公用设施入侵电力、通信线缆从检查井或破损处穿入管道内部障碍物碎片掉落的砖石、混凝土块、管道残片散落在管底障碍物标注时最容易翻车的是障碍物和碎片。我的血泪经验是障碍物强调“侵占管道的截面空间”比如树根长进管道、泥沙堆在管底碎片强调“掉落的离散块体”两者边界模糊时以矩形框内主目标为准不要一框多义。另一个容易翻车的是公用设施入侵有些标注员会把整条穿入的线缆全框进去矩形框里一半是背景正确的做法是只框“穿入管道可见段”框得紧不要框得松。裂纹这类线状目标在YOLO的矩形框表达下天生吃亏标注时宁可让框紧贴裂纹边缘也不要把周围管壁的阴影包进来。框松了模型学到的是“裂纹管壁阴影”换一段管道马上误检。2.2 YOLO格式标签解读与自动化质检脚本这套数据集的标签是标准YOLO格式每张jpg对应一个同名txttxt里每一行代表一个目标class_id x_center y_center width height其中x_center、y_center、width、height全部归一化到0到1之间除以图像宽高得到的。解压后建议先跑一遍质检脚本别直接开训练我吃过标签里混进非法坐标的亏。import os from pathlib import Path import cv2 def check_label(img_dir, label_dir, num_classes7): 检查YOLO标签中的类别越界、坐标越界和文件缺失 img_dir: 图像目录 label_dir: 标签目录 num_classes: 类别总数本数据集为7 img_paths list(Path(img_dir).glob(*.jpg)) bad_cnt 0 for img_path in img_paths: label_path Path(label_dir) / (img_path.stem .txt) if not label_path.exists(): print(f缺标签: {img_path.name}) bad_cnt 1 continue img cv2.imread(str(img_path)) img_h, img_w img.shape[:2] for line in label_path.read_text().strip().splitlines(): parts line.split() if len(parts) ! 5: print(f字段数不对: {label_path.name}: {line}) bad_cnt 1 continue cls_id int(parts[0]) xc, yc, w, h float(parts[1]), float(parts[2]), float(parts[3]), float(parts[4]) if not (0 cls_id num_classes): print(f类别越界: {img_path.name} cls{cls_id}) bad_cnt 1 if not (0 xc 1 and 0 yc 1 and 0 w 1 and 0 h 1): print(f坐标越界: {img_path.name} {line}) bad_cnt 1 print(f检查完成问题文件数: {bad_cnt}) # 使用示例 check_label(dataset/images, dataset/labels, num_classes7)这段脚本的逻辑很简单但很实用第一步确认每个图像文件都有同名标签文件第二步读图像真实宽高检查归一化坐标是否落在合法区间。归一化坐标越界最常见的来源是标注工具导出的格式不对或者图像resize后标签没有同步处理这类问题不查会在训练时被YOLO静默忽略导致mAP莫名偏低。还有一个很多人忽略的参数num_classes。这个值必须和data.yaml里的nc一致如果标注时类别编号从1开始而不是从0开始第一个类别会被直接判定为越界这时候不要急着改脚本先把标签生成逻辑改对。2.3 标注框精度对AP的影响两个一致性习惯980张图里的标签质量决定了模型上限。我在标注团队里定过两条硬规矩现在标注出来的数据基本不用返工。第一最小目标尺寸要有阈值。碎片和裂纹的小目标如果短边小于5个像素不标。这种目标在YOLO下采样后只剩一个点的信息强行标注只会变成标签噪声让模型在模糊预测和清晰预测之间摇摆不定。第二同一张图不同人标完框与框之间的IoU要大于0.7。低于这个值说明大家对目标边界的理解不一致需要回头重新对齐标注规则而不是继续往下标。3. YOLOv8复现流程Anaconda环境、数据划分与训练参数实测3.1 Anaconda环境配置与依赖版本YOLOv8的复现门槛不高但环境版本配错会浪费半天。我建议用Anaconda建独立环境Python版本选3.10PyTorch用CUDA 12.1对应的版本Ultralytics包选8.2.x这个稳定版本。conda create -n defect python3.10 -y conda activate defect pip install ultralytics8.2.0 torch2.1.2 torchvision0.16.2 --index-url https://download.pytorch.org/whl/cu121这里解释一下为什么固定版本torch 2.1.2和torchvision 0.16.2是配对的版本不匹配时训练可能直接崩在DataLoader阶段。Ultralytics选8.2.0而不是最新版本是因为后续版本对某些参数名做过调整教程和网上资料大多基于8.x早期版本踩坑时更容易搜到解决方案。安装完成后首次运行训练命令会自动下载yolov8s.pt预训练权重。如果网络受限可以手动把权重文件下载后放到当前目录训练命令里的model参数直接指到本地文件即可。3.2 数据集目录结构与train/val划分YOLOv8要求数据集按固定目录结构组织images下分train和vallabels下分train和val严格一一对应。误差在目录结构上是最亏的因为YOLO会把找不到标签的图像静默跳过只在启动时输出一行警告。dataset/ ├── images/ │ ├── train/ │ ├── val/ ├── labels/ │ ├── train/ │ ├── val/ └── data.yaml目录建好后用脚本按8:2划分训练集和验证集。这里有一个关键技巧不要按文件名随机划分要按管道来源划分。同一段管道连续帧里的缺陷高度相似随机划分会让验证集里混入训练集的“近亲”mAP虚高0.1以上换到真实管道上立刻现原形。import os import random import shutil from pathlib import Path # 假设原始文件在raw/目录下 src_img Path(raw/images) src_lbl Path(raw/labels) dst Path(dataset) train_ratio 0.8 random.seed(42) # 建立目标目录 for split in [train, val]: os.makedirs(dst / images / split, exist_okTrue) os.makedirs(dst / labels / split, exist_okTrue) # 收集所有图像文件名 names [p.stem for p in src_img.glob(*.jpg)] random.shuffle(names) split_idx int(len(names) * train_ratio) train_names, val_names names[:split_idx], names[split_idx:] # 复制图像和标签 for name in train_names: shutil.copy(src_img / f{name}.jpg, dst / images / train) shutil.copy(src_lbl / f{name}.txt, dst / labels / train) for name in val_names: shutil.copy(src_img / f{name}.jpg, dst / images / val) shutil.copy(src_lbl / f{name}.txt, dst / labels / val) print(ftrain{len(train_names)}, val{len(val_names)})shutil.copy是逐文件复制文件量大时稍慢但980张图完全够用。random.seed(42)保证每次运行划分结果一致这对后续对比实验很重要——同一个数据集如果每次划分不同训练结果就没有可比性。如果原始文件名里带管道编号或里程桩信息更稳妥的做法是按文件名前缀分组后划分我这边处理市政数据时基本都这么做。3.3 data.yaml与训练命令参数data.yaml是YOLOv8的数据集配置文件路径、类别数、类别名都在这里。注意names列表的顺序必须和txt标签里的class_id一一对应顺序错了模型训练出来预测结果全是乱的。path: dataset train: images/train val: images/val nc: 7 names: - joint_offset - obstacle - crack - buckle - hole - utility_intrusion - debris配置好data.yaml后训练命令如下yolo detect train \ datadataset/data.yaml \ modelyolov8s.pt \ epochs150 \ imgsz1280 \ batch16 \ patience20 \ device0 \ cacheTrue参数是我按管道缺陷场景试出来的经验值逐个说明epochs150是偏保守的设定配合patience20做早停验证集指标连续20轮不提升就自动停止省时间imgsz1280是这套数据的关键裂纹和碎片是小目标640分辨率下特征会被下采样抹掉1280能保留更多细节代价是显存占用翻倍batch16对应16G显存如果你的显卡只有8G建议降到8并关闭cache或者先用imgsz640跑通流程再调分辨率。cacheTrue会把图像预加载到显存里训练中不重复读磁盘能提速30%以上但会额外占用几个G显存。显存紧张时设cacheFalse即可。3.4 训练输出results.csv、混淆矩阵与权重选择训练结束后结果保存在runs/detect/train/目录下。里面最值得关注的是best.pt和last.pt这两个权重文件best.pt是按验证集mAP选出来的最优权重last.pt是最后一轮权重。推理和部署一律用best.ptlast.pt只用于断点续训。results.csv记录了每一轮的box_loss、cls_loss、dfl_loss和mAP指标。判断模型是否收敛不要只看loss要看验证集mAP50-95是否还有上升趋势。这个指标是测试集中每个类别的AP按IoU阈值0.5到0.95取平均能更真实反映目标定位精度。4. 训练与推理避坑五个踩坑记录从类别不平衡到误检4.1 类别不平衡洞和带扣的AP被裂纹压着抬不起来现象训练完成后看混淆矩阵裂纹的AP能到0.9以上但洞和带扣的Recall不到0.5几乎一半的真目标没框出来。原因这套数据集里裂纹样本占了将近四成而洞和带扣合计不到15%。YOLOv8默认的类别损失是平均计算的少数类正样本太少梯度被多数类淹没。解决先统计训练集每类的框数量再决定策略。from pathlib import Path from collections import Counter cnt Counter() for label_path in Path(dataset/labels/train).glob(*.txt): for line in label_path.read_text().strip().splitlines(): cls_id int(line.split()[0]) cnt[cls_id] 1 names [joint_offset, obstacle, crack, buckle, hole, utility_intrusion, debris] for i in range(7): print(f{names[i]}: {cnt[i]})如果两类样本数量差三倍以上常见做法有三种一是对少数类做过采样把含洞和带扣的图像复制到训练集但文件名要加后缀避免覆盖二是在训练参数里传class_weights按类别数量倒数给少数类更高的cls_loss权重三是把mosaic增强比例调大让每张训练图里能拼进更多小目标。我实测下来过采样加class_weights双管齐下最稳。4.2 小目标漏检imgsz640直接抹掉了细裂纹现象验证集上裂纹召回率低放大预测图才发现有些裂纹宽只有10个像素在640分辨率下经过五次下采样特征图只剩20×20细线状特征几乎消失。原因这不是模型问题是输入分辨率问题。YOLOv8默认imgsz640对细小缺陷不够友好。解决把训练和推理分辨率提到1280。显存不够时推理阶段可以做切片——把1920×1080的帧切成左右两半分别推理再合并结果。import cv2 import numpy as np from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) img cv2.imread(frame_0012.jpg) h, w img.shape[:2] mid w // 2 # 切成左右两半各自推理 left_res model.predict(img[:, :mid], imgsz1280, conf0.3)[0] right_res model.predict(img[:, mid:], imgsz1280, conf0.3)[0] boxes, scores, class_ids [], [], [] for res, offset_x in [(left_res, 0), (right_res, mid)]: for box in res.boxes: x1, y1, x2, y2 box.xyxy[0].cpu().numpy() boxes.append([x1 offset_x, y1, x2 offset_x, y2]) scores.append(float(box.conf)) class_ids.append(int(box.cls))切片推理的代价是拼接处可能漏检切的时候重叠10个像素合并后还要跑一次NMS把重复框去掉。逻辑上就是“切半→推理→坐标偏移→NMS合并”代码里offset_x是关键右侧半图的x坐标必须加回mid。4.3 标签文件名对不上训练时N images但M labels的隐患现象训练启动时YOLO提示找到了N张图像、M个标签M远小于N但训练还能跑完loss正常下降mAP却很低。原因部分图像的同名标签文件缺失或者标签目录里混入了其他文件中转残留的txt文件名对不上就被静默跳过。YOLO不会因为这些文件报错只会输出一行信息很容易忽略。解决训练前无论如何先跑一遍第2.2节的质检脚本保证每个jpg都有同名txt且txt里每行坐标合法。标签文件放在错误的路径是另一个翻车点YOLO只认images和labels同级目录放到annotations目录里等于没放。4.4 置信度0.25压不住潮湿管壁的误检现象验证集指标不差但把模型扔到完整管道视频上水迹、光照反光、管壁纹理全被当成碎片和裂纹一帧能出二三十个框。原因训练集图像相对干净现场视频的光照和管壁状态差异大模型输出的置信度整体偏低且分布偏移默认的conf0.25阈值压不住低置信度误检。解决不要用默认阈值在验证集上画F1-confidence曲线找最优阈值。管道缺陷场景我常用的现场阈值在0.35到0.45之间如果追求不漏检、容忍误检阈值往左移如果检测结果要进自动报告阈值往右移。4.5 现场光照一变模型Confidence整体漂移现象同一套权重白天拍的管道检测效果好雨天或夜间光照不足的视频漏检率升到40%以上。原因数据集采集环境相对单一模型学到的特征是“特定光照下的缺陷”光照分布一变特征分布就漂了。这类问题靠调参数解决不了必须往训练集里补充现场分布的数据。解决做法是把现有模型先压到新场景视频上做预标注人工修正后合并进训练集做第二轮训练。这就是第6章要展开的数据回灌闭环核心思路是用模型自己帮自己扩充数据。5. 验证优化混淆矩阵与置信度阈值把误检压下去5.1 用val模式单独跑验证定位易混淆类别训练结束后不要只盯着训练日志里的mAP单独跑一次验证拿到完整的混淆矩阵才能看清哪些类别在互相打架。yolo detect val \ datadataset/data.yaml \ modelruns/detect/train/weights/best.pt \ splitval参数说明splitval显式指定验证集避免YOLO在训练集和验证集上重复输出model参数指向best.pt。跑完后的confusion_matrix.png里非对角线上的亮点就是易混淆对。比如关节偏移和带扣互检碎片被错检成障碍物都在混淆矩阵上一目了然。这类混淆有两个修正方向一是回头检查标注看看是不是标注口径本来就没分开二是增加对应类别的难例数据让模型见过足够多的“边界样本”。5.2 F1-confidence曲线与现场阈值的确定方法YOLOv8验证结果里自带F1_curve.png横轴是置信度阈值纵轴是F1分数但后台生成的都是默认参数。我更习惯自己扫一遍置信度确定现场该用多少。from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) for conf in [0.25, 0.30, 0.35, 0.40, 0.45, 0.50]: metrics model.val( datadataset/data.yaml, splitval, confconf, iou0.45, verboseFalse ) print(fconf{conf:.2f} mAP50{metrics.box.map50:.4f})输出结果里挑mAP50下降不明显但预测框数量明显变少的阈值。比如conf从0.30调到0.40mAP50只降了0.02但整段视频的误检框从200个降到80个那0.40就是当前场景的最优阈值。注意这个阈值是场景相关的换一段光照完全不同的管道阈值要重新扫。5.3 损失函数侧微调cls_loss权重和box_loss的平衡YOLOv8的总损失由三部分组成box_loss负责定位框cls_loss负责分类置信度dfl_loss负责边界框回归的分布。管道缺陷场景里类别不平衡时最值得动的是cls_loss。YOLOv8的超参数文件里cls默认0.5左右box默认7.5左右。当少数类洞、带扣的AP明显偏低时我一般把cls调到1.0到1.5让分类误差在总损失里占更大比重。这个调整是通过训练命令传参实现的yolo detect train \ datadataset/data.yaml \ modelyolov8s.pt \ epochs100 \ imgsz1280 \ cls1.2cls从0.5调到1.2后常见变化是多数类裂纹的Recall轻微下降但少数类的AP能提升3到5个点。这在缺陷检测场景里通常是划算的——裂纹漏掉一条和洞漏掉一个后者造成的事故风险高得多。6. 数据回灌用难例框把下一轮训练集变厚的技巧第一轮模型跑通后最难啃的反而不是模型结构而是数据本身。我一般不会急着直接标注新视频而是用现有模型跑“难例回收”只标那些“模型拿不准”的框效率能高出一大截。import cv2 from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) # 假设video_path是一个管道cctv视频 cap cv2.VideoCapture(new_pipeline_video.mp4) frame_id 0 while True: ret, frame cap.read() if not ret: break # 每15帧抽一帧减少冗余 if frame_id % 15 ! 0: frame_id 1 continue # 用低置信度阈值0.15把模型的“犹豫区”全部捞出来 results model.predict(frame, conf0.15, iou0.5, verboseFalse)[0] for box in results.boxes: conf float(box.conf) # 只保留置信度在0.15~0.45之间的难例 if conf 0.45: x1, y1, x2, y2 box.xyxy[0].cpu().numpy().astype(int) cls_name model.names[int(box.cls)] crop frame[y1:y2, x1:x2] cv2.imwrite(fhard_examples/{cls_name}_{conf:.2f}_{frame_id}.jpg, crop) frame_id 1这段代码的核心逻辑是把置信度大于0.45的框过滤掉——那些是模型已经很确定的不需要人工参与把小于0.15的框也过滤掉——那些大多是噪声让标注员去看反而浪费时间只保留0.15到0.45这个“犹豫区间”它们要么是新的缺陷形态要么是模型易错样本。我一般让标注员只看这批裁剪图一小时能筛几百个难例筛完的框重新对齐到原图坐标补齐标签后合并进训练集跑第二轮训练。这个习惯让模型每迭代一版就更贴近现场真实分布。从那以后我每次拿到新场景的管道视频第一件事不是打开标注工具从零开始标而是先把模型压上去跑一遍难例回收把犹豫区的框抽出来筛。看似绕了一圈实际比全量标注省下至少一半时间模型效果还更稳。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

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

较早相关资讯

最新相关资讯

Claude Code + OpenRouter :接入超多免费大模型,告别 Token 焦虑 2026/9/26 12:21:37

Claude Code + OpenRouter :接入超多免费大模型,告别 Token 焦虑

Claude Code OpenRouter :接入超多免费大模型,告别 Token 焦虑 一句话速览:Claude Code 是 Anthropic 官方的命令行编程智能体,通过 OpenRouter 的 Anthropic Skin 端点接入,只需 4 个环境变量即可调用 13 款免费大模…

阅读更多 →
把刚才跑通的 Claude Code 全流程打包成 Skill:SKILL.md 骨架与验证清单 2026/9/26 12:21:37

把刚才跑通的 Claude Code 全流程打包成 Skill:SKILL.md 骨架与验证清单

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
open-code-review:用大语言模型实现自动化代码审查的工程实践 2026/9/26 12:21:30

open-code-review:用大语言模型实现自动化代码审查的工程实践

1. 从"PR 挂了三天没人理"到搭建 open-code-review我印象很深,上上个月周三下午,群里弹出一条消息:"各位,我的 PR 挂了两天半了,有没有人有空 review 一下?"三分钟后没人回&#xff0c…

阅读更多 →
AI算力模组连接器选型:PogoPin多元化方案与可靠性验证实践 2026/9/26 12:21:18

AI算力模组连接器选型:PogoPin多元化方案与可靠性验证实践

大家在AI服务器、液冷整机柜、GPU算力模组这些项目上也卷了蛮久了.真正干过硬件的小伙伴应该都有体会:算力芯片选型、散热方案、高速SerDes布线这几件事往往占据了80%以上的注意力,但最后整机在客户机房跑起来出问题,反而经常是“不起眼”的板…

阅读更多 →
Agent从脚本到产品:沙箱隔离与调度机制如何支撑百万级环境 2026/9/26 12:21:17

Agent从脚本到产品:沙箱隔离与调度机制如何支撑百万级环境

这两年做Agent应用,我最深的体感是:写Agent逻辑不难,真正让人头疼的是怎么把Agent稳定、安全、规模化地跑起来。模型输出不可控、工具调用越权、环境互相污染、一重启状态全丢,这些问题在Demo阶段还能忍,一旦要上生产&…

阅读更多 →
一些大语言模型(LLM)相关的开源项目:用 TaoToken 统一 Key 跑通本地工具链 2026/9/26 12:21:11

一些大语言模型(LLM)相关的开源项目:用 TaoToken 统一 Key 跑通本地工具链

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

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

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