简介:瓶装白酒疵品检测数据集.zip 是一份面向工业质检场景的图像数据集,聚焦瓶装白酒的外观瑕疵识别,适合计算机视觉、机器学习方向的开发者与研究者用于训练疵品检测模型。压缩包内共包含4516张JPG格式图片和1个JSON文件,图片覆盖正面、侧面等多角度瓶身视图,JSON文件可用于存储样本标签或元信息,辅助模型训练与数据管理,整个资源包约213MB。目前已有293人学习/下载,数据可直接用于搭建基于卷积神经网络的自动检测流程。借助这份数据集,读者能够开展数据清洗、模型训练、验证与测试等完整实践,掌握从图像预处理到瑕疵分类的工程方法;同时也可用于算法对比、消融实验或毕业设计,并可结合迁移学习快速适配多种瓶装产品线的质检需求,提升生产环节的自动化与智能化水平。
1. 瓶装白酒疵品检测数据集: 数据比模型更能决定产线能不能用
在白酒灌装产线上,疵品检测的难点从来不是“能不能检出”,而是“检出之后误报率能不能压得住”。漏液的瓶盖、破损的标签、液位线偏高或偏低、瓶身裂纹、异物悬浮——这些疵品形态分散、差异小,且同一瓶酒往往同时带两三种瑕疵。你会发现,换成更强的模型、调更久的参,都不如把训练数据里的“真实缺陷分布”补齐来得快。这也是“瓶装白酒疵品检测数据集”这类资源的价值所在:它不是一堆随手拍的图片,而是按疵品类别、拍摄机位、光照条件组织好的标注样本集,直接决定了你训练出来的模型是能干活的质检员,还是只能做演示的玩具。适合谁?做产线视觉质检的算法工程师、搞白酒行业自动化设备集成的团队,以及刚准备入坑工业视觉、想找一份带标注数据练手的人。
2. 拆包与盘点: 先把 zip 变成可训练的样本集
拿到“瓶装白酒疵品检测数据集.zip”,第一件事不是解压完就开训,而是先盘清楚目录结构、标注格式、类别定义和数据质量。工业检测数据集的坑往往不在算法侧,而在数据侧:标注错位、类别不均衡、同一类别在不同批次里标准不一致,这些问题不排查,后面训练和上线都会很被动。
2.1 先看目录结构再谈训练
常见的数据集压缩包有两种组织方式:一种是按类别分文件夹,适合分类任务;另一种是 images/labels 分离,配合 train/val/test 划分,适合目标检测。白酒疵品检测要定位瓶盖、标签、液位线这些区域,后者是主流。解压后先用 tree 或 find 命令把整体结构列出来。
unzip 瓶装白酒疵品检测数据集.zip -d baijiu_dataset cd baijiu_dataset find . -maxdepth 2 -type d | sort解压时建议指定-d目标目录,避免压缩包直接把文件散到当前目录。列目录这一步能让你在十分钟内判断数据集的真实构成:是整段产线视频切出来的连续帧,还是挑过的关键帧;是单相机固定角度拍的,还是多机位混合。连续帧的缺点是相邻画面高度相似,若不做去重,训练集和验证集之间会严重“串场”,模型指标虚高。
2.2 标注格式: YOLO 与 COCO 选哪个
白酒疵品数据集最常见的是 YOLO 格式的 txt 标签,也有 COCO 的 json 标注。YOLO 格式每个 txt 对应一张图,每行是“类别 cx cy w h”,坐标都是归一化的 0 到 1 小数,优点是训练时读取快、不依赖额外解析库;缺点是标签与图像文件是松散关联,靠同名定位,文件一多容易丢配对。COCO json 则把全量标注集中到一个文件里,方便做跨类别统计,但要解析 annotation 字段,得依赖 pycocotools 这类库。
新手我建议直接用 YOLO 格式,因为 Ultralytics YOLOv8 的默认输入就是它。你要做的是确认类别编号和类别名的映射关系,以及每个类别大概有多少目标。
import os from collections import Counter label_dir = "baijiu_dataset/labels/train" class_names = {0: "bottle_cap", 1: "label", 2: "liquid_line", 3: "crack"} counter = Counter() for name in os.listdir(label_dir): if not name.endswith(".txt"): continue with open(os.path.join(label_dir, name), "r", encoding="utf-8") as f: for line in f: cls = int(line.split()[0]) counter[class_names[cls]] += 1 print(counter)这段脚本统计训练集里每个类别的标注目标数。意义在于暴露类别不均衡:液位线相关的目标可能是瓶盖破损的十倍,说明漏液、裂纹这类高风险疵品在原始数据里本身就稀少,后续训练要重点补。别小看这一步,多数人一上来就跑训练,等到验证集 mAP 被大量正常样本拉高、现场误报压不住时才回头查数据,已经晚了。
2.3 校验脚本: 坏标签会静默吃掉你的精度
解压之后还得做一次标签合法性检查。YOLO 标签要求cx cy w h都是 0 到 1 的小数,且 w、h 为正;如果标注工具导出时出了错,可能会出现坐标越界、框宽高为负、类别编号超过 class 数的情况。这些问题不会让训练直接报错,只会让损失曲线莫名抖动,或者某个类别 AP 始终是 0。
import os label_dir = "baijiu_dataset/labels/train" num_classes = 4 for name in sorted(os.listdir(label_dir))[:500]: path = os.path.join(label_dir, name) with open(path, "r", encoding="utf-8") as f: lines = f.readlines() for i, line in enumerate(lines): parts = line.split() if len(parts) != 5: print(f"[格式错误] {name} 第{i+1}行: {line.strip()}") continue cls, cx, cy, w, h = map(float, parts) if cls >= num_classes: print(f"[类别越界] {name} 类别 {cls}") if not (0 <= cx <= 1 and 0 <= cy <= 1 and 0 < w <= 1 and 0 < h <= 1): print(f"[坐标异常] {name} 第{i+1}行: cx={cx} cy={cy} w={w} h={h}")校验脚本不必一次跑全量,先抽前几百个文件看有没有系统性问题。常见的情况是:某批标注的框中心点正好落在 0 或 1 边界上,说明当时标注员把目标顶到画面边缘,这类样本在 mosaic 增广下容易被切掉一半,模型会学到“边缘瓶子不用检”的坏习惯。
提示:做完目录盘点后,尽量把图片统一成 jpg 格式、标签统一成 txt,训练前的预处理能省掉后面 80% 的兼容性报错。
3. 用 YOLOv8 训练第一个白酒疵品检测模型: 参数与评估
数据盘清楚了,接下来就是跑通第一条训练链路。这一步的目标不是刷最高精度,而是摸清数据集的底:哪些类别好检、哪些类别不可分、验证集指标和真实场景预期差多少。模型选 YOLOv8m 起步,别一上来就上 x,工业场景训练集通常只有几千到几万张,大模型没有足够数据托底,泛化反而差。
3.1 组织数据集与配置文件
训练前先把数据集目录固定下来,YOLOv8 需要一份 yaml 配置文件,描述数据集根路径、类别名和训练/验证集的图片路径。注意 paths 尽量写绝对路径,避免在 IDE 和终端之间切换时相对路径失效。
# baijiu_dataset.yaml path: /home/linus/data/baijiu_dataset train: images/train val: images/val test: images/test names: 0: bottle_cap 1: label 2: liquid_line 3: crack有一点值得提醒:这里train和val填的是图片目录的路径,而不是图片列表。YOLOv8 会自行按同名规则去labels/下查找对应标注。如果你的压缩包里 train.txt / val.txt 是现成的图片路径列表,也可以用那种格式,但多数情况下目录组织更省事。
3.2 训练命令与关键参数
yolo detect train \ model=yolov8m.pt \ data=baijiu_dataset.yaml \ imgsz=1280 \ epochs=150 \ batch=16 \ device=0 \ project=baijiu_runs \ name=exp_v1 \ patience=30 \ close_mosaic=15参数拆开说:imgsz=1280是白酒疵品检测的关键。瓶盖裂纹、标签破损都是细小目标,640 的输入图上可能只占十几个像素,模型很难学到有效特征。1280 会显著提升小目标召回,但显存占用也跟着涨,batch 从 16 降到 8 甚至 4 都属于正常代价。close_mosaic=15表示最后 15 个 epoch 关闭 mosaic 增广,让模型在接近真实分布的尺度上微调,否则会出现训练集上 loss 正常、验证集上小目标回调的现象。
batch 大小怎么定?显存不够时优先调小 batch,不要先砍 imgsz。瓶盖瑕疵这类目标对分辨率本来就敏感,一旦降到 640,前期再怎么调都找不回分辨率带来的收益。混合精度训练默认开启,显存还能再省一点。
3.3 第一版评估看什么
训练完不要只盯着mAP@0.5,工业场景更该看每个类别的 AP 和误检分布。YOLOv8 的训练输出里会存results.png和混淆矩阵,你要做的是把验证集里置信度 0.25 以下的“近误检”样本也捞出来看一遍。
yolo detect val \ model=baijiu_runs/exp_v1/weights/best.pt \ data=baijiu_dataset.yaml \ imgsz=1280 \ conf=0.001 \ save_json=Trueconf=0.001全是为了排查:正常评估阈值 0.25 只让你看到最终指标,把阈值拉到极低,输出的 json 预测里会包含大量低置信度框,这些框恰恰透露出模型在哪些位置上“有想法但不敢确定”。如果低置信度框大量集中在瓶身反光区或标签边缘,说明训练数据里的正样本不够“脏”,后面增广要往光学干扰上靠。
注意:验证集指标好 ≠ 产线能用。产线验收要看的是每百瓶误报数,不是 PR 曲线下面积。第一版评估时就把“哪些样本是模型不会的”记下来,后面做数据迭代才有依据。
4. 数据增广与负样本迭代: 提升泛化能力的实操路径
白酒疵品数据集再全,也覆盖不完产线上的所有变化。同一瓶酒在上午和下午的采光不同、不同批次瓶身的透光度不同、产线震动导致相机位姿有微小偏移。这些变化靠标注采集成本太高,靠增广是性价比最高的补充方式。增广的原则只有一个:模拟真实产线里会出现、而你数据里没有的扰动。
4.1 白酒产线的增广重点
通用目标检测里的随机翻转、旋转、缩放,对这个场景只算基础配置。真正影响白酒检测效果的是三类增广:光照干扰、模糊扰动、局部遮挡。
先说光照。白酒瓶是玻璃或高透 PET 材质,反光、折射、暗角都常见。灌装车间通常还有防爆灯和传送带遮光罩,不同工位的灯光角度不同。增广时要随机调整亮度、对比度和色相,必要时加模拟高光的白色斑块。
再说模糊。产线相机有时会因震动或液体流动产生轻微运动模糊,疵品本身的边缘也不锐利——液位线是一段渐变的月牙形,不是清晰的横线。高斯模糊、运动模糊增广能让模型适应这种边缘不锐利的情况。
遮挡则是瓶子之间互相遮挡、标签上贴着合格证、瓶盖上有防盗环等。随机裁剪掉一部分图像区域做 cutout,能让模型不完全依赖某个固定视觉特征。
4.2 用 albumentations 做光学干扰增广
YOLOv8 自带 mosaic、hsv 等内置增广,但工业场景我习惯额外接 albumentations 做离线增广,生成一份增强样本并到标注里,而不是只靠在线随机。原因很简单:在线增广每轮 epoch 都在变,模型看不全,而离线增广你可以人工检查增广后样本是否还保留了可辨认的疵品特征。
import albumentations as A import cv2 transform = A.Compose([ A.RandomBrightnessContrast(brightness_limit=0.4, contrast_limit=0.4, p=0.7), A.HueSaturationValue(hue_shift_limit=10, sat_shift_limit=20, val_shift_limit=30, p=0.5), A.GaussNoise(var_limit=(20, 60), p=0.4), A.MotionBlur(blur_limit=(5, 11), p=0.3), A.CoarseDropout(max_holes=8, max_height=48, max_width=48, fill_value=0, p=0.3), A.RandomResizedCrop(height=1280, width=1280, scale=(0.7, 1.0), p=0.2), ], bbox_params=A.BboxParams(format="yolo", label_fields=["class_labels"])) image = cv2.imread("images/train/0001.jpg") boxes = [[0.21, 0.45, 0.12, 0.18]] class_labels = [2] augmented = transform(image=image, bboxes=boxes, class_labels=class_labels)参数上要注意两点:RandomResizedCrop的 scale 不要低于 0.7,白酒瓶是长条形,裁得太狠瓶身结构会失真,模型容易把瓶盖捻成裂痕;CoarseDropout的 max_height 和 max_width 控制在 48 像素以内,只模拟标签贴纸、反光点这类小面积遮挡,不要把整个瓶身挖空。增广后的标注框如果被裁掉超过 30% 面积,建议直接丢弃该样本,否则会引入半截目标,干扰训练。
4.3 错检回灌: 把漏检样本变训练集
增广之外,真正拉开工业检测效果差距的是负样本迭代。找一批产线实拍图,不标注疵品,只标记“这是正常瓶”,跑一次推理,把置信度最高的误检框截出来,人工确认后作为难例样本放进训练集。这个流程看似简单,其实比增广更有效,因为增广只能模拟你已知的扰动,而误检框是模型自己暴露出的知识盲区。
yolo detect predict \ model=baijiu_runs/exp_v1/weights/best.pt \ source=normal_frames/ \ conf=0.1 \ save_txt=True \ save_conf=Trueconf=0.1比常规评估阈值更低,就是为了多捞误检。跑完后去runs/detect/predict/labels/里看每个 txt 对应的类别和置信度,凡是置信度高且框在瓶盖、标签、瓶身这类正常位置的目标,十有八九是负样本。把它们人工标成“正常”类别或直接归入背景,重新训练一轮,误报率通常能有可感知的下降。
提示:负样本回灌时不要只加原图,最好对误检区域做 1.5 倍周边的裁剪。模型更容易从局部上下文里学到“这种纹理不是疵品”,比看整张图收敛更快。
5. 训练白酒疵品检测的 5 个踩坑与排查要点
这个方向我踩过不少坑,有些是数据标注层面的,有些是训练策略层面的。下面几条是按出现频率排的,遇到指标异常或现场翻车时,按这个顺序排查通常能定位问题。
5.1 液位线标注口径不一致导致验证集 AP 虚高
现象:训练时液位线类别的 AP 一直很高,但现场对同一瓶酒反复拍照,检测框位置跳来跳去,且偶尔把瓶肩上的装饰纹路当液位线。
原因:不同标注员对“液位线”的理解不一致。有人标的是液面与瓶壁接触的弧线最高点,有人标的是液面在瓶身投影的完整月牙区域,还有人把瓶颈处的气泡也标了进去。标注框的上下边界飘忽,模型学到的不是“液面位置”,而是“瓶身中上部的某种边缘”。
解决:重新定义液位线的标注规则——只标液面与瓶壁交线所在的水平区域,框高不超过瓶身高度的 8%。把这套规则写进标注规范,并做一轮全量复核。迭代数据时也沿用同一口径,否则每次新增样本都在拉偏模型。
5.2 高光反射被误检为瓶盖破损
现象:验证集指标正常,但产线打光一强,模型把瓶盖上的高光点、反光条误报成裂纹,误报率直接翻倍。
原因:训练数据里正样本的裂纹特征与高光特征高度重叠——都是细长的亮色纹理。模型没有见过足够的“高光但不是裂纹”的反例,把亮度纹理当成了充分条件。
解决:采集一批强光源下的正常瓶盖图,单独做成难例集。打光时也建议交替使用环形光和条光,让模型见过不同反射形态。如果现场光源已固定,增广里加大 brightness 和对比度扰动幅度,逼模型把注意力放到纹理走向而非单纯亮度上。
5.3 玻璃瓶身让检测框漂移
现象:同一张图跑两次推理,某些疵品的框位置变化明显,甚至同一批次瓶子在传送带不同位置时,召回率差距很大。
原因:玻璃瓶透光、折射,瓶身后方的背景纹理会被映到前景里。模型学到的不只是疵品本身,还连带学了背景纹理的位置关系。传送带一换、背景一变,特征就失效了。
解决:训练时把背景多样性做上去。在数据集中混入不同颜色的背景板、传送带挡板、光源阴影的样本,尤其要包含瓶身旋转不同角度后的画面。如果数据集本身拍照角度单一,可以用轻微透视增广模拟瓶子在传送带上的位姿变化。
5.4 训练后期 loss 震荡,小目标召回反而下降
现象:epoch 到 120 以后,损失曲线不再平稳下降,而是每隔几个 epoch 就跳一下;同时验证集上瓶盖裂纹的召回率在下降。
原因:默认的 mosaic 增广在整个训练过程后期仍然开启。白酒瓶是长条目标,mosaic 会把四张图拼到一张里,瓶盖和瓶身被切得七零八落,模型在最后阶段还在适应大量残缺目标,导致真实分布上的特征被冲淡。
解决:按前面训练命令的做法,设置close_mosaic=15——在最后 15 个 epoch 关闭 mosaic,让模型回到原始图像尺度微调。另外如果训练集里小目标本身就少,把mosaic=0.5的概率降到 0.3 也可以缓解。
5.5 现场换光源后模型集体翻车
现象:验证集指标依旧漂亮,模型一到另一个车间、换了不同色温的灯光,漏检率飙升,几乎所有类别都掉点。
原因:数据集里图片的色温和亮度分布太集中,模型把“特定光照下的外观”当成了疵品的本质特征。这是典型的域迁移问题,越是在固定机位采集的数据,越容易过拟合到当时的打光条件。
解决:在数据采集阶段就用多组光源各拍一轮,组间色温拉开差距;训练时把 HSV 增广强度调高。若现场已经部署了固定光源,则建议把现场实拍图的色温统计出来,对训练集做 tone mapping 匹配,缩小源域和目标域的差距。
注意:多数训练翻车不是模型结构问题,是数据口径问题。排查顺序一定是先校验标注,再看增广,最后才动网络结构和训练参数。
6. 用故障注入做后悔药: 把正常样本改造成疵品样本
数据不够、某类疵品占比极低,这是白酒疵品检测数据集最常见的短板。与其等着产线慢慢攒样本,不如对正常样本做故障注入——用图像处理手段把正常瓶“改坏”,生成合成的疵品样本。这类样本虽然不完全等于真实瑕疵,但能让模型先学会“这类纹理是异常”,等真实样本积累到一定量再逐步替换。
故障注入适合三类疵品:液位线异常、标签破损、瓶身裂纹。液位线可以用色块覆盖原液面位置实现;标签破损可以叠加撕裂纹理;裂纹可以用细长线段配合暗色阴影合成。下面是一个用 OpenCV 给正常瓶子注入裂纹的示例。
import cv2 import numpy as np img = cv2.imread("normal_bottle.jpg") h, w = img.shape[:2] overlay = img.copy() # 随机生成 2~3 条短裂纹,位置集中在瓶身上部 rng = np.random.default_rng(42) for _ in range(rng.integers(2, 4)): x_start = int(rng.integers(int(w*0.3), int(w*0.7))) y_start = int(rng.integers(int(h*0.2), int(h*0.55))) length = int(rng.integers(20, 60)) angle = rng.uniform(-30, 30) x_end = int(x_start + length * np.cos(np.deg2rad(angle))) y_end = int(y_start + length * np.sin(np.deg2rad(angle))) cv2.line(overlay, (x_start, y_start), (x_end, y_end), (30, 30, 30), 1) # 裂纹两侧加半透明浅色晕染,模拟玻璃折射 cv2.line(overlay, (x_start, y_start), (x_end, y_end), (120, 120, 120), 3) # 和原图按比例融合,控制瑕疵强度 alpha = 0.6 mask = cv2.absdiff(overlay, img).astype(bool) img[mask] = (overlay * alpha + img * (1 - alpha))[mask] cv2.imwrite("injected_crack.jpg", img)注入的逻辑是:先用暗色细线画裂纹主体,再用浅色粗线模拟玻璃裂开后的折射亮区,最后只在差异区域做融合,避免整张图色调漂移。生成的样本要人工抽检,把“一眼假”的过滤掉——比如裂纹方向过于规则、位置老在画面正中央,这类样本会让模型产生位置偏好。
我自己的经验是,故障注入的样本占比不要超过总训练集的 20%,且每轮训练后都要单独在真实疵品验证集上评估。合成样本是给模型搭骨架的,真实样本是给模型塑血肉的,两者平衡不好,模型就会被合成纹理带偏。线上跑一段时间后,定期把新积累的真实疵品样本并入训练集,同时逐步调低合成样本比例,模型才会越来越贴近产线实况。这个迭代流程没有终点,但每一步都能看到真实误报在减少——希望帮到你。
本文还有配套的精品资源,点击获取