资讯详情 番茄识别数据集实战:从数据采集到YOLOv8训练全解析
📅 2026/10/11 14:11:33
简介这是一份面向番茄目标检测任务的数据集适用于YOLO系列、Faster R-CNN、SSD等主流目标检测模型的训练与验证。资源包含未熟番茄、成熟番茄和病害番茄三个类别样本覆盖温室、背景复杂等多种场景可帮助初学者或算法工程师快速开展农业生产场景下的检测实验。压缩包共2000个文件以1999个txt格式标签文件为主配合1个yaml类别配置文件标签文件对应每张图像的检测框信息包含边界框坐标与类别标签yaml文件指定类别名称与索引整体包大小约157.46MB下载后可直接用于YOLO算法的训练流程无需额外格式转换。数据集已按训练集、验证集和测试集划分免去了手动拆分数据的步骤。目前已有281人学习下载适合用于目标检测入门实践、模型对比评估或番茄成熟度与病害识别等研究场景。1. 番茄识别数据集目标检测里最容易被低估的差事做目标检测的同行应该都有同感番茄识别数据集这六个字听着比行人检测、车辆识别简单太多但真上手才发现从采集、标注到训练、部署每一步都比想象中折腾。番茄目标检测之所以难不是难在模型结构而是数据本身太“狡猾”——果实颜色随成熟度连续变化、叶片遮挡严重、大棚光照忽强忽弱同一个番茄在不同角度下看起来像两个类别。这个标题想解决的问题很具体给采摘机器人、大棚估产、分拣线分级这类场景准备一套能真正训练出可用模型的番茄目标检测数据集并把它跑进 YOLO 系列框架。适合两类人一类想把目标检测落地到农业场景的开发者另一类是刚接触目标检测数据集构建、想避开“标注几个月却训不动”的初学者。我会从采集规范、标注选型、格式转换一路讲到数据增强、YOLOv8 训练、排错和部署验证每一步都附上可复现的命令和代码。2. 攒数据集的第一课从采集规范到 VOC 转 YOLO 的转换脚本先立一个观点目标检测模型的性能上限是由数据分布决定的模型只是一个拟合器。番茄识别数据集如果只从图库扒几百张干净背景的图片训练出来的模型一到真实大棚就会误检百出。所以攒数据集的第一步不是打开标注工具而是先定采集规范。2.1 采集阶段先定三类场景光照、遮挡、成熟度不能一把抓常见的做法是先把采集场景拆成三个维度场地类型、光照条件、成熟度状态。场地至少覆盖露地、温室大棚、分拣传送带三类因为背景差异很大——露地有天空和泥土大棚有立柱和薄膜反光传送带有强光和运动模糊。光照要覆盖晴天直射、阴天散射、背光、人工补光四种这样模型才不会只在某个固定色温下生效。成熟度建议分成三档青熟、转色、全红。做分拣线还想细分“软果”或“病斑”但那已经超出检测任务本身属于分类器的事。我一般建议在一开始只定这三档类别越细标注一致性越难保证。青果和叶片颜色接近转色果和黄果形态相似这三档边界已经足够让标注员头疼。采集参数上手机相机足够了但分辨率至少 1080p且要保证对焦准确。比连拍更推荐的是视频抽帧固定机位拍一段隔 N 帧抽一张。N 的判断标准是“相邻两帧里同一颗番茄的位移超过它直径的三分之一”太密会产生大量相似帧太疏会漏掉关键角度。另外同一串番茄用 3 到 5 个不同角度各拍一遍能显著提升遮挡样本的覆盖度。目标检测数据集的初始规模不需要贪多800 到 1500 张标注图就可以训练第一版后续根据坏例再补。从公开数据集找补充样本也有用但要注意比例控制。就像车辆检测数据集 BDD100K 强调天气多样性鸟类目标检测数据集强调不同姿态一样番茄数据集的核心是场景多样性和果实状态连续性。公开图和现场图混用建议控制在一比四以内公开图只用来丰富背景现场图才是模型真正要学的分布。2.2 标注工具选型LabelImg 管离线Roboflow 管协作单人标注阶段我一般用 LabelImg它是目标检测数据集构建里最常用的小工具。安装方式很简单pip install labelimg labelimg启动后打开图片目录和标注保存目录快捷键w画框d切换到下一张CtrlS保存。标注输出是 Pascal VOC 格式的 XML 文件每张图对应一个 XML里面记录了图片宽高、通道数和每个目标的类别名与框坐标。标注规范要在开工前写死这是整个项目里最便宜的一剂后悔药。我常用的一套规则是框四边紧贴果实可见轮廓留 2 到 3 像素余量两个果实挨在一起时框允许重叠但不要把两果之间的间隙包进同一个框遮挡超过 50% 的果实不标遮挡 20% 到 50% 的果实正常标但框只画到可见边缘。这套规则能避免后面训练时出现大量“半果框”和“空背景框”。多人协作时LabelImg 的本地文件夹模式会很不方便。这时候我一般换 Roboflow它支持在线分配标注任务、多人同步标注还能一键把 VOC 转成 YOLO 格式并做在线增强。但 Roboflow 免费额度有限团队协作频繁时值得付费单人小项目留在 LabelImg 足够。工具对比大概是LabelImg 免费、离线、上手快适合个人冷启动Roboflow 云端、协作好、格式转换方便但数据要传服务器对敏感项目不友好。2.3 用 Python 把 VOC XML 批量转成 YOLO txtLabelImg 导出的是 XML而 YOLO 系列框架训练时需要的是 txt 标签文件。每一行代表一个目标格式是类别索引 中心点x 中心点y 框宽 框高四个坐标值都是归一化到 0 到 1 之间的小数。转换脚本每个数据集项目都要写一遍我直接给你一个可用的版本import xml.etree.ElementTree as ET from pathlib import Path # 类别顺序一定要和后续 data.yaml 里的 names 一致 CLASSES [tomato_green, tomato_breaker, tomato_red] def voc_to_yolo(xml_path: Path, out_dir: Path): out_dir.mkdir(parentsTrue, exist_okTrue) tree ET.parse(xml_path) root tree.getroot() size root.find(size) img_w int(size.find(width).text) img_h int(size.find(height).text) if img_w 0 or img_h 0: raise ValueError(f{xml_path} size 缺失) lines [] for obj in root.findall(object): name obj.find(name).text if name not in CLASSES: continue cls_id CLASSES.index(name) b obj.find(bndbox) x1 float(b.find(xmin).text) y1 float(b.find(ymin).text) x2 float(b.find(xmax).text) y2 float(b.find(ymax).text) # 坐标越界裁剪防止训练时出现负数宽高 x1 max(0.0, min(x1, img_w)) x2 max(0.0, min(x2, img_w)) y1 max(0.0, min(y1, img_h)) y2 max(0.0, min(y2, img_h)) if x2 x1 or y2 y1: continue cx (x1 x2) / 2 / img_w cy (y1 y2) / 2 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h lines.append(f{cls_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) txt_path out_dir / (xml_path.stem .txt) txt_path.write_text(\n.join(lines), encodingutf-8) if __name__ __main__: # xml 目录和输出目录按实际路径改 xml_dir Path(labels/voc) out_dir Path(labels/yolo) for xml_file in xml_dir.glob(*.xml): voc_to_yolo(xml_file, out_dir) print(done)这段脚本的逻辑很直接从 XML 的size节点读取原始图片宽高再把每个object节点里的bndbox四角坐标换算成 YOLO 的归一化中心坐标和宽高。CLASSES.index(name)把类别字符串映射成数字编号这是 txt 文件里第一列的内容。参数上需要特别注意两点第一CLASSES列表的排序一旦确定后续所有版本的数据集都不能再改否则旧标签全部作废第二越界裁剪不是可有可无标注员手抖把框画到图片外是常有的事不裁剪会出现负数宽高。转换完成后挑一两张图把 txt 画回原图检查这一步不要省。提示转换后的 txt 是 UTF-8 编码别用 Excel 直接打开检查容易乱码用 VS Code 或文本编辑器看。3. 数据增强与切分让番茄小目标在训练前就站稳脚跟标注完成并不代表数据集合格。番茄识别数据集最典型的毛病是干净过头同一个大棚、同一时间段、同样的光照。直接把这种数据丢给目标检测模型它会把“这个大棚的绿色背景”当成番茄的隐式特征。数据增强和数据切分就是为了打破这种虚假的干净。3.1 针对番茄的增强策略调色要克制形状要保真通用目标检测增强套路是色彩抖动、旋转、翻转、缩放但番茄数据集有个特殊性成熟度判断高度依赖颜色。你把色相偏移拉满青色番茄变成紫色红色番茄变成橙色模型学到的就不是“成熟度”而是“某种色调”。所以我的经验是色相偏移量控制在 ±5 度饱和度和明度可以放宽到 ±20 左右。形状类增强对番茄同样重要。番茄果实是近似圆形叶片是细长条适当的旋转和随机缩放能让模型学会“不管果实朝哪边都认识它”。我一般用 Albumentations 在训练时做在线增强代码片段如下import albumentations as A train_transform A.Compose([ A.RandomBrightnessContrast( brightness_limit0.2, contrast_limit0.2, p0.8 ), A.HueSaturationValue( hue_shift_limit5, sat_shift_limit20, val_shift_limit20, p0.5 ), A.RandomScale(scale_limit(-0.3, 0.3), p0.5), A.Rotate(limit30, p0.4), A.RandomSizedBBoxSafeCrop( width640, height640, erosion_rate0.1, p1.0 ), ], bbox_paramsA.BboxParams( formatyolo, min_visibility0.4, label_fields[class_labels] ))逻辑上这个管线把图先做亮度和颜色扰动再做随机缩放和旋转最后统一裁剪到 640×640。A.BboxParams里的min_visibility0.4很关键增强后如果某个框被裁掉超过 60%这个目标就从标签里删掉避免训练时看到一个“残缺标签”。参数上RandomSizedBBoxSafeCrop的erosion_rate0.1表示允许裁剪时把目标边缘稍微切掉一点模拟真实遮挡scale_limit取 ±0.3 是为了让模型适应不同距离下的果实大小变化。注意 YOLO 训练时本身就带 Mosaic、翻转这类在线增强如果再用 Albumentations 做同样的翻转等于把数据重复增强边际收益会明显下降。3.2 目录划分与 data.yaml路径写错是第一个坑数据集切分不是随便按比例随机抽而是要先定目录结构。我习惯建这样的布局dataset/tomato/ ├── images/ │ ├── train/ # 训练集图片 │ ├── val/ # 验证集图片 │ └── test/ # 测试集图片不到最后不碰 └── labels/ ├── train/ ├── val/ └── test/图片和标签的文件名必须一一对应例如img_001.jpg对应img_001.txt。不要用子目录区分类别目标检测数据集本来就是一张图里多类别共存。训练前要写data.yaml这是 YOLO 框架读数据集的入口path: /data/tomato train: images/train val: images/val test: images/test names: 0: tomato_green 1: tomato_breaker 2: tomato_redpath是这个 YAML 文件所在机器的绝对路径train、val、test指定的目录会拼在path后面。注意train和val填的是目录名而不是图片文件的 txt 列表这是新人和老手切换时最容易翻车的地方——老版本要求提供train.txt文件现在用目录结构即可两套写法都能跑通但混用就会报“no labels found”。还有个容易忽略的点val必须独立提供。如果你不写valUltralytics 会默认从train里抽 20% 当验证集。新手会觉得“这挺好自动切分”但这样做的问题在于切分时机不可控而且每次复现随机种子不同验证结果不具备可比性。正确做法是自己先划分好目录yaml里写死。3.3 数据版本化的正向循环一轮训练后回补坏例第一版数据集训练结束后不要急着调模型结构先看失败样本。把验证集里预测错的图导出按失败原因分类是青果漏检还是遮挡严重造成误检或者是远处小目标完全没检出。然后针对每一类失败回补数据。回补的意思是回到现场补拍新照片重新标注而不是把已有的图复制一份再调亮度。复制增强只能让模型重复看同一批目标解决不了分布覆盖不足。我在项目里会给数据集打版本号例如tomato_v1、tomato_v2标注完成的图片和标签归档在一个目录另外维护一个 “回补清单”记录每个版本补了什么、因为什么失败补的。这个过程看起来琐碎但它是目标检测数据集从“能跑”变成“能用”的核心环节。4. YOLOv8 训练自己的番茄数据集最小启动配置与三个必调参数数据集准备好以后训练环节反而是最省心的因为框架已经把流程封装得很完整。这一章以 YOLOv8 为例它是当前做自定义目标检测数据集训练比较稳妥的选择社区资料多出问题容易查到解决方案。4.1 环境准备和预训练权重先跑通单卡训练再说调优环境配置遵循最小可用原则先不要折腾 Docker 和分布式训练单卡跑通再谈别的。创建 Python 环境后安装 Ultralytics 包pip install -U ultralytics yolo detect predict modelyolov8n.pt sourcehttps://ultralytics.com/images/bus.jpg第一条命令装的是整个 YOLO 训练预测工具链第二条命令下载官方预训练权重并跑一次推理输出一张带检测框的图片就算环境正常。这里用yolov8n.pt是因为它最小最快跑通验证环境足够。ultralytics包会自动拉起 PyTorch如果你用的是 NVIDIA 显卡先确认nvidia-smi能看到显卡再执行一次第二行命令看终端里是否出现device: CUDA如果是 CPU 就要查一下 PyTorch 的 CUDA 版本装没装对。为什么要选 YOLOv8 而不是从零写检测头因为番茄识别数据集的重点在数据不在模型。YOLOv8 在公开检测任务上的先验知识可以通过预训练权重迁移过来尤其是果实轮廓、叶片纹理这些低层特征迁移学习能省大量训练时间。等你的数据集足够大、任务足够特殊时再来考虑从yolov8s.pt还是yolov8m.pt起步的问题。4.2 训练命令与参数表imgsz、patience、batch 缺一不可训练命令比我见过的绝大多数博客写的都短yolo detect train \ dataconfig/data.yaml \ modelyolov8s.pt \ epochs200 \ patience30 \ imgsz640 \ batch16 \ device0 \ workers4 \ cacheTrue这段命令的逻辑是从官方预训练权重yolov8s.pt出发用指定的数据集配置开始训练epochs是最大训练轮数patience是早停耐心值连续 30 轮验证集指标不提升就自动停止imgsz决定输入图片的缩放尺寸batch是每轮喂进显卡的图片张数cacheTrue会在第一次 epoch 前把图片缓存到内存第二次启动训练会快很多。参数说明这块是重点。三个必须理解透的参数是imgsz、patience、batch参数番茄项目的建议值调参说明imgsz640 起步小目标多改 960必须是 32 的倍数增大输入等于给小目标更多像素但显存占用按平方增长batch1616GB 显存太小 BN 统计不稳定太大要同步调低学习率patience30验证指标连续 30 个 epoch 不涨就停避免无效等待epochs200 到 300有早停时设大一点没坏处batch和学习率是联动的如果你因为显存不足把batch从 16 降到 8理想情况下学习率也应该减半否则梯度噪声变大损失曲线会异常抖动。Ultralytics 默认会自动调度学习率但遇到 loss 炸到 NaN先查学习率和标签里有没有 NaN 坐标。还有一点imgsz640时一张 1080p 的原图会被缩小到 640×640原图中较小的番茄在缩放后可能只剩十几像素这种目标在这个尺寸下基本学不到特征。所以番茄这类小目标偏多的数据集我会优先把imgsz调到 960 再试。4.3 训练过程的黑匣子三条 loss 曲线怎么读训练开始后项目目录下会出现runs/tomato/exp/里面包含一堆曲线图。很多人把损失曲线当玄学看其实它是有规律可循的。重点关注三条box_loss、cls_loss、dfl_loss。box_loss下降说明模型预测的框位置在逼近真实框cls_loss下降说明类别判断在变准dfl_loss负责框的边界质量它收敛慢一点是正常的。读曲线时最容易误解的一个点是val曲线比train曲线高并不一定代表过拟合。可能是验证集分布确实比训练集难也可能是验证集里混入了和训练集相似的帧导致评估失真。真正的过拟合信号是train_loss持续下降、val_loss在某个点反弹并持续上升。遇到这种情况先别急着加正则化回头检查数据集切分是不是有问题第 5 章的相似帧坑就在这里。番茄遮挡严重的数据集还有一个特点box_loss不会像公开数据集那样收敛到特别低。因为大量果实边缘被叶片遮挡标注框本身就有不确定性模型再强也无法精确到像素级。看到 loss 停在某个平台期下不去先问数据噪声有多大再问模型容量够不够。5. 番茄训练翻车日志目标检测数据集的 5 个典型踩坑现场这一章全是踩坑记录。每个坑我都按“现象 → 原因 → 解决”讲透都是我实际做过番茄项目时遇到的。5.1 框松框紧不一致AP0.75 直接拉胯现象训练结束看验证结果mAP0.5不低但mAP0.75明显偏低画出来的 PR 曲线在 0.75 附近快速跌落。原因标注员 A 喜欢把框画得很宽把果蒂和一点叶子都包进去标注员 B 喜欢贴果肉边缘框小而紧。模型在训练时看到的 IoU 标准不一预测框只能“平均”这些标注习惯导致它永远无法和任何一套标准对齐。IoU 阈值取 0.75 时框位置差几个像素就判定为失败问题立刻暴露。解决开工前写死标注规范明确“框四边贴住果实可见轮廓最多留 3 像素余量”。做完一批标注后抽 20% 检查框的紧实度发现松框直接打回重标。如果是多人协作同一批图片最好由同一个人标完不要在训练集里混合两套标注风格。5.2 验证集混入相似帧val_loss 后期越洗越虚现象训练到第 80 轮时train_loss还在降但val_loss开始上涨看起来像过拟合。可模型在测试现场的漏检率并不高。原因数据切分用了随机打散而没有按“视频片段”维度切。同一个视频抽出来的相邻帧一张在训练集、一张在验证集视觉内容几乎一样。验证集里塞满了训练集的“亲戚帧”评估分数被大幅高估而 val_loss 曲线则因为验证集内部统计不独立而出现虚假上涨。解决视频抽帧后先按视频文件分组再把整个分组划分到训练集或验证集。比如 10 段视频8 段进训练2 段进验证保证没有任何一帧来自同一个视频片段。更进一步可以用感知哈希去重把肉眼几乎相同的帧删掉。5.3 青色番茄完全漏检类别不平衡被低估现象红色番茄的召回率 90%青色番茄的召回率连 40% 都不到而且模型把不少叶片当成青番茄。原因数据集中青色番茄只占 15%红色番茄占 60%转色期占 25%。类别不平衡让模型在训练中把“红色圆轮廓”当作主导特征青番茄与叶片形状和颜色都接近样本少学不到判别力误检自然高。解决先统计每个类别的标注框数量低于总数 20% 的类要回补。回补时优先去现场采集青熟期果实或者换个角度重新拍如果实在补不到可以把已有青番茄样本离线复制 2 到 3 倍配合轻微的颜色扰动。对损失函数层面也可以给类别权重但这是第二选择第一选择永远是数据本身。5.4 远处小目标全灭imgsz 和切片谁说了算现象画面近处的大番茄框得很准远处果园深处的番茄漏检一片如果把验证按尺寸分桶看小目标的 AP 接近零。原因原图 1080p 缩到 640×640 后远处番茄在图上可能只有 10×10 像素特征图下采样后只剩一两个特征点检测头根本分不清那是果实还是叶子。解决先尝试把imgsz提到 960显存不够就减batch。如果提到 960 仍然漏检就得切图推理把一张 1080p 的原图切成四张 640×640 的重叠块分别推理再把结果按坐标拼回去。注意切图时要留 10% 左右的重叠区域否则果实刚好在切缝处会被截成两半。不要一上来就上 MMROTATE 那套旋转框方案水平框在番茄场景下够用旋转框是遥感 DOTA 数据集的高价需求这里不需要。5.5 训练集 mAP 很高现场演示却翻车现象验证集 mAP0.5 达到 0.95拿到温棚现场跑误检和漏检却比测试时严重得多。原因数据分布偏移。训练集和验证集都来自同一天下午阳光充足模型学会了“顺光下红绿分明的番茄长什么样”。现场是阴天加人工补光叶片反射偏黄模型把反射高光误判为番茄果面。解决建立一套“现场验证集”专门从部署场地录 200 张照片标好框但永远不参与训练。任何模型版本上线前必须在这套现场集上评估指标过线才允许部署。如果现场集表现差最有效的办法是拿现场图做小样本微调而不是重新训练全院模型。微调用 50 到 100 张现场图跑 30 个 epoch 就够多了会破坏原有的泛化能力。6. 验证与落地之间的最后一公里从测试集拆分到 ONNX 导出6.1 测试集按场景分组避免数据集“掏洞”很多项目在切分时只做了 train/valtest 直接从剩余数据里随机抽。正确的做法是测试集完全不参与训练和验证并且在物理维度上隔离。对番茄数据集来说隔离单位是“大棚编号”或“植株行号”——同一行、同一株的果实不管怎么随机划分它的背景和光照条件都是高度近似的。按场景分组后训练集、验证集、测试集的分布才真正独立。如果你的数据来源比较多还要注意测试集的难度不要低于验证集。我吃过亏测试集选了大棚入口处光线最好的几排验证集反而更难结果模型“看起来测试不错”一到生产环境就露馅。6.2 用 val 和 predict 做落地的双保险训练完成后用两段代码完成最终验收from ultralytics import YOLO model YOLO(runs/tomato/exp/weights/best.pt) # 在测试集上做正式评估 metrics model.val( dataconfig/data.yaml, splittest, plotsTrue, ) print(metrics.box.map50, metrics.box.map) # 在现场新图片上做推理并保存可视化图 results model.predict( sourcedata/field_day1, conf0.25, iou0.45, saveTrue, projectruns/verify, namefield_day1, )这段代码的逻辑是先用val拿一批量化指标再用predict做实际效果的可视化检查。metrics.box.map50是 IoU 阈值 0.5 的 mAPmetrics.box.map是 0.5 到 0.95 的平均 mAP后者更严格对框的精确度更敏感。番茄这类小目标多的数据集我会重点看map而不是map50。predict时的conf和iou也需要调conf0.25是置信度阈值太高会漏掉遮挡严重的果实太低会有一堆叶片误检iou0.45是 NMS 阈值果实密集时建议降到 0.4让互相重叠的果实更容易被分开。6.3 从 s 到 n一张表把模型裁剪给现场训练时用的是yolov8s部署在 Jetson 或 arm 盒子上时如果帧率不够可以先蒸馏或者直接换成yolov8n再微调几轮。一个实用的做法是保留s模型训练结果作为教师模型用n模型在同一个训练集上继续训练学习率调低到原来的十分之一。这样裁剪后的模型能继承大部分精度又能在边缘设备上跑起来。如果要用 TensorRT 或 ONNX Runtime导出命令如下yolo export \ modelruns/tomato/exp/weights/best.pt \ formatonnx \ imgsz640 \ opset12导出后一定要做一次精度复核ONNX 和 PyTorch 推理结果在数值上通常会有微小差异如果差异超过 0.5% 的 mAP优先检查输入归一化逻辑是否一致。养成习惯之后我现在新开任何数据集项目一定会先花两天时间把采集规范、标注规范、验证集隔离规则全部写进项目文档再让模型进场。这些“看不见的数据集工程”决定了模型在现场是表现好还是只是演示好。希望帮到你。本文还有配套的精品资源点击获取