新闻详情

新闻详情

首页 / 资讯中心 / 详情

焊接图像语义分割实战:6k数据集处理与模型训练避坑

发布时间:2026/10/1 23:49:04来源:尧图网络
焊接图像语义分割实战:6k数据集处理与模型训练避坑
简介面向深度学习与工业视觉学习者这套焊接图像语义分割数据集提供了超过6000张经过预处理的图像及标签文件可服务于自动化焊接缺陷检测气孔、裂纹、未融合等场景。资源共2000个文件其中包含1238个png、760个jpg图像数据另附1个类别说明txt与1个python脚本png/jpg文件用于模型训练与验证txt与py文件则帮助理解标签体系及数据处理流程压缩包采用7z格式整体约418MB。图像已做对比度拉伸与resize等增广操作可直接投入语义分割模型训练。目前已有368人学习下载。配套的参考博客提供了网络结构及训练思路便于读者从数据到模型快速落地适合正在接触分割任务或从事工业质检的深度学习工程师。1. 焊接图像语义分割数据集6k张带标签图像能不能直接训出产线级模型做工业视觉检测的同行大概都有过这种体验拿到一批焊接图像想跑语义分割结果大部分时间耗在标注上。这份焊接图像语义分割数据集最直接的价值是把超过6k张已经带像素级标签的图像送到你手上省掉一两周的人工标注周期。它覆盖的是焊接过程中最常见的视觉要素包括焊缝本身、飞溅、气孔这类区域组织成原图加对应标签的形式能直接进入深度学习训练管线。适合两类人一是做焊缝质量检测的工程师想快速验证语义分割算法在实际工业图上的表现二是刚入门语义分割的学习者手里缺真实场景数据拿它练手比在玩具数据集上跑通更有参考价值。但拿到手别急着训练先花半小时把数据结构和标签格式摸清楚后面能少踩一半坑。2. 打开数据集先做三件事目录结构确认、标注格式判定、场景与类别核对我拆数据集的习惯是宁可慢一点先把家底摸清。焊接图像和自然场景图不一样背景往往是金属表面、工作台或者暗场焊缝区域和缺陷区域形态差异大标签错一点训练出来的模型就会在产线上翻车。下面这三件事做完再谈训练。2.1 目录结构确认先分清 images 与 masks 的对应关系绝大多数带标签图像数据集都会按原图和标签分两个目录存放这份焊接图像语义分割数据集也不例外。常见的目录长这样dataset/ ├── images/ │ ├── weld_0001.jpg │ ├── weld_0002.png │ └── ... └── masks/ ├── weld_0001.png └── ...images目录里可能混着jpg和pngmasks目录里标签统一是png。这是因为原始采集设备输出的格式不一定统一而像素级标签为了保证不丢信息几乎都用无损png保存。我第一次拆这类数据的时候直接用glob(images/*)去读结果jpg和png混在一起跑到第200张图时发现有的图像没有对应mask训练器直接崩了。所以第一步先核对两侧文件名ls images | sed s/\.[^.]*$// | sort /tmp/img_names.txt ls masks | sed s/\.[^.]*$// | sort /tmp/mask_names.txt diff /tmp/img_names.txt /tmp/mask_names.txt这段命令的逻辑是用sed去掉扩展名把images和masks两侧的文件名统一成纯名称再sort排序后交给diff比对。diff输出为空说明两边文件名一一对应有输出就说明存在只有原图、没有标签或者文件名对不上的情况需要先处理。常见问题是有数据集在mask文件名后加了_label后缀这种在拼接路径时替换一下就行别依赖glob的目录顺序。2.2 标注格式判定像素值是灰度索引还是RGB伪彩色标签图有两种常见存法一种是单通道灰度图每个像素的值直接是类别索引0是背景、1是焊缝另一种是RGB图每个类别用一种颜色表示比如焊缝是绿色、缺陷是红色。这两种格式训练代码里处理方式完全不同拿到手第一件事就是读一张mask看shape和像素值分布import numpy as np from PIL import Image mask np.array(Image.open(masks/weld_0001.png)) print(shape:, mask.shape, dtype:, mask.dtype) unique_vals, counts np.unique(mask, return_countsTrue) for v, c in zip(unique_vals, counts): print(fvalue {v}: pixels {c}, ratio {c / mask.size:.4f})这段代码做了两层检查mask.shape如果是(H, W)说明是单通道索引图直接用如果是(H, W, 3)说明是RGB伪彩色要先做颜色到索引的映射。np.unique配合return_countsTrue能同时看到有哪些像素值以及每个值占了多大比例。焊接图像里背景通常占九成以上如果你看到某个类别ratio只有0.001它就是要重点关注的缺陷区域后面训练时loss权重必须调高。RGB格式下可以再加一段if mask.ndim 3: colors np.unique(mask.reshape(-1, 3), axis0) for i, c in enumerate(colors): print(i, c)reshape(-1, 3)把每个像素的颜色展开成一行然后按行去重得到的就是这张mask里用到的颜色列表顺序就是类别映射的依据。这一步能避免后面把彩色图当单通道读导致类别数膨胀到几十个的翻车。2.3 场景与类别核对缺陷检测、焊缝提取两类任务怎么选同一份焊接图像数据集不同人用会有不同的用法取决于你想解决什么问题。常见任务和对应类别划分任务模型输出目标典型类别划分难点焊缝提取焊缝区域前景/背景背景、焊缝边缘模糊、反光干扰缺陷分割缺陷像素精确定位背景、焊缝、飞溅、气孔类别极度不平衡、缺陷尺寸小拿到这份资源后先确认压缩包里有没有classes.txt或者label_info.txt没有也没关系用2.2里的unique值自己建一份映射。我习惯把0固定为背景其余类别按面积从大到小排序这样可视化时小目标靠后排查问题更容易。另外要确认图像分辨率分布焊接图经常是长宽比较大的宽幅图如果有的图是1920x1080、有的是1280x720后面模型输入的resize策略就得单独设计。这一步不花多少时间但能直接决定第3章转换脚本怎么写。3. 把原始标签喂进训练管线COCO转写、数据集划分与路径重写脚本很多开源分割框架默认吃COCO格式而这份数据集的原始标签往往是文件夹里的png mask不能直接拖进训练脚本。转换这一步不复杂但写错类别映射或者漏掉mask转RLE训练时就会报维度错误。我一般分三步走先确认类别映射再转COCO JSON最后做划分和路径重写。3.1 生成类别映射与可视化检查转换前先确认类别索引是连续的。有的mask里像素值只有0、5、7说明标注时用的枚举值留了空位这种情况下直接训练会让CrossEntropyLoss的类别数对不上数据集真实类别数。先写一个小函数抽样检查import os import numpy as np from PIL import Image def build_class_map(mask_dir, sample_num10): palette {} for name in sorted(os.listdir(mask_dir))[:sample_num]: mask np.array(Image.open(os.path.join(mask_dir, name))) if mask.ndim 3: mask mask[:, :, 0] for v in np.unique(mask): palette[int(v)] palette.get(int(v), 0) 1 return palette mask_dir masks print(build_class_map(mask_dir, 10))这个函数遍历前10张mask统计出现的像素值以及出现次数。if mask.ndim 3这行是防御性写法防止RGB格式被误当索引图。输出的字典里key是类别索引value是出现次数如果出现了不连续的数字就说明需要重映射。重映射的做法很简单把出现的值按大小排成0、1、2替换mask里的像素值。3.2 mask转COCO JSONpolygon与RLE怎么选语义分割的COCO标注里segmentation字段可以用polygon也可以用RLE。焊接缺陷形状不规则边界锯齿多polygon要转成闭合轮廓再采样点容易丢失细节RLE是按行编码的压缩掩码能精确保留每个像素的归属缺陷分割这种任务我用RLE更多。代码import json import os import numpy as np from PIL import Image from pycocotools import mask as mask_util def mask_to_rle(mask, class_id): binary_mask (mask class_id).astype(np.uint8) rle mask_util.encode(np.asfortranarray(binary_mask)) rle[counts] rle[counts].decode(ascii) return rle def build_coco(image_dir, mask_dir, class_map): coco { images: [], annotations: [], categories: [ {id: 0, name: background}, {id: 1, name: weld}, {id: 2, name: spatter}, ], } ann_id 0 for idx, img_name in enumerate(sorted(os.listdir(image_dir))): stem os.path.splitext(img_name)[0] img_path os.path.join(image_dir, img_name) mask_path os.path.join(mask_dir, stem .png) if not os.path.exists(mask_path): continue img Image.open(img_path) w, h img.size coco[images].append({ id: idx, file_name: img_name, width: w, height: h, }) mask np.array(Image.open(mask_path)) for class_id, class_name in class_map.items(): if class_id 0: continue rle mask_to_rle(mask, class_id) area int(mask_util.area(rle)) bbox [int(x) for x in mask_util.toBbox(rle)] coco[annotations].append({ id: ann_id, image_id: idx, category_id: class_id, segmentation: rle, area: area, bbox: bbox, iscrowd: 0, }) ann_id 1 if idx % 500 0: print(fprocessed {idx} images) return coco class_map {0: background, 1: weld, 2: spatter} coco build_coco(images, masks, class_map) with open(weld_train.json, w) as f: json.dump(coco, f)这段代码有几个参数容易踩坑。mask_util.encode要求传入的mask必须是np.asfortranarray格式否则会报内存顺序错误编码出来的RLE里counts是bytes类型json.dump不认必须decode成ascii字符串。toBbox返回的是浮点数组转成int再存。每个类别单独生成一条annotation如果某张图里没有这个类mask_to_rle会得到一个空的RLEarea是0这类空标注最好直接跳过否则训练时可能计算出NaN。这里的class_map只是示例具体以这份数据集里实际类别为准。3.3 数据集划分与路径重写固定随机种子比玄学可靠划分训练集和验证集时最怕每次跑出来的随机划分不一样导致对比实验失去意义。常见做法是固定随机种子也有人按文件名分组比如weld_前缀后面的编号前两位代表焊件批次按批次划分更能模拟产线换型号的场景。两种做法我给一份代码import random import os names sorted(os.listdir(images)) random.seed(42) random.shuffle(names) val_count int(len(names) * 0.15) val_names set(names[:val_count]) train_names names[val_count:] with open(train.txt, w) as f: for n in train_names: stem os.path.splitext(n)[0] f.write(fimages/{n} masks/{stem}.png\n) with open(val.txt, w) as f: for n in sorted(val_names): stem os.path.splitext(n)[0] f.write(fimages/{n} masks/{stem}.png\n)random.seed(42)固定了随机序列保证每次跑脚本生成的划分完全一致。val_count int(len(names) * 0.15)把15%的数据留作验证集焊件编号多、批次多的情况下我一般建议加大到20%让验证集覆盖更多未见过的工况。这里生成的txt文件每行是“原图路径 标签路径”PyTorch的Dataset里直接按行读就行不需要再写一套路径映射逻辑。4. 选型与训练配置UNet、DeepLabV3与焊接场景的参数匹配数据准备完下一步是选模型和定训练参数。焊接图像分割任务既考验边缘细节又要抗住噪声背景模型选型不能只看榜单上谁准。4.1 模型选型UNet、DeepLabV3 怎么匹配焊接场景模型骨干网络适合场景显存占用推理速度UNet自编码结构小数据集、边缘分割低快DeepLabV3ResNet50中等数据集、多类别中中SegFormerMiT-B2较大数据集、精度优先高慢这份数据集有6k张量级上UNet和DeepLabV3都够用。我的经验是如果主要做焊缝提取这种二分类任务UNet起步性价比最高训练一轮只要几分钟如果要做多类别缺陷分割比如区分飞溅和气孔DeepLabV3的空洞卷积能扩大感受野对小目标召回更好。SegFormer精度更高但对显存和训练时间的要求也上去了不是产线初版的选择。4.2 损失函数交叉熵、Dice 的组合策略焊接图像类别不平衡问题很严重焊缝区域占图幅比例小气孔更是只有几十个像素。只用CrossEntropyLoss模型会倾向把所有像素预测成背景。我常用的做法是把交叉熵和Dice Loss按比例混合import torch import torch.nn as nn import torch.nn.functional as F class DiceLoss(nn.Module): def __init__(self, smooth1.0): super().__init__() self.smooth smooth def forward(self, logits, target): probs F.softmax(logits, dim1) target_onehot F.one_hot(target, num_classesprobs.shape[1]).permute(0, 3, 1, 2).float() intersection (probs * target_onehot).sum(dim(2, 3)) union probs.sum(dim(2, 3)) target_onehot.sum(dim(2, 3)) dice (2 * intersection self.smooth) / (union self.smooth) return 1 - dice.mean() ce nn.CrossEntropyLoss(weighttorch.tensor([0.1, 1.0, 2.0])) dice DiceLoss() criterion lambda logits, target: 0.5 * ce(logits, target) 0.5 * dice(logits, target)Dice Loss的核心是计算预测概率图和真实标签的重合度smooth参数防止分母为0一般设1.0。target_onehot把GT索引转成one-hotprobs.shape[1]取类别数permute把channel维换到第2维保证和probs形状对齐。交叉熵的weight参数按类别传权重这里的0.1、1.0、2.0是示例背景权重低、缺陷权重高实际操作时按2.3里统计出的类别比例反着设。两个损失各取0.5既保留交叉熵的收敛稳定性又让Dice去拉高小目标的IoU。4.3 训练参数与数据增强焊接图像原始分辨率经常是1920x1080直接整图送进网络显存不够。我一般先做crop和缩放固定训练尺寸同时注意保持宽高比避免焊缝变形。一份可用的训练配置model: deeplabv3plus backbone: resnet50 input_size: [512, 512] batch_size: 8 base_lr: 0.01 lr_policy: poly power: 0.9 momentum: 0.9 weight_decay: 0.0001 num_epochs: 60base_lr从0.01起步poly策略让学习率随训练轮次衰减power控制衰减曲线形状一般0.9。batch_size设8是常见起点如果你的卡是12G显存这个配置跑得动显存小于8G就降到4配合梯度累积。数据增强我习惯用albumentationsimport albumentations as A transform A.Compose([ A.RandomBrightnessContrast(brightness_limit0.2, contrast_limit0.2, p0.5), A.GaussNoise(var_limit(10.0, 30.0), p0.3), A.HorizontalFlip(p0.5), A.VerticalFlip(p0.3), A.Rotate(limit15, border_mode0, p0.4), ])RandomBrightnessContrast模拟焊接产线不同工位的打光差异这是焊接图像里最关键的增强GaussNoise模拟相机传感器噪声但var_limit别设太大否则会盖过细小缺陷翻转增强对焊接缺陷这种方向性不强的目标有效。要注意的是如果原始图焊件位置有固定方向比如焊缝总是水平走向VerticalFlip可能会让模型学到错误的先验这类场景我一般只保留HorizontalFlip。5. 避坑手册焊接图像分割的五个常见翻车现场与排查顺序训练焊接图像分割模型的坑很多是数据集本身带来的。下面五条来自实际踩坑记录每条按现象、原因、解决三步写排查时按这个顺序过一遍。5.1 训练loss下降很快预测图却是全黑的现象训练到第30轮loss从1.2降到0.2验证集accuracy超过95%但把预测结果可视化后发现所有像素都被预测为背景焊缝和缺陷完全没分割出来。原因焊接图像里背景占比经常超过90%小缺陷区域只有几千像素。标准交叉熵在这种类别极度不平衡下会被背景主导模型只要全部输出背景类loss就已经很低了accuracy指标也虚高。解决换用Dice Loss或Focal Loss或者给CrossEntropyLoss的weight参数传入类别权重把缺陷类权重调到背景的5到10倍。更重要的一点是评估时不要只看整体accuracy要看每类的IoU和Dice背景类的高分数会掩盖所有目标类的失败。5.2 反光区域被分割成缺陷焊缝被漏掉现象模型对金属反光区域输出大片前景真实焊缝边缘反而断断续续。可视化叠加图上一块块白色高亮区域被标成缺陷产线上误检率居高不下。原因焊接图像里的镜面反光在像素值和纹理上和飞溅、气孔区域非常接近。如果训练集里反光区域没有对应的负样本标签网络就只能靠强度特征猜测反光处自然会被错判。解决一是在预处理阶段做亮度归一化比如CLAHE自适应直方图均衡压掉高光区域二是把反光区域单独归为一类让网络学习区分真实缺陷和光学假象三是在数据增强里加RandomBrightnessContrast让模型不要依赖绝对亮度这个特征。我一般先做预处理对比实验改一处看一组mIoU别同时改多个变量。5.3 验证集mIoU很高换个焊件批次就崩现象在原始数据集上按7:3随机划分验证集mIoU能到0.85把模型部署到另一个焊件批次现场实测mIoU跌到0.6以下焊缝边缘和缺陷位置全乱。原因随机划分让训练集和验证集来自同一批焊接过程相近的工艺参数、光照条件、焊件材料都太像了。模型学到的是这批数据的整体偏差而不是焊接缺陷的通用特征。解决按焊件批次或采集时间划分数据保证验证集里包含至少一个完全没见过的批次。如果文件名编号里能看出批次信息就按前缀分桶再划分如果数据集没提供分组信息先用k-means对图像的亮度直方图聚类按聚类结果划分能近似模拟工况变化。5.4 mask用PIL读成三通道类别数莫名翻倍现象转换脚本统计类别数明明数据集说明里写了3个类结果unique值有十几个loss和模型输出维度对不上训练直接报错。原因这份资源里的标签图可能是RGB伪彩色格式每类用一种RGB颜色。如果读图后没有做颜色到索引的映射而是直接把三通道数组当成数据每个不同的RGB组合都会被当成一个新类别。解决严格按2.2的流程先看mask.shape。三通道图先提取颜色列表建一个[(255,0,0), (0,255,0), ...]到[0,1,2,...]的映射表然后用np.select或者逐像素查表转成索引图。转完后再用np.unique验证类别数必须和数据集标注说明一致才能继续训练。5.5 resize时直接拉伸标签边界错位现象原图是1920x1080训练配置里input_size是512x512直接把图像resize成正方形。训练几轮后验证集mIoU始终在0.7左右上不去叠加可视化发现预测边界和真实标签边缘有明显偏移。原因直接拉伸改变了焊缝的宽高比。焊接缺陷往往呈细长形横向拉长或纵向压扁后模型学到的是变形的形状特征推理时对真实比例的缺陷分割自然偏大或偏小。解决不要直接resize先按短边等比例缩放让长边略大于目标尺寸再中心裁剪到正方形或者等比例缩放后pad到正方形。这样缺陷的相对比例不变只是图像被裁剪或填充。我一般把短边缩放到512长边保持比例超过512的部分随机crop既保证长宽比又保留缺陷全貌。6. 模型验证与进阶用mIoU联合曲线和可视化输出来把关产线很多初学者只看训练集和验证集的loss曲线认为loss降下来模型就能用。焊接图像分割不是这样loss下降只代表优化收敛不代表每个类都被正确学习尤其是气孔、飞溅这种小目标。我验证模型只看两个东西每类IoU的数值表和预测结果叠加在原图上的效果图。6.1 按类看IoU平均分掩盖气孔类没学出来import numpy as np def compute_per_class_iou(pred, gt, num_classes3): ious [] for c in range(num_classes): p (pred c) g (gt c) inter (p g).sum() union (p | g).sum() ious.append(float(inter) / float(union 1e-6)) return ious这段代码对每个类别单独计算交并比。p g是两个布尔数组按位与算出预测和GT重合的像素数union是并集加1e-6防止某个类别在一张图里完全没出现导致除零。逐张图跑完再按类取平均就能看到背景类IoU可能接近0.99气孔类平均IoU却只有0.3说明这个类基本没被模型学出来。只看mIoU均值会把背景的高分平均进去掩盖这个问题。6.2 可视化推理输出与原始图像叠加数值指标只能告诉你类别的平均表现边界抖在哪、小缺陷漏在哪必须靠人眼过一遍。常见做法是把预测结果转成彩色掩码叠到原图上import cv2 import numpy as np def overlay_prediction(image_path, pred, alpha0.5): img cv2.imread(image_path) overlay np.zeros_like(img) overlay[pred 1] (0, 255, 0) overlay[pred 2] (0, 0, 255) out cv2.addWeighted(img, 1, overlay, alpha, 0) cv2.imwrite(result_overlay.png, out)addWeighted的第一个参数是原图权重1第二个参数是彩色掩码权重alpha设0.5让预测区域半透明显示在原图上。绿色代表焊缝红色代表缺陷。保存后放大检查三处焊缝边缘是否平滑、缺陷区域是否完整、反光区域有没有误判。如果缺陷类别IoU不低但边缘有大量锯齿说明模型对边界像素的置信度不够后续可以加CRF后处理或者换更大感受野的骨干网络。我从那次全黑预测翻车之后养成了一个习惯不管用什么数据集训练语义分割模型先跑一小批预测把每类IoU打印出来再叠加到原图上肉眼过一遍。尤其是焊接图像这种背景大、目标小的场景accuracy高不代表能用只有每个类别的IoU和实际分割边界都过得了眼才敢往产线上放。希望帮到你。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

车载测试日志抓取实战:从adb logcat到问题定位 2026/10/2 2:11:07

车载测试日志抓取实战:从adb logcat到问题定位

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Piik:基于WebRTC的P2P屏幕共享,观众零安装浏览器即看 2026/10/2 2:11:00

Piik:基于WebRTC的P2P屏幕共享,观众零安装浏览器即看

这个标题一看就让人想点进去:GitHub 上又出现了一个 Star 数暴涨的开源项目,主打 P2P 屏幕共享,观众端零安装就能看。先给结论:如果你正在做远程演示、在线教学、临时协作这类事情,这个叫 Piik 的开源项目值得你花半小…

阅读更多 →
PyTorch Dataset类实战指南:核心方法、DataLoader协作与常见坑解析 2026/10/2 2:11:00

PyTorch Dataset类实战指南:核心方法、DataLoader协作与常见坑解析

PyTorch里最容易被新手玩坏的就是Dataset类。很多人写了两三行就跑起来,结果碰到点奇怪的数据就卡壳,或者数据集一大就慢得像蜗牛。我自己刚开始学的时候也被它坑过几次,所以这篇就打算把Dataset类彻底讲清楚:它到底是什么、为什么…

阅读更多 →
前端特殊字符避坑指南:Unicode、UTF-8与HTML解析的三重博弈 2026/10/2 2:11:00

前端特殊字符避坑指南:Unicode、UTF-8与HTML解析的三重博弈

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
WinForm上位机接入WebSocket:异步线程模型与断线重连实战 2026/10/2 2:10:53

WinForm上位机接入WebSocket:异步线程模型与断线重连实战

我最近在给一台设备做上位机,原来的数据链路是串口轮询,服务端改成 WebSocket 主动推送后,实时性一下子提上去了。但接进去的过程比预想痛苦得多——C# WinForm 里接入 WebSocket 客户端,网上搜出来的教程十个有八个是控制台代码一…

阅读更多 →
Presenton Mac App Store 构建实战:MAS 打包的证书、Profile 与脚本完整避坑指南 2026/10/2 2:10:47

Presenton Mac App Store 构建实战:MAS 打包的证书、Profile 与脚本完整避坑指南

Presenton Mac App Store 构建实战:MAS 打包的证书、Profile 与脚本完整避坑指南 【免费下载链接】presenton Open-Source AI Presentation Generator and API (Gamma, Canva, Beautiful AI, Decktopus, Presentations AI Alternative) 项目地址: https://gitcode…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉