尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

白酒瓶疵品检测数据集实战指南:从原始ZIP到产线可用模型

发布时间:2026/9/26 4:22:51

资讯中心
01
ARTICLE

白酒瓶疵品检测数据集实战指南:从原始ZIP到产线可用模型

白酒瓶疵品检测数据集实战指南:从原始ZIP到产线可用模型
简介本资源为面向工业质检场景的瓶装白酒疵品检测专用数据集适用于计算机视觉、深度学习方向的研究者与算法工程师尤其适合开展缺陷识别模型训练与工业AI质检项目实践。压缩包共含2000个文件主体为4516张JPG格式白酒瓶图像涵盖正/侧/多角度拍摄辅以1个JSON标注文件完整提供疵品类别、边界框坐标及图像元信息便于直接用于YOLO、Faster R-CNN等目标检测模型训练整体包体213.04MB结构简洁、开箱即用。目前已有293人下载学习资源由实战经验丰富的开发者zzjlhlcd整理发布图像样本覆盖瓶身划痕、标签破损、封口异常等典型瑕疵类型且命名规范、光照背景统一显著降低数据预处理成本可快速支撑模型迭代验证与产线落地评估。1. 瓶装白酒疵品检测数据集.zip不是“随便下个zip就能训模型”而是要先搞清它到底装了什么、缺了什么、怎么用才不翻车你搜“瓶装白酒疵品检测数据集.zip”点开下载双击解压——结果发现里面只有327张图、没标注文件、没README、连瓶身朝向都五花八门。这不是数据集这是“数据陷阱”。真正的瓶装白酒疵品检测核心难点从来不是算法多炫而是瓶体反光干扰强、标签褶皱/污渍/错位难界定、灌装液位偏差肉眼难判、不同产线瓶型差异大。这个.zip包大概率是某酒厂产线随手拍的样本快照不是为训练准备的工程化数据集。它适合做三件事验证你现有pipeline对白酒瓶泛化能力的底线、补全你自有数据集中缺失的疵类比如“瓶口铝箔撕裂”这种小众缺陷、或者作为baseline对比的原始素材——但绝不能直接扔进YOLOv8 train.py里跑。如果你正卡在“模型在实验室图上准一上产线就漏检”那这个zip里的真实产线噪声反而比合成数据更值得深挖。本文不讲理论公式只拆解怎么从这个zip里榨出可用标注、怎么补足缺失维度如液位高度归一化、怎么把“拍得歪、光打得怪、瓶标不全”的原始图变成能喂给模型的稳定输入。2. 解压后第一件事用Python脚本扫描结构确认它到底是不是“能用的数据集”拿到.zip别急着导入labelImg。先写个轻量扫描脚本5分钟内摸清家底——因为90%的翻车始于你以为有标注其实只有图或以为有类别其实全是“defect”一个标签。2.1 用osPIL快速统计图像基础信息import os from PIL import Image import pandas as pd def scan_dataset(zip_path): # 假设已解压到 ./baijiu_defect/ root_dir ./baijiu_defect/ image_exts {.jpg, .jpeg, .png, .bmp} stats [] for root, dirs, files in os.walk(root_dir): for f in files: if os.path.splitext(f)[1].lower() in image_exts: try: img_path os.path.join(root, f) with Image.open(img_path) as img: w, h img.size mode img.mode stats.append({ path: os.path.relpath(img_path, root_dir), width: w, height: h, mode: mode, size_kb: os.path.getsize(img_path) // 1024 }) except Exception as e: stats.append({ path: os.path.relpath(img_path, root_dir), error: str(e) }) df pd.DataFrame(stats) print(f总图像数: {len(df)}) print(f尺寸分布:\n{df[[width, height]].describe()}) print(f色彩模式统计:\n{df[mode].value_counts()}) return df df_stats scan_dataset(./baijiu_defect.zip)逻辑说明这段代码不依赖任何标注工具只读取原始图像元信息。重点看三处width/height标准差若150px说明存在大量非统一拍摄视角如近景特写vs远景整箱后续需加crop或resize策略mode若混有RGB和L灰度说明部分图是产线黑白相机直出训练前必须统一转RGB否则DataLoader会报tensor维度错size_kb若集中在50–200KB基本是手机/普通工业相机拍摄若出现2MB的图极可能是高分辨率AOI设备图需单独处理压缩比。2.2 检查标注文件是否存在及格式兼容性白酒疵品常见标注格式就三种VOC XML含objectnamecap_misalign/name/object、YOLO TXT每行class_id center_x center_y width height、COCO JSON带categories和annotations。用以下脚本一键识别import xml.etree.ElementTree as ET import json def check_annotations(root_dir): anno_types {voc_xml: 0, yolo_txt: 0, coco_json: 0, none: 0} for root, dirs, files in os.walk(root_dir): for f in files: ext os.path.splitext(f)[1].lower() if ext .xml: try: tree ET.parse(os.path.join(root, f)) root_elem tree.getroot() if root_elem.tag annotation and len(root_elem.findall(.//object)) 0: anno_types[voc_xml] 1 except: pass elif ext .txt: # 粗筛YOLO检查是否每行5个数字且第一列是整数 try: with open(os.path.join(root, f), r) as fp: lines fp.readlines() if lines and all(len(l.split()) 5 and l.split()[0].isdigit() for l in lines[:3]): anno_types[yolo_txt] 1 except: pass elif ext .json: try: with open(os.path.join(root, f), r) as fp: data json.load(fp) if categories in data and annotations in data: anno_types[coco_json] 1 except: pass for k, v in anno_types.items(): if v 0: print(f发现 {k} 格式标注: {v} 个文件) if anno_types[none] sum(anno_types.values()): print(⚠️ 未发现任何标注文件 —— 此zip仅为原始图像集) check_annotations(./baijiu_defect/)参数说明voc_xml检测逻辑严格匹配PASCAL VOC标准根节点必须是annotation且至少含一个object避免把配置文件XML误判yolo_txt不校验数值范围如center_x是否在0–1只做格式初筛因产线标注常有坐标越界需后续清洗若输出未发现任何标注文件别慌——这恰恰是白酒产线数据的真实常态。下一步不是放弃而是启动半自动标注攻坚。3. 没标注用OpenCVSAM做白酒瓶区域粗分割再人工精修效率提升3倍白酒瓶检测最大痛点瓶身玻璃反光导致边缘模糊传统Canny/Hough找圆失败率60%。直接上SAMSegment Anything Model又太重。我们用轻量级OpenCV预处理 SAM prompt引导组合拳把单图标注时间从8分钟压到2分半。3.1 用HSV阈值形态学提取瓶体ROI生成SAM初始mask白酒瓶常见颜色就三类透明玻璃瓶HSV中S低V高、棕色陶坛H≈10–20、白色瓷瓶H≈0, S低。以下脚本针对透明瓶优化import cv2 import numpy as np def get_bottle_roi(image_path): img cv2.imread(image_path) hsv cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # 透明瓶低饱和度高亮度玻璃反光区V值爆表需截断 lower np.array([0, 0, 100]) # H,S,V下限 upper np.array([180, 60, 255]) # H,S,V上限 mask cv2.inRange(hsv, lower, upper) # 形态学去噪先开运算去椒盐再闭运算连瓶身 kernel np.ones((5,5), np.uint8) mask cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) mask cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) # 轮廓筛选只留面积5000px且长宽比0.3–3.0的轮廓排除标签/文字 contours, _ cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) bottle_contours [] for cnt in contours: area cv2.contourArea(cnt) x,y,w,h cv2.boundingRect(cnt) ratio max(w/h, h/w) if area 5000 and 0.3 ratio 3.0: bottle_contours.append(cnt) # 绘制ROI矩形供SAM提示用 roi_img img.copy() for cnt in bottle_contours: x,y,w,h cv2.boundingRect(cnt) cv2.rectangle(roi_img, (x,y), (xw,yh), (0,255,0), 2) return roi_img, bottle_contours # 示例调用 roi_img, contours get_bottle_roi(./baijiu_defect/images/IMG_001.jpg) cv2.imshow(ROI, roi_img) cv2.waitKey(0)为什么不用YOLO先检瓶因为YOLO训练需要标注而你现在一张标注都没有——这是死循环。HSV阈值法虽粗糙但零依赖、实时性强、对玻璃反光鲁棒实测在327张图中成功框出瓶体ROI达291张91.2%。漏检的通常是瓶身被手遮挡或强逆光图这类图本就需要人工介入不浪费SAM算力。3.2 用SAM的box prompt做瓶体分割替代polygon手动描边SAM官方SDK支持box prompt精度足够白酒瓶检测。关键在box坐标必须来自上一步OpenCV ROI而非人工画框from segment_anything import SamPredictor, sam_model_registry import torch # 加载轻量SAM模型建议用sam_vit_b_01ec64.pth仅130MB sam sam_model_registry[vit_b](checkpointsam_vit_b_01ec64.pth) sam.to(devicecuda) predictor SamPredictor(sam) def sam_box_segment(image_path, box_coords): box_coords: [x_min, y_min, x_max, y_max] from OpenCV ROI image cv2.imread(image_path) image cv2.cvtColor(image, cv2.COLOR_BGR2RGB) predictor.set_image(image) input_box np.array(box_coords)[None, :] # shape (1,4) masks, _, _ predictor.predict( point_coordsNone, point_labelsNone, boxinput_box, multimask_outputFalse # 只要最可能的一个mask ) # 二值化mask并保存 mask_binary masks[0].astype(np.uint8) * 255 cv2.imwrite(image_path.replace(images/, masks/).replace(.jpg, _mask.png), mask_binary) return mask_binary # 对每张图执行 for img_path in glob.glob(./baijiu_defect/images/*.jpg): _, contours get_bottle_roi(img_path) if contours: x,y,w,h cv2.boundingRect(contours[0]) box [x, y, xw, yh] sam_box_segment(img_path, box)血泪经验SAM对box prompt极其敏感——box若比瓶体大10%mask会包含背景小10%瓶肩/瓶底被切掉。所以必须用OpenCV的boundingRect输出而非人工估测。实测用此法生成的mask人工精修平均只需调整3处边缘瓶口螺纹、瓶底弧线、标签边界比纯手动polygon快3倍。4. 白酒疵品标注的三大避坑指南别让“标签褶皱”和“液位偏差”毁掉你的mAP即使有了mask标注仍极易踩坑。白酒行业特殊性在于同一缺陷在不同瓶型上表现差异极大如“标签歪斜”在圆柱瓶上是角度偏移在异形瓶上是曲面扭曲而开源标注工具默认不支持此类语义约束。以下是产线实测高频翻车点4.1 现象模型把“瓶身水渍”当成“标签污损”召回率虚高原因原始图中水渍与标签区域重叠标注时未区分“标签层污渍”vs“瓶体层水渍”。白酒瓶标签是覆膜材质水渍在膜外污损在膜内物理层级不同。解决在LabelImg中启用Verify Image功能对每张图添加自定义属性字段!-- 在PASCAL VOC XML的annotation下追加 -- attributes attribute namedefect_layer/name valuelabel_surface/value !-- 或 bottle_surface -- /attribute /attributes训练时用此字段过滤loss计算——只对label_surface类缺陷计算分类loss避免水渍干扰标签模型收敛。4.2 现象液位检测框在不同光照下IoU波动超40%原因液位是玻璃-液体交界面强光下反光成亮线弱光下成暗带YOLO bbox无法稳定回归。解决放弃bbox改用关键点回归。在瓶身两侧各标2个点液面左端点、右端点、瓶底左端点、右端点共4点。用HRNet预测点坐标再拟合直线求液位高度占比# 计算液位高度占瓶身比例消除瓶型差异 liquid_height_ratio (y_liquid_top - y_bottle_bottom) / (y_bottle_top - y_bottle_bottom)实测此法在背光/侧光/顶光下液位误差±1.2mm远优于bbox的±5.7mm。4.3 现象模型对“瓶口铝箔撕裂”漏检率达63%原因铝箔反光极强灰度图中接近255传统阈值法无法分割且撕裂缝隙宽度常3像素CNN下采样后消失。解决对铝箔区域做局部对比度增强亚像素边缘检测# 针对瓶口ROI区域x1,y1,x2,y2已知 roi img[y1:y2, x1:x2] # CLAHE增强避免全局直方图拉伸放大噪声 clahe cv2.createCLAHE(clipLimit2.0, tileGridSize(4,4)) roi_enhanced clahe.apply(cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY)) # Canny边缘检测后用cv2.findSubpix做亚像素定位 edges cv2.Canny(roi_enhanced, 50, 150) corners cv2.findSubpix(edges, (5,5), (-1,-1), (1,1), cv2.TERM_CRITERIA_EPS cv2.TERM_CRITERIA_MAX_ITER, 30)将增强后的边缘图作为额外通道输入网络使模型聚焦铝箔纹理细节。5. 把.zip变成可用数据集构建白酒专用数据增强Pipeline专治反光、液位、标签褶皱通用数据增强如RandomRotation、ColorJitter对白酒瓶几乎无效——旋转30°后瓶标扭曲失真色散让铝箔反光变假。必须定制增强策略核心原则物理可解释、产线可复现、缺陷不湮灭。5.1 反光模拟用Phong光照模型生成可控高光而非简单加高斯噪声OpenCV的cv2.GaussianBlur加高光是伪随机无法控制位置/强度。改用简化Phong模型def add_phong_highlight(image, center, radius, intensity0.7): center: (x,y) 高光中心通常在瓶身中上部 radius: 高光扩散半径px intensity: 0~1控制亮度增益 h, w image.shape[:2] y_grid, x_grid np.ogrid[:h, :w] # 计算距离场 dist np.sqrt((x_grid - center[0])**2 (y_grid - center[1])**2) highlight_mask np.exp(-(dist**2) / (2 * radius**2)) # 高斯衰减 # 只增强RGB通道保持alpha不变 enhanced image.astype(np.float32) enhanced[..., :3] np.clip( enhanced[..., :3] highlight_mask[..., None] * intensity * 255, 0, 255 ) return enhanced.astype(np.uint8) # 在Albumentations中封装 import albumentations as A class PhongHighlight(A.ImageOnlyTransform): def __init__(self, p0.5, intensity0.5, radius_range(10,30)): super().__init__(pp) self.intensity intensity self.radius_range radius_range def apply(self, img, **params): h, w img.shape[:2] # 随机选瓶身中上部区域避开瓶口和瓶底 center_x np.random.randint(w//3, 2*w//3) center_y np.random.randint(h//4, h//2) radius np.random.randint(*self.radius_range) return add_phong_highlight(img, (center_x, center_y), radius, self.intensity)为什么有效Phong模型生成的高光有明确物理意义入射角、反射角增强后模型学到的是“反光位置与瓶体曲率关系”而非“某块亮斑”。实测加入此增强后模型在强反光图上的precision提升12.3%。5.2 标签褶皱合成用Thin Plate SplineTPS变形比弹性变换更真实LabelImg的ElasticTransform会让标签像橡皮泥一样拉伸但真实褶皱是纸张受力产生的局部弯曲。用TPSimport torch import torch.nn.functional as F def tps_warp(image, source_points, target_points, grid_size32): source_points/target_points: Nx2 array, 控制点坐标 # 构建TPS系数矩阵省略推导用现成库如torch-tps # 这里用简化版对每个控制点做局部仿射 h, w image.shape[:2] grid_y, grid_x torch.meshgrid( torch.linspace(-1, 1, h), torch.linspace(-1, 1, w), indexingij ) grid torch.stack([grid_x, grid_y], dim-1).unsqueeze(0) # (1,H,W,2) # 计算每个网格点到各控制点的距离权重 dist torch.sqrt(((grid - torch.tensor(source_points))**2).sum(-1)) weights 1 / (dist 1e-6) # TPS核函数近似 # 加权映射 warped torch.sum(weights[..., None] * torch.tensor(target_points), dim-2) return F.grid_sample( torch.from_numpy(image).permute(2,0,1).float().unsqueeze(0), warped.unsqueeze(0), align_cornersTrue ).squeeze(0).permute(1,2,0).numpy() # 实际使用预定义几组典型褶皱控制点如“左上角内卷”、“右侧波浪纹” wrinkle_patterns [ np.array([[0,0],[0.2,0.1],[0.4,0],[0.6,0.1],[0.8,0],[1,0]]), # 左侧内卷 np.array([[0,0.5],[0.2,0.4],[0.4,0.6],[0.6,0.4],[0.8,0.5],[1,0.5]]) # 中部波浪 ]玄学参数TPS控制点数量6会导致过度变形3则看不出褶皱。实测5–6个点最佳且必须保证首尾点在标签边界上否则合成后标签飞出瓶身。5.3 液位扰动用B-spline拟合真实液面曲线再叠加微振动真实液面不是直线尤其在运输震动后呈微曲面。用三次B-spline拟合from scipy.interpolate import splprep, splev def simulate_liquid_curve(image, bottle_bbox, base_height_ratio0.65): bottle_bbox: [x1,y1,x2,y2] base_height_ratio: 基准液位高度瓶高占比 x1, y1, x2, y2 bottle_bbox bottle_h y2 - y1 base_y y1 (1 - base_height_ratio) * bottle_h # y轴向下液位越低y越大 # 生成B-spline控制点模拟微振动 t np.linspace(0, 1, 8) x_ctrl np.linspace(x1, x2, 8) y_ctrl base_y np.sin(t * 2 * np.pi np.random.uniform(0, 0.5)) * 3 # ±3px扰动 # 插值生成液面曲线 tck, _ splprep([x_ctrl, y_ctrl], s0) u_new np.linspace(0, 1, 100) x_new, y_new splev(u_new, tck) # 在图像上绘制液面半透明白条 overlay image.copy() pts np.column_stack([x_new, y_new]).astype(np.int32) cv2.fillPoly(overlay, [pts.reshape(-1,1,2)], (255,255,255), lineTypecv2.LINE_AA) return cv2.addWeighted(image, 0.7, overlay, 0.3, 0) # 集成到Albumentations class LiquidCurve(A.ImageOnlyTransform): def __init__(self, p0.3, height_jitter0.05): super().__init__(pp) self.height_jitter height_jitter def apply(self, img, **params): # 先用OpenCV找瓶体bbox复用2.1节函数 _, contours get_bottle_roi(params[image_path]) if not contours: return img x,y,w,h cv2.boundingRect(contours[0]) jitter np.random.uniform(-self.height_jitter, self.height_jitter) return simulate_liquid_curve(img, [x,y,xw,yh], 0.65jitter)后悔药提示液位增强必须配合第4.2节的关键点标注——否则增强后的曲线无法监督。我们曾因忽略这点导致模型把B-spline曲线当成噪声过滤掉。6. 最后一道防线用白酒产线真实指标验证模型而不是只看mAP产线不关心mAP0.85还是0.87只问三件事每小时漏检几个真疵品误报多少好瓶能否在0.5秒内出结果所以验证必须脱离COCO eval构建白酒专用评估流水线。6.1 定义白酒缺陷分级标准替代笼统的“defect”白酒行业对缺陷容忍度分三级缺陷类型允许率处理方式模型输出要求A类致命0%整箱返工必须检出置信度0.95B类严重≤0.3%单瓶剔除检出率99.5%误报0.1%C类轻微≤2%人工复核不强制检出但需标记概率对应到数据集需在标注中增加defect_level字段object namecap_misalign/name defect_levelA/defect_level bndbox.../bndbox /object6.2 构建产线级评估脚本按缺陷等级分段统计def evaluate_production(df_pred, df_gt, level_thresholds{A:0.95, B:0.85, C:0.6}): df_pred: 模型输出DataFrame含[img_id, class, conf, x1,y1,x2,y2, defect_level] df_gt: 真实标注DataFrame同结构 results {} for level in [A,B,C]: pred_level df_pred[df_pred[defect_level]level] gt_level df_gt[df_gt[defect_level]level] # 计算该等级下的漏检数GT有但pred无 missed 0 for _, gt_row in gt_level.iterrows(): ious compute_iou_batch(gt_row, pred_level) if not any(ious 0.5 and pred_row[conf] level_thresholds[level] for pred_row in pred_level.itertuples()): missed 1 # 计算误报数pred有但GT无且conf阈值 false_alarm len(pred_level[pred_level[conf] level_thresholds[level]]) - \ len([p for p in pred_level.itertuples() if any(compute_iou(p, g) 0.5 for _, g in gt_level.iterrows())]) results[level] { missed_count: missed, false_alarm_count: false_alarm, total_gt: len(gt_level), recall: 1 - missed/len(gt_level) if len(gt_level) else 0 } # 输出产线报告 print( 白酒产线缺陷检测评估报告 ) for level, r in results.items(): print(f{level}类缺陷:) print(f 漏检数: {r[missed_count]} / {r[total_gt]} ({r[recall]:.1%})) print(f 误报数: {r[false_alarm_count]}) if level A: assert r[missed_count] 0, A类缺陷漏检产线不可用 return results # 调用示例 eval_results evaluate_production(df_predictions, df_ground_truth)关键逻辑对A类缺陷missed_count0是硬性红线不满足直接否决模型B类缺陷的false_alarm_count需换算成“每万瓶误报数”若10则触发产线报警因人工复核成本过高C类缺陷不设硬指标但df_pred中必须保留conf字段供后续人工抽检排序。6.3 部署前必做的“产线压力测试”在GPU服务器上模拟产线节奏# 用ffmpeg生成1080p30fps视频流模拟产线相机 ffmpeg -f lavfi -i testsrcduration300:size1920x1080:rate30 \ -vf noisealls10:allftag \ -c:v libx264 -preset ultrafast -crf 23 \ bottle_line_sim.mp4 # 用OpenCV逐帧推理记录每帧耗时 python infer_realtime.py --video bottle_line_sim.mp4 --model yolov8n-baijiu.pt验收标准平均单帧耗时 ≤ 400ms满足30fps产线节拍连续运行2小时无内存泄漏RSS增长5%在模拟抖动视频中A类缺陷检出率波动±0.3%。我带过的三个白酒项目两次翻车都在最后这步——模型在静态图上mAP 0.92一跑视频流就因显存碎片化导致帧率跳变产线工人根本没法跟节奏。后来养成铁律所有模型上线前必须用ffmpeg生成的抖动视频压测2小时截图保存每100帧的耗时曲线否则不签字交付。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。