墙面缺陷检测数据集5737张增强样本:YOLO与VOC格式实战避坑指南
发布时间:2026/10/1 20:06:59来源:尧图网络
简介本资源为墙面缺陷检测数据集面向从事建筑外墙病害识别、结构健康监测及计算机视觉目标检测的开发者与研究人员可用于训练YOLO系列或VOC格式的目标检测模型解决墙面裂缝、剥落、锈迹等缺陷的自动定位与分类问题。压缩包共2000个文件以1999个xml标注文件和1个说明txt为主整体约143.08MB内含JPEGImages、Annotations、labels三个文件夹分别存放5737张jpg图片、5737个xml文件与5737个txt文件VOC与YOLO两种格式可直接切换使用。数据集已做约60%增强图像清晰标注为矩形框覆盖7类标签Armatura in vista、Delaminazione、Fessura、Scaling、Spalling、Tracce di ruggine、Umidita总框数达15733其中Fessura与Armatura in vista样本较多Scaling相对稀少便于读者直接开展多类别检测训练与类别不平衡实验。目前已有666人学习下载适合作为墙面缺陷检测项目的数据基础与对比基准。1. 墙面缺陷检测数据集5737 张增强样本到底怎么用才不白瞎拿到「数据集墙面缺陷检测数据集yolovoc格式5737张已增强.zip」这个标题多数人第一反应是解压、看图片、跑train.py。但真正决定模型能不能落地的不是那 5737 张图本身而是你有没有搞清楚三件事缺陷类别定义是否统一、增强后的数据分布是否还像真实工地、YOLO 和 VOC 两套标注之间有没有隐藏的坐标偏移。墙面缺陷检测在建筑巡检、老旧小区改造、隧道衬砌检测里都是刚需场景裂缝、空鼓、渗水、剥落这几类缺陷的视觉特征差异极大模型很容易在「增强过头」的样本上过拟合。这份数据集适合两类人一是想快速验证 YOLO 系列在墙面场景下限的算法工程师二是需要给巡检系统做缺陷识别原型的产品团队。但如果你直接拿增强后的图当验证集指标会好看得离谱上线就翻车。2. 先搞懂墙面缺陷检测的数据集结构YOLO 与 VOC 双格式到底差在哪2.1 两种标注格式的目录组织与字段含义YOLO 格式和 VOC 格式最核心的差异不在文件后缀而在坐标表达和类别索引方式。YOLO 用归一化中心点加宽高VOC 用绝对像素的左上角加右下角。墙面缺陷检测里裂缝经常是细长条归一化后的宽高可能小到 0.003这时候如果增强时做了随机裁剪YOLO 的归一化坐标会直接失真而 VOC 的绝对坐标反而更容易排查。常见做法是先把压缩包解压到独立目录不要直接扔进datasets/里混着放。我一般会建一个wall_defect/根目录下面分images/、labels_yolo/、annotations_voc/、ImageSets/四个子目录。VOC 的Annotations里是 XMLYOLO 的labels里是 txt两者通过文件名主键对应。项目YOLO 格式VOC 格式标注文件.txt每行class x_center y_center w h.xml含bndbox的xmin/ymin/xmax/ymax坐标类型归一化 0~1 浮点绝对像素整数类别表达数字索引依赖classes.txt顺序字符串name直接可读增强后风险裁剪/缩放易导致坐标越界裁剪后需同步改size字段2.2 用脚本核对两套标注的一致性不要相信「已增强」三个字增强脚本如果没同步更新标注YOLO 和 VOC 会对不上。下面这段 Python 做三件事统计每个类别的实例数、检查 YOLO 坐标是否越界、抽查 VOC 与 YOLO 的框是否指向同一区域。import os import xml.etree.ElementTree as ET from collections import Counter def parse_voc(xml_path): tree ET.parse(xml_path) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) boxes [] for obj in root.findall(object): name obj.find(name).text bnd obj.find(bndbox) xmin int(bnd.find(xmin).text) ymin int(bnd.find(ymin).text) xmax int(bnd.find(xmax).text) ymax int(bnd.find(ymax).text) boxes.append((name, xmin, ymin, xmax, ymax)) return w, h, boxes def parse_yolo(txt_path): boxes [] with open(txt_path) as f: for line in f: parts line.strip().split() if len(parts) ! 5: continue c, x, y, bw, bh parts boxes.append((int(c), float(x), float(y), float(bw), float(bh))) return boxes voc_dir wall_defect/annotations_voc yolo_dir wall_defect/labels_yolo counter Counter() bad_yolo 0 for xml_file in os.listdir(voc_dir): if not xml_file.endswith(.xml): continue stem xml_file[:-4] w, h, voc_boxes parse_voc(os.path.join(voc_dir, xml_file)) for name, *_ in voc_boxes: counter[name] 1 yolo_path os.path.join(yolo_dir, stem .txt) if not os.path.exists(yolo_path): print(缺失 YOLO 标注:, stem) continue for c, x, y, bw, bh in parse_yolo(yolo_path): if not (0 x 1 and 0 y 1 and 0 bw 1 and 0 bh 1): bad_yolo 1 print(类别分布:, counter) print(YOLO 越界框数量:, bad_yolo)逻辑说明parse_voc读取 XML 里的图像尺寸和每个目标框parse_yolo读取归一化坐标。参数上bad_yolo统计的是中心点或宽高超出 0~1 的框这类框在训练时会被 YOLO 的 dataloader 直接丢弃或产生 NaN 损失。如果越界数量超过总框数的 1%说明增强时的裁剪没有同步修正标注必须回退到未增强版本重新生成。提示类别分布如果出现某个类别占比超过 70%比如「裂缝」远多于「空鼓」训练时要在data.yaml里考虑类别权重或者用重采样。3. 把 5737 张增强样本喂给 YOLOv8目录改造与训练参数3.1 从 VOC 转 YOLO 的转换脚本与四个边界坑虽然标题说同时有 YOLO 和 VOC但实际训练时我建议统一走 YOLO 格式因为 Ultralytics 系对 VOC 的支持需要额外配置。转换脚本本身不复杂坑在边界处理。import os import xml.etree.ElementTree as ET classes [crack, spalling, efflorescence, hollow] # 按你的实际类别改 class_to_id {c: i for i, c in enumerate(classes)} def voc_to_yolo(xml_path, out_path): tree ET.parse(xml_path) 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 if name not in class_to_id: continue bnd obj.find(bndbox) xmin max(0, int(bnd.find(xmin).text)) ymin max(0, int(bnd.find(ymin).text)) xmax min(w, int(bnd.find(xmax).text)) ymax min(h, int(bnd.find(ymax).text)) if xmax xmin or ymax ymin: continue xc (xmin xmax) / 2.0 / w yc (ymin ymax) / 2.0 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{class_to_id[name]} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}) with open(out_path, w) as f: f.write(\n.join(lines)) src wall_defect/annotations_voc dst wall_defect/labels_yolo os.makedirs(dst, exist_okTrue) for f in os.listdir(src): if f.endswith(.xml): voc_to_yolo(os.path.join(src, f), os.path.join(dst, f[:-4] .txt))四个边界坑第一xmin可能为负增强时的旋转填充会引入负坐标必须max(0, ...)第二xmax可能超过图像宽度同理要min(w, ...)第三转换后宽高为 0 的框要丢弃否则 YOLO 会报ZeroDivisionError第四类别名要和data.yaml里的names顺序完全一致差一个顺序训练出来的模型会把空鼓认成裂缝。3.2 data.yaml 与训练命令的最小配置目录改造完成后data.yaml是唯一入口。我一般这样写path: /data/wall_defect train: images/train val: images/val test: images/test nc: 4 names: [crack, spalling, efflorescence, hollow]训练命令用 YOLOv8n 先跑通不要一上来就上 x 版本yolo detect train \ data/data/wall_defect/data.yaml \ modelyolov8n.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/wall \ namebaseline参数说明imgsz640是墙面缺陷的常用输入裂缝在 640 下如果小于 8 像素建议切到 1024 但 batch 要降到 8。patience20表示 20 轮验证指标不升就早停增强数据容易过拟合早停比固定 epoch 更稳。lr00.01是 SGD 的初始学习率如果用 AdamW 要降到 0.001。注意增强后的数据集如果验证集也来自增强样本mAP 会虚高 10~20 个点。正确做法是从原始未增强图里切 15% 做验证集增强只作用于训练集。4. 增强数据集的避坑与排查5 个血泪教训4.1 现象训练 loss 正常但验证 mAP 极低原因验证集图片被增强过比如做了随机亮度、模糊、裁剪而训练集和验证集的分布不一致。解决把验证集换成原始未增强图或者至少保证验证集只做 resize 不做其他增强。4.2 现象模型把整面墙预测成一个巨大裂缝框原因VOC 转 YOLO 时某些 XML 的bndbox覆盖了整张图通常是标注人员偷懒或增强脚本把多个框合并了。解决在转换脚本里加一条规则宽高超过图像 80% 的框直接丢弃并人工抽查。4.3 现象训练到第 30 轮突然 BN 崩溃loss 变 NaN原因增强样本里存在全黑或全白的图或者某张图的标注框数量超过 300 个batch 内梯度爆炸。解决训练前用脚本统计每张图的框数量超过 100 的单独拿出来看同时把batch降到 8加ampFalse排除混合精度问题。4.4 现象YOLO 和 VOC 的类别数对不上原因VOC 的name字段有拼写变体比如crack和Crack被当成两类。解决转换前统一转小写并去空格用Counter打印所有原始类别名人工确认。4.5 现象增强后的图看起来很多但模型只学会认增强伪影原因增强方法里用了过强的色彩抖动或马赛克墙面缺陷的真实纹理被破坏。解决把增强强度调低hsv_h0.015、hsv_s0.7、hsv_v0.4是 Ultralytics 默认值墙面场景建议再减半马赛克增强mosaic0.5而不是 1.0。5. 用混淆矩阵和单类 AP 验证这份数据集值不值得继续投入训练完不是看一个 mAP 就结束。墙面缺陷检测的落地价值取决于单类表现尤其是裂缝这种细长目标。我一般会跑一次验证并导出混淆矩阵yolo detect val \ modelruns/wall/baseline/weights/best.pt \ data/data/wall_defect/data.yaml \ imgsz640 \ conf0.25 \ iou0.5 \ plotsTrue跑完后重点看confusion_matrix.png和val_batch0_pred.jpg。如果裂缝的 AP 低于 0.4而空鼓的 AP 高于 0.8说明数据集中裂缝样本的标注质量或数量有问题这时候继续加增强没意义应该回去补原始标注。另一个技巧是算一下每个类别的实例密度。5737 张图如果裂缝实例只有 800 个平均每张图 0.14 个裂缝模型很难学到。我习惯用下面这段代码快速统计import os from collections import Counter label_dir wall_defect/labels_yolo cls_counter Counter() img_with_cls Counter() for f in os.listdir(label_dir): if not f.endswith(.txt): continue seen set() with open(os.path.join(label_dir, f)) as fh: for line in fh: c int(line.split()[0]) cls_counter[c] 1 seen.add(c) for c in seen: img_with_cls[c] 1 for c in sorted(cls_counter): print(f类别{c}: 实例{cls_counter[c]}, 出现于{img_with_cls[c]}张图)如果某个类别的img_with_cls低于 200这个类别在 5737 张里基本学不动要么补数据要么在data.yaml里给它更高的损失权重。我自己的习惯是任何单类 AP 低于 0.5 且出现图数少于 300 的类别先不投入标注成本直接用规则后处理兜底等模型其他类稳定了再回头补。这套流程跑下来你就能判断这份增强数据集到底是省了事还是埋了雷。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网