简介本资源为焊接件表面缺陷检测数据集面向从事工业质检、机器视觉与深度学习目标检测的开发者及研究人员可用于训练与验证焊接件表面缺陷识别模型。数据集同时提供Pascal VOC与YOLO两种标注格式包含jpg图片及一一对应的xml与txt标注文件共2292张图像、2292份xml与2292份txt标注覆盖crease、crescent_gap、inclusion、oil_spot、punching、rolled_pit、silk_spot、waist_folding、water_spot、welding_line共10类缺陷。压缩包为7z格式内含约2000个文件以xml标注文件为主另附使用前必读说明整体约256.38MB目录结构清晰便于直接接入主流检测框架。目前已有913人学习下载适合需要快速构建焊接缺陷检测基线、扩充工业质检样本或开展多类别缺陷识别实验的读者参考使用。1. 焊接件表面缺陷检测数据集2292 张图、10 类缺陷VOC 与 YOLO 双格式到底怎么落地拿到一份工业质检数据集第一反应往往不是「有多少张」而是「标注能不能直接喂进训练脚本」。这份焊接件表面缺陷检测数据集给的是 2292 张 jpg 图片配套 2292 个 Pascal VOC 格式 xml 和 2292 个 YOLO 格式 txt10 个类别覆盖 crease、crescent_gap、inclusion、oil_spot、punching、rolled_pit、silk_spot、waist_folding、water_spot、welding_line。它解决的是焊接件表面缺陷检测从零标注成本高、类别定义不统一的问题适合做 YOLO 系列训练、VOC 格式迁移验证以及工业质检方向的数据集下载后快速复现。下面按「资源是什么 → 怎么用 → 坑在哪」拆开讲。2. 双格式标注拆解VOC xml 与 YOLO txt 的字段对应关系2.1 VOC xml 里到底存了什么VOC 格式的 xml 是这套数据集的「原始档案」。每个 xml 对应一张 jpg根节点是annotation下面挂folder、filename、sizewidth/height/depth、segmented以及若干个object。每个object里有name类别名、pose、truncated、difficult和bndboxxmin/ymin/xmax/ymax。焊接件缺陷的边界框通常比较紧凑rolled_pit 和 inclusion 这类小目标在 xml 里坐标差可能只有十几个像素读的时候别用整数截断保留原始值。常见做法是先用脚本统计一遍每类 object 数量确认 10 类是否均衡。下面这段代码直接遍历 xml 目录输出类别计数和框的宽高分布跑完心里就有数了。import os import xml.etree.ElementTree as ET from collections import Counter xml_dir Annotations # 替换为你的 xml 目录 cls_counter Counter() wh_list [] for fname in os.listdir(xml_dir): if not fname.endswith(.xml): continue tree ET.parse(os.path.join(xml_dir, fname)) root tree.getroot() for obj in root.findall(object): name obj.find(name).text cls_counter[name] 1 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) wh_list.append((xmax - xmin, ymax - ymin)) print(类别分布:, cls_counter) print(框数量:, len(wh_list)) print(平均宽高:, sum(w for w, _ in wh_list) / len(wh_list), sum(h for _, h in wh_list) / len(wh_list))逻辑说明ET.parse逐文件解析findall(object)拿到所有标注框cls_counter统计类别频次wh_list收集宽高用于判断小目标比例。参数上xml_dir指向解压后的 Annotations 目录如果 xml 和 jpg 混在一起先按扩展名过滤。跑完如果发现某一类只有几十个框训练时就要考虑过采样或类别权重。2.2 YOLO txt 的归一化坐标怎么读YOLO 格式每行是class_id x_center y_center width height全部归一化到 0~1。class_id 从 0 开始顺序必须和你的data.yaml里names列表一致。这套数据集的 10 类顺序在摘要里给了crease、crescent_gap、inclusion、oil_spot、punching、rolled_pit、silk_spot、waist_folding、water_spot、welding_line。如果你自己重排了类别顺序txt 里的 id 不会自动跟着变这是最常见的翻车点。验证 txt 和图片是否一一对应用下面这段脚本顺便检查有没有越界坐标。import os img_dir images txt_dir labels img_ext (.jpg, .jpeg, .png) img_names {os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.lower().endswith(img_ext)} txt_names {os.path.splitext(f)[0] for f in os.listdir(txt_dir) if f.endswith(.txt)} print(图片无标注:, img_names - txt_names) print(标注无图片:, txt_names - img_names) bad [] for fname in os.listdir(txt_dir): if not fname.endswith(.txt): continue with open(os.path.join(txt_dir, fname)) as f: for line in f: parts line.strip().split() if len(parts) ! 5: bad.append((fname, 字段数不对)) continue cls_id, x, y, w, h parts vals list(map(float, [x, y, w, h])) if any(v 0 or v 1 for v in vals): bad.append((fname, 坐标越界)) print(异常标注:, bad[:20], 总数:, len(bad))逻辑说明集合差集快速定位缺失配对逐行检查字段数和归一化范围。参数上img_dir和txt_dir按你解压后的实际目录改。如果图片无标注不为空说明有图没标训练时要么删图要么补标坐标越界通常是转换时除了零或用了未归一化的像素值。2.3 两种格式的选型理由VOC 适合做数据审查和跨框架迁移xml 可读性强LabelImg、Labelme 都能直接打开YOLO txt 适合直接进 ultralytics 训练省去转换步骤。这套数据集同时给两份等于把「审查」和「训练」拆开了。我一般先用 VOC 过一遍标注质量确认没问题再用 YOLO txt 训练避免在训练脚本里 debug 标注问题。常见做法是保留 VOC 作为存档YOLO txt 作为训练输入两边类别顺序对齐后不再改动。3. 从解压到训练YOLOv8 跑通 10 类焊接缺陷的完整步骤3.1 目录组织与 data.yaml 配置解压后先按 YOLO 训练的标准结构整理。ultralytics 默认找images/train、images/val、labels/train、labels/val。2292 张按 8:2 切训练集约 1833 张验证集约 459 张。切分时注意同一张图不能同时出现在两边否则验证指标会虚高。# 假设解压后图片在 images_all标注在 labels_all mkdir -p dataset/images/train dataset/images/val mkdir -p dataset/labels/train dataset/labels/val # 用 python 做可复现切分固定随机种子 python - PY import os, random, shutil random.seed(42) img_dir images_all lbl_dir labels_all pairs [(f, os.path.splitext(f)[0] .txt) for f in os.listdir(img_dir) if f.endswith(.jpg)] random.shuffle(pairs) split int(len(pairs) * 0.8) for i, (img, lbl) in enumerate(pairs): phase train if i split else val shutil.copy(os.path.join(img_dir, img), fdataset/images/{phase}/{img}) shutil.copy(os.path.join(lbl_dir, lbl), fdataset/labels/{phase}/{lbl}) print(train:, split, val:, len(pairs) - split) PY逻辑说明random.seed(42)保证每次切分一致方便复现shutil.copy保留原文件避免切分脚本出错后原始数据被破坏。参数上0.8是训练比例小数据集可以调到 0.85但验证集别少于 300 张否则 mAP 波动大。接着写data.yaml类别顺序必须和 txt 里的 id 严格对应。path: ./dataset train: images/train val: images/val nc: 10 names: 0: crease 1: crescent_gap 2: inclusion 3: oil_spot 4: punching 5: rolled_pit 6: silk_spot 7: waist_folding 8: water_spot 9: welding_linenc是类别数names的键就是 txt 里的 class_id。如果这里写错顺序训练不会报错但混淆矩阵会一塌糊涂这是最隐蔽的坑之一。3.2 训练命令与关键参数用 ultralytics 的 YOLOv8n 或 YOLOv8s 起步焊接缺陷属于小目标偏多输入尺寸别低于 640。下面命令直接跑。yolo detect train \ datadataset/data.yaml \ modelyolov8s.pt \ epochs150 \ imgsz640 \ batch16 \ lr00.01 \ patience30 \ projectruns/weld \ nameexp1逻辑说明modelyolov8s.pt是预训练权重小数据集上比从头训收敛快epochs150配合patience3030 轮没提升就早停batch16在 8G 显存上比较稳显存不够降到 8lr00.01是初始学习率如果 loss 震荡明显降到 0.005。imgsz640对 rolled_pit、inclusion 这类小缺陷比较友好再低容易漏检。训练过程中重点看三个指标box_loss是否稳定下降、mAP50是否在 50 轮后还在涨、cls_loss是否远高于box_loss。如果cls_loss居高不下多半是类别不平衡或标注里有错类。3.3 推理与结果检查训练完先别急着导出用验证集跑一遍推理肉眼抽查 20 张。yolo detect predict \ modelruns/weld/exp1/weights/best.pt \ sourcedataset/images/val \ conf0.25 \ saveTrue \ projectruns/weld/pred逻辑说明conf0.25是置信度阈值工业质检通常宁可多报不可漏报可以先设 0.2 看召回saveTrue把画框结果存下来。抽查时重点看 welding_line 这种长条缺陷有没有被截断以及 oil_spot 和 water_spot 有没有互相误判——这两类在灰度图上差异小是这套数据集的主要难点。4. 避坑与排查标注、类别、训练里最容易翻车的五件事4.1 现象训练 loss 正常但 mAP 始终接近 0原因data.yaml里names顺序和 txt 的 class_id 不一致模型学的是错位标签。解决用 2.2 的脚本统计每个 id 对应的类别名和 yaml 逐行核对。最稳妥的办法是直接从 VOC xml 重新生成一遍 YOLO txt保证两边同源。4.2 现象验证集图片无标注训练报「No labels found」原因切分时只复制了图片没复制 txt或者 txt 文件名和图片名大小写不一致。解决跑 2.2 的配对检查脚本确认图片无标注为空。Windows 解压出来的文件名有时带大写扩展名统一转小写再切分。4.3 现象小目标 rolled_pit 大量漏检原因输入尺寸太小或 anchor 不匹配。解决把imgsz提到 800 或 960同时开mosaic1.0增强如果显存不够用 YOLOv8m 换 YOLOv8s别硬降尺寸。另外检查 xml 里这些小框的宽高如果普遍小于 10 像素考虑切图训练。4.4 现象oil_spot 和 water_spot 混淆严重原因两类视觉特征接近标注边界本身模糊。解决先抽样看 50 张这两类的图确认标注是否一致训练时加label_smoothing0.1缓解过拟合或者在data.yaml里临时合并两类跑一版基线看 mAP 提升多少再决定是否保留细分。4.5 现象训练到一半 loss 突然变 NaN原因学习率过高或某张图标注坐标异常如宽高为 0。解决先用 2.2 脚本过滤掉宽高为 0 的框把lr0降到 0.001加warmup_epochs5。如果还崩检查是不是有图片损坏用 PIL 批量打开一遍。5. 进阶技巧用 VOC 原始 xml 反查标注质量与类别边界这套数据集的价值不只在「能训」更在「能查」。YOLO txt 是归一化后的结果丢了原始像素坐标反查标注质量得回到 VOC xml。我一般会做一件事把每个类别的框按宽高画散点图横轴宽、纵轴高正常标注应该聚成几团离群点就是可疑框。import os import xml.etree.ElementTree as ET import matplotlib.pyplot as plt xml_dir Annotations cls_points {} for fname in os.listdir(xml_dir): if not fname.endswith(.xml): continue root ET.parse(os.path.join(xml_dir, fname)).getroot() for obj in root.findall(object): name obj.find(name).text b obj.find(bndbox) w float(b.find(xmax).text) - float(b.find(xmin).text) h float(b.find(ymax).text) - float(b.find(ymin).text) cls_points.setdefault(name, []).append((w, h)) for name, pts in cls_points.items(): xs, ys zip(*pts) plt.scatter(xs, ys, s6, labelname) plt.legend(fontsize7) plt.xlabel(box width) plt.ylabel(box height) plt.savefig(box_dist.png, dpi150) print(类别数:, len(cls_points), 总框数:, sum(len(v) for v in cls_points.values()))逻辑说明按类别收集宽高散点图能直观看出哪些类的框尺寸异常。比如 welding_line 应该是细长条如果出现大量接近正方形的点大概率是标错了。参数上s6控制点大小类别多的时候图例会挤可以分两张画。跑完这张图再决定要不要清洗标注。另一个技巧是用 VOC xml 生成一份「类别-文件」索引训练后发现某类 mAP 低直接定位到具体图片复查。我习惯在训练前把这份索引存成 csv后面排查省很多时间。下面这段生成索引。import os import csv import xml.etree.ElementTree as ET rows [] for fname in os.listdir(Annotations): if not fname.endswith(.xml): continue root ET.parse(os.path.join(Annotations, fname)).getroot() for obj in root.findall(object): rows.append([fname, obj.find(name).text]) with open(cls_index.csv, w, newline) as f: writer csv.writer(f) writer.writerow([xml_file, class_name]) writer.writerows(rows) print(写入, len(rows), 条)逻辑说明每行记录 xml 文件名和类别名训练后哪类指标差直接grep这个 csv 找到对应图片。参数上没什么可调的注意 xml 目录路径别写错。这份索引配合前面的散点图基本能把标注问题在训练前拦掉大半。从那以后我每次拿到新数据集都强制先跑一遍配对检查、类别计数和宽高散点再动训练脚本。这套流程帮我省过至少两次通宵 debug。希望帮到你。本文还有配套的精品资源点击获取