
简介面向目标检测任务的番茄识别数据集共含4786张番茄图片的标注信息类别覆盖未成熟番茄、成熟番茄和患病番茄适用于YOLO系列、Faster Rcnn、SSD等主流目标检测模型的训练与评估。压缩包共2000个文件以txt标签文件和yaml配置文件为主整体约157.46MBtxt标签记录每个目标的边界框与类别yaml文件定义类别名称可直接用于配置YOLO训练环境。数据已按训练集、验证集和测试集划分无需手动拆分可即开即用适合番茄成熟度判别、病害识别等农业视觉场景。每个txt文件命名与对应图片一致便于数据关联与结果可视化有助于快速检查标签质量。该数据集面向深度学习和计算机视觉学习者与开发者既可用于算法训练与调参也可作为农业智能检测项目的实验基础目前已有281人学习下载。1. 番茄识别数据集不是“有图就能训”数据分布决定模型上限做温室大棚自动化采摘或产量统计的人多半都栽过这个跟头拿现成的目标检测模型去识别番茄熟果还好青番茄和叶子混在一起时漏检一大堆阴天、逆光、重叠遮挡下更是基本靠猜。真正卡住你的往往不是模型而是数据集。番茄识别数据集就是一套专门服务于目标检测任务的图片加标注集合它包含类别定义、标框坐标和样本分布直接决定模型能不能在你的大棚里干活而不是只在测试集上好看。这篇文章适合准备用 YOLO 等检测算法做番茄成熟度识别、采摘计数和产量评估的人。先把一个反直觉结论放这儿盲拍 5000 张图不如按光照、遮挡、成熟度分层选 2000 张数据分布比数据量更接近效果真相。2. 番茄识别数据集里到底装什么从类别定义到数据分布2.1 目标检测数据集的通用结构图片、标框与类别标签不管你做车牌检测还是遥感舰船检测数据集的底子是一样的一张图片对应一个标注文件标注文件里记录着目标类别和边界框坐标。常见做法是在本地维护三个目录images/放原始图片labels/放标注文件classes.txt放类别清单。训练时模型做的事情就是学“什么样的像素组合对应什么样的框、框里是什么类别”。同样是目标检测数据集不同领域的结构差异能给番茄识别提供选型参考。像 CCPD 这种车牌数据集目标单一、结构规整框与框之间几乎不重叠标注工作量大头在车牌区域的截取和字符校正。而 HRSC2016 这类遥感舰船数据集目标朝向任意必须用旋转框才能框准。番茄识别数据集正好介于两者之间番茄接近圆形水平框足够用不需要旋转框但果实之间重叠、被枝叶遮挡、强光影变化又让它比车牌检测复杂得多。这也是为什么刚开始接触番茄识别的人最好的学习起点是看一套层次分明的目标检测数据集长什么样——这比纠结模型网络结构更接近实际痛点。2.2 类别定义按成熟度拆还是按目标物拆设计番茄识别数据集第一步不是拍照而是定义类别。常见的做法有两种。第一种是只设一个tomato类别所有果实不论成熟度全部框进去模型输出的是“哪里有个番茄”。第二种是拆分成熟度比如green、half_ripe、ripe三个类别。如果你的应用是采摘机器人或者分级质检强烈建议用第二种因为采摘决策需要的不是“有没有番茄”而是“这个番茄熟了没有、现在能不能摘”。类别拆分也能反过来暴露数据集的问题。只做单类别时标注员对青番茄和熟番茄一视同仁模型学到的是“圆形的红色或绿色物体”做成熟度拆分后青番茄和叶子在颜色上极度接近模型被迫去学形状、纹理和边缘特征特征学习更扎实。代价是标注工作量上升而且熟番茄、半熟番茄、青番茄的比例如果不均匀训练时模型会对样本多的类别倾斜。这里有一个实操上的建议第一次做番茄识别数据集先把类别定成“青果 - 转色果 - 红果”三档就够用了别一上来搞七个成熟度级别标注一致性会崩。2.3 数据分布的五个维度光照、遮挡、重叠、视角、生长时期做番茄识别数据集的人最容易忽略一件事数据分布比数据总量重要。我见过有人买了果园监控视频自己抽了一万张图结果全部是白天、顺光、单串果实的画面模型在测试集上 mAP 高得吓人一拿到真实大棚就翻车。归纳下来番茄识别数据集的分布至少要覆盖五个维度。光照是最关键的维度。晴天正午的高光、阴天的柔光、早晚的低照度逆光对应完全不同的图像特征。建议按“强光 : 正常光 : 弱光 2 : 6 : 2”的比例采集。遮挡和重叠是番茄识别的独特难点番茄是簇生植物一串果实往往挤在一起前果挡后果是常态数据集里必须包含大量互相遮挡的样本否则模型学不会处理边界模糊的框。视角维度上固定摄像头的俯视视角和机器人机械臂的水平视角拍出来是两个世界。生长时期则是指番茄整个挂果周期的状态从刚坐果的绿色小果到完全成熟的红果尺寸和颜色跨度非常大。这五个维度不需要在采集时精确量化控制但在整理数据集时应当逐一核对每张图的属性。常用做法是建一个 CSV 清单每张图片标注所属大棚、拍摄时段、光照条件、遮挡等级后续训练时如果发现某个场景下漏检就能回溯是数据分布缺失还是模型参数问题。这一步听着麻烦实际上就是数据集的“后悔药”。3. 从零构建番茄识别数据集采集、清洗、标注与格式转换3.1 视频抽帧低成本拿到海量原始图建立番茄识别数据集的第一步是采集原始图像。如果条件允许用相机在果园拍一圈当然好但大多数场景下更现实的做法是利用监控摄像头录视频然后抽帧得到图片。我曾经帮人处理过 30 个小时的大棚监控视频抽帧之后得到的图像数量足够覆盖多个生长周。# 使用 ffmpeg 从视频中每 5 秒抽取一帧输出到 images_raw 目录 ffmpeg -i greenhouse_01.mp4 -vf fps1/5 -q:v 2 images_raw/greenhouse_01_%04d.jpg这段命令的逻辑是-i指定输入视频-vf fps1/5表示每 5 秒输出一帧-q:v 2控制输出 jpg 质量2 是高质量数值越大画质越差%04d是输出文件名的四位序号占位符。抽帧间隔要按视频内容变化速度来调如果摄像头是固定机位且画面变化缓慢5 秒一帧足够了如果画面里有人在走动或者镜头在转动建议改成 1 秒一帧避免漏掉关键角度。这里有一个需要特别留意的坑连续抽帧得到的图像存在严重的时间相关性。同一串番茄在相邻帧里的画面几乎一样如果直接把这些图全部喂进数据集训练集和验证集之间会出现数据泄露最后评估出来的 mAP 虚高。所以抽帧之后一定要做去重或分组后面第 3.4 节会专门讲怎么按视频源划分数据集。3.2 标注工具选择与标注规范拿到原始图片后接下来是标注。番茄识别数据集的标注工具我用过 labelImg 和 labelme 两个。labelImg 上手快、快捷键效率高适合做矩形框标注labelme 支持多边形标注适合要精细边界或者以后要转分割任务的场景。目标检测用矩形框的话labelImg 是更常见的做法。标注规范是比工具更值得花时间的事。番茄识别里最常见的标注错误有三个。第一把被叶子挡住一半的果实也框成完整矩形。如果你的目标是采摘计数被遮挡的果实确实算一个目标但框的范围应该只圈住可见部分否则模型会学到一个“一半是叶子一半是番茄”的错误模板。第二把背景里模糊不清的目标也标进去模型会学到一堆噪声。第三同一张图上半熟和熟果的颜色边界本身就模糊不同标注员的判断标准不一致——解决办法是开工前先拿 20 张图让所有标注员一起标统一完口径再批量干活。标注过程中还有一条经验每标完 100 张图用图像查看器快速浏览一遍重点看框有没有错位。这个步骤建议不要省后期返工的成本比前期多看一眼高得多。3.3 VOC 格式转 YOLO 格式转换脚本与四个边界坑大多数检测框架特别是 YOLO 系需要的标注格式是每张图片一个同名.txt文件每行一个目标格式为类别id x_center y_center width height坐标值归一化到 01。而 labelImg 默认保存的是 VOC XML 格式。自己写转换脚本并不复杂但边界情况不少。import os import xml.etree.ElementTree as ET from pathlib import Path def voc2yolo(xml_path, out_dir, classes): tree ET.parse(xml_path) root tree.getroot() img_w int(root.find(size).find(width).text) img_h int(root.find(size).find(height).text) lines [] for obj in root.findall(object): cls obj.find(name).text.strip() if cls not in classes: continue cls_id classes.index(cls) 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) xmin max(0, min(xmin, img_w)) xmax max(0, min(xmax, img_w)) ymin max(0, min(ymin, img_h)) ymax max(0, min(ymax, img_h)) if xmax xmin or ymax ymin: continue w xmax - xmin h ymax - ymin cx xmin w / 2 cy ymin h / 2 lines.append(f{cls_id} {cx/img_w:.6f} {cy/img_h:.6f} {w/img_w:.6f} {h/img_h:.6f}) out_path Path(out_dir) / (Path(xml_path).stem .txt) out_path.write_text(\n.join(lines) \n, encodingutf-8)这段脚本的逻辑是解析 XML 里的图片宽高和每个目标的类别、坐标把边界框从xmin ymin xmax ymax形式换算成cx cy w h并归一化。参数上需要注意classes列表的顺序就是训练时的类别 ID必须和后面的data.yaml保持一致坐标做了max/min裁剪是为了处理标注框越界的脏数据。转换脚本有四个常见的边界坑每一个我都踩过。第一标注框越界标注员手抖把框拉出图片边界导致归一化坐标大于 1脚本里不做裁剪的话训练时会出现诡异的 loss 波动。第二空标注文件某些图片确实没有目标转换脚本会生成空.txt这个空文件要保留删掉它会导致训练时找不到对应的标签文件。第三类别名大小写Tomato和tomato在脚本里是两个类别但训练时只认你写在classes列表里的那个不一致会静默丢弃目标。第四XML 里有difficult1/difficult标记的难例目标这类目标模型很难学建议直接过滤掉别让它拖累正常样本。3.4 划分训练集与验证集按视频源分组防止数据泄露数据划分直接影响评估可信度。最常见的错误是直接把所有图片随机打散按 8:2 分训练集和验证集。对于番茄识别数据集这个做法几乎必定导致数据泄露——因为同一段视频的相邻帧画面高度相似随机划分会把同一个果实的多张近景图同时分到训练集和验证集验证集的 mAP 虚高到没参考价值。import random from pathlib import Path def split_by_group(image_dir, group_field, train_ratio0.8, seed42): images list(Path(image_dir).glob(*.jpg)) groups {} for img in images: # group_field 是文件名中的视频来源标识例如 greenhouse_01 或 graft_03 gid img.name.split(_)[0] _ img.name.split(_)[1] groups.setdefault(gid, []).append(img) all_groups list(groups.values()) rng random.Random(seed) rng.shuffle(all_groups) train_cut max(1, int(len(all_groups) * train_ratio)) train_images [img for g in all_groups[:train_cut] for img in g] val_images [img for g in all_groups[train_cut:] for img in g] with open(train.txt, w) as f: for img in train_images: f.write(str(img.resolve()) \n) with open(val.txt, w) as f: for img in val_images: f.write(str(img.resolve()) \n) print(f训练集 {len(train_images)} 张验证集 {len(val_images)} 张)这个脚本的核心是按视频来源分组而不是按图片分组。group_field的提取规则要根据你的文件名约定来调整我在示例里用下划线分隔取前两段作为视频来源标识。这样同一段视频里的所有帧只会进同一个集合验证集的评估结果才真实反映模型在陌生场景上的表现。seed42保证每次划分结果可复现后面调模型参数对比效果时不会因为数据划分变了而得出错误结论。4. 番茄识别数据集训练避坑五个常见问题排查与修复4.1 现象验证集 mAP 很高田间实测一塌糊涂这是做番茄识别数据集最典型的翻车现场。训练集的 mAP 到了 0.85 以上拿到真实大棚里一测识别率掉到六成。原因几乎总是数据泄露加场景单一划分的时候没有按视频源分组把同一串番茄的不同时刻帧分进了训练集和验证集模型等于背下了那串番茄的样子同时采集的时候没有考虑光照变化训练集里全是晴天顺光图阴天一到就露馅。解决方法是回头统计训练集和验证集的视频来源重叠情况然后按第 3.4 节的分组逻辑重新划分再按“光照、遮挡、成熟度”做一层分层抽样确保验证集包含弱光、逆光、重叠严重的样本。4.2 现象青番茄漏检严重红番茄检测正常青番茄和叶子在颜色空间上的距离太小模型如果偷懒靠颜色来区分目标必然对青番茄失效。这里有一个需要讲透的机制YOLO 系列模型的输入会做色彩归一化和数据增强但默认增强里的色域变换是全局的不会针对性拉大“青番茄”和“叶子”的区分度。常用的解决手段有两个。第一个是在数据增强配置里增强 HSV 空间的饱和度扰动迫使模型去学形状和纹理而不是色彩。第二个是给青番茄样本在采样器里加权重让每个 batch 里青番茄的比例不低于三成。如果这两种方法做了之后青番茄漏检还是明显就要回头检查标注框——是不是把遮挡严重的青番茄也标进去了如果是模型学到的其实是“叶子形状”。4.3 现象模型把叶子卷边、果实套袋误检成番茄误检本质上说明模型学到了错误的判别特征。叶子卷边被误检为番茄通常是因为标注框把被叶子遮挡的果实完整框了进去模型学到的是一个“周围带叶子纹理的番茄轮廓”这张模板和叶子卷边的特征高度重叠。套袋误检则是因为套袋的纸白色和半熟番茄的转色期颜色接近。解决分两步第一步是把标注规范改成“只圈可见部分”被遮挡超过一半的果实要么不标要么在数据集中单独增加一个“被遮挡”标注策略说明第二步是在训练之后收集误检图把这些图加入训练集重训一轮。这种方法业内叫“硬负样本挖掘”做一轮往往比盲目加数据更有效。4.4 现象训练 loss 正常但召回率始终上不去如果你的番茄识别数据集里存在大量小目标——比如固定摄像头俯拍一串番茄在画面里只有 30×30 像素——召回率上不去就很正常了。YOLOv8 这类模型训练自己的数据集时输入分辨率默认是 640小目标经过几次下采样后特征图上的有效信息可能只剩几个像素。常见做法是先统计数据集里标注框的尺寸分布如果确实小目标多就把训练输入分辨率提高到 1280或者把大图切块成 640 的小图再训练。这里顺便说一个容易误解的地方YOLOv8 已经不需要手动设置 anchor 了你不需要在这个版本里调 anchor 相关参数但框的尺寸分布仍然会影响模型行为数据集里框普遍偏小时用小目标增强策略比如 copy-paste 要比硬调网络结构更划算。4.5 现象标注了一个月训练时报“标签格式错误”这种问题最委屈——标注工作量大结果格式全错了。常见原因有三个把类别名直接写进了.txt而训练框架要求的是类别 ID 数字坐标没有归一化直接写了像素值或者标注文件的文件名和图片文件名不一致导致标签匹配不上。排查顺序是先用命令行打印出一个标注文件的内容人工核对再看文件名是否完全一致包括扩展名最后确认data.yaml里的类别顺序和转换脚本里classes的顺序一致。我在做法里会在训练前加一个校验脚本统计每个标注文件的坐标值范围是否在 01 之间、行数是否和图片里的目标数对得上。这个脚本跑一次几十秒能省下后面排查“玄学报错”的半天时间。5. 不训练也能预判效果数据集质量的三个验证技巧训练一次番茄识别模型动辄几个小时如果最后发现是数据集的问题时间就白花了。这里分享三个我在开工训练前必做的验证技巧全部不需要训练就能执行。第一个技巧是把标注框画回原图人眼抽查。用 OpenCV 把标注框和类别 ID 叠加到图片上重点看三类图严重遮挡的、强光照过曝的、背景杂乱的。这一步能快速发现标注规范执行不到位的问题比如框偏大、框错位、漏标。第二个技巧是统计标注框的面积分布一条命令能出结果把所有标注框的宽高算出来看看百分之多少的框小于 32×32 像素。如果占比超过了一半直接考虑提高拍摄分辨率或做切片训练否则小目标会把整体 mAP 拉低一截。第三个技巧是按第 3.4 节的分组逻辑检查训练集和验证集的场景覆盖画一个简单的柱状图确认弱光和遮挡样本在两个集合里都有足够数量。这三个技巧我每次做数据集都先跑一遍。以前有一次偷懒没做场景覆盖检查训练完拿出去实测才发现在逆光场景下模型几乎全瞎最后回头补了 1000 张逆光图重训一进一出浪费了两周。从那以后我把数据集质量检查当训练前的固定步骤宁可多花一个小时排查也不想再吃一次“训完才发现不对劲”的亏。做番茄识别数据集本质上是在为模型铺路——路铺得平不平在训练前就能看出来。希望帮到你。本文还有配套的精品资源点击获取