简介:本资源为三星油污缺陷检测数据集,聚焦头发丝(TFS)与小黑点(XZW)两类典型缺陷,面向工业质检算法工程师、视觉检测方向的研究生及需要训练缺陷识别模型的开发者,可用于目标检测与分类任务的模型训练、验证与调优。压缩包共1324个文件,包含660张jpg图像、660个同名xml标注文件以及4个txt说明文件,标注与图像一一对应,整体约314.54MB,采用rar打包,便于直接接入主流检测框架进行训练。目前已有1412人学习下载,说明该数据集在油污缺陷检测场景中具备一定参考价值。图像覆盖正常样本与两类缺陷样本,命名规范、类别清晰,读者可据此构建训练集与验证集,复现缺陷检测流程,并结合博客中的优化思路提升检测精度,适合作为工业缺陷检测项目的入门与进阶数据基础。
1. 660 张三星油污缺陷图:头发丝与小黑点,这份数据集到底能跑出什么
产线上最让人头疼的缺陷,往往不是那种一眼就能看出来的大块脏污,而是头发丝和直径不到零点几毫米的小黑点。前者是线状异物,后者是点状异物,两者在灰度图上都表现为局部对比度骤降,传统阈值分割一上就翻车。这份三星油污缺陷数据集一共 660 张图,专门覆盖这两类缺陷,图像来源是实际产线采集,不是实验室摆拍。适合谁用?做工业质检算法验证的工程师、想跑通小样本缺陷检测的学生、以及需要快速验证分割或分类方案可行性的团队。660 张不算大,但胜在缺陷类型聚焦,头发丝和小黑点这两类恰好是很多公开数据集缺失的细粒度样本。如果你手头正缺一批能直接跑通 pipeline 的真实缺陷图,这份资源值得先拆开看看结构再决定怎么用。
2. 拆开数据集:660 张图的目录结构与标注格式
2.1 先搞清楚文件组织方式
拿到一份数据集,第一件事不是急着写模型,而是把目录结构摸清楚。660 张图如果按缺陷类型分目录,通常有两种常见组织方式:一种是按类别分文件夹,比如hair/和black_dot/各放对应图像;另一种是图像统一放在images/下,标注信息单独放在labels/或annotations/里。工业缺陷数据集因为采集批次不同,还可能出现按日期或产线编号再分子目录的情况。
我一般会先用命令行把整体结构扫一遍,确认图像数量、格式和命名规律:
# 统计图像总数和格式分布 find ./dataset -type f \( -name "*.jpg" -o -name "*.png" -o -name "*.bmp" \) | wc -l # 查看目录层级,限制深度避免输出过长 tree ./dataset -L 3 --filelimit 20 # 按扩展名统计,确认是否有混合格式 find ./dataset -type f | sed 's/.*\.//' | sort | uniq -c | sort -rn这几条命令的逻辑很直接:第一条确认总量是否与标称的 660 张一致,第二条看目录层级和文件分布,第三条排查是否存在 jpg 和 png 混用的情况。参数上,--filelimit 20是防止某个目录下文件太多导致输出刷屏,-L 3限制递归深度,避免把每一张图都列出来。如果统计结果和 660 有出入,先检查是否有隐藏文件或非图像文件混入。
2.2 标注格式决定后续工具链
标注格式直接决定你用什么框架、写什么解析代码。工业缺陷数据集常见的标注形式有三种:VOC 风格的 XML、COCO 风格的 JSON、以及 YOLO 风格的 txt。头发丝这类细长缺陷,如果标注是矩形框,框的宽高比会非常极端,后续做数据增强时要特别注意;小黑点如果是点标注,可能只有中心坐标没有宽高。
先抽样看几个标注文件的内容:
import os, json, xml.etree.ElementTree as ET # 假设标注在 annotations 目录下,先列出所有标注文件 ann_dir = "./dataset/annotations" files = os.listdir(ann_dir) print(f"标注文件总数: {len(files)}") print(f"前 5 个文件: {files[:5]}") # 如果是 XML,解析一个样本看结构 sample_xml = os.path.join(ann_dir, files[0]) if files[0].endswith(".xml"): tree = ET.parse(sample_xml) root = tree.getroot() for obj in root.findall("object"): name = obj.find("name").text bbox = obj.find("bndbox") xmin = int(bbox.find("xmin").text) ymin = int(bbox.find("ymin").text) xmax = int(bbox.find("xmax").text) ymax = int(bbox.find("ymax").text) print(f"类别: {name}, 框: ({xmin},{ymin})-({xmax},{ymax}), " f"宽高: {xmax-xmin}x{ymax-ymin}")这段代码先确认标注文件数量是否与图像一一对应,再解析一个 XML 样本查看类别名和边界框坐标。关键参数是xmax-xmin和ymax-ymin,这两个值能直接告诉你头发丝标注框有多扁。如果宽高比超过 10:1,后续做随机裁剪或缩放时很容易把缺陷裁掉或压变形,这是细长缺陷标注的第一个坑。
提示:如果标注文件数量少于图像数量,说明有部分图像没有标注,训练前必须过滤掉这些无标注样本,否则评估指标会失真。
3. 把 660 张图跑通训练:从划分到增强的完整流程
3.1 训练集验证集划分不能随手 random
660 张图如果按 8:2 划分,验证集只有 132 张。头发丝和小黑点两类如果分布不均,随机划分可能导致某一类在验证集里只有十几张,指标波动会非常大。更稳妥的做法是按类别分层抽样,保证验证集里两类缺陷的比例与整体一致。
import os, random, shutil from collections import defaultdict # 按类别收集图像路径 data_dir = "./dataset/images" class_files = defaultdict(list) for fname in os.listdir(data_dir): if "hair" in fname.lower(): class_files["hair"].append(fname) elif "dot" in fname.lower() or "black" in fname.lower(): class_files["black_dot"].append(fname) # 分层抽样,每类取 20% 做验证 random.seed(42) train_files, val_files = [], [] for cls, files in class_files.items(): random.shuffle(files) split = int(len(files) * 0.8) train_files.extend(files[:split]) val_files.extend(files[split:]) print(f"{cls}: 总数 {len(files)}, 训练 {split}, 验证 {len(files)-split}") # 按划分结果拷贝到对应目录 for phase, flist in [("train", train_files), ("val", val_files)]: for fname in flist: src = os.path.join(data_dir, fname) dst = os.path.join("./dataset", phase, fname) os.makedirs(os.path.dirname(dst), exist_ok=True) shutil.copy(src, dst)这段代码的核心是defaultdict(list)按类别归集文件,然后对每一类单独做 8:2 切分。random.seed(42)保证每次运行划分结果一致,方便复现。参数上,split = int(len(files) * 0.8)是训练集比例,如果某类样本少于 50 张,建议改成 7:3 甚至 6:4,给验证集留够样本。拷贝而不是移动,是为了保留原始数据不动,后续换划分策略时不用重新解压。
3.2 针对头发丝和小黑点的增强策略
通用增强策略在这份数据集上会踩坑。头发丝是细长结构,随机旋转 90 度后可能变成水平线,如果产线场景里头发丝方向有固定规律,旋转增强反而引入噪声。小黑点面积小,随机裁剪很容易把它裁出画面。我一般会这样配增强:
import albumentations as A # 训练增强:保守旋转 + 亮度扰动 + 小范围缩放 train_transform = A.Compose([ A.HorizontalFlip(p=0.5), # 水平翻转,头发丝方向不变 A.RandomBrightnessContrast( brightness_limit=0.15, contrast_limit=0.15, p=0.5 ), # 模拟产线光照波动 A.ShiftScaleRotate( shift_limit=0.05, scale_limit=0.1, rotate_limit=15, border_mode=0, p=0.5 ), # 小角度旋转,避免细长目标变形 A.Resize(640, 640), # 统一输入尺寸 ], bbox_params=A.BboxParams(format="pascal_voc", label_fields=["labels"])) # 验证集只做 resize,不做随机增强 val_transform = A.Compose([ A.Resize(640, 640), ], bbox_params=A.BboxParams(format="pascal_voc", label_fields=["labels"]))参数选择的理由:rotate_limit=15是经验值,超过 30 度后头发丝的形态和产线实际分布偏差太大;brightness_limit=0.15对应产线光照的正常波动范围,再大就可能把小黑点淹没在背景里;scale_limit=0.1控制缩放幅度,防止小黑点被缩到几个像素以下。border_mode=0是填充黑色,避免旋转后边缘出现镜像伪影。验证集不做随机增强,是为了让评估指标稳定可比较。
注意:如果标注格式是 COCO JSON,
BboxParams里的 format 要改成coco,否则坐标解析会错位,训练 loss 会一直不降。
4. 训练中常见的翻车现场与排查手册
4.1 现象:loss 震荡不收敛,mAP 在 0.1 附近徘徊
原因通常有三个:标注坐标格式和框架要求不匹配、类别名映射错误、或者学习率过大。先检查标注解析后的可视化结果,把框画到图上确认位置对不对。如果框整体偏移,大概率是 VOC 的xmin,ymin,xmax,ymax被当成了 COCO 的x,y,w,h。解决方法是统一转成框架要求的格式,转换后抽样可视化验证。
4.2 现象:头发丝漏检严重,小黑点误检多
头发丝漏检是因为细长目标在特征图上响应弱,尤其是经过多次下采样后,宽度可能只剩一两个像素。常见做法是增大输入分辨率,或者改用对细长目标更友好的 anchor 比例。小黑点误检多,往往是因为背景里的灰尘、噪点与缺陷外观接近,需要在数据增强里加入更多负样本,或者提高分类头的置信度阈值。
4.3 现象:验证集指标很好,上线后一塌糊涂
这是典型的过拟合到采集环境。660 张图如果全部来自同一批次、同一光照条件,模型学到的是环境特征而不是缺陷特征。排查方法是把验证集按采集批次分组,看组间指标差异。如果差异超过 20%,说明数据多样性不足。解决方向是补充不同批次的图像,或者在增强里加入更强的光照和对比度扰动。
4.4 现象:训练到一半突然报显存不足
头发丝标注框宽高比极端,某些检测框架在计算 loss 时会对宽高做指数运算,数值不稳定导致显存异常增长。排查时先看报错前的 batch 里是否有异常大的框。解决方法是对框的宽高做裁剪,限制在合理范围内,或者改用对宽高比不敏感的 loss 函数。
提示:每次改完标注格式或增强策略,先跑 10 个 iteration 看 loss 是否正常下降,再开完整训练。这个习惯帮我省过很多次通宵重跑的时间。
5. 用 660 张图验证一个想法:小样本下的快速迭代技巧
这份数据集最大的价值不是刷高指标,而是快速验证一个想法能不能跑通。660 张图,单卡训练一轮通常不超过两分钟,这意味着你可以在一小时内试完五六种增强组合或损失函数。我一般会固定一个轻量 backbone,比如 ResNet-18 或 MobileNetV3,先把 pipeline 跑通,再换大模型对比。
具体做法是写一个配置化的训练脚本,把增强策略、学习率、输入尺寸做成参数,用命令行覆盖:
# 快速对比两组增强策略,每组只跑 20 个 epoch python train.py --config configs/base.yaml --aug strong --lr 0.001 --epochs 20 python train.py --config configs/base.yaml --aug weak --lr 0.001 --epochs 20 # 对比不同输入分辨率对头发丝召回的影响 python train.py --config configs/base.yaml --imgsz 640 --epochs 20 python train.py --config configs/base.yaml --imgsz 960 --epochs 20每组实验记录验证集上头发丝和小黑点各自的召回率和精确率,而不是只看总体 mAP。因为这两类缺陷的优化方向经常是矛盾的:提高分辨率能救头发丝,但小黑点的误检可能上升。把两类指标分开看,才能找到平衡点。
还有一个技巧是拿 50 张图做一轮极速验证。从训练集里抽 50 张,跑 5 个 epoch,看 loss 能不能降到合理范围。如果 50 张都跑不降,说明标注或代码有问题,不用浪费时间去跑全量。这个习惯是我被一次标注坐标错位坑了整整两天之后养成的,从那以后每次拿到新数据集,都强制先跑一遍 50 张的 sanity check。希望这份 660 张的三星油污缺陷数据集能帮你少走一段弯路。
本文还有配套的精品资源,点击获取