
简介面向超市秤盘场景的水果目标检测任务这套数据集围绕4592张图片整理标注覆盖苹果、香蕉、黑莓、辣椒、葡萄、柠檬、树莓、番茄等14个常见品类类别名称区分了wb与wob两种外观形态如apple_wb、apple_wob便于按需筛选样本并兼顾VOC与YOLO两种格式的模型训练需求。压缩包共2000个文件以1999个xml标注文件为主体另含1个txt使用说明整体约515.89MBxml文件可按VOC流程直接读取txt说明有助于快速掌握数据组织结构。目前已有291人学习下载。对零售称重、智能结算、水果识别等方向的开发者可基于这些标注快速构建训练集利用14类标签开展模型调优同时参考类别划分逻辑理解不同外观状态对检测的影响作为算法验证与基线评测的基础数据。1. 超市秤盘水果检测数据集一份能直接练手的标注数据坑却集中在格式与解压这个标题指向的是一个目标检测数据集压缩包超市称重台俯拍视角的水果图片共4592张边界框标注同时给了VOC的XML和YOLO的txt两套格式覆盖14种常见水果。它要解决的场景非常具体——自助结算秤台、无人收银通道里的水果识别模型得在固定俯拍角度下同时定位多个果子并给出类别。适合谁用准备跑通yolov8训练、但还没攒够样本的从业者或者想复现“秤盘固定视角检测”基线方案的研究者。一个反直觉的点4592张对目标检测不算多但视角固定、背景近乎单一它往往比两万张乱视角网图更顶用。真正容易翻车的不是数据量而是7z解压编码、VOC与YOLO路径错位以及训练时对秤台高光的过度拟合后面逐章拆。2. 拆开数据集先看门道VOC格式与YOLO格式并存到底在表达什么2.1 一套标注两套格式先分清哪个喂训练、哪个留作转换与复查解开压缩包之后你大概率会看到以下几种目录形态之一要么是VOC的经典骨架VOCdevkit/Annotations加JPEGImages加ImageSets/Main要么是更现代的images加labels平铺结构再带一份classes.txt。具体是哪个取决于打包人习惯标题写的“VOCYOLO格式”意思是同一批标注内容做了两份序列化VOC用XML记录每个目标的name、bndbox、difficult、truncated字段YOLO用txt每行记录class_id center_x center_y width height四个坐标都归一化到0到1。很多人拿到手第一反应是“我得把VOC转成YOLO才能训练”。在这个数据集上不必多此一举压缩包里已经带了两套你要做的不是转换而是校验两套格式指向同一份图像、同一批目标并选定一套作为训练输入。我一般只认YOLO txt作为训练数据因为ultralytics训练管线直接读它就是顺手VOC XML留在工程里当“可读真值”用来画框对比、做后验分析、和别人协作时作交接凭据。原因在于VOC XML在标注工具和评估脚本里兼容性更广YOLO txt在训练链路里是免预处理格式二者其实不能互相替代。还有一个背景值得你知道市面上很多行业数据集都在用二元格式的模式——电力红外检测的 firc-dataset、燃气管道图像数据集、开关闭合检测数据集下载下来看到的几乎都是VOCYOLO同步给。也就是说你现在练会的这套“先校验、后训练”的习惯迁移到任何同类工业数据集时都是通用的。不要把这份数据集当成孤例它是这个行业一个很小的切面。2.2 4592张与14个类别先看分布均衡性再决定要不要补数据4592这个数字单独看没有结论得和14个类别一起算。按每类平均大约是328张每类再考虑训练/验证划分按8:2或9:1切训练集每类大约260张左右。这个体量对目标检测来说属于“放下限有余、上限不足”用yolov8的中小模型在这个样本量上收敛出不错的mAP问题不大但它离“超市收银台可商用”的线还有距离。可商用通常意味着mAP0.5要到0.9附近同时误检率低到能通过业务验收。这个目标不是堆图片堆出来的是靠持续补充边界样本和做数据增强一点点磨出来的。还有一类问题比总量更关键——类别分布不均衡。如果某一类是另一类的3到5倍模型会明显向高频类别倾斜低频类别的AP被压在很低的位置。所以我拿到任何数据集的第一件事是统计类别分布而不是着急开训练。通常我会写一段短脚本读labels/*.txt里每一行的第一个int按类目累加输出分布同时统计“每张图平均几个目标”。如果平均框数低于1.2说明存在不少空背景图这会影响训练效果因为模型会在空图上白白消耗损失。知道了分布后面设类别权重、调数据增强概率的时候才有依据。这里补一句14个类别具体是哪14种要以解压后文件里的classes.txt或自带data.yaml为最终依据不要相信任何二手描述。常见零售场景会覆盖苹果、香蕉、橙子、梨这类高频散称水果但也会混入小番茄、猕猴桃、柠檬这样的“低价值但高频出现”品类。拿到手先看清单再对照你自己的业务品类做增删。2.3 解压后的目录结构若有偏差先按自己的规范归一遍网络下载的数据集解压出来目录命名经常百人百样。有人把包内根目录叫FruitWeight有人叫dataset/Images还是大写开头YOLO标签可能已经按train/val分好但data.yaml里写的却是相对路径一换机器就失效。我的习惯是拿到手不做任何格式转换先把目录盘成一份最小可用结构scale_fruit/ ├── images/ │ ├── train/ # 训练图像 │ └── val/ # 验证图像 ├── labels/ │ ├── train/ # 与images/train同名的.txt │ └── val/ ├── voc_annotations/ │ ├── train/ │ └── val/ ├── classes.txt # 14行每行一个类名 └── data.yaml # 指向上述相对路径注意不要在目录名和文件名里掺空格与中文。YOLO训练管线对中文路径的兼容性时好时坏尤其在bash和zsh混合环境下容易出现编码问题。宁可在磁盘上多复制一份到纯英文路径也不要赌它不出错。目录定好后要检查标注与图像同名同行images/train/000001.jpg对应labels/train/000001.txt。如果压缩包里是IMG_20240301_102233.jpg这类长文件名建议先批量重命名为000001.jpg这类定长序列号再去写data.yaml。长文件名本身不会报错但会让训练日志、可视化结果和后续的模型部署调试变得很难受。用一条find命令加rename就能处理cd scale_fruit/images/train ls *.jpg | awk {printf mv %s %06d.jpg\n, $0, NR} | bash这个命令的意思是列出所有jpg文件按行号生成六位序号再用bash逐条执行重命名。标签目录里的txt文件名要跟着同步改顺序不能乱否则就会出“图对不上标”的严重问题。3. 从7z压缩包到可训练数据集解压、体检、路径规范三步走3.1 Linux下解压7z文件两条命令解决安装选择困难拿到.7z文件第一件事是别在系统里翻图形工具。Linux下解压7z的主流方案基本就两套p7zip-full和7-Zip官方Linux二进制。大多数Ubuntu/Debian发行版用前者就够了# 安装唯一需要的包 sudo apt-get update sudo apt-get install -y p7zip-full # 解压到目标目录x保留原始目录结构 mkdir -p ~/datasets/scale_fruit 7z x ~/Downloads/超市秤盘水果检测数据集VOCYOLO格式4592张14类别.7z -o~/datasets/scale_fruit参数说明x是解压并保留包内目录层级e则是把所有文件平铺到同一目录。后者非常危险因为不同子目录里的同名文件会被后者直接覆盖等你发现的时候数据已经缺了一部分。-o指定输出目录注意-o后面直接跟路径中间不要加空格写成-o/home/user/dir。如果压缩包有密码建议追加-p但不直接把密码写在命令行里让程序交互式提示输入避免密码进shell历史。解压完成后先跑一个du -sh ~/datasets/scale_fruit看看体积量级。4592张图按常见超市监控图片尺寸1080p到4K压缩包解压后一般在几百MB到1GB上下。如果解压结果只有几十MB大概率是解压中断了或者包不完整重下比排查更快。Windows下的操作逻辑一致装7-Zip后右键“提取到当前文件夹”即可命令行版也是一条7z x 文件名.7z -o目标路径。但如果你在Linux下已经跑顺了这套流程强烈建议正式的数据处理都在Linux或WSL里做后面批量重命名、路径拼接、训练管线都要在命令行环境里操作。3.2 体检脚本解压后先跑一遍统计防止白训一场这是每次换新数据集必跑的步骤。目的很单纯在训练前把三类问题全部暴露出来——缺图、缺标注、标注坐标越界。下面这份脚本不依赖任何深度学习框架纯Python标准库就能跑# check_dataset.py # 用法python3 check_dataset.py --root ~/datasets/scale_fruit import argparse import os from collections import Counter def parse_yolo_txt(path): rows [] with open(path, r, encodingutf-8) as f: for line in f: line line.strip() if not line: continue # 空行跳过空标注文件是合法的 parts line.split() cid int(parts[0]) coords [float(v) for v in parts[1:5]] rows.append((cid, coords)) for v in coords: if v 0 or v 1: raise ValueError(f{path} 存在越界坐标: {line}) return rows def main(root): img_dir os.path.join(root, images, train) lbl_dir os.path.join(root, labels, train) imgs {os.path.splitext(f)[0] for f in os.listdir(img_dir) if f.lower().endswith((.jpg, .jpeg, .png))} lbls {os.path.splitext(f)[0] for f in os.listdir(lbl_dir) if f.endswith(.txt)} print(f图像数量: {len(imgs)} 标签数量: {len(lbls)}) print(f缺标注的图像: {len(imgs - lbls)} 缺图像的标注: {len(lbls - imgs)}) cls_counter Counter() box_count 0 for name in imgs lbls: rows parse_yolo_txt(os.path.join(lbl_dir, name .txt)) cls_counter.update(r[0] for r in rows) box_count len(rows) print(标注框总数:, box_count) print(平均每图框数: %.2f % (box_count / max(len(imgs lbls), 1))) for cid in sorted(cls_counter): print(f 类别{cid}: {cls_counter[cid]} 框) if __name__ __main__: ap argparse.ArgumentParser() ap.add_argument(--root, requiredTrue, help数据集根目录) main(ap.parse_args().root)脚本逻辑很直白先对比images/与labels/的文件名前缀差集把缺标注的图和缺图的标注一次性全部找出来。再逐行读txt除了统计框数量还检查四个坐标是否全部落在[0,1]区间。一个越界坐标就可能让训练loss在某个batch上突然爆炸而这种问题体检脚本10秒就能抓出来。--root参数指向数据集根目录如果目录结构不是2.3节的规范把脚本里的两个路径改成你的实际路径即可。这里特别提醒一句不要忽略空标注文件。一个xxx.txt长度为零是完全合法的它表示“这张图里没有目标”。但如果空文件数量占到总数5%以上你要回头想想是标注时漏了还是这批图像本身就不该放进训练集。3.3 双格式对照验证坐实VOC与YOLO标注的对应关系数据集既然同时给了VOC和YOLO就有必要做一次双轨校验。最常见的问题场景是压缩包里的YOLO txt是从VOC XML自动转换来的自动脚本在某个批处理上出现了偏移漏框导致少部分标注两边对不上。这种不一致在单格式训练时很难发现因为模型会把“错的真值”也当成学习目标学进去。对照思路很简单对同一张图把XML里的bndbox坐标归一化再与对应txt逐坐标比较允许千分之一以内的浮点误差。用xml.etree.ElementTree解析XML按filename字段索引到同名YOLO标注逐框对比。如果发现坐标差异超过阈值说明转换过程中发生了取整误差建议以XML侧为准重新生成YOLO格式。如果差异巨大那就是打包时文件错位了得重新下载或人工复核。另一个更省力的验证手段是直接短训验证用这份数据跑10到15轮yolov8n开启plotsTrue训练结束后翻看val_batch_pred.jpg预测图目测预测框与真值框的重叠形态。视觉判断往往比数值指标更直接框错位、类别错乱、漏检严重一眼就能看出来。这类双轨校验在firc-dataset、燃气管道这类同样以VOCYOLO打包的行业数据里都适用值得养成习惯。4. 用yolov8训练自己的数据集从yaml配置到损失函数与混淆矩阵4.1 先完成yolo环境配置ultralytics一条pip命令别在源码上死磕正式训练之前环境要装得干净。当前跑yolo系列的主流入口是ultralytics包它统一了YOLOv8和YOLO11的训练、验证、导出接口。安装并不复杂# 建议先建独立conda环境避免污染base conda create -n fruit_det python3.11 -y conda activate fruit_det # 安装核心库 pip install ultralytics # 确认CLI可用 yolo --help # 有GPU时确认torch能调用显卡 python -c import torch; print(torch.cuda.is_available())pip install ultralytics会自动拉取torch、opencv-python这些依赖但这里有一个常见的坑如果你机器上已经有GPU版torch直接装ultralytics可能会被pip降级成CPU版torch导致torch.cuda.is_available()输出False。稳妥做法是先装GPU版torch再装ultralytics或者装完后单独检查torch版本。CPU也不是不能训练4592张图、100个epoch的yolov8s在纯CPU上要跑半天到一天有临时算力需求还是建议租卡。环境配置是最不值得花时间折腾的环节能用一条pip命令解决的问题不要自己去编译源码。4.2 写data.yaml并启动训练三个必调参数和yolo损失函数曲线怎么看有了规范目录之后配置文件非常简单。下面这份data.yaml直接放在数据集根目录# data.yaml path: /home/user/datasets/scale_fruit # 改成你的数据集绝对路径 train: images/train val: images/val names: 0: apple 1: banana 2: orange 3: pear 4: grape 5: kiwi 6: peach 7: plum 8: persimmon 9: lemon 10: mango 11: pitaya 12: watermelon 13: cherry_tomato上面names列表里的类名只是演示占位真实类别名以解压包内classes.txt为准顺序尤其不能错。YOLO标签里每行开头的int就是类别索引它和names列表的序位置必须一一对应错一个序整个训练全盘作废。写完后启动一次基线训练# 用yolov8s做迁移学习基线epochs开100轮 yolo detect train data/home/user/datasets/scale_fruit/data.yaml \ modelyolov8s.pt pretrainedTrue \ imgsz640 epochs100 batch16 device0 \ projectruns/fruit_det namebaseline_s参数逐个说pretrainedTrue表示加载COCO预训练权重这对4592张的中等规模数据几乎是必需品从零训练在这个样本量上很难收敛到理想状态。imgsz640是秤盘俯拍图的默认尺寸如果你的原图里目标普遍偏小比如小番茄只有30×30像素可以降到480甚至416换取更稳定的收敛。batch16要根据显存调节12G显存跑yolov8s在640×640下开16没问题显存不足就降到8。patience默认是50轮意思是50轮没有改善就停止数据量不大时我习惯显式设patience30模型早就不涨了还多等十几轮很浪费时间。训练过程中主要盯三路lossbox_loss边框回归、cls_loss分类、dfl_loss分布式聚焦损失负责边界框质量。正常状态下三者都应该是平滑下降并趋于稳定。如果某个loss在第20轮之后突然回升先看学习率和batch是否匹配如果cls_loss一直降不下去大概率是类别不平衡回到第2章的分布表给低频类别加权重或者删掉一些过量的近重复样本。训练这条路子本身没有玄学数据干净、参数合理loss曲线一定给你正反馈。4.3 yolo混淆矩阵总合不唯一的真相验证结果应该盯哪几个格子训练结束后的验证环节很多人会先打开confusion_matrix.png然后产生一个困惑混淆矩阵每一行的样本数加起来和该类别实际总数对不上或者说“总合不唯一”。这不是代码bug是YOLO混淆矩阵的绘制逻辑决定的——它在输出前按行做了归一化同时在预测侧把低于置信度阈值的框归入background列在真值侧把iou低于0.5的匹配框也归入background。所以每一行的百分比各自独立行与行之间不能直接横向相加这是正常的不是训练出错。真正需要关注的是对角线往下和旁边延伸的密集格子。若某个类别有大量真值框落到background行说明模型在该视角下频繁漏检优先查目标过小或者与背景颜色接近的问题若大量落到另一个水果类别说明这两个类在视觉上高度混淆回到第2章统计分布表里看是不是样本量差距过大。我自己看这张图有个习惯只关心对角线的相对高低和非对角线上的集中点。如果错误分布得很散先调nms和置信度阈值不要急着加轮数。4592张图练出来的模型mAP50在0.85到0.9属于正常水平mAP50-95受小目标拖累一般落后10到15个点。要往生产标准走必须回到光线、托盘、秤盘边缘的兼容性上做针对性的增强。5. 从压缩包到模型的避坑清单7z、格式、训练三处最容易翻车5.1 7z压缩文件密码是正确的但一直报错先查文件名和终端编码现象明明密码没记错执行7z x 文件名.7z却提示Wrong password或者报CRC Failed。这是很典型的“看似密码错实际另有隐情”。原因最常见的有三种。一是文件名带中文而Linux终端当前locale不是UTF-8传给7z的字节序列对不上文件头校验失败二是密码中混有$、!、\这些特殊符号被bash当成了语法解释实际传到7z里的字符串早就被改掉了三是这个压缩包可能根本没有密码只是文件名编码问题导致报错信息被误读成了密码问题。解决先看包内文件列表执行7z l 文件名.7z | head。如果能正常列出结构说明没有加密报错来自编码或路径问题解压前先export LANGC.UTF-8再重新执行解压命令如果列表本身就读不出来再用7z x -p你的密码密码用单引号包裹防止shell吞掉特殊字符。Windows上如果压缩包内是GBK编码文件名不要用系统自带zip工具直接用7-Zip打开解压到文件夹即可。5.2 训练启动时报训练集找不到data.yaml的路径写法问题现象执行训练命令后报AssertionError: train set not found或者直接FileNotFoundError。原因data.yaml里path写的是相对路径而执行命令的工作目录不在数据集根目录另一个常见诱因是把train: images/train写成了train: ./images/train在ultralytics某些版本里前者合法后者会把路径解析成././images/train。这类问题换目录之后就爆发特别隐蔽。解决直接把path写成绝对路径train和val写成相对path的子路径每换一台机器只改这一行。同时检查图片扩展名是否是小写.jpg有些压缩包内是.JPG模型训练到第30轮才发现最后几百张图从没被读进去的情况也不少见。统一后缀可以用find . -name *.JPG -exec rename s/\.JPG$/.jpg/ {} \;。这句血泪经验来自我自己的一次翻车记录血的教训。5.3 训练中bn崩溃与loss突然回弹先查数据与学习率别急着换模型现象loss前几轮正常下降第五到第八轮突然出现nan重开之后依然稳定复现或者loss不nan但mAP一直在0附近震荡。原因数据侧最可能是存在面积过小的目标框在dfl_loss和cls_loss的联合计算中产生了梯度爆炸类别索引超出names长度的数据也会引发类似问题。参数侧最可能是学习率偏大而batch偏小梯度更新步长与噪声不匹配这在数据量只有几千张时尤其敏感。解决顺序是一条排除链。先用3.2节的体检脚本把空标注和越界坐标清掉再把batch从16调回8学习率降为原来的五分之一重新训练如果仍崩换用yolov8n.pt小模型跑20轮来判断数据是否干净再换回大模型。绝大部分情况下问题出在数据里藏着几条“毒标注”而不是模型容量不够。这个排查过程看起来像玄学实际是把锅从数据、训练配置、模型容量里逐个排除的工程方法。5.4 只看mAP会骗人把预测框画到原图上的视觉验证现象验证集mAP挺高一到实际秤台现场就全是误检把托盘边缘黑色缝隙识别成水果把圆形价签识别成苹果。原因公开数据集的采集视角是秤正上方验证集与训练集同源模型学到的高响应区域有很大一部分是托盘塑料膜的高光反射。mAP虚高掩盖了分布偏移模型过拟合了“秤盘固定视角”这个强先验。解决训练结束后翻看runs/fruit_det/目录里的val_batch_pred.jpg再用训练好的模型对几段现场手机拍摄视频抽帧推理重点看两类镜头无水果但有托盘、水果数量超过5个且堆叠。只要堆叠水果的漏检率超过10%赶紧回数据侧补“密集摆放”负样本与“带价签干扰”正样本这比任何调参都直接。数值指标是门槛视觉验证是安全感两者缺一不可。6. 把秤盘水果检测做到生产可用的三个进阶技巧前面把4592张图、14类水果的流程走通了最后补三个直接面向落地转化的技巧。第一把验证基准从“图上框”推进到“秤台上框”。我训练中的一个习惯是单独制作一组“非秤盘视角”测试图用手持手机环绕拍摄、在纸箱侧上方拍然后拿训练好的模型做测评。原因是公开数据集视角都固定在秤正上方模型很容易把这个视角当成强先验一旦实装机顶摄像头被货架遮挡导致角度偏移15度mAP会明显下滑。用50张盲测图做门槛mAP50低于0.8的模型不进入部署评估这个习惯能挡住一大批“看着挺好、现场翻车”的模型。第二删减类别或合并易混淆对。14个类在秤盘上真正能稳定区分的通常只有10到12类青苹果和梨、绿番茄和青提这类同色系水果在俯拍低分辨率下尤其难分。我的做法是看混淆矩阵确认易混淆对如果一对类别的互相混淆率超过15%就考虑合并成“浅色圆果”这类业务语义更宽容的类用计价上的差异对冲视觉上的不可分。工业落地的逻辑里分类类别越少误检边界越清晰准确率从85%拉到93%有时候靠的不是加数据而是做减法。第三给推理端加一个“秤盘区域ROI”前置过滤。模型输入的整张图中真正需要检测的只有中间一块秤盘四角往往是收银台、手和塑料袋。与其让模型去学“忽略背景”不如在预处理阶段直接裁剪ROI把输入从1920×1080裁到1200×1200左右再缩放到640。这样做能减少背景误检也让小目标的相对尺寸变大mAP50-95会明显回升。生产部署时我还会在推理链路上保留一个最大框面积过滤比如水果框面积必须占ROI的0.3%到60%以此为条件排除秤盘边缘的价签和手部误检。这层逻辑用OpenCV或ONNX Runtime的前处理节点都能实现代价只有几毫秒推理时间。这三个技巧做完再用上一章的方法画一次现场预测图大概率就能把“数据集可用”变成“方案可交付”。四五千张的体量上限就在那里靠技巧而不是靠堆数据把它发挥到极致是这类固定视角检测项目最实在的路径。以上是我从解压、训练到部署跑通几次之后沉淀下来的个人习惯希望帮到你。本文还有配套的精品资源点击获取