ARTICLE DETAIL

资讯详情

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

铝片表面缺陷检测数据集构建:从采集标注到训练验证的完整实践

铝片表面缺陷检测数据集构建:从采集标注到训练验证的完整实践 简介面向铝片表面工业质检场景的缺陷检测数据集适合计算机视觉初学者及工业视觉算法工程师使用。包含412张铝片表面图像覆盖针孔、擦伤、脏污、褶皱四类常见缺陷全部按COCO格式标注位置与类别并提供train.json/valid.json划分便于直接开展目标检测模型训练与验证。资源包共402个文件其中400张jpg图片为主要数据2个json为标注与划分文件整体大小约15.74MB结构紧凑、便于本地快速加载。目前已有161人学习/下载。借助该数据可完成数据增强、特征提取、模型调参与评估等完整流程为生产线缺陷自动识别、质量管控及智能化改造提供标准化实验样本。1. 铝片表面缺陷检测卡点不是模型是数据集“铝片表面工业缺陷目标检测-数据集”这个标题听起来像是去找一份现成数据然后喂给模型真正做起来完全不是那么回事。铝片是强反光的金属面缺陷形态从亚毫米级的针孔、几十毫米的长划痕到边缘毛刺、水渍晕影尺度跨度大而且各类缺陷之间视觉特征差异很小产线上一个下午能拍成千上万张图真正干净、可用、缺陷类别完整的样本可能不到一百张。这篇笔记按采集、标注、格式转换、数据划分、模型验收的顺序把从零搭一套铝片缺陷检测数据集的方法与参数写清楚。适合正在做工业质检、手上有产线图却不知道怎么构训练集的工程师也适合刚入门目标检测、想拿真实工业场景练手的同学。2. 铝片缺陷检测数据集怎么建缺陷分类、打光与拍摄参数2.1 先把缺陷分类定下来六类典型铝片表面缺陷建数据集的第一步不是拍照而是把“要检出什么”这个分类决策定死。分类粒度决定了标注成本、模型难度和产线可用性。铝片表面缺陷常见的形态可以归成六类划痕、凹坑、脏污、边角缺损、氧化斑、压痕。划痕是细长条方向通常是轧制方向或者后加工方向宽度很窄但长度不小在低角度光下呈明显亮线或暗线凹坑是局部受到撞击形成的下陷点面积小但边界清晰脏污则是附着物形态不规则、灰度不均匀常常带水渍轮廓。边角缺损发生在大张铝片的边缘和卷材接缝处是锯齿状的缺料氧化斑是白色或灰白色斑块边界模糊压痕和凹坑在二维图像上非常像区别在于压痕是面状受力、边缘平缓凹坑是点状受力、边缘陡峭。分类粒度要遵循一个原则先能区分再谈精细。如果把凹坑和压痕合并成一类模型训练会很快准确率也好看但产线后续分拣无法区分这两种缺陷等于白做。反过来如果两类样本都不到五十个实例强行分开会让模型学不到稳定的类别边界。我一般会在项目启动时先定一个可扩展的标签体系同一个缺陷的模糊形态先标成子类等数据积累后再合并。2.2 采集方案怎么定光源角度、相机分辨率与拍摄角度铝片表面同时存在镜面反射和漫反射普通光源垂直照射时划痕这种微小的V形沟槽几乎不产生对比度拍出来的就是一片白亮。要让缺陷“显形”核心是控制光源角度划痕和凹坑需要用低角度环形光或者同轴光利用沟槽边缘的散射光形成明暗差异脏污和氧化斑则需要漫射光避免反光掩盖灰度差异。常见的光源与缺陷类型匹配见下表。缺陷类型推荐光源光源安装角度成像特征划痕低角度条光/环形光10°-20°亮线或暗线对比度明显凹坑同轴光或低角度环形光15°-30°中心暗、边缘亮脏污漫射板面光45°-60°灰度与背景差异氧化斑漫射板面光45°-60°灰白色斑边界模糊压痕/凹坑区分多角度组合光0°/30°/60°各拍一张阴影方向不同深度信息显现边角缺损背光或高角度光60°-75°轮廓缺失清晰相机分辨率的设定要按“最小可检缺陷”反推不能用一张图看着好看来定。经验公式是缺陷在图像上占的像素数 缺陷实际尺寸 / 视场宽度 × 图像宽度。假设视场宽度300毫米图像宽度4000像素要看到0.1毫米的针孔计算出来只有约1.3像素模型根本学不动。想让小缺陷在特征图上保留可用的响应至少要让缺陷主体占20像素以上这意味着要么把视场缩到100毫米以内要么把分辨率提到8000像素以上。工业现场常采用的办法是“先拍大图再切瓦片”——相机分辨率不变把一张图切成若干小图送进模型等于变相放大目标。拍摄角度还有一个容易被忽略的点同一个缺陷要从不同方位拍。划痕方向与光源方向平行时几乎不可见垂直时非常明显只拍一组角度会让模型学到“光照方向与缺陷方向的组合特征”换一条产线就失效。这跟户外车牌数据集的采集逻辑相似——车牌和铝片都反光光线一变数据分布就变了。我一般会要求每个缺陷样本至少覆盖两个光照角度并且在同一张铝片的不同区域中心、边缘、卷材接头都采一些。2.3 一张图拍多大、一类缺陷拍多少才够训练样本量是工业缺陷检测项目里最容易被吹成玄学的环节其实有个可参照的底线。以目标检测任务来说每类缺陷至少要有50到100个标注实例才敢开始做实验也就是框的数量而不是图片的数量。当一类缺陷少于50个框模型的建议框几乎学不到稳定的边界特征训练损失波动非常大当一类超过300个实例时继续加样本的收益明显递减。折中下来我一般会把每个缺陷类别先按形态分成三到四个子形态每个子形态拍够20到30张图确保形态覆盖率然后再看总框数是否超过2000。如果产线上缺陷率极低凑不够这个数就先上合成增强这个在第4章会展开讲。总框数达到2000以后再谈图片尺寸。原始大图比如6000像素宽不要直接整张喂模型常规做法是切成1024或1280的正方形瓦片每片之间保留20到30像素重叠防止边缘缺陷被切断。切完后要记录每张瓦片对应的原始图像位置后续推理阶段要用同样的切法训练和推理不一致会直接引发漏检。3. 标注规范与 VOC/COCO 转 YOLO脚本、规则与可视化校验3.1 标注工具怎么选Label Studio、labelImg、X-AnyLabeling标注工具选型取决于团队人数和后续格式需求。单人标注、希望最快上手用 labelImg 足够它原生支持VOC XML导出换到YOLO再写个转换脚本即可三人以上并行标注或者需要在线协同和缺陷复筛建议用 Label Studio 或 X-AnyLabeling两者都支持COCO格式导出、多人协作、标签热键配置。我的选择逻辑是项目第一周先用 labelImg 快速标出一百来张验证图确认类别定义没有歧义再切换到支持多人协同的工具做批量标注避免一开始就上重工具、标完发现标签定义错了白干。工具对比见下表。对比项labelImgLabel StudioX-AnyLabeling原生导出格式VOC XMLCOCO JSON 等COCO JSON / YOLO txt多人协同不支持支持不支持标签热键支持支持支持适合阶段小规模试标中大规模正式标注单机快速打点3.2 标注规范四个把标注质量拉满的规则标注规范是最影响模型效果、又最容易被跳过的环节。这里给出四条我实际落地时用过的规则。第一小缺陷不缩框。缺陷本体只有几个像素时标注者容易下意识只框缺陷最亮的核心区域这么做会让YOLO的整框回归目标丧失边界信息——训练时损失震荡推理时框偏移半个身位。第二密集缺陷分开标。两个凹坑几乎贴在一起时要标成两个独立的框如果标成一个框模型学到的是“这一团就是一个缺陷”推理时NMS一压两个目标只会出一个框。第三边缘缺损必须完整包住缺口只框锯齿部分会让模型学不到“正常边缘”这个上下文导致误检翻倍。第四模棱两可的样本标成 unknown 单独处理不要硬塞到某个缺陷类别里。类别噪声比标注框偏差更伤模型宁可让一个类少几十个框也不要在里面混入“猜”的标签。3.3 转换脚本VOC 转 YOLO 格式与实际边界处理标注工具导出成 VOC XML 后YOLO 训练需要的是归一化的中心点坐标。转换脚本本身不难真正的坑在坐标越界和类别映射上。下面是实用版本的转换脚本带越界处理和最小尺寸过滤。import os import glob import xml.etree.ElementTree as ET # 类别名到 id 的映射注意 id 从 0 开始和训练配置里的 class names 顺序要一致 category_mapping { scratch: 0, dent: 1, stain: 2, edge_nick: 3, oxide_spot: 4, indentation: 5, unknown: 6, } def clamp(value, min_val, max_val): 把坐标限制在 [0, max_val] 范围内避免越界框影响 anchor 匹配 return max(min_val, min(value, max_val)) def voc_to_yolo(xml_path, output_dir, min_size_px3): tree ET.parse(xml_path) root tree.getroot() # 尺寸信息从 XML 的 size 节点读不要从文件名猜 width int(root.find(size/width).text) height int(root.find(size/height).text) yolo_lines [] for obj in root.findall(object): name obj.find(name).text if name not in category_mapping: print(f忽略未定义类别: {name} in {xml_path}) continue category_id category_mapping[name] bndbox obj.find(bndbox) xmin float(bndbox.find(xmin).text) ymin float(bndbox.find(ymin).text) xmax float(bndbox.find(xmax).text) ymax float(bndbox.find(ymax).text) # 过滤可疑的小框小于 min_size_px 的框大概率是误标注 box_w xmax - xmin box_h ymax - ymin if box_w min_size_px or box_h min_size_px: print(f过滤小框: {name} ({box_w:.1f}x{box_h:.1f}) in {xml_path}) continue # 坐标越界 clamp 到图片边界 xmin clamp(xmin, 0, width) xmax clamp(xmax, 0, width) ymin clamp(ymin, 0, height) ymax clamp(ymax, 0, height) # 转 YOLO 格式归一化的中心点和宽高 x_center (xmin xmax) / 2.0 / width y_center (ymin ymax) / 2.0 / height box_w (xmax - xmin) / width box_h (ymax - ymin) / height yolo_lines.append(f{category_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) # 输出同名 .txt 文件保持和图片文件名一致 txt_path os.path.join(output_dir, os.path.basename(xml_path).replace(.xml, .txt)) with open(txt_path, w) as f: f.write(\n.join(yolo_lines)) if __name__ __main__: xml_dir annotations/xml output_dir annotations/yolo os.makedirs(output_dir, exist_okTrue) for xml_file in glob.glob(os.path.join(xml_dir, *.xml)): voc_to_yolo(xml_file, output_dir)这段脚本的逻辑并不复杂解析XML里每个object的矩形坐标映射类别id做越界裁剪和最小尺寸过滤最后归一化写出YOLO格式。两条参数值得单独说明。一是min_size_px3这个值要按实际项目调如果你的真小缺陷本身就只有2像素这个过滤会把它们全扔掉需要改成1或直接关掉但大多数情况下小于3像素的框都是标注时手抖留下的噪声留着会让训练损失变大。二是越界裁剪标注工具在框到图片边缘时经常留下超出边界1到2像素的坐标Ultralytics在训练时会打印Warning但不会中断问题是你不知道哪张图、有多少框越界与其在训练日志里大海捞针不如在转换这一步一次性抹平。类别映射要注意category_mapping里的id是YOLO训练配置文件里 class names 的下标从0开始。很多人在这里栽跟头——配置文件里写了8个类别标注转换时却用了1到8的id训练能跑但mAP全乱。转换完成后强行走一遍可视化检查不要直接开始训练。3.4 用可视化脚本复查标注偏移把YOLO格式的txt画回原图是数据集的“后悔药”。训练前花十分钟看一眼框的位置和大小比训练后对着混淆矩阵猜测要快得多。简单的做法是读取txt里每行的类别id和归一化坐标乘回原图宽高用OpenCV画框并写入类别名。这一步能直接暴露三类问题框偏移、框过小、类别和形态明显不匹配。检查时不要只看前几张按xml转换成txt的时间顺序抽查重点看容易出错的高光区域和边缘区域。对斜向长划痕这种缺陷水平框会框进大量正常铝面背景如果划痕的框面积超过画面20%模型会学到“大片均匀亮区周围有细线缺陷”的错误特征。这时候两个选择一个是用旋转框检测方案类似mmrotate处理遥感目标的方式但换检测头成本高数据标注链路也要重做另一个是切瓦片时旋转方向把斜向划痕尽量摆正或者让模型在水平框较大的前提下容忍一部分背景。工业项目里我一般先试试后者多数场景够用。4. 数据划分与增强策略让铝片小样本数据不翻车4.1 按批次分组划分而不是按图片随机划分工业数据集和公开数据集最大的区别是“图像之间有血缘关系”同一卷铝带连续拍摄几十张图缺陷形态几乎来自同一个物理来源彼此高度相似。如果按图片随机划分训练集和验证集同一批次的相似图会同时出现在两边验证指标虚高一上线就打回原形。正确做法是以卷材批号或生产批次为单位分组按组划分数据。import pandas as pd from sklearn.model_selection import GroupShuffleSplit # 假设有一张 metadata.csv每行对应一张图 # columns: image_path, batch_id, defect_type df pd.read_csv(metadata.csv) # 第一层切分分出 trainval 和 test gss1 GroupShuffleSplit(n_splits1, test_size0.15, random_state42) train_val_idx, test_idx next(gss1.split(df, groupsdf[batch_id])) train_val_df df.iloc[train_val_idx] test_df df.iloc[test_idx] # 第二层切分在 trainval 内部再分出 val gss2 GroupShuffleSplit(n_splits1, test_size0.15 / 0.85, random_state42) train_idx, val_idx next(gss2.split(train_val_df, groupstrain_val_df[batch_id])) train_df train_val_df.iloc[train_idx] val_df train_val_df.iloc[val_idx] # 验证每个 split 的缺陷类别数量类别实例数 20 时评估结果不可信 for name, split_df in [(train, train_df), (val, val_df), (test, test_df)]: print(name, split_df[defect_type].value_counts().to_dict())这里用的是GroupShuffleSplit把所有相同batch_id的样本视为一个整体进行划分确保同一批次的相似图不会泄漏到验证集里。参数上7:1.5:1.5是常用比例但如果整体样本量只有几百张验证集会太薄需要调成8:1:1并保证验证集每个类别至少20个实例。打印类别的value_counts不是可选项它决定你后面看验证指标时有没有底气——某类只有5个验证样本时mAP波动0.1都是正常的这时候调参没有意义。4.2 贴图合成把缺陷从原始图中“抠出来”再贴到干净背景真实缺陷样本不够时贴图合成是最快的数据扩充手段而且在工业场景里特别好用。做法是从已标注的原始图中裁剪出缺陷前景区域带上原始环境光照特征随机粘贴到无缺陷铝片图上。关键参数有三个粘贴数量每张图控制在一到三个太多会让模型把“多个缺陷共现”当成判别特征缩放因子按原始缺陷的像素尺寸反推比如原始针孔在1024像素的图上占8像素贴图时就不要放大到40像素裁剪时保持原始尺度羽化边缘做5到10像素的模糊过渡防止贴图边界产生高反差轮廓被模型当成缺陷学走。一个重要原则合成样本的比例不要超过全部样本的30%。超过这个值模型会学到“缺陷是干净的背景上悬浮出来的孤立形状”真实产线上缺陷周围必然有纹理、灰尘、遮挡模型反而更难泛化。我见过一个项目把合成样本比例拉到70%离线验证集F1到了0.98换一条产线直接掉到0.6后来把合成比例压回25%换线测试才回到0.85以上。合成样本是用来补形态覆盖的不是用来冲数据量的。4.3 小缺陷增强Mosaic、Copy-Paste 与 Cutout 的取舍Mosaic 是 YOLO 系列常用的数据增强把四张图拼成一张能有效增加小目标密度。但铝片缺陷场景下Mosaic有个问题缺陷本身稀疏四张图拼一起可能只有一两个目标远不如自然场景里物体密集增强效果打折。相比之下Copy-Paste思路更贴合工业缺陷——因为铝片缺陷和背景没有强语义关系贴到哪里都不违和。实现上也不复杂读一批训练图随机选一个缺陷框按4.2的前景裁剪方式复制到另一张图对应坐标区域。Cutout 做随机遮挡对餐具、电子元件外观检测有用铝片缺陷检测中收益不大。真实产线上镜面反光造成的“伪缺陷”要比遮挡多得多与其Cutout模拟遮挡不如把反光区域作为背景增强来处理。一个可行的做法是从反光强烈的无缺陷图上裁剪高光块粘贴到有缺陷图上让模型学会“反光不等于缺陷”的边界。4.4 类别不平衡先量化再做过采样和损失权重对缺陷检测来说类别不平衡是常态氧化斑可能是划痕样本的二十倍。处理前先统计各类实例数我是用一张类别分布表来决策的。最多类与最少类的比值超过20倍时优先做少类别的复制粘贴或过采样而不是调整损失权重——因为工业检测里少类别往往就是最危险的缺陷比如边角缺损过采样让模型至少见过足够的正样本比单纯调权重更直接。如果各类数量差距在10倍以内直接在数据加载层面按类别概率采样即可每个batch里包含固定数量的少类别样本。在线采样时还有一个“先验陷阱”训练集里含缺陷图和无缺陷图的比例会变成模型对缺陷率的先验估计。如果训练集全部来自筛选过的缺陷图推理时模型在正常产线流上会产生大量误检。我会把纯无缺陷图按训练样本的20%到30%混入并让每个batch里无缺陷图占比稳定在一个固定值而不是随机浮动。5. 铝片缺陷数据集五个高频踩坑与排查5.1 标注框大小飘忽不定损失怎么都降不下来现象同一类划痕一张图上标的是贴合划痕的细长框另一张图却把周围大片正常区域包进去训练loss震荡val mAP在0.7附近上不去。原因标注规范没有明确“框住缺陷的外接矩形”还是“框住缺陷主体”不同标注员甚至同一个人在不同状态下理解不一致。尤其划痕这种细长目标多框几像素和少框几像素在外观上没有明显区别但对回归损失的影响很大。解决重新梳理标注规范明确框的统一规则同类型数据尽量由同一个人标完用3.4的可视化脚本按批次抽查框宽高比分布画一张直方图看有没有异常尖峰。发现问题批次后直接回到标注工具里修不要用数据清洗脚本删除那些框——删除会让该类样本量进一步缩小饮鸩止渴。5.2 高光反光区被当成缺陷误检全堆在图片边缘现象模型在画面侧边强反光带上连续出高置信度检测框那些区域明明没有缺陷。原因训练过程中反光区极少作为“背景”被有效学习。有缺陷图里缺陷大多在光照均匀的区域无缺陷图虽然包含反光带但数量少且没有正样本约束模型把“亮白色的条带”错误关联成了“缺陷”。解决采集时特意保留不同角度反光的无缺陷正样本尤其把反光带上的小区域也拍清楚再在数据集里混入带高光的含缺陷图让模型学习“反光区域也可能有缺陷但反光本身不是缺陷”的边界。更彻底的办法是打光阶段加偏振片削弱镜面反射从源头压掉反光这比指望模型自己学会更可靠。5.3 小缺陷明明在训练集里模型却一直漏检现象val mAP50在0.9以上但实际跑到产线2毫米以下的针孔一个都检不出来。原因原始图像缩放成训练分辨率的640或1280后针孔只剩两三个像素骨干网络采样的过程中响应直接被池化丢弃。val指标虚高的原因在于验证集中小缺陷占比不大整体mAP被中大缺陷拉上去了。解决不要只依赖全局缩放。常规做法是切瓦片训练和推理原图切成1024×1024的瓦片单独过模型再拼回结果。切瓦片时重叠区至少留20像素否则位于切缝上的缺陷会被切成两半两个瓦片各看到一部分NMS合并时无法生成有效框。另一个方案是把训练分辨率提高到1280Ultralytics里直接设置 imgsz1280显存占用会明显上涨需要同步缩小batch size。5.4 压痕和凹坑互相混淆混淆矩阵里这两个类乱成一团现象压痕被误判成凹坑的比例能到30%产线分拣无法处理。原因二维灰度图上面状压痕和点状凹坑的边缘形态几乎一致区别在深度方向的光影变化。只拍一张正面光照图模型根本没有深度线索。解决数据侧的做法是对这两类专门采集多角度光照样本让阴影变化成为判别特征——比如0度和30度入射光各拍一张模拟深度信息。如果产线无法布置多角度光照最现实的方案是先把压痕和凹坑合并成一个大类用两级模型处理第一级只判“有缺陷/无缺陷”第二级对裁剪出的缺陷块做精细分类。这是工业项目里最常见的妥协也往往是最稳的方案。5.5 验证集指标漂亮上线同一产线就翻车现象离线评估的F1有0.95连着跑两小时产线漏检率却高得不可接受。原因随机划分导致同一批次的相似图同时出现在训练集和验证集造成数据泄漏。另一个原因是产线切换了产品型号表面纹理、背景灰度分布与训练集有明显差别——而这种分布上的偏移离线指标是看不出来的。解决用4.1的按批次分组重新划分数据重训重测。正式上线前从目标产线单独抽30张从未参与训练的真实图做盲测只看这30张的漏检率不看整体mAP。三十张图不多但足以暴露“换产线就失效”这类问题。6. 数据集验收用漏检率和热力图确认能不能上产线6.1 用关键点激活可视化核查模型关注的是不是缺陷本体模型训练完不要只盯着mAP曲线。挑二十张典型缺陷图做激活区域可视化类Grad-CAM思路每张图注册骨干网络最后一个卷积层的前向和反向hook用预测类别的得分对特征图求梯度再对梯度加权求和得到热力图叠加到原图上。看两个地方激活区域是否落在缺陷附近以及是否存在激活集中在图片四边或固定区域的现象。如果划痕的激活集中在划痕本身说明数据标注质量过关如果激活分布在图像边框多半是训练集里所有图像都有同样的暗角或支架边缘模型学偏了背景特征。这个检查对数据集质量的意义在于它能区分“数据量不足”和“标注有噪声”两种问题。激活弥散、温度图杂乱先查标注框不要急着换模型结构。一个经验是同一个项目里清洗标注数据带来的mAP提升经常大于换一个更大骨干网络。6.2 产线口径的三条验收线数据集的最终验收要用产线口径的指标而不是训练指标。我习惯用下面这个表来定验收标准。验收项测试集要求通过标准漏检率全部是有缺陷图不能从混合产线流随机抽样按缺陷类别分别计算每类召回率 ≥ 90%误检率无缺陷图500张以上置信度阈值0.25时每张图平均误检框 ≤ 1单类稳定性每个类至少50个实例各缺陷类别召回率极差 ≤ 10%随机抽1000张产线图来评估是无效的——铝片缺陷率常在1%以下随机抽一千张可能只有几张有缺陷漏检率的置信区间宽到没有意义。要测漏检率就必须先筛出有缺陷的真实图要测误检率就单独准备无缺陷图。评估时按缺陷类别逐类算召回率某一个类低于90%就直接定位到该类数据通常拿到的是“某类形态覆盖不全”的结论。我自己的教训是第一个铝片项目为了省事用了随机划分验证集mAP 0.95上线第一天连续误检了一整卷产品查到最后就是同一批的相似图同时落在训练和验证里模型根本没有泛化。后来把数据按卷材批号重划分、标注规范重新洗了两遍才稳住产线指标。“先查数据再调模型”这话在工业缺陷场景不是口号模型结构那点差异常常不如一个错标框的影响大。前期的采集角度、标注规则、划分方式决定了后面所有调参的边界。希望帮到你。本文还有配套的精品资源点击获取
返回列表