简介航拍视角的路面病害检测数据集资源面向从事道路裂缝、坑槽、修补等目标检测算法训练的研究者与工程人员可用于YOLO系列、Faster R-CNN等模型的训练与效果评估。压缩包内共2000个文件以1999个Pascal VOC格式的xml标注文件为核心附带1个使用说明txt整体包体约166.21MB方便直接对接常见检测框架的VOC/YOLO数据管线。数据对应3302张道路图像的标注内容共7个类别包括Alligator crack、Longitudinal crack、Oblique crack、Pothole、Repair、Transverse crack等典型路面病害xml与txt两种标注形式并存适合作为监督学习训练集或算法验证基准。已有近1200人学习下载可直接利用现成标注开展模型迭代省去人工标注成本是路面病害检测项目起步阶段的高效数据支撑。1. 航拍路面裂缝数据集先别急着解压3302张图能做什么搞航拍路面病害检测最卡人的往往不是模型而是“带标注的图从哪来”。我拿到这份VOCYOLO格式、3302张、7个类别的数据集压缩包时第一反应不是急着解压而是先想清楚它能干什么VOC的XML方便人工核对边界YOLO的txt可以直接进训练管线两者都齐意味着从标注到训练只差一次正确的格式转换。适合两类人想验证航拍视角能不能稳定检出路面积水、裂缝的算法工程师以及给道路巡检产品做技术验证的团队。这篇把解压、转格式、训练、避坑一条线讲清楚照做能少浪费至少两个工作日。2. 从7z压缩包到可训练目录VOC格式解析与YOLO转换拿到这种“VOCYOLO双格式”的数据集最容易犯的错是直接把XML丢给YOLO训练。YOLO不读XML只读txt。所以第一步是看懂目录、理清类别顺序然后把VOC的绝对像素坐标换算成YOLO需要的归一化中心坐标。这一步不做对后面训练曲线再漂亮mAP也起不来。2.1 解压7z与目录结构先看清3302张照片怎么组织先别用图形界面双击解压很多解压工具在路径含中文时会“静默失败”——解压完少几张图程序不报错。我用命令行解压Linux下这样写7z x 航拍路面病害检测道路裂缝检测数据集VOCYOLO格式3302张7类别.7z -o./road_crack_datax表示保留压缩包内完整路径解压-o指定输出目录注意-o后面直接接路径中间不加空格。Windows下同样用 7-Zip 的命令行版本或者右键“提取到当前文件夹”后手动核对文件数。解压后标准Pascal VOC布局一般长这样road_crack_data/ ├── Annotations/ # 每张图对应的XML标注 ├── JPEGImages/ # 全部jpg原图 ├── ImageSets/Main/ # train.txt / val.txt / test.txt ├── labels/ # 转换好的YOLO txt └── classes.txt # 类别名一行一个先确认照片和标注数量是否对得上再确认类别数。find JPEGImages -name *.jpg | wc -l find Annotations -name *.xml | wc -l find labels -name *.txt | wc -l cat classes.txt3302张图正常情况 JPEGImages、Annotations、labels 三个目录里的文件数应该都接近3302。如果labels目录里少了文件说明数据集作者只给了VOC格式YOLO格式需要自己转如果classes.txt只有6行也要警惕是不是压缩包版本和标题描述不一致。任何时候以实际解压结果为准。2.2 VOC格式的核心XML标注与class顺序Pascal VOC的XML标注长这样核心信息是filename、size、object里的name和bndboxannotation filenameIMG_0001.jpg/filename size width1920/width height1080/height depth3/depth /size object nametransverse_crack/name bndbox xmin415/xmin ymin230/ymin xmax642/xmax ymax268/ymax /bndbox difficult0/difficult /object /annotationbndbox里的坐标是绝对像素值name是类别字符串。YOLO不认这个字符串只认classes.txt里的行号。比如classes.txt第一行是transverse_crack那transverse_crack的class id就是0。类别顺序一旦和训练配置里的names对不上所有目标都会被错分这是数据集使用中最隐蔽的坑。2.3 转成YOLO格式脚本实现与归一化坐标如果压缩包里已经有labels目录可以跳过这步。如果没有或者你想重新核对一遍标注就写个转换脚本。核心是用Python的xml.etree.ElementTree读XML再把绝对坐标按图片宽高归一化import os import xml.etree.ElementTree as ET # 以classes.txt实际内容为准顺序不能乱 classes [ transverse_crack, longitudinal_crack, alligator_crack, block_crack, pothole, repair_patch, bleeding ] def convert_one(xml_path, txt_path, img_w, img_h): tree ET.parse(xml_path) root tree.getroot() with open(txt_path, w, encodingutf-8) as f: for obj in root.iter(object): name obj.find(name).text.strip() if name not in classes: continue # 未定义的类别直接跳过 cls_id classes.index(name) xmin float(obj.find(bndbox/xmin).text) ymin float(obj.find(bndbox/ymin).text) xmax float(obj.find(bndbox/xmax).text) ymax float(obj.find(bndbox/ymax).text) # 归一化到[0,1]区间 x_center (xmin (xmax - xmin) / 2) / img_w y_center (ymin (ymax - ymin) / 2) / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h # 防止标注越界导致训练报错 x_center min(max(x_center, 0.0), 1.0) y_center min(max(y_center, 0.0), 1.0) w min(w, 1.0) h min(h, 1.0) f.write(f{cls_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}\n) # 批量处理 xml_dir road_crack_data/Annotations label_dir road_crack_data/labels os.makedirs(label_dir, exist_okTrue) for xml_name in os.listdir(xml_dir): if not xml_name.endswith(.xml): continue xml_path os.path.join(xml_dir, xml_name) img_name xml_name.replace(.xml, .jpg) # 读取图片实际宽高不能用固定值 # 常见做法是先用PIL读一遍图片尺寸 txt_path os.path.join(label_dir, img_name.replace(.jpg, .txt)) # convert_one(xml_path, txt_path, img_w, img_h)这段代码的逻辑是逐条读取XML里的目标框把左上角、右下角坐标换算成中心点加宽高的归一化坐标再写入txt。每行格式是class_id x_center y_center width height所有数值都在0到1之间。图片宽高必须用每张图实际尺寸不能用1920或1080硬套。如果同一类名在不同XML里写法和大小写不一致转换后就会漏标这也是VOC转YOLO最常见的隐性错误。2.4 三类数据集划分train/val/test的比例与随机种子YOLOv8训练需要自己划分数据集建议在转完格式后立刻划分并且保证图片和txt必须成对出现。3302张图按7:2:1划分大约是2311张训练、660张验证、331张测试。写一个简单脚本import os import random import shutil random.seed(42) base road_crack_data img_dir road_crack_data/JPEGImages label_dir road_crack_data/labels images [f for f in os.listdir(img_dir) if f.lower().endswith(.jpg)] random.shuffle(images) n len(images) train_imgs images[: int(n * 0.7)] val_imgs images[int(n * 0.7): int(n * 0.85)] test_imgs images[int(n * 0.85):] def copy_split(img_list, split_name): os.makedirs(f{base}/images/{split_name}, exist_okTrue) os.makedirs(f{base}/labels/{split_name}, exist_okTrue) for img in img_list: shutil.copy2(os.path.join(img_dir, img), f{base}/images/{split_name}/{img}) txt img.replace(.jpg, .txt) if os.path.exists(os.path.join(label_dir, txt)): shutil.copy2(os.path.join(label_dir, txt), f{base}/labels/{split_name}/{txt}) copy_split(train_imgs, train) copy_split(val_imgs, val) copy_split(test_imgs, test)随机种子固定成42别人复现你的训练划分时才能得到一模一样的结果。训练集和验证集严格按文件名切分不要用ImageSets/Main里的旧txt直接套因为如果压缩包里的列表是筛选过的子集切完很容易出现“验证集里2张图训练集里也有”的数据泄漏。3. 用YOLOv8训练路面病害模型环境搭建与命令行落地VOC和YOLO格式都准备好之后就可以进入训练环节。这里我用YOLOv8举例因为它在路面缺陷检测上开箱即用既是检测模型也是分类、分割模型的外壳。训练过程就是“数据yaml 预训练权重 参数”三者对齐的事。3.1 用PyCharm安装YOLO环境并验证GPU可用很多新手卡在环境上。在PyCharm里新建项目创建虚拟环境后在Terminal里执行python -m venv venv source venv/bin/activate pip install ultralytics然后验证GPU是否被识别import torch print(torch.__version__) print(torch.cuda.is_available())如果torch.cuda.is_available()返回False多半是装成了CPU版torch需要按CUDA版本重装pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118不用急着装最新版Ultralytics版本稳定即可。装完先跑一次自带权重yolo detect predict modelyolov8n.pt sourcehttps://ultralytics.com/images/bus.jpg能出结果说明环境和模型链路正常。3.2 编写YOLO yaml配置与模型选型训练前要写一个数据配置文件告诉YOLO数据在哪、有多少类、叫什么名字。注意names的顺序必须和classes.txt保持一致# road_crack.yaml path: /data/road_crack_data # 数据总目录绝对路径最稳 train: images/train val: images/val test: images/test nc: 7 names: 0: transverse_crack 1: longitudinal_crack 2: alligator_crack 3: block_crack 4: pothole 5: repair_patch 6: bleeding模型选型上yolov8n.pt参数最少适合快速跑通yolov8s.pt是平衡点显存8G以上就能训练yolov8m.pt对裂缝这类细长目标更友好但训练时间几乎翻倍。航拍裂缝尺寸小、对比度低我一般不从n直接上先拿s跑通再用m微调。3.3 训练参数imgsz、epochs、batch、patience怎么调命令行训练是最直接的方式yolo detect train \ dataroad_crack.yaml \ modelyolov8s.pt \ epochs150 \ imgsz640 \ batch16 \ patience20 \ cacheTrue \ device0imgsz是训练输入尺寸路面裂缝宽度可能只有几像素如果原图是1920×1080缩到640后裂缝基本糊掉。显存允许就直接上1280。batch决定单次进GPU的图片数16适合8G显存大图建议降到8。patience是早停耐心连续20个epoch验证集mAP不涨就自动停避免空跑。cacheTrue把图片预加载到内存训练速度快很多但16G内存以下建议换成cachedisk。3.4 训练过程怎么看损失函数与mAP50/75的监控训练时终端会刷一堆指标YOLO的损失函数不是单一值而是三个部分box_loss是检测框回归损失cls_loss是分类损失dfl_loss是分布焦点损失。正常情况三者都下降偶尔震荡没关系。想看更完整的变化曲线训练完直接读runs/detect/train/results.csvimport pandas as pd import matplotlib.pyplot as plt df pd.read_csv(runs/detect/train/results.csv) plt.plot(df[epoch], df[train/box_loss], labeltrain box_loss) plt.plot(df[epoch], df[val/box_loss], labelval box_loss) plt.xlabel(epoch) plt.ylabel(loss) plt.legend() plt.savefig(loss_curve.png)如果训练集损失降得很好验证集损失不降或反弹说明过拟合。如果两者都降但metrics/mAP50(B)纹丝不动说明类别标签有问题优先排查names顺序和标注框是否错位。4. 路面病害检测的7个类别与标注边界哪些坑让模型翻车数据集给了7个类别并不意味着模型能天然区分它们。路面病害本身在视觉上高度相似标注员的判断标准稍有偏差就是一场灾难。这章讲的是“类别定义”和“视觉边界”的问题比调参更能决定模型上限。4.1 裂缝 vs 龟裂 vs 修补类别定义决定AP常见路面病害标注会把横向裂缝、纵向裂缝、龟裂、块状裂缝、坑槽、修补、泛油分成7类。但“龟裂”本质上是一群相互交织的细小裂缝标注员有时把它框成一个大矩形有时把每条小裂缝分别框出来。前者让模型学到“大片纹理”后者让模型学到“单根线”同一个类别内部标注风格不统一AP自然被拉低。解决办法是在训练前把分类规则固化成文档裂缝类只标主裂缝轮廓龟裂类只标网状区域外接框修补类遇到“裂缝边缘有修补带”时优先标修补。如果数据集本身标准混乱YOLO会学到一种“平均特征”换一个场景立刻失效。4.2 阴影、水渍与车辙航拍视角的误检重灾区航拍视角下裂缝和很多干扰物长得几乎一样。树影投在路面上是一条条深色线很容易被当成横向裂缝雨后积水是暗色斑块和坑槽混淆车辙往往是两条平行压痕和纵向裂缝类似。更麻烦的是路面标线、接缝、伸缩缝也都呈线形。我在验证集上吃过这个亏模型在数据集上的mAP50超过0.75一换到有树影的实拍视频precision直接掉一半。后来做法是训练时把augment参数开到保守值并且刻意保留数据里的阴影样本不做过度的降噪预处理让模型学会区分“裂缝边缘尖锐、阴影边缘柔和”的差异。4.3 样本不均衡与图像尺寸小目标裂缝为什么难学3302张里7类分布通常不均衡。裂缝类可能占了一半泛油或者坑槽可能只有几百张。这种不均衡会让模型把多数类的权重拉高少数的类别mAP低得吓人。常见做法是给少样本开更高的copy_paste增强或者用类别权重。但更隐蔽的问题是尺寸一张1080p的航拍图里裂缝框可能只有30×300像素缩到640分辨率后变成10×100像素在YOLO的检测头里已经接近特征图的极限。如果显存够直接把imgsz提到1280如果不够就把大图切成瓦片比如切成512×512的块每块里的小裂缝能保留更多像素。后续推理也切块再用NMS把跨块的检测结果合并。这一步比换大模型有效得多。5. 避坑排查训练路面裂缝数据集常见的6个问题这一章都来自真实训练里的踩坑记录每一条都是“先看到现象再定位原因最后给出解决方案”。5.1 解压后图片打不开7z分卷与编码问题现象用自带归档工具解压后JPEGImages里有空文件某些XML打开是乱码甚至解压到一半报“CRC错误”。原因中文路径编码在解压时被转错最常见是Windows下解压工具默认按GBK处理而压缩包内部文件名是UTF-8另一个可能是压缩包下载不完整。解决先用7z t测试压缩包完整性7z t 航拍路面病害检测道路裂缝检测数据集VOCYOLO格式3302张7类别.7z测试通过后再解压Linux下强制使用UTF-8编码输出文件名LANGzh_CN.UTF-8 7z x 航拍路面病害检测道路裂缝检测数据集VOCYOLO格式3302张7类别.7z -o./road_crack_data解压完抽查3到5张图如果发现文件数为0或XML标签不完整重新解压不要手动修复。5.2 训练时mAP一直是0标签索引与类别映射错位现象训练和验证损失都在下降但metrics/mAP50(B)一直停留在0.0附近偶尔从0跳到0.001又掉回去。原因YOLO txt里的第一个数字是类别索引它按classes.txt的行号排序。如果你的 yaml 里names顺序和classes.txt不一致模型会把裂缝当龟裂把修补当坑槽类别全错mAP自然上不去。解决打开一个label文件检查cat road_crack_data/labels/IMG_0001.txt看到类似0 0.42 0.53 0.28 0.01的行后回看road_crack.yamlnames: 0: transverse_crack确保classes.txt第一行也是transverse_crack否则改yaml的顺序不要改txt。经验是直接编辑yaml里的names让顺序和压缩包里一致。5.3 显存OOM与训练中断再说batch与cache策略现象训练到第二个epoch直接CUDA out of memory或者训练中断后重启又从第一个epoch开始。原因batch开太大加上cacheTrue把整个训练集读进内存显存和内存同时吃紧。解决先用batch-1让YOLO自动找能塞下的最大batchyolo detect train dataroad_crack.yaml modelyolov8s.pt epochs150 imgsz640 batch-1 cachedisk device0中断后不要重跑用last.pt恢复yolo detect train resumeTrue modelruns/detect/train/weights/last.pt我用的是三选一的策略优先降低batch其次imgsz从1280降回960最后才考虑换小模型。OOM发生在验证阶段时多半是batch和输入分辨率共同作用。5.4 验证集虚空划分时路径分隔符和镜像问题现象训练提示Found 0 images in val.甚至train也是0。原因yaml里的路径用了反斜杠或者images/train目录下没有图又或者分割脚本把图复制到了错误层级。解决在yaml里全部用正斜杠绝对路径path: /data/road_crack_data train: /data/road_crack_data/images/train val: /data/road_crack_data/images/val然后在命令行手动检查find road_crack_data/images/train -type f | wc -l find road_crack_data/images/val -type f | wc -l如果两张图片数量都对但YOLO还是报0检查txt是否和图片同名。YOLO会通过图片名自动寻找同名txt只要有一张图缺txt整个目录就算0。5.5 航拍图片画幅太大要不要切块现象训练过程一切正常train loss很低val mAP50也有0.7但目视检测结果里裂缝框总是偏小或漏检。原因大图缩到640后原本就细的裂缝变成了2到3像素的短线特征完全丢失。解决给数据做切片。我用imgsz1280缓解过但4K航拍图还是不够必须切块。切块时保证标注框跟随图像平移每块固定512×512步长256让相邻块有重叠。目标只保留中心点落在块内的标注避免同一目标被切碎。训练后用同样的切块方式做推理最后把重叠框做NMS合并。5.6 模型泛化差换数据集前须做的预处理现象在这个训练集上mAP不错换一批不同时段、不同季节的航拍图漏检和误检明显增加。原因路面裂缝数据最容易过拟合到光照和背景纹理上。航拍图的亮度、对比度、道路材质变化太大模型学到的是“暗色线条”而不是“裂缝结构”。解决训练阶段开启适量的数据增强yolo detect train dataroad_crack.yaml modelyolov8s.pt imgsz1280 epochs150 batch8 augmentTrue degrees30 hsv_h0.02 hsv_s0.5 hsv_v0.3推理前做CLAHE自适应对比度增强能让裂缝边缘更明显。最重要是留一个独立测试集最好是不同路段的数据不要用和训练集同一批拍摄来源的图片做验证。6. 从验证到落地TTA、混淆矩阵和ONNX导出训练结束只是起点落地部署前还要做三件事用验证集生成混淆矩阵、开启TTA评估、导出ONNX。混淆矩阵能直观告诉你哪两个类别互相打架TTA能压榨最后的mAPONNX则让模型脱离Python环境跑起来。yolo detect val dataroad_crack.yaml modelruns/detect/train/weights/best.pt验证结束后runs/detect/val/confusion_matrix.png就是7个类别互相混淆的可视化。如果transverse_crack和longitudinal_crack之间有大量误判说明类别定义本身有问题需要回头修正标注而不是调阈值。TTA是对同一张图做翻转、缩放后再推理最后合并结果。YOLOv8命令行里直接加ttaTrue即可mAP一般能提升0.5到1.5个点但推理时间会翻倍适合离线评估不适合实时巡检。导出ONNX用一句话yolo export modelruns/detect/train/weights/best.pt formatonnx opset12导出后检查动态轴如果要在Jetson AGX Orin上跑opset12比默认兼容性更好。我习惯在导出前用imgsz定死推理尺寸比如1280这样TensorRT优化时不会因为动态shape多出额外开销。踩过最深的坑是看到mAP高就急着打包结果在嵌入式设备上因为输入尺寸过小裂缝框全部变成“半截线”。从那以后我都是在验证集上先跑TTA再导ONNX最后拿一段完全没有参与训练的航拍视频做目视回归。这套流程走完这个数据集才算真正落地。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?