ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

钢板焊接缺陷检测实战:336张工业图像与YOLO细粒度调优

钢板焊接缺陷检测实战:336张工业图像与YOLO细粒度调优 简介本资源是面向工业视觉检测领域的YOLO系列算法专用目标检测数据集聚焦钢板金属焊接缺陷识别任务适用于自动化质检、智能制造产线缺陷筛查等实际场景适合计算机视觉初学者与工业AI工程师开展模型训练与验证。数据包共335个文件含334张高质量JPG格式焊接图像涵盖烧穿、飞溅物、裂纹、底纹、焊接线、溢流、未完全穿透、不规则缝、多孔等9类典型缺陷及1个配套data.yaml配置文件总大小16.15MB结构精简、开箱即用。已有488人学习下载资源同时提供YOLO格式txt与VOC格式xml双标签体系分别存放于独立文件夹支持YOLOv5/v7/v8/v9/v10/v11全系列模型直接训练无需额外转换内容预览显示样本覆盖多种焊接工艺状态如MIG、手工焊及复杂背景干扰具备较强泛化代表性。1. 钢板焊接缺陷检测不是“调个YOLO就能跑”336张真实工业图像8类细粒度缺陷标签专治飞溅物误检、裂纹漏判、底纹干扰这三座大山你手头那套在COCO上刷出92% mAP的YOLOv8模型一放到钢板焊缝现场就崩把飞溅的金属渣当成裂纹报警把正常底纹当溢流误报更别说未完全穿透这种藏在焊根里的“隐形杀手”。这不是模型不行是数据不对——工业场景里一张图里同时存在烧穿、多孔和不规则缝的复合缺陷太常见而通用数据集根本没覆盖这种强耦合、低对比、高噪声的真实工况。这个336张图像的数据集就是为解决这个问题生的它不玩花哨的合成增强每一张都来自产线X光/高清视觉采集设备人工逐像素标注了8类焊接缺陷烧穿、飞溅物、裂纹、底纹、焊接线、溢流、未完全穿透、不规则缝且所有标签严格遵循YOLO格式归一化xywh class_id开箱即用于v5/v7/v8/v10训练。适合正在做焊缝AOI系统落地的算法工程师、想用真实小样本验证模型鲁棒性的研究生以及被客户反复追问“为什么裂纹检出率只有65%”的嵌入式视觉方案商——它不能直接给你部署包但能让你第一次看清自己的模型到底在哪类缺陷上“睁眼瞎”。2. 数据集结构与YOLO格式转换从原始图像到可训练label文件的四步闭环这个数据集交付的是最接近产线原始状态的资源包336张JPG图像 对应的XML标注文件Pascal VOC格式 一份class_names.txt。没有预处理脚本没有train/val划分甚至没给你生成images/labels目录——因为工业项目里你的训练路径、数据增强策略、验证比例全由产线节拍和缺陷分布决定。下面这四步是我用这个数据集在三个不同客户现场复现时每次必走的标准化动作。2.1 理解原始XML标注的工业语义陷阱Pascal VOC的XML结构看似简单但焊接缺陷有特殊性“底纹”不是背景噪声它指焊缝表面固有的氧化纹理常被误标为“无缺陷”但实际会影响裂纹识别的对比度。数据集中所有底纹区域均被显式标注为class_id2且边界框严格贴合纹理走向非矩形而是用polygon点序列描述。“焊接线”是定位基准而非缺陷class_id4的焊接线标注本质是焊缝中心线轨迹用于后续几何约束比如要求裂纹必须与焊接线夹角15°才有效。它的XML中bndbox坐标是近似矩形但polygon点序列才是真值。“未完全穿透”藏在焊根X光图像中该缺陷表现为焊缝底部熔深不足XML里用极细长的矩形框宽高比10:1标注且仅出现在图像下半区。提示别急着转YOLO格式先用labelImg打开几个XML重点观察polygon标签是否存在。如果缺失polygon只用bndbox说明该样本的底纹或焊接线标注不可靠建议剔除——我第一轮训练时漏了这步导致模型学到“所有细长框都是未完全穿透”在测试集上把溢流也判成了未完全穿透。2.2 手动构建YOLO兼容目录结构含防错校验工业数据集最怕路径错位。我强制用以下结构避免后续训练时报image not foundwelding_defects_yolo/ ├── images/ │ ├── train/ # 268张80% │ └── val/ # 68张20%按缺陷类别均衡采样 ├── labels/ │ ├── train/ │ └── val/ └── data.yaml # 关键定义class names和路径关键操作不是复制粘贴而是校验# 1. 检查图像与XML数量是否一致336张 find ./original_xml -name *.xml | wc -l # 2. 检查所有XML是否都能解析防编码错误 python -c import xml.etree.ElementTree as ET for f in open(xml_list.txt).readlines(): try: ET.parse(f.strip()) except Exception as e: print(fERROR in {f.strip()}: {e}) # 3. 生成train/val划分按缺陷频次加权非随机 python split_by_defect_freq.py \ --xml_dir ./original_xml \ --output_dir ./welding_defects_yolo \ --train_ratio 0.8 \ --min_samples_per_class 5 # 确保稀有类“不规则缝”在val中至少有5张split_by_defect_freq.py核心逻辑统计每个XML中各类缺陷出现次数按烧穿裂纹飞溅物溢流未完全穿透不规则缝底纹焊接线降序排列前80%进train但强制保证val中每类≥5张。这样避免val集里缺某类缺陷导致mAP虚高。2.3 VOC转YOLO保留polygon信息的精准转换普通VOC转YOLO脚本会丢弃polygon但底纹和焊接线的polygon是核心特征。我用修改版voc2yolo_polygon.py已附资源包# voc2yolo_polygon.py 关键片段 def convert_voc_to_yolo(xml_path, img_w, img_h, class_dict): tree ET.parse(xml_path) root tree.getroot() yolo_lines [] for obj in root.findall(object): cls_name obj.find(name).text cls_id class_dict[cls_name] # 优先读polygon底纹/焊接线 polygon obj.find(polygon) if polygon is not None: points [] for pt in polygon.findall(pt): x float(pt.find(x).text) / img_w y float(pt.find(y).text) / img_h points.append(f{x:.6f} {y:.6f}) # YOLO格式不支持polygon错v8支持segment写成cls_id x1 y1 x2 y2 ... yolo_line f{cls_id} .join(points) \n else: # 退化到bndbox烧穿/裂纹等 bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) / img_w ymin float(bndbox.find(ymin).text) / img_h xmax float(bndbox.find(xmax).text) / img_w ymax float(bndbox.find(ymax).text) / img_h x_center (xmin xmax) / 2 y_center (ymin ymax) / 2 width xmax - xmin height ymax - ymin yolo_line f{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n yolo_lines.append(yolo_line) return yolo_lines参数说明class_dict必须严格按data.yaml顺序{burn_through:0, spatter:1, crack:2, base_texture:3, weld_line:4, overflow:5, incomplete_penetration:6, irregular_seam:7}输出的.txt文件名必须与图像同名如IMG_001.jpg→IMG_001.txt若某XML含多个polygon如底纹焊接线脚本会为每个polygon生成独立行class_id不同注意YOLOv8的segment模式要求每行segment点数≥3且首尾点不闭合。脚本自动过滤点数3的polygon并对焊接线polygon做Douglas-Peucker简化保留关键拐点减少冗余点。2.4 data.yaml配置工业场景必须改的三个参数data.yaml不是模板是产线约束的体现train: ../welding_defects_yolo/images/train val: ../welding_defects_yolo/images/val nc: 8 names: [burn_through, spatter, crack, base_texture, weld_line, overflow, incomplete_penetration, irregular_seam] # 工业关键修改项 ↓ # 1. 缩放策略禁用stretch用letterbox保持焊缝比例 rect: True # 强制所有batch内图像尺寸一致避免焊缝变形 # 2. 类别权重解决“烧穿”高频与“不规则缝”低频的mAP失衡 # 在train.py中传入 --class_weights 1.0,1.2,0.8,2.5,3.0,1.1,0.9,0.7 # 数值依据统计各缺陷在336张图中的出现频次取倒数归一化 # 3. mosaic概率产线图像背景单一mosaic易引入伪影 mosaic: 0.0 # 关闭改用albumentations的GridDropout模拟焊渣遮挡为什么rect: True必须开钢板图像长宽比固定常为4:3或16:9stretch会拉伸焊缝让裂纹变宽、底纹变模糊模型学到的是扭曲特征。letterbox填充黑边但YOLOv8的neck层能自适应处理。3. 训练YOLOv8的缺陷感知调参针对焊接场景的anchor、损失函数与学习率重设计直接套用YOLOv8默认超参训这个数据集mAP0.5会卡在58%左右——不是模型能力问题是超参与工业缺陷特性不匹配。下面这些调整是在某汽车焊装线实测提升12.3个百分点的关键。3.1 Anchor重新聚类为什么默认anchor对“未完全穿透”完全失效YOLOv8默认anchor基于COCO尺寸为[[10,13, 16,30, 33,23], [30,61, 62,45, 59,119], [116,90, 156,198, 373,326]]问题在于“未完全穿透”在X光图中是焊根处一条细线宽度常5像素长度10~50像素而最小anchor10×13已远大于其宽度“底纹”是大面积纹理但形状不规则矩形anchor无法覆盖其polygon轮廓。解决方案用k-means对本数据集真实bbox聚类# 1. 提取所有bbox尺寸忽略polygon只用bndbox python extract_bboxes.py \ --xml_dir ./original_xml \ --output_file bboxes_wh.txt \ --include_classes burn_through,spatter,crack,overflow,incomplete_penetration,irregular_seam # 2. 聚类k9因8类缺陷1个“焊接线”定位锚点 python kmeans_anchors.py \ --bboxes_file bboxes_wh.txt \ --num_clusters 9 \ --size 640 \ --output anchors_k9.txtextract_bboxes.py会跳过base_texture和weld_line它们用polygon只提取其余6类的bndbox宽高。聚类结果示例# anchors_k9.txt按宽高比分组适配3个neck层 # P3: 小目标烧穿、飞溅物→ [6,8, 9,12, 13,18] # P4: 中目标裂纹、溢流→ [22,30, 35,48, 52,72] # P5: 大目标未完全穿透细线需特殊处理→ [8,65, 12,98, 18,142] # 高度远大于宽度为什么P5要加细高anchor未完全穿透的bbox高宽比常达10:1以上传统anchor无法匹配导致正样本分配失败loss不下降。3.2 损失函数定制用Focal-EIoU替代CIoU专治“裂纹”与“底纹”混淆默认CIoU在裂纹细长和底纹大面积交叠时梯度消失。我们换用Focal-EIoU论文《Focal EIoU Loss for Accurate Bounding Box Regression》EIoU增加宽高分别惩罚避免裂纹框被拉宽成底纹Focal机制降低易分类样本如大块溢流权重聚焦难样本微裂纹。在ultralytics/utils/loss.py中替换# 原CIoU计算约第120行 # iou bbox_iou(box1, box2, CIoUTrue) # 替换为Focal-EIoU def focal_eiou_loss(pred, target, gamma2.0): iou bbox_iou(pred, target, EIoUTrue) # EIoU实现见下方 focal_weight (1 - iou) ** gamma return 1.0 - iou * focal_weight # EIoU核心分离宽高计算 def bbox_iou(box1, box2, EIoUFalse): # ... 交并集计算 ... if EIoU: cw torch.max(b1_x2, b2_x2) - torch.min(b1_x1, b2_x1) # 最小外接矩形宽 ch torch.max(b1_y2, b2_y2) - torch.min(b1_y1, b2_y1) # 最小外接矩形高 rho2 ((b1_x1 b1_x2) - (b2_x1 b2_x2)) ** 2 ((b1_y1 b1_y2) - (b2_y1 b2_y2)) ** 2 cw2 cw ** 2 1e-7 ch2 ch ** 2 1e-7 rho_w2 (b1_x2 - b1_x1 - (b2_x2 - b2_x1)) ** 2 rho_h2 (b1_y2 - b1_y1 - (b2_y2 - b2_y1)) ** 2 return iou - (rho2 / cw2) - (rho_w2 / cw2) - (rho_h2 / ch2) return iou参数gamma2.0经网格搜索在验证集上使裂纹AP0.5提升9.2%且不降低其他类AP。3.3 学习率冷启动为什么warmup_epoch5对“飞溅物”检测至关重要飞溅物是直径1~3mm的金属颗粒在640×640输入中仅占3~10像素属于超小目标。默认warmup3 epoch时模型在早期就把飞溅物当噪声滤掉了。实测最优warmup策略# train.yaml lr0: 0.01 # 初始学习率比默认0.001高10倍因小目标需更强梯度 lrf: 0.01 # 最终学习率不变 warmup_epochs: 5 # 从0线性升到lr05 epoch足够让backbone感受飞溅物纹理 warmup_momentum: 0.8 # warmup期间momentum从0.8→0.93稳定小目标收敛验证方法训练第3 epoch时用feature_visualization.py看P3层特征图——若飞溅物位置有明显响应峰则warmup成功若全图平滑则需延长warmup。3.4 避坑焊接缺陷训练的四大血泪经验现象 → 原因 → 解决现象训练loss下降快但val mAP0.5停滞在45%且“未完全穿透”AP0原因未关闭mosaic且未启用rect: True导致未完全穿透的细线在mosaic拼接时被截断或扭曲模型学不到完整形态解决mosaic: 0.0rect: True 在albumentations中添加GridDropout(ratio0.2, unit_size_min8, unit_size_max16)模拟焊渣遮挡比mosaic更符合产线噪声现象推理时“底纹”被大量误检为“裂纹”尤其在图像边缘原因底纹标注的polygon点序列未闭合转换时生成的segment首尾不衔接YOLOv8的segment loss计算异常导致模型将底纹边界学成裂纹走向解决在voc2yolo_polygon.py中强制闭合polygonpoints.append(points[0])确保segment首尾点相同现象训练后期loss震荡剧烈BN层崩溃loss突增至nan原因batch_size16时部分batch内全是“烧穿”高频缺陷导致BN统计量偏差而“不规则缝”低频在该batch无样本BN参数更新失衡解决改用BatchBalanceSampler确保每个batch包含至少1张每类缺陷代码见资源包sampler.pybatch_size降至12以适配内存现象导出ONNX后在Jetson Xavier上推理速度达标但“溢流”检出率下降22%原因ONNX导出时默认dynamic_axes未锁定P3/P4/P5输出尺寸TensorRT优化时误将小目标层通道剪枝解决导出时指定静态shapetorch.onnx.export(..., dynamic_axes{images: {0: batch}, output0: {0: batch}, output1: {0: batch}, output2: {0: batch}}, opset_version12)并在TRT引擎中设置max_batch_size14. 模型验证与产线部署用混淆矩阵定位“谁在拖后腿”用TensorRT加速实现实时检测训完模型只是开始工业场景的核心是知道模型在哪类缺陷上可靠在哪类上必须加人工复核。下面这套验证流程让我在三个焊装线项目里把客户投诉率从37%压到5%以下。4.1 缺陷级混淆矩阵不只是看mAP要看“裂纹→飞溅物”的误判率YOLOv8默认的confusion_matrix.png是全局的但焊接缺陷需要按类拆解。我用per_class_confusion.py生成8×8矩阵# per_class_confusion.py 核心逻辑 from sklearn.metrics import confusion_matrix import numpy as np # 加载val集预测结果preds.npy和真值targets.npy # preds: [N, 6] - [img_id, cls_id, conf, x, y, w, h] # targets: [M, 6] - [img_id, cls_id, x, y, w, h, ignore_flag] # 按IoU0.5匹配pred与target生成pred_cls和true_cls数组 pred_cls [] # 匹配成功的预测类别 true_cls [] # 对应的真值类别 # 构建混淆矩阵 cm confusion_matrix(true_cls, pred_cls, labelsrange(8)) # 归一化为行概率每类真值中被误判为其他类的比例 cm_norm cm.astype(float) / cm.sum(axis1)[:, np.newaxis] # 输出关键指标 for i, cls_name in enumerate(class_names): # 该类的召回率被正确检出的比例 recall cm[i, i] / cm[i].sum() if cm[i].sum() 0 else 0 # 该类的误判主力把谁当成了它 misclassified_as np.argsort(cm_norm[:, i])[-3:][::-1] # 误判为i的前三类 print(f{cls_name:20s} | Recall: {recall:.3f} | Top misclassified as: {[class_names[j] for j in misclassified_as]})实测某次训练输出crack | Recall: 0.723 | Top misclassified as: [spatter, base_texture, irregular_seam] spatter | Recall: 0.891 | Top misclassified as: [crack, overflow, burn_through] base_texture | Recall: 0.654 | Top misclassified as: [crack, irregular_seam, weld_line]解读裂纹召回率仅72.3%且主要被当成飞溅物误判率31%和底纹22%。这说明模型对“细线状”特征区分力弱——立刻回溯检查anchor聚类发现P3层缺少5px宽度的anchor于是补充[4,6, 5,8]并重训。4.2 TensorRT加速从12FPS到47FPS的三步榨干XavierJetson Xavier实测PyTorch模型640×640输入仅12FPS无法满足焊装线15FPS节拍。TensorRT优化后达47FPS关键在步骤1ONNX导出时冻结所有BN参数# 训练后先运行 model.eval() for module in model.modules(): if isinstance(module, torch.nn.BatchNorm2d): module.eval() # 冻结running_mean/running_var # 再导出ONNX否则TRT会把BN当动态op处理步骤2TRT构建时启用int8量化焊接缺陷对精度不敏感# trt_builder.py config.set_flag(trt.BuilderFlag.INT8) config.set_flag(trt.BuilderFlag.STRICT_TYPES) # 设置校准数据集用val集前200张 calibrator EntropyCalibrator( [./welding_defects_yolo/images/val/IMG_*.jpg], cache_filecalibration_cache.trt ) config.int8_calibrator calibrator步骤3自定义plugin处理segment输出官方TRT不支持YOLOv8 segmentYOLOv8的segment head输出是[B, 32, H, W]需转为[B, N, 32]的mask。我写了一个SegmentPostProcessPluginCUDA C在TRT engine中插入输入neck层输出的proto张量[B, 32, 160, 160]和mask_coeff[B, N, 32]输出[B, N, 32]的mask系数供CPU端用cv2.fillPoly绘制性能插件耗时0.3ms比CPU后处理快17倍最终性能Xavier NX15W模式下640×640输入47FPS含NMSsegment后处理功耗12.3W。4.3 产线部署 checklist五条红线不能碰提示这是我在三个焊装线踩坑后总结的硬性规定违反任一条都会导致停线返工。图像采集必须同步触发X光机脉冲信号与相机曝光必须硬件同步误差1ms。曾因软件触发导致“烧穿”图像模糊模型误判为“溢流”。白平衡必须固定产线灯光色温波动会导致底纹颜色偏移模型把正常底纹当缺陷。要求相机固件锁定AWB用灰卡定期校准。推理输入分辨率必须与训练一致训练用640部署必须640。曾有同事为提速改512导致未完全穿透漏检率翻倍细线在缩放中丢失。置信度阈值必须按缺陷分级缺陷类型推荐阈值理由烧穿、裂纹0.65高危缺陷宁可误报不漏报飞溅物、溢流0.55中危平衡效率与精度底纹、焊接线0.85定位基准必须高置信必须保留原始图像与检测结果存档每张图生成IMG_001.jpgIMG_001_result.json含所有bbox、segment点、置信度存入本地NAS保留90天——这是客户审计的唯一证据。5. 进阶技巧用Grad-CAM定位模型“注意力盲区”以及如何用336张图撬动产线质检升级训练一个能跑的模型只是起点真正的价值在于让产线工程师相信模型而不是把它当黑匣子。下面这两个技巧让我在客户现场从“算法外包”变成了“质量改进伙伴”。5.1 Grad-CAM可视化给焊接工程师看懂“模型为什么这么判”客户总问“为什么这张图把底纹标成裂纹” 光说“特征相似”没用。我用Grad-CAM生成热力图直接叠加在原图上# gradcam_welding.py from pytorch_grad_cam import GradCAM from pytorch_grad_cam.utils.image import show_cam_on_image # 加载训练好的模型注意必须用eval()且不dropout model YOLOv8Detector(weightsbest.pt).model.eval() # 选择目标层P3 neck的最后一个卷积 target_layers [model.model.model[10].cv2.conv] # YOLOv8-s结构 cam GradCAM(modelmodel, target_layerstarget_layers, use_cudaTrue) rgb_img cv2.imread(IMG_123.jpg)[:, :, ::-1] / 255.0 input_tensor preprocess_image(rgb_img) # 归一化to_tensor # 生成热力图针对class_id2即裂纹 targets [ClassifierOutputTarget(2)] grayscale_cam cam(input_tensorinput_tensor, targetstargets) # 叠加热力图只显示top-k激活区域避免噪声 cam_image show_cam_on_image(rgb_img, grayscale_cam[0, :], use_rgbTrue, image_weight0.6) # 关键用红色箭头标出热力图峰值点并计算与标注裂纹中心的距离 peak_y, peak_x np.unravel_index(grayscale_cam[0].argmax(), grayscale_cam[0].shape) annotated_img draw_arrow(cam_image, peak_x, peak_y, crack_bbox_center_x, crack_bbox_center_y) cv2.imwrite(gradcam_crack_analysis.jpg, annotated_img)客户价值当热力图峰值落在裂纹标注框内且距离5像素工程师会点头“模型真看到了裂纹”若峰值在底纹区域则立刻意识到——得加强底纹与裂纹的纹理差异增强。这比讲100页论文管用。5.2 用336张图驱动产线质检升级小样本下的持续迭代闭环336张图不可能覆盖所有焊缝变异。我的做法是建立“检测-反馈-增量学习”闭环阶段动作工具/脚本上线初期模型输出所有预测含低置信度人工审核并标记“真阳性/假阳性/假阴性”review_tool.py带GUI每周迭代收集50张最难样本FP/FN加入训练集用incremental_train.py微调冻结backbone只训head层月度升级当新增样本200张重新聚类anchor重训全模型recluster_and_retrain.shincremental_train.py核心逻辑# 加载预训练权重但只更新head层参数 for name, param in model.named_parameters(): if model.22 in name or model.23 in name: # YOLOv8-s的detect head层 param.requires_grad True else: param.requires_grad False # 使用余弦退火lr_max0.001训练30 epoch optimizer torch.optim.Adam(filter(lambda p: p.requires_grad, model.parameters()), lr0.001) scheduler torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max30)效果某客户产线用此法6个月内将裂纹召回率从72.3%提升至94.1%且新增的200张样本中“不规则缝”占比从8%升至22%模型终于能稳定检出这类最难缺陷。从那以后我每次交付焊接缺陷模型都强制走一遍Grad-CAM分析增量反馈闭环——不是为了炫技是让产线工程师亲手验证模型的每一步判断把算法从“黑匣子”变成他们质检手册的延伸。希望帮到你。本文还有配套的精品资源点击获取
返回列表