简介这是一份面向桥梁健康监测与工业缺陷检测方向的目标检测数据集适合从事YOLO系列模型训练、算法验证及工程落地的开发者与研究人员使用可解决桥梁表面病害样本稀缺、标注不规范的问题。压缩包共2000个文件以1999个txt标签文件和1个Python脚本为主整体约123.37MB标签已统一处理为YOLO格式可直接接入YOLO各系列网络训练。数据集涵盖腐蚀、裂纹、白石灰、泄漏、剥落等5类典型桥梁缺陷包含超过3千张图像及对应labelme标注信息并附有class类别文本文件便于类别映射。配套的show脚本可将预测框绘制到图像上方便快速检查标注质量与可视化效果。目前已有419人学习下载适合需要构建缺陷检测基线、开展数据增强实验或进行模型对比的读者参考使用。1. 桥梁缺陷检测数据集从零构建一个能跑通的目标检测数据管线桥梁缺陷检测这件事真正卡住大多数团队的从来不是模型结构而是数据。你手里可能有一堆巡检拍回来的照片裂缝、露筋、剥落、渗水混在一起标注口径不统一正负样本极度失衡直接丢进 YOLOv8 训练mAP 看着还行一上真实桥面就集体翻车。桥梁缺陷检测数据集要解决的核心问题是把「现场采集的原始影像」变成「模型能稳定收敛、且能迁移到新桥的标注样本」。它适合三类人做交通基础设施巡检的算法工程师、想把目标检测落到工业缺陷场景的学生、以及需要给桥梁养护系统补一套视觉能力的后端开发者。这一章先把数据集的边界讲清楚——它检测的是可见表观缺陷不是结构内部损伤它的难点在长尾类别、极小目标和跨桥域偏移而不是类别数量本身。后面几章会从采集、标注、格式转换、训练参数一路讲到验证和避坑全部按可复现的路径来写。2. 桥梁缺陷检测数据集怎么采、怎么定类别先想清楚再按快门2.1 缺陷类别体系与标注口径的确定桥梁表观缺陷的类别划分直接决定后面标注成本和模型上限。行业里常见的做法是参考公路桥梁技术状况评定标准里的缺陷描述但那份标准是给人看的颗粒度不适合直接当检测类别。我一般会把它压缩成 5 到 7 类兼顾可标注性和业务价值类别名英文标签判定要点标注难点裂缝crack线性、有走向、宽度可辨细长目标框容易画歪露筋exposed_rebar混凝土剥落后钢筋外露与剥落边界重叠剥落spalling混凝土块状脱落与渗水区域混淆渗水seepage水渍、泛碱、变色边界模糊框大小主观蜂窝麻面honeycomb表面密集孔洞小目标密集易漏标锈蚀corrosion钢构件表面锈斑与渗水颜色接近类别定完之后必须写一份标注口径文档明确「一个缺陷一个框」还是「一片区域一个框」。裂缝如果分叉是整体一个框还是分段标注这个不统一后面模型学出来的框会非常玄学。我的习惯是裂缝按连通域整体标注分叉算同一个实例渗水按可见变色区域外接矩形标注不追求像素级边界。2.2 采集设备、角度与光照的覆盖策略数据采集阶段最容易犯的错是只在一个天气、一个时间段、一个焦段下拍。桥梁缺陷检测模型上线后面对的是全年全时段影像训练集如果只有晴天正午的顺光照片模型一到逆光或阴影区就废了。采集时我会强制覆盖这几个维度光照晴天顺光、晴天逆光、阴天散射光、桥下阴影、黄昏弱光每类至少占 10%。距离远景整跨概览、中景构件级、近景缺陷特写比例大约 2:5:3。角度正射、斜射 30 度到 60 度、贴近表面掠射掠射对裂缝最友好。设备手机、单反、无人机各拍一部分避免模型只认某一种成像风格。采集数量上如果只做单桥验证2000 到 3000 张原始图能撑起一个可用的基线要做跨桥泛化建议至少 5 座桥、每座 800 张以上且桥梁类型要有差异梁桥、拱桥、斜拉桥各来一点。提示采集时同步记录每张图的桥梁编号、构件类型、拍摄距离和光照条件这些元数据后面做分层抽样和误差分析时非常值钱事后补是补不回来的。2.3 从原始影像到可训练样本的清洗流程拍回来的图不能直接标。先跑一遍清洗把废片、重复片、严重模糊片剔掉。下面这段脚本做的是基础去重和模糊检测用的是感知哈希加拉普拉斯方差依赖 opencv 和 imagehashimport cv2 import os import imagehash from PIL import Image def is_blurry(img_path, threshold80): # 拉普拉斯方差低于阈值判为模糊阈值需按分辨率调整 img cv2.imread(img_path, cv2.IMREAD_GRAYSCALE) if img is None: return True return cv2.Laplacian(img, cv2.CV_64F).var() threshold def dedup_by_hash(img_dir, hash_size8, max_dist5): # 感知哈希去重汉明距离小于 max_dist 视为重复 seen {} keep, drop [], [] for name in sorted(os.listdir(img_dir)): path os.path.join(img_dir, name) try: h imagehash.phash(Image.open(path), hash_sizehash_size) except Exception: drop.append(path) continue dup False for k, v in seen.items(): if h - v max_dist: dup True break if dup: drop.append(path) else: seen[name] h keep.append(path) return keep, drop if __name__ __main__: src ./raw_images keep, drop dedup_by_hash(src) print(f保留 {len(keep)} 张剔除 {len(drop)} 张)逻辑说明is_blurry用拉普拉斯算子响应方差衡量清晰度方差越小越模糊阈值 80 是针对 1080p 以上图像的经验值手机小图要往下调。dedup_by_hash用 phash 把图像压成 8x8 指纹汉明距离小于 5 认为是同一场景的重复拍摄。参数hash_size越大越敏感max_dist越大去重越激进建议先设 5 跑一遍看剔除比例超过 30% 就说明阈值太松要收紧。清洗完之后做分层抽样保证每个光照、距离、桥梁类别在训练集和验证集里都有代表。不要随机切分随机切分会让同一座桥的相似图同时进训练和验证指标虚高这是血泪经验。3. 标注、格式转换与增强把数据喂进 YOLO 的完整链路3.1 标注工具选择与标注质量控制标注工具上LabelImg 适合小规模矩形框CVAT 适合多人协作和视频抽帧Labelme 适合以后要转分割。桥梁缺陷检测用矩形框就够我一般用 CVAT 起项目因为它的快捷键和属性配置能强制标注员填构件类型和缺陷严重度。质量控制靠三件事预标注、交叉复核、抽样验收。预标注用一个先在通用数据上训过的检测模型跑一遍标注员只做修正效率能提 2 到 3 倍。交叉复核是每 10 张抽 1 张让第二个人重标算 IoU 一致性低于 0.7 的批次打回。抽样验收是训练前随机抽 50 张可视化检查重点看小目标和边界模糊的渗水。标注格式统一用 YOLO 的 txt每行class_id cx cy w h全部归一化到 0 到 1。这里有个容易翻车的点cx cy 是框中心点不是左上角很多人第一次转格式就栽在这。3.2 VOC 与 COCO 转 YOLO 格式的脚本与边界处理现场标注工具导出的往往是 VOC XML 或 COCO JSON需要转成 YOLO txt。下面这段脚本处理 VOC 转 YOLO同时处理越界框和零面积框import os import xml.etree.ElementTree as ET CLASSES [crack, exposed_rebar, spalling, seepage, honeycomb, corrosion] CLASS_MAP {c: i for i, c in enumerate(CLASSES)} def voc_to_yolo(xml_path, img_w, img_h, out_path): tree ET.parse(xml_path) root tree.getroot() lines [] for obj in root.findall(object): name obj.find(name).text.strip() if name not in CLASS_MAP: continue # 未定义类别直接跳过避免训练时报错 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) # 裁剪到图像边界防止越界框导致归一化后为负 xmin max(0, min(xmin, img_w)) xmax max(0, min(xmax, img_w)) ymin max(0, min(ymin, img_h)) ymax max(0, min(ymax, img_h)) w xmax - xmin h ymax - ymin if w 1 or h 1: continue # 零面积或极小框丢弃 cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h nw w / img_w nh h / img_h lines.append(f{CLASS_MAP[name]} {cx:.6f} {cy:.6f} {nw:.6f} {nh:.6f}) with open(out_path, w) as f: f.write(\n.join(lines))逻辑说明CLASS_MAP把类别名映射成从 0 开始的整数顺序必须和训练时的data.yaml完全一致错一位模型就全乱。边界裁剪那两行是后悔药标注员手抖画出图像外的框很常见不裁归一化后会出现负数训练直接报错。w 1 or h 1过滤掉退化的框这种框在损失计算里会贡献异常梯度。参数上img_w和img_h必须读原图真实尺寸不能写死。如果图像被预处理过比如统一缩放到 640标注框也要同步缩放否则坐标全错。常见做法是转换前先统一图像尺寸再按统一尺寸转换标注。3.3 针对小目标和长尾类别的增强参数桥梁缺陷里裂缝和蜂窝麻面属于小目标渗水和锈蚀属于长尾。增强策略要分开对待。YOLO 训练时常用的增强有 mosaic、mixup、copy-paste、随机缩放和 HSV 抖动。对小目标mosaic 和随机缩放最有效mosaic 把 4 张图拼成 1 张等于变相增加小目标密度。但 mosaic 对小目标也有副作用拼接边缘会切断裂缝所以 mosaic 概率我一般设 0.5 到 0.7不拉满。copy-paste 适合长尾类别把稀少的渗水区域抠出来贴到其他图上能显著提升召回但贴的时候要注意光照一致性否则模型学到的是「贴上去的渗水」而不是真实渗水。HSV 抖动里色调 h 的幅度要小0.015 左右因为缺陷颜色是有物理意义的色调大改会让锈蚀和渗水混淆。饱和度和明度可以给到 0.7 和 0.4模拟不同光照。注意增强只对训练集做验证集和测试集保持原始分布否则指标不可信。很多人把增强写进 dataloader 全局生效验证指标虚高上线就露馅。4. 训练参数与评估桥梁缺陷检测模型的调参与验收4.1 YOLOv8 训练配置与关键参数含义数据管线通了之后训练本身反而简单。以 YOLOv8 为例data.yaml长这样path: ./bridge_defect train: images/train val: images/val nc: 6 names: [crack, exposed_rebar, spalling, seepage, honeycomb, corrosion]训练命令yolo detect train \ data./bridge_defect/data.yaml \ modelyolov8s.pt \ epochs200 \ imgsz1024 \ batch8 \ lr00.01 \ lrf0.01 \ mosaic0.6 \ mixup0.1 \ patience30 \ device0参数说明imgsz1024是关键桥梁缺陷小目标多640 会丢细节1024 显存吃得消就上 1024吃不消用 896 折中。batch8配合 1024 输入8G 显存大概能跑显存不够就降 batch 并开梯度累积。lr00.01是初始学习率lrf0.01是最终学习率系数余弦退火到初始的 1%。patience30是早停30 轮验证指标不升就停省时间。mosaic0.6和mixup0.1按上一节说的不拉满。模型规模上yolov8s是性价比之选yolov8n太快但小目标召回差yolov8m以上精度提升有限但推理慢边缘部署不划算。如果做跨桥泛化建议从yolov8s起步数据量上万再考虑yolov8m。4.2 mAP、召回与分桥验证指标怎么看才不骗自己训练日志里会打一堆指标重点看三个mAP50、mAP50-95、每类召回。mAP50 是 IoU 0.5 下的平均精度反映「框得差不多就算对」的能力mAP50-95 更严格反映框的精准度。桥梁缺陷检测里裂缝的 mAP50-95 通常明显低于 mAP50因为细长目标框的 IoU 很难做高这是正常的不用慌。真正要警惕的是整体指标高但分桥指标崩。做法是把验证集按桥梁编号分组分别算每座桥的 mAP。如果 A 桥 0.85、B 桥 0.4说明模型过拟合到 A 桥的成像风格跨桥泛化不行。这时候要么补 B 桥数据要么做域增强颜色抖动、风格迁移。还有一个坑是类别不平衡导致的指标幻觉。渗水样本少模型干脆不预测渗水mAP 里渗水那一类算 0但整体 mAP 被裂缝拉高看着还行。所以必须逐类看召回长尾类召回低于 0.3 就要专门处理加样本或调类别权重。4.3 推理部署时的输入尺寸与置信度阈值训练完导出模型部署时输入尺寸要和训练一致训练 1024 推理也 1024改成 640 精度会掉。置信度阈值conf默认 0.25桥梁缺陷场景建议调到 0.3 到 0.4因为误检一个裂缝的代价比漏检一个渗水高巡检报告里假阳性太多会失去信任。NMS 的 IoU 阈值默认 0.45密集小目标蜂窝麻面可以调到 0.5 到 0.6避免相邻缺陷被合并。from ultralytics import YOLO model YOLO(best.pt) results model.predict( source./test_images, imgsz1024, conf0.35, iou0.55, saveTrue )逻辑说明conf0.35过滤低置信度框iou0.55控制 NMS 合并力度。这两个值没有万能解要在验证集上画 PR 曲线按业务对误检和漏检的容忍度选点。我一般会跑一组 conf 从 0.2 到 0.5 的对比看召回下降的拐点在哪拐点前一点就是合适值。5. 避坑与排查桥梁缺陷检测数据集最常见的 5 个翻车现场5.1 现象训练 loss 正常下降但验证 mAP 一直 0.1 以下原因九成是标注格式或类别映射错了。常见的是data.yaml里names顺序和 txt 里的class_id对不上或者 cx cy 写成了左上角坐标。还有一种隐蔽情况是图像和标注文件名不匹配YOLO 按文件名找标注找不到就当负样本模型学了个寂寞。解决先拿 5 张图做可视化把标注框画回原图上看位置对不对。再检查data.yaml的names和转换脚本里的CLASSES是否逐字一致。文件名不匹配的写个脚本比对 images 和 labels 目录的文件名集合差集就是问题所在。5.2 现象裂缝检测召回很低框总是断成几截原因裂缝是细长目标标注时如果按连通域整体标框的长宽比极大YOLO 的 anchor 和损失对这种极端长宽比不友好。加上 mosaic 增强会切断裂缝模型学到的裂缝是碎片化的。解决两个方向。一是标注时对超长裂缝分段每段单独一个框降低长宽比二是训练时降低 mosaic 概率到 0.3 以下并开启scale增强让小目标尺度更丰富。如果还不行考虑用旋转框OBB任务YOLOv8 支持 OBB对细长目标更友好但标注成本会上升。5.3 现象模型在训练集上很好换一座桥就崩原因跨桥域偏移。不同桥的混凝土颜色、光照条件、拍摄设备差异很大模型学到了「这座桥的裂缝长这样」而不是「裂缝长这样」。数据采集时如果只覆盖一两座桥这个问题必然出现。解决补数据是最直接的每座目标桥至少 500 张。补不了就做域增强随机调整亮度、对比度、色调加高斯噪声和运动模糊模拟不同成像条件。进阶做法是用风格迁移把 A 桥的图转成 B 桥的风格但工程量大一般项目用域增强就够。5.4 现象渗水类别几乎检不出来召回接近 0原因长尾类别样本太少且渗水边界模糊标注一致性差。模型在损失里被裂缝等大类主导渗水的梯度被淹没。解决先确认渗水样本数量低于总样本 5% 就要补。补不了就用 copy-paste 增强把渗水区域抠出来贴到其他图上。训练时给渗水类别加权YOLO 不直接支持类别权重但可以通过过采样含渗水的图来间接实现。另外检查标注渗水框如果画得太大或太小模型学不到稳定特征要统一口径。5.5 现象推理速度远低于预期边缘设备跑不动原因输入尺寸 1024 加上yolov8m以上的模型在边缘设备上推理一帧要几百毫秒。很多人训练时用大模型大尺寸部署时才发现算力不够。解决训练和部署要一起规划。边缘部署优先yolov8n或yolov8s输入 640 或 768。如果精度不够用知识蒸馏把大模型的能力迁到小模型或者用 TensorRT 量化加速。量化会掉一点精度要在验证集上确认掉幅可接受再上线。6. 让数据集越用越值钱主动学习与版本管理的一个具体习惯数据集不是标完就完事它应该随着项目推进持续增值。我自己的习惯是每上线一轮模型就把线上误检和漏检的图回收人工确认后补进训练集下一轮再训。这套流程本质是主动学习重点在「挑哪些图来标」——不是随机挑而是挑模型最不确定的。具体做法是推理时输出每个框的置信度把置信度落在 0.3 到 0.6 之间的图挑出来这些是模型拿不准的样本标注价值最高。低于 0.3 的可能是纯背景高于 0.6 的模型已经会了都不用优先标。下面这段脚本做不确定性筛选from ultralytics import YOLO import os model YOLO(best.pt) uncertain [] for name in os.listdir(./unlabeled): path os.path.join(./unlabeled, name) results model.predict(path, imgsz1024, conf0.1, verboseFalse) boxes results[0].boxes if boxes is None or len(boxes) 0: uncertain.append((path, 0.0)) # 完全没检出也可能是难样本 continue confs boxes.conf.cpu().numpy() # 取置信度落在不确定区间的框比例 mid ((confs 0.3) (confs 0.6)).sum() / len(confs) uncertain.append((path, mid)) uncertain.sort(keylambda x: -x[1]) print(优先标注, [u[0] for u in uncertain[:20]])逻辑说明conf0.1放低阈值尽量多检出候选框再看置信度分布。mid是不确定框占比占比越高说明模型对这张图越没把握优先送标。完全没检出的图单独标记可能是新出现的缺陷类型价值也高。参数上0.3 和 0.6 这两个边界可以按业务调误检代价高的场景把下界提到 0.4。版本管理上数据集要像代码一样打 tag。每次补数据、改标注口径、调类别都记一个版本号训练配置里写清楚用的哪个版本。这样模型效果变化时能回溯是数据变了还是参数变了。我吃过亏改了一版标注没记录后来模型掉点查了两天才发现是标注口径变了。这套流程跑顺之后数据集会从「一次性成本」变成「持续资产」每轮迭代模型都更强标注量却不用线性增长。希望帮到你。本文还有配套的精品资源点击获取