ARTICLE DETAIL

资讯详情

深耕网站建设、视觉设计与SEO优化的一线实战洞察。

罐装饮料识别数据集实战:COCO转YOLO与YOLOv8训练全攻略

罐装饮料识别数据集实战:COCO转YOLO与YOLOv8训练全攻略 简介面向目标检测与图像识别学习者的罐装饮料识别数据集涵盖薯片、东鹏特饮、红牛、芬达、养乐多、可乐、雪碧、王老吉、AD钙奶、金典、特仑苏、蒙牛、伊利、旺仔牛奶等常见商品标注信息完整可直接用于零售场景下的商品检测模型训练。打包文件共1681个以1676张jpg图片为主体配有3个JSON标注文件和2个TXT说明文件标注遵循COCO格式适合Faster R-CNN、YOLO等主流模型直接读取省去人工标注环节。每张图片的目标框与类别信息均保存在JSON中TXT文件可作类别映射或训练说明数据覆盖不同拍摄角度、光照和摆放方式有助于增强模型在货架或自动售货机等实际场景中的泛化能力。整体大小45.57MB便于下载与快速迭代实验。已有823人学习浏览适合需要现成训练数据的学生、算法工程师及零售AI项目开发者也可用于毕业设计、课程实践或迁移学习基础训练。1. 罐装饮料识别数据集一千多张图能支撑起什么场景货架盘点、自动售货机视觉结算、无人零售柜这些场景背后都有一个共同的技术需求快速准确地识别货架上的饮料品牌。市面上公开的饮料数据集不少但要么类别太杂、背景太乱要么标注格式需要二次加工。这份罐装饮料识别数据集提供了一千多张真实场景图片覆盖东鹏特饮、红牛、芬达、养乐多、可乐、雪碧、王老吉、AD钙奶、金典、特仑苏、蒙牛、伊利、旺仔牛奶等常见品类并且直接给出COCO格式的标注文件省去了自己画框标类别的功夫。对刚接触目标检测的开发者来说它是一份可以直接喂给训练框架的现成数据对做零售视觉方案的工程师来说它则是一个可以用来验证算法选型和调参思路的基准集。本文就从数据格式、转换脚本、训练配置到踩坑记录完整拆一遍这套资源的用法。2. 数据集构成与COCO格式先看清这一千多张图里藏着什么2.1 文件命名里的信息来自Roboflow的导出痕迹打开数据集压缩包你会发现文件名长这样294_jpg.rf.9c5ca41979ee0399ba8106f011a025a2.jpg、pepsi-cola24_png.rf.24fd4e671b63b84b31712c206ba8290e.jpg。这里的.rf.是 Roboflow 平台导出文件的典型标记294_jpg表示原始文件名和图片格式后面那串十六进制字符串是图片在平台上的唯一标识。这意味着这份数据大概率是从 Roboflow 项目里导出的而 Roboflow 在导出时会自动完成训练集、验证集、测试集的划分并且按标注格式重新组织文件结构。这个信息对你后续使用有实际影响。Roboflow 导出时默认会做数据增强如翻转、旋转、亮度调整所以同一张原图可能会在数据集中出现多次但文件名后缀不同。如果你发现训练集里有两张看起来几乎一样的图不用惊讶这是增强后的副本不是数据重复。另外Roboflow 导出的 COCO 格式里图片的id和标注的image_id对应关系是打乱的不能想当然认为第一张图对应第一个标注条目一定要通过 JSON 里的字段关联。2.2 COCO标注的JSON结构看懂categories与annotationsCOCO 格式的核心是一个 JSON 文件里面有三个关键字段images、annotations、categories。images是一个列表每个元素包含id、file_name、width、height四个基本属性annotations列表里每个元素描述一个目标框包含id、image_id、category_id、bbox、area、iscrowdcategories列表则定义了类别 ID 到类别名称的映射。这份数据集里bbox的格式是[x, y, width, height]注意这是左上角坐标加宽高不是中心点坐标加宽高。很多人在写转换脚本时在这里翻车把 COCO 的 bbox 当成了中心点格式导致画出来的框位置完全错位。另外category_id是从 1 开始编号的不是 0这在转 YOLO 格式时要做减一操作因为 YOLO 的类别索引是从 0 开始的。{ images: [ {id: 1, file_name: 294_jpg.rf.9c5ca41979ee0399ba8106f011a025a2.jpg, width: 640, height: 640} ], annotations: [ {id: 1, image_id: 1, category_id: 5, bbox: [210, 180, 120, 240], area: 28800, iscrowd: 0} ], categories: [ {id: 1, name: coca-cola}, {id: 5, name: red-bull} ] }上面这段 JSON 说的是编号为 1 的图片里有一个目标框它的类别 ID 是 5框的左上角在 (210, 180)宽 120、高 240面积 28800 像素。这里iscrowd为 0 表示这是一个独立目标不是一群人挤在一起的那种密集标注。2.3 类别清单与场景边界从摘要描述看这份数据集的类别包括薯片、东鹏特饮、红牛、芬达、养乐多、可乐、雪碧、王老吉、AD钙奶、金典、特仑苏、蒙牛、伊利、旺仔牛奶等。这些类别分两类一类是瓶装/罐装饮料一类是利乐砖或塑料袋包装的乳制品。后者的外观差异比饮料罐更小比如金典、特仑苏、蒙牛、伊利这四个品牌的外包装主色调都是白色系区分难度明显高于可乐和雪碧。这个类别结构决定了模型的难点不在“检测”而在“分类”。检测阶段只需要把货架上的物体框出来但分类阶段要区分白底包装上极其相似的文字和图案。如果你用这份数据训练完发现金典和特仑苏经常混淆不用怀疑数据质量这是这类细粒度分类任务的固有难点后面会专门讲怎么缓解。3. 从COCO到YOLO标注格式转换脚本与参数调整3.1 为什么要转格式训练框架的输入差异COCO 格式是很多检测框架的通用标准但 YOLO 系列包括 YOLOv5、YOLOv8默认使用自己的 TXT 标注格式。YOLO 的标注方式是每张图片对应一个同名 TXT 文件文件里每行描述一个目标框class_id x_center y_center width height四个数值全部归一化到 0~1 之间就是除以图片宽高后的比例值。如果你直接用 COCO 的 JSON 去训练 YOLO需要写个 DataLoader 做适配但更省事的做法是转成 YOLO 原生格式。转换的核心就是把 COCO 的[x, y, width, height]像素坐标变成 YOLO 的[x_center, y_center, width, height]归一化坐标同时把category_id减 1 作为 YOLO 的类别索引。3.2 转换脚本实现与逐段说明下面是我常用的 COCO 转 YOLO 脚本基于 Python 和 pycocotools在 Windows 和 Linux 上都能直接跑。脚本会读取 COCO 的 JSON 文件为每一张图片生成对应的 TXT 标注文件并按train、val、test三个子目录分别存放。import os import json from pycocotools.coco import COCO def coco_to_yolo(coco_json_path, output_dir): # 读取 COCO 标注文件 coco COCO(coco_json_path) # 建立 category_id 到 yolo_id 的映射注意减 1 cat_id_map {cat_id: idx for idx, cat_id in enumerate(coco.getCatIds())} # 遍历所有图片 for img_id in coco.getImgIds(): img_info coco.loadImgs(img_id)[0] img_width img_info[width] img_height img_info[height] file_name img_info[file_name] # 图片文件名去掉扩展名作为 txt 文件名 txt_name os.path.splitext(file_name)[0] .txt txt_path os.path.join(output_dir, txt_name) ann_ids coco.getAnnIds(imgIdsimg_id) anns coco.loadAnns(ann_ids) lines [] for ann in anns: # bbox 格式是 [x, y, width, height] x, y, w, h ann[bbox] # 转成 YOLO 需要的中心点格式并归一化 x_center (x w / 2) / img_width y_center (y h / 2) / img_height norm_w w / img_width norm_h h / img_height yolo_id cat_id_map[ann[category_id]] lines.append(f{yolo_id} {x_center:.6f} {y_center:.6f} {norm_w:.6f} {norm_h:.6f}) with open(txt_path, w) as f: f.write(\n.join(lines)) if __name__ __main__: coco_to_yolo(annotations/instances_train.json, labels/train)这个脚本的关键逻辑就三步。第一步通过coco.getCatIds()拿到所有类别 ID然后用 enumerate 重新编号让类别从 0 开始第二步遍历每张图片的标注把 bbox 从左上角坐标加宽高换算成中心点坐标加宽高第三步写 TXT 文件时保留六位小数避免精度丢失。参数方面coco_json_path指向你的 COCO JSON 文件路径output_dir是 TXT 文件输出目录需要提前建好。转换前建议先检查 bbox 是否有超出图片边界的框。COCO 允许框略微越界但 YOLO 训练时大部分框架会报警甚至忽略这些框。我一般会在转换脚本里加一个判断如果归一化后的值小于 0 或大于 1就打印图片名和框坐标手动排查。3.3 转换结果验证可视化与统计转换完成后别急着训练先做两步验证。第一步是可视化在图片上画出 TXT 标注的框看位置是否和原目标吻合。可以用 OpenCV 快速画框确认转换没有出现坐标偏移或类别错位。第二步是统计检查生成的所有 TXT 文件里有没有空文件空文件说明对应图片没有标注目标这在推理阶段可能被误认为是背景。import cv2 import os def visualize_yolo_annotation(image_path, txt_path, class_names): img cv2.imread(image_path) h, w img.shape[:2] with open(txt_path, r) as f: for line in f.readlines(): parts line.strip().split() cls_id int(parts[0]) x_center, y_center, box_w, box_h map(float, parts[1:]) # 反归一化还原像素坐标 x1 int((x_center - box_w / 2) * w) y1 int((y_center - box_h / 2) * h) x2 int((x_center box_w / 2) * w) y2 int((y_center box_h / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, class_names[cls_id], (x1, max(0, y1 - 5)), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255), 2) cv2.imshow(check, img) cv2.waitKey(0) cv2.destroyAllWindows()这段可视化脚本把归一化的 YOLO 坐标反算回像素坐标注意中心点要减去宽高的一半得到左上角加上一半得到右下角。class_names是一个列表索引对应 YOLO 的类别 ID顺序必须和训练时的data.yaml一致否则画出来的类别名会错乱。建议随机抽 20 到 30 张图做可视化重点看多目标场景下框之间的重叠情况和边界贴合度。4. 用YOLOv8把数据集跑起来训练配置与参数调优4.1 数据集yaml的写法与路径坑数据准备好后第一步是写 YOLOv8 的data.yaml文件。这个文件告诉训练框架三件事类别列表、每张图片的路径、验证集的路径。路径建议写绝对路径因为相对路径在不同环境下解析结果不一样经常出现 “No labels found” 的报错其实就是路径没写对。# data.yaml path: D:/datasets/beverage_dataset # 数据集根目录 train: images/train val: images/val test: images/test names: 0: chips 1: dongpeng 2: redbull 3: fanta 4: yakult 5: cola 6: sprite 7: wanglaoji 8: ad-milk 9: jindian 10: telunsu 11: mengniu 12: yili 13: wannaixn注意path指向的是数据集根目录train和val是相对这个根目录的子路径。names列表的索引和转换脚本里的类别 ID 必须一一对应顺序错了模型不会报错但你的预测结果会全乱。这里colab环境或者 Windows 路径带中文的情况尤其容易踩坑YOLO 框架在部分版本里对中文路径支持不好建议数据集路径保持纯英文。4.2 训练命令与关键超参数数据集就绪后用下面的命令启动训练。这里选择 YOLOv8s 作为基础模型因为数据集规模只有一千多张用 v8x 或 v8l 这种大模型很容易过拟合训练时间还长。imgsz设为 640这是速度和精度的平衡点如果你的目标场景是货架远端拍摄可以试 832 或 1024但显存占用会明显上升。yolo detect train \ modelyolov8s.pt \ datadata.yaml \ epochs100 \ imgsz640 \ batch16 \ workers8 \ lr00.01 \ optimizerauto \ patience20 \ projectruns/detect \ namebeverage_exp1参数说明epochs100对一千多张图来说足够配合patience20做早停连续 20 轮验证集指标不提升就自动停止节省时间batch16在 8GB 显存下比较稳如果你的显卡显存更大可以提到 32lr00.01是初始学习率YOLOv8 默认使用 SGD 优化器如果是 AdamW 建议降到 0.001workers8是数据加载线程数Windows 下如果报 DataLoader 相关错误降到 2 或 4。实际跑起来你会发现训练前几个 epoch 的 loss 下降很快但到 30 到 50 个 epoch 后会进入平台期。这时候不用急着加 epoch 数先看验证集的 mAP 变化曲线如果 mAP50 还在缓步上升就让它继续跑如果已经持平甚至下降说明开始过拟合了应该提前终止。4.3 训练过程中的监控指标训练日志里重点看三个指标box_loss、cls_loss、mAP50-95。box_loss衡量预测框和真实框的回归误差持续下降是正常的cls_loss是分类损失如果这个值降不动说明相似类别比如金典和特仑苏的区分有问题。mAP50-95是 COCO 标准评估指标mAP50 表示 IoU 阈值为 0.5 时的平均精度mAP50-95 是多个阈值下的平均后者更严格。我一般同时开着 TensorBoard 看曲线命令是tensorboard --logdir runs/detect。看到 mAP50-95 连续 10 个 epoch 不涨就手动 CtrlC 停掉然后去分析错误样本。训练结束后runs/detect/beverage_exp1/weights目录下会有best.pt和last.ptbest.pt是验证集指标最好的一轮权重推理时用这个。5. 避坑指南标注数据训练最常见的五个问题5.1 图片尺寸不一致导致归一化坐标错位现象训练时 loss 正常下降但用best.pt做推理时检测框的位置整体偏移有的框跑到目标旁边去了。原因数据集里的图片尺寸不统一部分图片是 640×640部分是 416×416还有少量竖版长图。Roboflow 导出时通常会自动 resize 到统一尺寸但这份数据里混入了原始尺寸的图片。转换脚本里如果直接拿每张图片的宽高做归一化理论上没问题但 YOLO 训练时会对图片做 letterbox 填充把图缩放到正方形再补灰边如果训练时输入的图和标注时的图尺寸不一致归一化坐标就被拉偏了。解决训练前用脚本统一检查所有图片尺寸。YOLOv8 的imgsz640会自动做 letterbox理论上能处理任意尺寸输入但前提是标注文件里每张图的归一化坐标是对应它自己原始尺寸的。我在转换脚本里加了一步读取图片实际宽高打印所有尺寸分布如果有超过 10% 的图片尺寸和主流尺寸不一致先统一 resize 再转换。5.2 类别 ID 减 1 的细节漏掉现象训练顺利完成但预测出来的类别名和实际目标对不上比如把红牛识别成了可乐。原因COCO 的category_id从 1 开始YOLO 的类别索引从 0 开始。转换时忘记减 1导致所有类别整体错位一位模型学到的类别对应关系和真实情况差了一格。解决转换后随机抽 10 个 TXT 文件手动核对类别 ID 是否和data.yaml的names对应。我习惯在转换脚本里写一个自检函数输出每个类别 ID 的样本数和 COCO 原始 JSON 里的统计对比数量一致才继续训练。5.3 小目标漏检货架远端饮料框太小现象训练集 mAP 很高但实际拍一张货架全景图远处的饮料瓶全部漏检一个框都没出。原因一千多张图里大部分标注框是近景或中景占图片面积比例较大。远场景下饮料罐可能只有 20×30 像素对于 YOLOv8s 的原生检测头来说小目标特征在多次下采样后已经丢失。mAP 高是因为验证集里也以小目标为主模型没学会检测小目标不代表它不行只是数据分布没覆盖。解决不要只依赖原始数据集用 Roboflow 的增强功能或自己写脚本对小目标区域做裁剪生成一批“大目标”训练样本。或者训练时开启 YOLOv8 的augmentTrue和mosaic1.0让模型在多尺度输入下看到更多中间态。另一个实用思路是把imgsz从 640 提到 960让小目标在输入时占更多像素。5.4 相似包装类别互相混淆现象金典、特仑苏、蒙牛、伊利经常互相识别错误验证集 mAP 不低但实际用起来这几个类别总是错。原因这四个品牌的包装主色调都是白色系形状也都是利乐砖检测特征几乎一致。模型只能靠包装上的文字和图案细节区分但一千多张图里每个类别的样本量可能只有几十张远不够学到稳定的文字特征。解决这是典型的细粒度分类问题。第一种方案是增加每类的样本量到 200 张以上第二种方案是把模型从 v8s 升级到 v8m 或 v8l更大的模型能学到更细的特征第三种方案是接受现实把这几个类别合并成一个 “white-milk” 类后接一个 OCR 模块读包装上的文字用文本内容做最终区分。我在实际项目里经常用第三种方案效果稳定且不受光照影响。5.5 数据集划分不合理导致评估虚高现象训练时验证集 mAP50 高达 0.98但放线上完全不是这么回事识别率掉到 60% 多。原因这份数据集是从 Roboflow 导出的导出时的划分可能是随机的。同一场景的连续帧比如同一瓶可乐在视频里的多帧可能同时出现在训练集和验证集里模型相当于记住了答案。这种“数据泄漏”让评估结果虚高实际场景的光照、角度、遮挡变化后模型立马现原形。解决按图片分组或按场景划分数据集保证同源图片不跨集。你可以看文件名前缀比如294_jpg里的 294 如果是一个场景编号就按这个编号划分。更好的做法是手动拍一批现场照片作为验证集验证集不参与训练这样评估结果才真实。6. 进阶用混淆矩阵与可视化验证模型再谈部署取舍训练完拿到best.pt只是第一步我一般会先跑一遍yolo detect val然后去看三样东西confusion_matrix.png、results.png、val_batch0_pred.jpg。confusion_matrix.png能直接看出哪两个类别经常混淆如果金典和特仑苏的矩阵格子里数值很高就得用上一节说的合并策略或者加样本val_batch0_pred.jpg是验证集第一张图的预测结果可视化用肉眼扫一遍能发现框偏移、漏检、重复框这类机器指标看不出来的问题。验证通过后下一步是部署。这份数据集训练的模型有两个典型部署路径。第一个是边缘设备部署把best.pt用yolo export modelbest.pt formatonnx导出成 ONNX再用 TensorRT 转成 engine 文件跑在 Jetson Orin 或 Jetson Nano 上。一千多张图训练出来的模型做推理时单帧耗时在 10 到 30 毫秒完全够收银台或者货架摄像头的实时识别。第二个是服务端部署用 FastAPI 包一个推理接口接收图片返回检测框和类别配合数据库做商品陈列分析。部署时要特别注意类别 ID 的映射一致性。data.yaml里的names顺序、ONNX 模型输出的索引、后端代码里读到的类别名三处必须完全一致。我踩过这个坑训练时names里可乐在第 6 位导出 ONNX 后模型输出索引 5 对应可乐但后端代码写死了索引 5 是红牛结果线上跑了一周红牛识别率接近 100%其实是把可乐全识别成了红牛。从那以后我每次部署前都会拿一张标注过的测试图跑一次推理接口把输出的类别名和真实目标逐一核对再放量上线。如果你打算把这套模型往产品里推还有一个值得做的优化调低置信度阈值。默认的conf0.25对大多数场景够用但像远距离瓶装饮料这种目标置信度普遍在 0.2 到 0.3 之间阈值设太高会漏检。我一般会跑一次验证集统计所有正确检测框的置信度分布把阈值设到分布的最低点附近。当然阈值降低会带来误检增多实际调参时可以结合部署场景的温度宁可漏检也不误检的时候比如结算场景就调高一点主打召回的场景就调低。这套调参思路同样适用于你手里的其他检测项目希望帮到你。本文还有配套的精品资源点击获取
返回列表