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

4592张超市秤盘水果检测数据集:VOC+YOLO双格式与YOLOv8训练实战

发布时间:2026/9/27 23:09:37

资讯中心
01
ARTICLE

4592张超市秤盘水果检测数据集:VOC+YOLO双格式与YOLOv8训练实战

4592张超市秤盘水果检测数据集:VOC+YOLO双格式与YOLOv8训练实战
简介面向超市智能秤盘与目标检测应用场景这份数据集涵盖苹果、香蕉、黑莓、辣椒、葡萄、柠檬、树莓、番茄等14类常见水果并区分带包装wb与不带包装wob状态共对应4592张图片的VOC与YOLO格式标注。压缩包内共2000个文件以XML标注文件为主另附使用前必读的TXT说明整体约515.89MBXML便于在LabelImg等工具中复核TXT类别清单可直接对应YOLO训练配置省去格式转换环节。已有291人学习下载适合正在做零售称重识别、水果分类检测的学生或工程师作为模型训练与验证数据。拿到后可按照14类标注划分训练集与验证集快速迭代检测模型真实秤盘摆放带来的光照、遮挡和角度差异也能帮助提升模型在实体门店环境中的泛化能力尤其适合需要区分包装与否的视觉称重方案。1. 超市秤盘水果检测数据集4592张、14类的VOCYOLO双格式先看清楚再动手「超市秤盘水果检测数据集」解决的是自助称重最核心的问题水果往秤盘上一放摄像头要先认出苹果、香蕉、橙子再对着单价表算钱。这场景看着简单实际做检测比想象中麻烦——秤盘反光、水果遮挡、同品类还有不同品种都直接影响识别率。这份数据集用4592张实拍图覆盖14个类别同时提供VOC和YOLO两种标注格式把数据整理和格式转换提前做完了。适合在做自助称重、无人零售、水果分拣的开发者也适合想拿真实业务数据跑一遍YOLO训练流程的人。拆完我的体会是数据不复杂真正花时间的是解压、校验和训练参数调整这几步坑不少。2. 数据集结构拆解VOC与YOLO双格式到底存了什么2.1 VOC格式目录JPEGImages、Annotations与ImageSets三件套解压之后最先看到的通常是一个VOCdevkit风格的目录。VOC格式源自PASCAL VOC竞赛的标注约定现在几乎所有检测框架都保留了读取接口所以很多公开数据集都拿它当发布格式。展开目录大概是这个结构VOCdevkit/ └── VOC2007/ ├── JPEGImages/ # 4592张jpg原图 ├── Annotations/ # 与图片同名的xml标注也是4592个 ├── ImageSets/ │ └── Main/ # train.txt / val.txt / test.txt └── labels.txt # 按行排列的14个类名清单JPEGImages放原始图片Annotations放同名XML标注ImageSets/Main下的txt记录每张图归属哪个集合内容就是不带扩展名的文件名一行一个。labels.txt是本数据集额外附上的类别清单从第0行开始按索引排列后面转YOLO格式和写训练配置都要靠它先别删。打开任意一个XML看标注细节annotation folderJPEGImages/folder filenameIMG_00001.jpg/filename size width1280/width height720/height depth3/depth /size object nameapple/name truncated0/truncated difficult0/difficult bndbox xmin412/xmin ymin258/ymin xmax589/xmax ymax431/ymax /bndbox /object /annotationsize里的宽高是后续坐标换算的基准object可以重复出现表示一张图里框了多个目标name是类别名bndbox是左上角和右下角的像素坐标。我拿到手会先做一件事把所有name去重打印一遍和labels.txt逐行对照检查有没有大小写、带空格、中文别名这类隐蔽差异。# 统计XML里出现过的所有类名按出现次数排序 grep -h name Annotations/*.xml | sort | uniq -c这个命令两分钟出结果能提前暴露类名不一致的问题省掉后面训练时类别错位的排查时间。2.2 YOLO格式标签归一化坐标与类别索引YOLO训练不吃XML吃的是纯文本标签。数据集在VOC之外直接给了转换好的YOLO目录yolo_dataset/ ├── images/ │ ├── train/ # 训练集图片 │ └── val/ # 验证集图片 ├── labels/ │ ├── train/ # 与images/train一一对应的txt │ └── val/ └── classes.txt # 14个类别每行一个每个txt与同名图片对应内容形如0 0.3906 0.4785 0.1383 0.2403 3 0.7312 0.5208 0.1214 0.2146五个数字依次是类别索引、归一化中心x、归一化中心y、归一化宽、归一化高。类别索引从0开始对应classes.txt的行号四个坐标全部除以图片宽高范围在0到1之间。这种设计的价值在于模型训练时不管输入图缩放成640还是1280标签都不用跟着改因为坐标是相对值。4592张图14个类别平均每类300多张放到检测任务里属于中小规模。框的密度也值得留意秤盘场景一般一张图是单个水果或小堆水果框的数量不会像街景那样动辄十几个。想算平均目标数可以用Python统计所有txt的总行数除以4592这个数字会直接影响你对模型召回率的预期——目标越多漏检风险越高。2.3 双格式并存的转换关系VOC转YOLO脚本数据集既然已经给好了YOLO格式大部分情况下直接用就行。但我建议把VOC转YOLO的脚本留一份因为你后续一定会往数据集里补自己的标注——比如给一批新的芒果特写打框打标工具导出的大概率是VOC或COCO格式。转换逻辑不复杂核心是XML里的像素坐标除以图片宽高# voc2yolo.py把VOC格式XML转成YOLO格式txt import xml.etree.ElementTree as ET from pathlib import Path def convert_voc_annotation(xml_path, class_names, out_dir): tree ET.parse(xml_path) root tree.getroot() size root.find(size) w int(size.find(width).text) h int(size.find(height).text) lines [] for obj in root.iter(object): name obj.find(name).text if name not in class_names: # 忽略类别表之外的目标 continue cls_id class_names.index(name) # 类名映射到数字索引 box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) x_center (xmin xmax) / 2 / w y_center (ymin ymax) / 2 / h bw (xmax - xmin) / w bh (ymax - ymin) / h lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {bw:.6f} {bh:.6f}) out_path out_dir / (xml_path.stem .txt) out_path.write_text(\n.join(lines))逻辑说明ET解析XML拿到size和所有objectclass_names是从classes.txt读出来的列表用列表index完成类名到索引的映射坐标转换就是中心点等于两端坐标均值除以宽高宽高等于差值除以宽高。参数说明class_names顺序必须和后续训练用的yaml完全一致顺序错一位标签全错out_dir要提前创建不然write_text直接报错。转换完必须跑一遍第三章的标签校验脚本再入训练别跳过。3. 解压、校验、划分拿到7z之后的三步落地操作3.1 7z解压先查看、再测试、后解压压缩包是7z格式Linux上默认没装解压工具先装p7zip-full。我的习惯是解压前做三步查看内容、测试完整性、正式解压。# Ubuntu/Debian 安装 p7zip sudo apt install p7zip-full # 列出压缩包内容确认有没有顶层目录 7z l 超市秤盘水果检测数据集VOCYOLO格式4592张14类别.7z # 测试CRC完整性提前发现下载损坏 7z t 超市秤盘水果检测数据集VOCYOLO格式4592张14类别.7z # 正式解压到指定目录-o后面没有空格路径不存在会自动创建 7z x 超市秤盘水果检测数据集VOCYOLO格式4592张14类别.7z -o./fruit_dataset7z l只列出内容不解压先看有没有顶层目录避免解压后一堆文件散落得到处都是7z t做CRC校验下载不完整、文件损坏在这步直接暴露7z x保留目录结构解压和7z e的区别是e会把所有文件平铺到当前目录数据集这种带目录结构的必须用x。Windows用户装7-Zip后右键解压即可如果包设了密码先单独解压classes.txt这种小文件验证不要一上来全量解压。注意7z x的-o参数后面直接跟路径没有空格写成-o ./fruit_dataset会被解析成输出到当前目录再拼一个多余路径解压位置就错了。3.2 标签完整性校验图片和标签必须一一对应解压后第一件事不是急着训练而是确认图片和标签的对应关系。这个数据集4592张图如果某几张图缺标签、或者标签文件没有对应图片YOLO训练时空标签会被跳过验证集里多一张无标签图还会把mAP莫名拉低。我习惯用脚本扫一遍# check_dataset.py核对图片与标签是否一一对应 from pathlib import Path img_dir Path(fruit_dataset/yolo_dataset/images) label_dir Path(fruit_dataset/yolo_dataset/labels) for split in [train, val]: imgs {p.stem for p in (img_dir / split).glob(*.jpg)} lbls {p.stem for p in (label_dir / split).glob(*.txt)} print(f[{split}] 图片 {len(imgs)} 张, 标签 {len(lbls)} 个) print(f 有图片无标签: {sorted(imgs - lbls)[:5]}) print(f 有标签无图片: {sorted(lbls - imgs)[:5]})逻辑说明用不带扩展名的文件名stem做集合比对差集就是问题文件。参数说明glob里的*.jpg只匹配jpg后缀如果数据集混入了jpeg或png会漏统计稳妥做法是先rglob(*)列出所有文件按类型过滤。两个集合的差集如果非空先手工看图是不是空文件或损坏图再决定补标签还是删图。3.3 标签内容合法性检查数量和对应关系对上还不够标签内容本身也可能有雷。常见的三类问题类别索引越界14类文本的有效索引是0到13、坐标小于0或大于1、一行凑不够5个字段。这些问题直接导致训练损失异常或崩溃。# check_labels.py检查YOLO标签内容合法性 from pathlib import Path def check_label_file(txt_path, num_classes14): bad 0 with open(txt_path) as f: for line_no, line in enumerate(f, 1): parts line.strip().split() if len(parts) ! 5: print(f {txt_path} 第{line_no}行字段数不对: {line.strip()}) bad 1 continue cls_id int(parts[0]) coords [float(p) for p in parts[1:]] if cls_id 0 or cls_id num_classes: print(f {txt_path} 类别越界: {cls_id}) bad 1 if any(c 0 or c 1 for c in coords): print(f {txt_path} 坐标越界: {parts[1:]}) bad 1 return bad total_bad 0 for txt in Path(fruit_dataset/yolo_dataset/labels).rglob(*.txt): total_bad check_label_file(txt) print(f共发现 {total_bad} 处问题)逻辑说明逐行切分字段先查长度再查范围避免用错误字段继续算。参数说明num_classes按数据集的14传以后自己加类别要同步改。坐标越界最常见的来源是VOC转YOLO时读错了size比如把显示分辨率当成原图分辨率转出来的坐标就会超1。3.4 训练集划分随机划分有风险按类分层更稳如果数据集的YOLO目录已经分好train和val直接用如果想重新划分注意两点固定随机种子、按类别分层。直接random.shuffle在类别不均衡时容易翻车——某个类别样本少随机一抽可能把它的验证样本全抽走。# split_dataset.py按类别组合分层划分train/val import random from collections import defaultdict from pathlib import Path random.seed(42) # 固定随机种子保证可复现 img_dir Path(images_all) label_dir Path(labels_all) val_ratio 0.2 samples defaultdict(list) for lbl in label_dir.glob(*.txt): with open(lbl) as f: classes {int(line.split()[0]) for line in f if line.strip()} samples[tuple(sorted(classes))].append(lbl.stem) val_set set() for key, stems in samples.items(): random.shuffle(stems) val_set.update(stems[:max(1, int(len(stems) * val_ratio))]) with open(val.txt, w) as f: f.write(\n.join(val_set)) with open(train.txt, w) as f: train_stems [s for s in sum(samples.values(), []) if s not in val_set] f.write(\n.join(train_stems))逻辑说明以「类别组合」为key分组再从每个组里按比例抽验证集保证每个类在train和val里都有样本。参数说明val_ratio取0.2是4592张图规模常用的8:2划分如果目标总数少于1000建议降到0.1避免训练样本不够。4. 接进YOLOv8/YOLOv5训练从yaml配置到参数选择4.1 数据集yaml配置names顺序错了就全错了YOLOv8和YOLOv5都吃同一个结构的yaml。最容易错的是names顺序它必须和数据集classes.txt的行号完全一致差一位整个标签就错位到别的类别上了。配置长这样# fruit_scale.yaml path: /home/user/fruit_dataset/yolo_dataset train: images/train val: images/val names: 0: apple 1: banana 2: orange 3: pear 4: kiwi 5: dragon_fruit 6: grape 7: strawberry 8: mango 9: watermelon 10: cantaloupe 11: lemon 12: cherry_tomato 13: peach上面names里的类名是按常见超市水果整理的示例真实类别以解压后的classes.txt为准逐行替换。path建议写绝对路径写相对路径时yolo命令的工作目录一变就会报train: not found。提示训练前先用随机权重跑一次yolo detect val能快速验证yaml路径和标签格式别等训练跑完才发现路径错。4.2 训练命令与关键超参数YOLOv8的命令行格式是keyvalueYOLOv5是双横线参数两者配置含义一致。4592张图这个量级我从预训练权重开始而不是从零初始化# YOLOv8 yolo detect train \ datafruit_scale.yaml \ modelyolov8n.pt \ epochs120 \ imgsz640 \ batch16 \ device0 \ workers4 \ patience20 \ lr00.001# YOLOv5 等价命令 python train.py \ --data fruit_scale.yaml \ --weights yolov5s.pt \ --img 640 \ --batch 16 \ --epochs 120 \ --device 0 \ --patience 20关键参数取舍参数推荐值说明imgsz640速度与精度平衡点圣女果这类小目标多再试1280batch16yolov8n在24G显存下够用显存小降到8epochs120配合patience早停4592张图足够收敛patience20验证mAP连续20轮不升就停省时间lr00.001预训练权重微调用0.001从零训练才用0.01这里多说一句预训练权重14个类别平均每类300多张图属于中小规模数据用yolov8n.pt或yolov5s.pt做起点收敛速度和最终精度都比从yaml随机初始化好很多。训练过程中重点看终端打印的box_loss、cls_loss和mAP50前几十个epoch正常是稳定下降如果loss震荡不降优先怀疑lr0。4.3 训练结果评估混淆矩阵行和不是1才是常态训练完先跑验证yolo detect val datafruit_scale.yaml modelruns/detect/train/weights/best.pt评估时不要只盯整体mAP。整体mAP50高不代表每个类都行要打开runs目录下的混淆矩阵看一眼。这里有个高频困惑为什么混淆矩阵每一行加起来不是100%因为YOLO的混淆矩阵带了background列行里除了预测到各类的比例剩下的部分是被漏检的样本所以行和小于1是正常的不是bug网上很多人问的「yolo混淆矩阵总合不唯一」就是这件事。真正要看的是非对角线上的数值。比如苹果被大量预测成梨、橙子被预测成柠檬这类视觉相似类别的混淆才是mAP上不去的直接原因。看到这种混淆常规做法是先补对应的负样本数据或者检查是不是标注框本身有类别标错的噪声而不是急着换网络结构。每类单独的mAP在results.csv里也能查到按类筛一遍比看整体数字有用得多。5. 训练翻车排查YOLO训练中五个高频坑的现象与解法5.1 损失函数NaN与BN崩溃现象训练到几十个epoch时loss突然变成NaN终端打印出NaN或者精度剧烈波动模型权重文件越来越大但验证mAP一路往下掉。原因最常见是学习率过大导致梯度爆炸其次是batch太小让BN统计量不稳定再就是数据集里有坏图——纯黑图、损坏图——或者标签里出现宽度或高度为0的框。解决先把lr0降到0.001、batch提到16以上重跑同时扫坏图from PIL import Image from pathlib import Path for p in Path(fruit_dataset/yolo_dataset/images).rglob(*.jpg): try: img Image.open(p) img.verify() # 只校验文件完整性不加载像素 except Exception as e: print(f坏图: {p} - {e})再检查标签中有没有宽高为0的框。这三步走完绝大多数NaN都能定位到根因。如果数据本身没问题大概率是lr0的问题。5.2 标签越界与类别数对不上现象训练刚开始报错提示类别索引超出范围或者某个类别的AP一直是0、一张都没检出。原因VOC转YOLO时class_names顺序和XML里的name实际顺序不一致或者数据集里混入了labels.txt之外的类别名常见于类名带空格、带中文。解决写脚本把所有XML的name去重打印和classes.txt逐一对照。中文类名必须提前映射成拼音或英文。记住一个原则模型训练真正读的是txt第一列的数字索引yaml里的names只是给人看的索引和classes.txt错位才是真问题。5.3 mAP虚高或偏低数据泄漏与背景域差异现象验证集mAP50高达0.95部署到现场识别率掉一半反过来mAP一直上不去但随便拿一张图推理看着又很准。原因前者是数据泄漏——同一场景连拍的多帧被同时分进了train和val模型等于把验证图内容背下来了后者是训练和验证的拍摄背景差异大比如训练图全是白底台面现场是反光不锈钢。解决先按文件内容去重find images -type f -exec md5sum {} | sort | awk {print $1} | uniq -d | wc -l这个命令统计重复的md5数量。如果同一哈希出现多次就是连拍帧泄漏。再按拍摄场景或时间段重新划分而不是随机划分。背景域差异没有好办法只能靠补充现场样本来拉平。5.4 7z解压报错密码正确却一直失败现象输入正确密码7z依旧提示wrong password或者解压到一半报cannot open file同一个包换个机器反而能解出来。原因三选一——p7zip版本太老不支持压缩算法压缩包内文件名是GBK编码而当前Linux系统是UTF-8文件名解不出来被误报密码在Windows上输入时带了全角字符或末尾空格。解决先升级p7zip再试怕编码问题就Windows和Linux各试一次哪个能解用哪个密码末尾空格和全角字符是重灾区手动重新输入一遍而不是从文本复制。实用技巧是只解压一个小文件先验证比如7z x 包名.7z classes.txt确认密码和编码都没问题再全量解压避免解压到一半才发现是坏包。5.5 图片分辨率不一致导致变慢或OOM现象训练时显存占用波动大偶尔OOM或者训练速度明显低于该imgsz应有的速度。原因数据集的4592张图原始分辨率参差不齐从720p到4K都有。YOLO虽然会等比resize到640但高分辨率图在数据加载和随机裁剪阶段开销更大还会让batch间的计算量抖动。解决训练前先统计所有图片的分辨率分布把过大的图统一缩放到长边不超过1920pxffmpeg -i input.jpg -vf scale1920:1920:force_original_aspect_ratiodecrease -qscale 2 output.jpg参数说明scale目标框是1920x1920force_original_aspect_ratiodecrease表示只缩不放小图原样保留大图等比缩到长边1920以内。因为YOLO标签是归一化坐标等比缩放后txt完全不用改。如果OOM还是发生就把batch降到8、workers降到2。6. 从best.pt到秤盘实景模型导出与边界验证6.1 导出ONNX与TensorRT训练完的best.pt要落到实际部署第一站通常是导出ONNX之后按推理设备决定要不要TensorRT。# 导出ONNX yolo export modelbest.pt formatonnx imgsz640 opset12 # 导出TensorRT engine仅NVIDIA GPU yolo export modelbest.pt formatengine device0 halfTrue导出时imgsz必须和训练一致否则有精度损失。halfTrue开FP16能显著提速但建议先用FP32在真机跑一遍确认mAP没有明显下降再切FP16。6.2 秤盘实景的三个边界验证数据集里是真实的秤盘照片但部署还要补三门课。第一是反光不锈钢秤盘和保鲜膜反光会制造高光区域小目标容易在这里漏检我一般带30张现场照片单独跑一遍专挑反光最强的角度。第二是遮挡与叠加多个水果堆叠时框容易漂如果现场这种情况多把imgsz从640提到1280或者启动TTA测试时增强。第三是品种差异训练集里的苹果可能只有红富士一个品种现场来了青苹果一个label覆盖多种外观时如果该类别mAP偏低要么补数据要么拆类。6.3 一个保留至今的验收习惯这个数据集项目让我养成一个习惯每次拿到任何数据集先跑标签校验脚本再统计每类样本数和图片尺寸分布然后才开始写训练配置训练完不先看整体mAP而是先看混淆矩阵和每类mAP挑出最差的两类去翻原始图片确认是标注噪声还是视觉混淆。这套流程帮我在好几个项目里提前避开了「模型看着准、上线就翻车」的尴尬。从那以后我每次拿到数据集都强制自己走一遍这套校验再急也不跳步。希望帮到你。本文还有配套的精品资源点击获取
02
RELATED NEWS

相关资讯

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

03
WHY YAOTU

想打造同款高转化官网?

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

◈

场景化定制

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

◐

营销型架构

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

▲

全周期服务

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

免费获取你的建站方案

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