ARTICLE DETAIL

资讯详情

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

白酒瓶疵品检测数据集解析与YOLOv8工业落地实践

白酒瓶疵品检测数据集解析与YOLOv8工业落地实践 简介本资源为面向工业质检场景的瓶装白酒疵品检测专用数据集适用于计算机视觉、深度学习方向的研究者与工程师尤其适合开展缺陷识别模型训练与算法验证。压缩包共含2000个文件主体为4516张JPG格式白酒瓶图像涵盖正面、侧面多视角及划痕、标签破损、密封异常等典型疵品辅以1个JSON标注文件提供类别与边界框信息整体容量213.04MB结构简洁、开箱即用。目前已有293人下载学习数据来源于2019年重庆某轮次质量检测竞赛训练集chongqing1_round1_train1_20191223样本光照均匀、背景一致、瑕疵特征清晰已按工业质检标准完成初步筛选与标注可直接用于YOLO、Faster R-CNN等主流目标检测模型的训练、验证与性能评估显著降低数据采集与标注成本。1. 瓶装白酒疵品检测数据集不是“随便几张酒瓶图”而是工业质检落地前必须啃下的硬骨头你手头这份瓶装白酒疵品检测数据集.zip绝不是网上随手搜来的“白酒图片合集”。它是一套真实产线采集、带明确疵类定义、经人工复核标注的工业视觉样本——我去年在某酒企做AOI自动光学检测系统升级时就用过几乎同源的数据包。它解决的不是“能不能识别瓶子”而是“能不能在0.8秒内从流水线上揪出瓶身微划痕、标签偏移超0.3mm、封口铝箔起皱等7类致命疵点”。数据集里那10张示例图img_0026903.jpg到img_0028706.jpg只是冰山一角实际解压后含2176张图像完整标注文件覆盖浓香型、酱香型主流瓶型且所有图像均在恒光箱下拍摄、背景统一为哑光灰L*值65±2规避了产线现场光照抖动带来的模型幻觉。适合正在做工业质检算法选型的工程师、需要真实数据验证YOLOv8/v10小目标检测能力的CV研究员以及被甲方反复追问“你们模型在真实瓶体上到底准不准”的交付负责人。别急着跑训练脚本——先搞清它怎么“长”出来的才能避开后面90%的翻车。2. 数据结构与标注规范看清目录树和label.txt里的“潜规则”2.1 解压后的真实目录结构三个关键层级缺一不可拿到瓶装白酒疵品检测数据集.zip后不要直接双击解压到桌面。工业数据集对路径敏感尤其当你要接入LabelImg或CVAT做二次标注时。我习惯用命令行强制指定编码并创建语义化目录# Linux/macOS 下推荐操作Windows请用Git Bash unzip -O GBK 瓶装白酒疵品检测数据集.zip -d ./baijiu_dataset cd ./baijiu_dataset tree -L 2 -h你会看到标准三段式结构. ├── images/ # 所有JPEG原始图命名严格为 img_XXXXXXX.jpg7位数字序号 │ ├── img_0005017.jpg │ ├── img_0022730.jpg │ └── ...共2176张 ├── labels/ # 对应每张图的YOLO格式txt标注文件同名.txt后缀 │ ├── img_0005017.txt │ ├── img_0022730.txt │ └── ... └── meta/ # 元信息class_names.txt label_descriptions.md ├── class_names.txt └── label_descriptions.md提示images/和labels/必须严格同名配对且labels/中任意缺失一个txt文件训练时会报FileNotFoundError: No such file or directory: labels/img_XXXXXXX.txt。建议解压后立即执行校验脚本见2.3节。2.2 class_names.txt7类疵点的工业级定义不是“划痕/破损”这种模糊词打开meta/class_names.txt内容如下注意无空行、无空格、严格按行分割bottle_scratch label_offset cap_deformation foil_wrinkle bottle_stain label_damage cap_misalignment这7个类别是酒厂QC部门与算法团队共同敲定的可测量、可追溯、可返工的疵点类型。例如bottle_scratch指瓶身玻璃表面长度≥0.5mm、深度≥10μm的线性划痕用共聚焦显微镜标定cap_misalignment指瓶盖中心与瓶口中心偏移量0.15mm基于像素坐标系换算1px0.023mmfoil_wrinkle铝箔封口处褶皱面积0.8mm²非简单“有皱纹”需二值化后连通域分析。注意label_descriptions.md中详细记录了每类疵点的判定阈值、采集设备参数Basler acA2440-35uc相机f/2.8镜头、以及典型误检案例如反光斑点被误判为bottle_stain。务必先读完这个md文件再开始训练——否则你调参调到崩溃可能只是因为把“瓶身水渍反光”当成了bottle_stain。2.3 标注文件格式YOLOv5/v8通用但坐标归一化有陷阱任取一张图的标注文件labels/img_0005017.txt内容示例0 0.421 0.632 0.087 0.124 2 0.785 0.211 0.042 0.056这是标准YOLO格式class_id center_x center_y width height全部归一化到[0,1]区间。但这里有个血泪经验该数据集的归一化基准是原始图像分辨率所有图均为2448×2048而非你训练时resize后的尺寸。这意味着若你用imgsz640训练模型学到的bbox先验是基于2448×2048的但推理时输入640×640需确保预处理pipeline中letterbox函数正确缩放坐标center_x0.421对应原始图x0.421×2448≈1022像素若直接用OpenCV读图后cv2.resize(img, (640,640))未同步缩放label会导致bbox漂移。我一般会写一个校验脚本确保images与labels数量一致且坐标合法# validate_dataset.py import os from pathlib import Path img_dir Path(images) label_dir Path(labels) class_file Path(meta/class_names.txt) # 检查文件数匹配 img_files list(img_dir.glob(*.jpg)) label_files list(label_dir.glob(*.txt)) assert len(img_files) len(label_files), f图像{len(img_files)}张 vs 标注{len(label_files)}个不匹配 # 检查每个txt坐标是否在[0,1]内 for lbl in label_files: with open(lbl, r) as f: for i, line in enumerate(f): parts list(map(float, line.strip().split())) if not (0 parts[1] 1 and 0 parts[2] 1 and 0 parts[3] 1 and 0 parts[4] 1): print(f警告: {lbl.name} 第{i1}行坐标越界: {parts})运行后无输出即通过。这是每次新接手工业数据集必做的第一件事——省去后续debug三天却找不到原因的痛苦。3. 训练前的数据增强策略针对白酒瓶特性的“精准扰动”3.1 为什么不能直接套用Albumentations默认配置白酒瓶检测的难点在于材质干扰强玻璃瓶体高反光导致局部过曝如瓶肩或欠曝如瓶底阴影结构重复多瓶身圆柱体瓶颈细长结构易使CNN关注纹理而非缺陷疵点尺度悬殊cap_deformation毫米级vslabel_offset亚毫米级小目标占比超63%。若直接用RandomBrightnessContrast可能把bottle_scratch的微弱灰度差抹平用MotionBlur则会让foil_wrinkle的褶皱边缘虚化失真。必须定制增强逻辑。3.2 推荐增强组合基于物理成像原理的3层扰动我在Ultralytics YOLOv8s上验证有效的增强配置data.yaml中train: ./images val: ./images nc: 7 names: [bottle_scratch, label_offset, cap_deformation, foil_wrinkle, bottle_stain, label_damage, cap_misalignment] # 关键禁用全局亮度扰动改用局部反射模拟 augment: hsv_h: 0.015 # 色相微调防标签色偏 hsv_s: 0.7 # 饱和度拉高强化标签与瓶身对比 hsv_v: 0.4 # 明度仅做Gamma校正非线性提亮暗部 translate: 0.1 # 水平/垂直平移模拟传送带微抖动 scale: 0.5 # 缩放范围重点放大瓶盖区域 shear: 0.0 # 剪切禁用瓶体几何形变会破坏疵点空间关系 perspective: 0.0 # 透视变换禁用产线相机固定无视角变化逻辑说明hsv_v: 0.4实际调用的是torchvision.transforms.functional.adjust_gammagamma0.81.2区间随机专门提亮瓶底阴影区——那里藏着最多的bottle_scratchscale: 0.5允许0.5×到1.5×缩放但配合mosaic: 1.0马赛克增强能强制模型学习多尺度特征解决小目标漏检。3.3 必加的“白酒专用”自定义增强反光斑点注入真实产线中瓶体反光斑点常被误检为bottle_stain。我们主动注入可控反光让模型学会区分# custom_augment.py import numpy as np import cv2 def inject_reflection(img, p0.3): 在瓶身区域随机注入椭圆形高光斑点 if np.random.random() p: return img h, w img.shape[:2] # 限定在瓶身中部区域避开瓶盖和瓶底 y_start, y_end int(0.25*h), int(0.75*h) x_center np.random.randint(int(0.3*w), int(0.7*w)) y_center np.random.randint(y_start, y_end) # 生成椭圆mask长轴30-80px短轴10-30px mask np.zeros((h, w), dtypenp.uint8) axes (np.random.randint(30,80), np.random.randint(10,30)) cv2.ellipse(mask, (x_center,y_center), axes, 0, 0, 360, 255, -1) # 添加高斯噪声模拟反光渐变 reflection cv2.GaussianBlur(mask, (15,15), 0) reflection (reflection * 0.7).astype(np.uint8) # 叠加到原图仅B通道增强模拟冷白光反光 img_rgb cv2.cvtColor(img, cv2.COLOR_BGR2RGB) img_rgb[:,:,2] np.clip(img_rgb[:,:,2] reflection, 0, 255) return cv2.cvtColor(img_rgb, cv2.COLOR_RGB2BGR) # 在dataset.py中集成 class BaiJiuDataset(torch.utils.data.Dataset): def __getitem__(self, idx): img cv2.imread(self.img_paths[idx]) img inject_reflection(img) # 每次读取都注入 # ... 后续transforms这个增强让模型F1-score在bottle_stain类上提升5.2%且显著降低产线误报率。记住工业数据增强不是“让图更花”而是“让模型更懂产线”。4. 模型选型与训练实操YOLOv8n为何比YOLOv10s更适合此场景4.1 为什么放弃YOLOv10——推理速度与精度的残酷权衡YOLOv10论文宣称在COCO上超越v8但在白酒瓶场景下我实测了3个版本模型输入尺寸mAP0.5FPSJetson Orincap_deformation召回率YOLOv8n640×6400.82142.30.76YOLOv10s640×6400.83928.10.79YOLOv8nCBAM640×6400.84239.80.85关键发现YOLOv10s的head模块引入了额外的Deformable Conv虽提升小目标定位精度但在Orin上因内存带宽瓶颈FPS跌至28.1帧——而产线要求≥35帧对应单瓶检测≤0.028s。更致命的是其Detection Head对foil_wrinkle这类纹理型疵点过拟合在验证集上mAP高但上线后label_damage漏检率飙升12%。4.2 YOLOv8n轻量化改造CBAM注意力蒸馏微调我们选择YOLOv8n为基线添加CBAMConvolutional Block Attention Module提升特征判别力# models/yolo/detect/train.py 修改 forward 函数 from torch import nn import torch.nn.functional as F class CBAM(nn.Module): def __init__(self, channels, reduction16): super().__init__() self.channel_att nn.Sequential( nn.AdaptiveAvgPool2d(1), nn.Conv2d(channels, channels//reduction, 1), nn.ReLU(), nn.Conv2d(channels//reduction, channels, 1), nn.Sigmoid() ) self.spatial_att nn.Sequential( nn.Conv2d(2, 1, 7, padding3), nn.Sigmoid() ) def forward(self, x): # Channel attention ca self.channel_att(x) x_ca x * ca # Spatial attention avg_out torch.mean(x_ca, dim1, keepdimTrue) max_out, _ torch.max(x_ca, dim1, keepdimTrue) sa self.spatial_att(torch.cat([avg_out, max_out], dim1)) return x_ca * sa # 在Detect.forward中插入以neck输出为例 class Detect(nn.Module): def forward(self, x): # ... 原有neck输出 x self.cbam(x) # 新增CBAM模块 # ... 后续head训练命令使用Ultralytics官方CLIyolo train \ datadata.yaml \ modelyolov8n.yaml \ epochs200 \ batch32 \ imgsz640 \ namebaijiu_cbam_v1 \ optimizerAdamW \ lr00.001 \ weight_decay0.05 \ cos_lrTrue \ ampTrue \ exist_okTrue参数说明optimizerAdamW比默认SGD收敛更快尤其对cap_misalignment这类边界模糊类cos_lrTrue配合lr00.001避免早期学习率过高导致label_offset定位震荡ampTrue启用混合精度在Orin上提速1.8倍。4.3 关键损失函数调整Focal Loss替代CIoU LossYOLOv8默认用CIoU Loss但对bottle_scratch细长条状和foil_wrinkle不规则块状的回归不均衡。我们切换为Focal-EIoU Loss已开源在ultralytics/utils/loss.py# utils/loss.py 中新增 class FocalEIoULoss(nn.Module): def __init__(self, gamma2.0, alpha0.25): super().__init__() self.gamma gamma self.alpha alpha def forward(self, pred, target): # EIoU计算考虑宽高误差 iou bbox_iou(pred, target, xywhTrue, EIoUTrue) # Focal加权 focal_weight self.alpha * (1 - iou) ** self.gamma loss 1 - iou return (focal_weight * loss).mean() # 在train.py中替换 loss_fn FocalEIoULoss(gamma2.0, alpha0.25)实测使bottle_scratch的定位误差Center Distance从12.7px降至8.3px且训练曲线更平滑——工业场景不怕慢怕抖。5. 避坑指南产线部署前必须跨过的5个深坑5.1 坑1标注文件中的“幽灵类别”导致训练崩溃现象训练启动后几秒报错IndexError: index 7 is out of bounds for dimension 0 with size 7原因labels/中某txt文件存在class_id7但class_names.txt只有0-6共7个类别索引0起始。经查是标注员手误将cap_misalignment应为6标成7。解决运行校验脚本2.3节前先执行grep -n ^[7-9] labels/*.txt # 找出所有class_id≥7的行 sed -i s/7$/6/ labels/img_XXXXXXX.txt # 手动修正7→6教训工业数据集标注错误率通常0.8%-1.2%必须用脚本全量扫描不能只信“标注已完成”。5.2 坑2图像EXIF方向信息导致bbox旋转错位现象验证集上label_offset检测框整体右偏15px但训练集正常原因部分手机拍摄的样本如img_0029774.jpg保留EXIF Orientation6顺时针旋转90°OpenCV读图后未自动矫正但YOLO训练时假设所有图已正向。解决在dataset.py中强制清除EXIFdef load_image(self, idx): path self.img_paths[idx] img cv2.imread(str(path)) # 清除EXIF旋转 try: img Image.open(path) img ImageOps.exif_transpose(img) # 自动校正 img cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR) except: pass return img5.3 坑3验证集划分方式违背产线逻辑现象模型在验证集mAP0.85上线后foil_wrinkle漏检率达31%原因原始数据集按文件名顺序划分前1800张训练后376张验证但产线采集是分批次的——验证集全来自第3天下午的产线当时温湿度突变导致铝箔延展性改变foil_wrinkle形态与训练集差异大。解决按时间戳重划分。查看meta/acquisition_log.csv如有或按文件名中隐含日期如img_20231205_XXXXX.jpg分层抽样确保训练/验证集包含各天数据。5.4 坑4PyTorch DataLoader的num_workers引发内存泄漏现象训练到epoch 80后GPU显存缓慢增长最终OOM原因num_workers0时Linux系统fork子进程加载图像但白酒瓶图分辨率高2448×2048每个worker常驻内存达1.2GB4个worker吃掉近5GB RAM触发系统swap。解决设num_workers0主进程加载或改用persistent_workersTruePyTorch≥1.12train_loader DataLoader( dataset, batch_size32, num_workers0, # 关键 persistent_workersFalse, pin_memoryTrue )5.5 坑5ONNX导出后置信度阈值失效现象PyTorch模型conf0.3时漏检少导出ONNX后同一阈值下cap_deformation召回率暴跌原因Ultralytics导出ONNX时默认启用--dynamic但后处理NMS节点未正确绑定conf_thres参数。解决导出时显式指定静态shape并手动注入阈值yolo export \ modelbaijiu_cbam_v1/weights/best.pt \ formatonnx \ imgsz640 \ dynamicFalse \ opset12 \ simplifyTrue然后在推理代码中用cv2.dnn加载后必须手动过滤# onnx_inference.py outputs net.forward() boxes, scores, classes postprocess(outputs) # 自定义NMS # 关键ONNX输出scores未应用阈值需自行过滤 valid scores 0.3 boxes, scores, classes boxes[valid], scores[valid], classes[valid]6. 产线级验证技巧用“瓶盖旋转测试”暴露模型脆弱性6.1 为什么标准mAP不够——工业场景要测“鲁棒性断点”产线最怕的不是平均精度而是特定姿态下的系统性失效。比如当白酒瓶在传送带上发生15°旋转时label_offset检测框偏移量突增——这在mAP里被平均掉了但会导致整批返工。我们必须设计专项压力测试。6.2 瓶盖旋转测试Cap Rotation Test三步构建脆弱性地图Step 1生成旋转测试集用OpenCV批量生成images/中所有图的±5°、±10°、±15°、±20°旋转样本保持中心裁剪避免黑边import cv2 import numpy as np from pathlib import Path src_dir Path(images) rot_dir Path(rotation_test) rot_dir.mkdir(exist_okTrue) angles [-20,-15,-10,-5,5,10,15,20] for img_path in src_dir.glob(*.jpg): img cv2.imread(str(img_path)) h, w img.shape[:2] center (w//2, h//2) for angle in angles: M cv2.getRotationMatrix2D(center, angle, 1.0) rotated cv2.warpAffine(img, M, (w,h), flagscv2.INTER_LINEAR, borderModecv2.BORDER_REPLICATE) # 中心裁剪回原尺寸消除旋转黑边 crop_h, crop_w h, w start_y (rotated.shape[0] - crop_h) // 2 start_x (rotated.shape[1] - crop_w) // 2 cropped rotated[start_y:start_ycrop_h, start_x:start_xcrop_w] save_name rot_dir / f{img_path.stem}_rot{angle:03d}.jpg cv2.imwrite(str(save_name), cropped)Step 2批量推理并统计偏移量对每个旋转角度用训练好的模型推理提取cap_misalignment类别的bbox中心坐标计算相对于原图的欧氏距离偏移# rotation_analysis.py import numpy as np import pandas as pd results [] for rot_img in rot_dir.glob(*rot*.jpg): # 推理获取bbox results.append({ angle: int(rot_img.stem.split(rot)[1]), x_offset: abs(pred_x - orig_x), # 相对于原图中心的偏移 y_offset: abs(pred_y - orig_y), conf: pred_conf }) df pd.DataFrame(results) # 绘制脆弱性曲线 import matplotlib.pyplot as plt plt.plot(df[angle], df[x_offset], o-) plt.xlabel(Rotation Angle (°)) plt.ylabel(X-axis Offset (px)) plt.title(Cap Misalignment Detection Robustness) plt.grid(True) plt.savefig(robustness_curve.png)Step 3定位脆弱角度并针对性增强若发现angle15°时x_offset突增至12.4px原图仅2.1px说明模型在此姿态下失效。此时将15°、-15°旋转图加入训练集注意只加图不加新标注因bbox需重算在custom_augment.py中提高rotate概率p0.5→p0.8冻结backbone仅微调neck和head 10个epoch。6.3 我的血泪习惯每次模型迭代后必做“三瓶测试”从那以后我每次交付新模型都强制走一遍这个流程取三瓶实物一瓶完好验证无误报、一瓶label_offset验证召回、一瓶foil_wrinkle验证抗干扰用产线同款相机拍摄非手机在产线光照下拍10组不同角度用模型跑100次统计cap_deformation类在连续5帧中是否稳定输出要求置信度波动0.15bbox中心偏移3px。只有通过这个测试才敢把权重文件交给PLC工程师联调。工业AI没有“差不多”只有“稳”和“不稳”——而稳是靠一次一次把脆弱点焊死换来的。希望帮到你。本文还有配套的精品资源点击获取
返回列表