
简介铝片表面工业缺陷检测数据集面向制造行业视觉质检与工业自动化场景适合算法工程师、科研人员以及相关专业学生用来训练和验证铝材表面缺陷识别模型。数据采集自铝片表面涵盖擦伤、脏污、褶皱、针孔四类典型缺陷共四百张图像标注框总数为一千零六十二个其中脏污框四百五十六个、擦伤框二百七十个、针孔框二百一十二个、褶皱框一百二十四个各类别样本量不均衡可结合数据增强或类别加权优化模型性能。压缩包为7z格式共1202个文件以jpg原图、VOC格式xml标注和YOLO格式txt标注为主包体仅15.25MB轻量易传输解压后即可按需划分训练集与测试集。所有标注使用labelImg完成图像与xml、txt一一对应兼容主流目标检测框架省去格式转换环节。目前已有526人浏览学习适合工业视觉入门者进行算法练习也适合制造业项目用于缺陷检测方案的前期验证。1. 为什么 400 张铝片缺陷图值得认真对待铝板轧制、冲压和阳极氧化产线上表面缺陷出现得随机、拍下来却很快——一台工业相机架在传送带上方一天就能攒几千张原始图。但真正被筛选过、标注过、能直接进模型的往往只剩几百张。标题里这份数据集是典型的开源数据集形态VOC 和 YOLO 双格式、一共 400 张、4 个类别看起来规模不大却恰好对应工业视觉项目最常见的开局数据少、类别明确、标注统一。对检测工程师来说能不能把 400 张图的潜力挖干净决定了项目是停在 demo 阶段还是能走向产线试运行。下面从标注格式拆起落到转换脚本和训练配置最后收在验证技巧上适合刚开始跑 YOLO 或准备落地铝片表面缺陷检测的工程师。2. 铝片缺陷数据集目录拆解VOC 与 YOLO 两份标注的对应关系2.1 images 与 annotations 分开存的目录约定先看这份数据集最常见的目录形态aluminum_defect/ ├── images/ │ ├── train/ # 320 张 jpg │ └── val/ # 80 张 jpg ├── annotations/ │ ├── voc/ │ │ ├── train/ # 320 个 XML │ │ └── val/ # 80 个 XML │ └── yolo/ │ ├── train/ # 320 个 txt │ └── val/ # 80 个 txt └── classes.txt # 类别顺序训练前不能改images 和 annotations 分区存放是当前主流约定。VOC 的 XML 给转换脚本用也可以直接喂给 mmdetection、detectron2 这类框架YOLO 的 txt 则给 Ultralytics 训练链路用。两份标注靠同名文件对应AL_000123.xml、AL_000123.txt指向同一张AL_000123.jpg换框架时不重新标注靠的就是这份约定。train/val 按 8:2 划分对 400 张图来说比较合理。工业缺陷数据集不建议再单独分 test 集类别之间的形态差异明显val 结果基本能反映模型真实水平部署前直接用 val 上表现最好的权重测产线样张即可。2.2 VOC 的 XML 标注字段逐个拆解VOC 格式本质是 Pascal VOC 的 XML 描述一条划痕标注长这样annotation folderaluminum_defect/folder filenameAL_000123.jpg/filename size width1280/width height960/height depth3/depth /size object namescratch/name bndbox xmin412/xmin ymin233/ymin xmax789/xmax ymax355/ymax /bndbox /object /annotationname是类别名bndbox是像素整数坐标。工业相机拍的铝片图原图分辨率通常很高如果数据集在制作时做过缩放size字段必须和 jpg 实际尺寸完全一致否则转 YOLO 时归一化坐标会整体偏移。这是 VOC 转 YOLO 最常见的坑3.2 节的脚本里会专门加校验逻辑。2.3 YOLO txt 的归一化坐标从哪来YOLO 格式每行一个目标class_id cx cy w h四个坐标值都是相对图片宽高的浮点数范围 0 到 1。像素坐标转归一化坐标的公式cx (xmin xmax) / 2 / widthcy (ymin ymax) / 2 / heightw (xmax - xmin) / widthh (ymax - ymin) / height上面那条 scratch 按 1280×960 换算后是0 0.4691 0.3062 0.2945 0.1271。坐标变成相对值后模型训练不再受输入图原始分辨率限制任意尺寸的推理图都能复用同一套标注。对比项VOC XMLYOLO txt坐标单位像素整数相对宽高浮点类别标识name 字符串class_id 数字解析方式ElementTree 解析按行 split 读取训练支持需写自定义 DatasetYOLO 原生读取依赖文件无classes.txt 或 data.yaml可视化解析 XML 后画框直接读行画框需要注意YOLO txt 本身不存类别名只存 class_id这个 id 对应 classes.txt 里的行号。训练时data.yaml的names列表顺序必须与转换脚本里的 class_names 一致。scratch 排第 0 位就一直是第 0 位中途不要因为看着不顺眼重排否则模型输出和真值标注会整体错位而且损失函数不会报错只会默默掉点。3. 用 Python 批量解析 VOC 统计类别分布并转成 YOLO 格式3.1 先统计 4 个类别的目标数量400 张图、4 个类别类别不平衡是常态。转换格式之前先跑一段统计确认每类到底有多少实例import os import xml.etree.ElementTree as ET from collections import Counter voc_dir annotations/voc/train counter Counter() for xml_file in os.listdir(voc_dir): if not xml_file.endswith(.xml): continue tree ET.parse(os.path.join(voc_dir, xml_file)) for obj in tree.getroot().iter(object): counter[obj.find(name).text] 1 print(counter)这段代码用标准库xml.etree.ElementTree解析每个 XMLiter(object)遍历所有目标节点按 name 字段累计实例数。输出类似Counter({scratch: 231, pit: 148, oxide: 89, stain: 67})。拿到分布后做一次形态对照类别实例数示例典型形态scratch231细长条状宽高比大pit148近圆形小斑oxide89大片不规则暗区stain67点状或絮状如果某个类别不足 50 个实例训练时要单独处理离线复制该类别样本做水平翻转和亮度扰动或者训练时给该类别 loss 加权重。4 类里 pit 和 stain 在灰度图上容易混淆统计完还要额外确认这两类是否存在像素形态重叠。3.2 VOC 转 YOLO 的完整脚本import os import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, class_names, out_path): tree ET.parse(xml_path) root tree.getroot() w int(root.find(size/width).text) h int(root.find(size/height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_names: continue cls_id class_names.index(name) box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) # 裁剪越界框半自动标注工具导出结果偶尔会超出图片边界 xmin max(0, xmin); xmax min(w, xmax) ymin max(0, ymin); ymax min(h, ymax) cx (xmin xmax) / 2 / w cy (ymin ymax) / 2 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) with open(out_path, w) as f: f.write(\n.join(lines)) class_names [scratch, pit, oxide, stain] voc_to_yolo(annotations/voc/train/AL_000123.xml, class_names, annotations/yolo/train/AL_000123.txt)脚本流程读 size 拿到宽高 → 遍历 object → 换算归一化坐标 → 裁剪越界 → 写 txt。裁剪这步不能省越界框不处理训练时锚框匹配和 loss 计算都会异常。class_names.index(name)用列表下标确定类别 id顺序完全由列表决定这就是 classes.txt 不允许乱排的原因。批量转换时用 for 循环包住整个 XML 目录即可400 张图 1 秒内能跑完。注意如果源 XML 里出现过 script 里没有的类别名continue会把它静默跳过导致那张图的标签漏掉。建议在跳过时打印警告信息转换完成后核对 txt 文件数与 XML 文件数是否一致。3.3 用 OpenCV 画框抽查脏数据转完格式后最怕的不是类别少而是框和铝片表面特征对不上。画框抽查是最直接的手段import cv2 img cv2.imread(images/train/AL_000123.jpg) with open(annotations/yolo/train/AL_000123.txt) as f: for line in f: cls_id, cx, cy, bw, bh map(float, line.split()) h, w img.shape[:2] x1 int((cx - bw / 2) * w) y1 int((cy - bh / 2) * h) x2 int((cx bw / 2) * w) y2 int((cy bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(img, str(int(cls_id)), (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) cv2.imwrite(check_AL_000123.jpg, img)画框输出后每类挑 10 张以上人工看一遍重点确认划痕框是否覆盖整条缺陷、凹坑框是否偏大或偏离目标中心。铝片缺陷普遍细长转 YOLO 后 w 或 h 可能只有 0.01 量级这类极窄框最容易漏检抽查时要单独标记。如果某张图框明显错位优先怀疑图片被旋转或缩放而 XML 的 size 没有同步更新。4. 用 YOLOv8 训练 400 张铝片数据集的最小配置4.1 data.yaml 与目录关联Ultralytics YOLO 训练时按约定从 images 路径推导标签路径它会自动把路径里的images替换成labels。如果数据集目录像第 2 章那样把 txt 放在annotations/yolo下需要先建软链接YOLO 才能找到标签ln -s annotations/yolo/train aluminum_defect/labels/train ln -s annotations/yolo/val aluminum_defect/labels/val然后写 data.yamltrain: aluminum_defect/images/train val: aluminum_defect/images/val nc: 4 names: [scratch, pit, oxide, stain]names的顺序必须和 classes.txt、以及第 3 章转换脚本里的 class_names 完全一致。类别错位不会报错只会以精度下降的形式表现出来排查时非常隐蔽。YOLO 从 v8 到 v11 的 data.yaml 写法保持一致工业项目里首选轻量模型数据量小时大模型收益不明显反而更容易过拟合。4.2 训练命令与超参数选择yolo detect train \ modelyolov8n.pt \ dataaluminum_defect.yaml \ epochs120 \ imgsz640 \ batch16 \ lr00.01 \ patience30 \ projectruns/aluminum \ namedefect_120eyolov8n.pt 预训练权重用 COCO 初始化骨干网络400 张图在它基础上微调比随机初始化收敛快得多。patience30表示 30 个 epoch 内验证集 mAP 没有明显提升就提前停止适合数据量小、不想干等的情况。参数建议值说明modelyolov8n.pt小数据集用 nl/x 容易过拟合epochs120~150配合 patience 自动停imgsz640铝片缺陷最小目标约 20×20 像素batch8~1616GB 显存可跑通lr00.005~0.01微调场景保持默认量级patience20~30防止无效等待训练结束后runs/aluminum/defect_120e/weights/best.pt是验证集上 mAP 最高的权重last.pt是最后一个 epoch 的权重。工业落地习惯只保留 best.ptlast.pt 留作意外中断时的恢复点。显存不够需要降 batch 时优先从 16 降到 8而不是缩小 imgsz——铝片缺陷的细长形态对输入分辨率更敏感缩图会先吃掉小目标。4.3 400 张图的数据增强策略数据量小增强必须用但也不能用过。YOLO 内置增强里和铝片场景最相关的是这几个yolo detect train \ modelyolov8n.pt \ dataaluminum_defect.yaml \ epochs120 \ imgsz640 \ batch16 \ mosaic0.5 \ hsv_h0.015 \ translate0.1 \ fliplr0.5mosaic0.5只在前一半 epoch 生效YOLO 会在最后 10 个 epoch 自动关闭 mosaic避免增强分布和真实分布差异过大导致欠拟合。hsv_h0.015对铝片很重要产线光照变化是常态但色相偏移太大会破坏氧化斑的颜色语义。fliplr0.5可以放心开铝片缺陷左右对称。不要开flipud产线相机固定朝下拍摄上下翻转会引入不存在的视角。如果第一轮跑完发现某个类别 recall 明显低优先做离线补充把该类别的图复制出来做亮度、对比度扰动混入原训练集而不是盲目加大全局增强强度。5. 铝片缺陷模型验证时先查这三处标注框、类别映射、预测输出训练结束不代表模型可用。部署前按优先级查三处。第一处是标注框本身。用 3.3 节的画框脚本重新过一遍 val 集确认每个框的宽高比符合缺陷形态划痕框应接近细长矩形凹坑框接近正方形。如果发现大量框的 w 或 h 小于 0.02说明标注源存在贴边或极窄框这类框在 NMS 阶段容易被抑制直接表现为 recall 偏低而不是 mAP 整体难看。第二处是类别映射。检查 val 预测输出与 VOC 原始 name 是否对应from ultralytics import YOLO model YOLO(runs/aluminum/defect_120e/weights/best.pt) results model.predict(images/val/AL_000456.jpg, conf0.25) for r in results: for box in r.boxes: cls_id int(box.cls[0]) conf float(box.conf[0]) xyxy box.xyxy[0].tolist() print(fcls{model.names[cls_id]} conf{conf:.2f} box{xyxy})model.names[cls_id]读取模型配置文件里的类别名与 classes.txt 比对即可发现错位。0.25 的置信度阈值只用于快速排查实际部署阈值按产线误报和漏报的成本调到 0.3~0.5 之间。第三处是预测输出与原图叠加和 VOC 真值标注放一起对比。铝片表面反光容易把高光区域误判为划痕如果预测框集中在固定区域优先怀疑打光不均匀而不是模型问题此时可以给推理加 ROI 限制或对输入做去高光预处理。验证通过后测推理性能。工业场景一般要求单张推理低于 50ms用完整 val 集跑一次yolo predict modelruns/aluminum/defect_120e/weights/best.pt \ sourcealuminum_defect/images/val imgsz640 conf0.3看输出日志里的平均耗时。超出 50ms 时优先用 TensorRT 导出或者把 imgsz 降到 512不要一上来换大模型——这个判断和第 4 章选 yolov8n 的理由是同一个小数据集容不下复杂模型瓶颈往往在标注质量和类别区分度上不在网络容量。本文还有配套的精品资源点击获取