1. 为什么我要搞一个番茄叶片检测数据集
做智慧农业这行的人,手里没几个拿得出手的数据集,出门都不好意思跟人打招呼。但说真的,市面上的公开数据集要么是国外的(病害种类对不上国内品种),要么是纯学术场景拍的(背景干净得像实验室),真拿到大棚里去跑,效果一言难尽。所以我在实际推进一个温室大棚病害预警项目时,索性自己动手,搞了一套3100张的番茄健康叶片检测数据集,配合YOLO系列做目标检测训练。
这个数据集的核心应用场景很明确:配合定点摄像头或者巡检机器人,在番茄生长周期内持续拍摄叶片图像,实时识别叶片是否健康、是否存在早期病害迹象。目标不是替代植保专家的判断,而是帮种植户在大面积种植时快速筛查出问题区域,把"人眼看得过来"变成"算法先筛一遍,人工重点复查"。
适合谁参考?如果你正准备训练自己的农业检测模型,或者在YOLO数据集的构建、标注、训练上踩坑,这篇文章应该能给你省不少时间。我会把从数据采集、标注规范、训练参数到落地部署的关键细节全部摊开讲,包括那些文档里不会写的坑。
3100张不多,但对一个垂直于单作物、单部位检测的任务来说,配合好的数据增强和迁移学习,已经能训练出可用性相当高的模型。关键不在于数量堆到几万张,而在于每一张数据的质量、标注的一致性和训练策略的适配性。
2. 数据集设计与制作的整体思路
2.1 为什么选番茄叶片作为检测对象
番茄是全球种植面积最大的蔬菜作物之一,大棚种植尤其密集,叶片病害传播速度快。常见的叶霉病、早疫病、晚疫病、灰叶斑,一旦漏检几天,整棚蔓延,损失很大。而叶片又是病害表现最早的部位——很多系统性病害在果实显现症状之前,叶片上已经有明显的颜色和形态变化。所以把检测目标锁定在叶片上,是性价比最高的切入方式。
另一个原因是番茄叶片的结构特征清晰。番茄叶片是羽状复叶,背景相对简单,叶片边缘轮廓明显,病害区域的颜色变化(黄化、褐斑、灰霉层)在视觉上辨识度高。比起果实检测(果实遮挡严重、颜色受光照影响大),叶片检测对标注和模型来说都更友好,准确率更容易做上去。
选择单一作物还有一个实际考量:模型容量有限,检测类别越多,单类数据的均衡性要求越高。当前项目聚焦番茄,后面可以按同样的流程扩展到黄瓜、辣椒,每个作物单独训练专属模型,部署时按需加载。
2.2 数据集的类别体系如何设计
这是我最想强调的一点。很多人在做农业数据集时,一上来就把类别分得很细,什么"番茄叶霉病早期"、"番茄叶霉病中期"、"番茄晚疫病斑点",标注起来痛苦不说,模型学到的特征往往互相混淆。病害发展是一个连续过程,划分过细的类别边界本来就是模糊的。
我最终把类别收敛为两类:
- 健康叶片(healthy_leaf)
- 病害叶片(diseased_leaf)
病害叶片这一类是广义的,涵盖叶霉病、早疫病、斑枯病等多种常见病害的叶片表现。实际训练中,模型只需要学习"什么样的叶片看起来不正常",这个特征边界比"具体是哪一种病"要清晰得多,检测置信度也更稳定。
那具体病害的细分识别怎么做?我的方案是分两阶段:第一阶段用当前数据集跑YOLO做健康/病害的快速筛查;第二阶段对检出的病害区域做图像分类(或用多模态模型识别具体病种)。这样既保证了检测精度的稳定性,又保留了后续细分的扩展空间。
类别体系确定后,标注工作就简单得多,只需框选叶片区域并标记类别,不需要在叶片上细抠病斑轮廓,省了大量工时。
2.3 3100张数据的构成比例
整个数据集3100张,我按以下比例分配:
| 用途 | 数量 | 说明 |
|---|---|---|
| 训练集 | 2480张 | 用于模型权重训练 |
| 验证集 | 310张 | 每轮训练结束后评估,调整超参数 |
| 测试集 | 310张 | 最终模型效果的独立评估,数据不参与任何训练决策 |
病害叶片与健康叶片的比例控制在约6:4。病害样本略多一点,因为病害叶片的形态多样性更高——不同病害、不同严重程度、不同光照条件下的表现差异都需要覆盖。但如果病害样本占比过高,模型会倾向于"宁可错杀也不放过",导致健康叶片的误检率上升。
每张图片的平均标注框数量在1到3个之间,取决于拍摄时是单叶特写还是整株多叶。多叶场景对模型在大棚实景下的泛化能力很重要,单叶特写则有助于学习细致的纹理特征,两者搭配使用。
3. 数据采集与标注的实操细节
3.1 采集设备和拍摄环境的真实要求
对农业数据集来说,采集设备不需要特别高端,我用的就是普通工业相机(500万像素级),手机摄像头其实也能用,但要注意保持分辨率在1280x1280以上,否则叶片纹理细节丢失,小病斑根本看不清。
拍摄场景我分了三种,尽量覆盖实际部署环境:
第一种是大棚自然光环境。上午9点到11点、下午3点到5点这两个时间段光照比较均匀,不会产生过强的阴影和反光。这个场景拍出来的数据最接近实际运行状态,占比约70%。
第二种是人工补光环境,模拟阴天、傍晚等弱光条件。我用了一盏LED补光灯,色温5000K左右,亮度调低于正午阳光。这部分数据能有效提高模型在不同光照条件下的鲁棒性。
第三种是室内白底背景拍摄,作为数据增强的"干净样本"。这类图片背景无干扰,模型学到的叶片特征更纯粹,占比约10%。
拍摄时注意叶片状态要自然——不能刚喷完水就拍,叶片上的水珠会产生高光反射,干扰病害特征提取;也不要刻意把病叶洗得干干净净再去拍,那就失去了实际检测的意义。
3.2 标注工具选择与标注规范
标注工具我用的是LabelImg和X-AnyLabeling,都支持YOLO格式直接导出。LabelImg是老牌工具,稳定可靠,适合批量操作;X-AnyLabeling支持AI辅助预标注,先用一个初版模型自动标一遍,人工再修正,效率能提升不少。
标注规范上,我踩过不少坑,总结几条硬性原则:
一、标注框必须完整包住叶片,宁大勿小。很多人标注时喜欢紧贴叶片边缘,但叶片边缘有锯齿状突起,框得太紧会把一部分叶片切出框外,训练时模型学到的是"残缺的叶片",检测效果反而不好。我就吃过这个亏,最初一版数据标注框都紧贴边缘,结果模型对边缘遮挡的叶片几乎完全无法识别。
二、遮挡情况的处理要统一。如果叶片被其他叶片遮挡超过50%,不标注;遮挡少的部分,按可见轮廓框。这个标准在整个标注过程中必须一以贯之,否则模型对是否应该检测一个不完整的叶片会产生混乱。
三、一个叶片一个框,不要试图把一丛叶片框在一起。哪怕两片叶子紧紧挨着,只要边缘可辨认,就要分开标注。模型依赖每个框学习"一片叶子"的视觉范围,框里装了两片半叶子,特征就浑浊了。
标注完成后,导出YOLO格式的txt标签文件(类别ID加归一化坐标),建议再用一个小脚本做一遍格式校验和可视化检查,把标注框画回原图上快速扫一遍,看看有没有错位和漏标。这一步不能省,肉眼直接看txt坐标文件根本发现不了问题。
3.3 数据清洗和增强策略
数据采集回来不是直接就能用的,清洗这一步决定了数据集的底线质量。我清洗了三类问题:
第一类是模糊图片,手持相机拍摄时容易产生轻微运动模糊,雾天或大棚内湿度大时也会导致画面发灰。我按人工逐张筛选删除,标准是叶片脉络是否清晰可辨。
第二类是严重过曝和欠曝的图片,曝光问题的图片后期很难通过简单增强救回来,删掉比留着好。
第三类是标注错误率偏高的图片,抽查时有超过20%的标注框明显错位的,整个文件直接丢掉重新拍。
清洗完的数据集做增强,我主要用了以下几种方式:
- 水平翻转、垂直翻转(注意垂直翻转在真实场景中不太常见,占比控制在10%以内)
- 亮度扰动:随机调整亮度正负25%,模拟一天中不同时段的光照变化
- 对比度与饱和度微调:让模型对颜色变化不那么敏感,减少过拟合
- 轻微随机旋转(±10度)与缩放(0.8~1.2倍),模拟相机角度变化
- Mosaic增强(YOLO自带):将四张图拼接训练,让模型学会处理叶片密集和互相遮挡的情况
增强数据不是越多越好,尤其注意不要引入现实中不可能出现的状态。比如翻转后的叶片阴影方向会和自然光方向不一致,这不会干扰YOLO训练,但如果做的是需要方向敏感的任务就得格外留意。
4. YOLO训练全流程实操
4.1 环境配置和baseline选择
这个项目的模型我选了YOLOv8s作为baseline。原因很简单:YOLOv8的生态成熟,文档齐全,训练推理速度平衡,部署到一般工控机甚至边缘设备上都没有压力。YOLO系列发展到v8在backbone和neck上的改进已经相当完善,对农业场景这种目标尺度较小、背景复杂程度中等的任务,完全能胜任。
环境配置我用的是PyTorch框架,CUDA版本11.8,GPU用RTX 3090(24G显存),训练这个规模的数据集毫无压力。CPU训练非常不推荐,哪怕只是2480张图,用CPU训练YOLOv8s的推理速度会很痛苦。
ultralytics这个库直接pip安装就行,YOLO训练的基础流程非常简单,重点在于参数调优。
4.2 关键训练参数设置与调优思路
以下是我实际训练中用的核心参数,附上选择理由:
| 参数 | 设定值 | 选择理由 |
|---|---|---|
| imgsz | 640 | YOLOv8的默认输入尺寸,精度和速度的折中。对叶片这种目标,640像素足够分辨常见病斑 |
| batch | 16 | 3090显存下比较稳妥,太大容易OOM,太小训练不稳定 |
| epochs | 300 | 数据集较小,拉长训练轮数配合早停机制 |
| optimizer | SGD | 比Adam收敛更稳定,泛化性更好,这是实际对比出来的结果 |
| lr0 | 0.01 | SGD的常用初始学习率 |
| patience | 50轮 | 验证集指标连续50轮不提升就停止,节省时间 |
| workers | 8 | 数据加载进程数,取决于CPU核心数 |
一个重要心得:不要在一开始就把imgsz调到1280甚至1536去追求精度。imgsz提升会显著增加显存占用和计算量,而640下的精度在小目标检测上已经够用。如果你要检测的是特别小的早期病斑,可以试试将imgsz提到960,同时注意Mosaic增强的比例需要相应调整,否则小目标信息丢失得更严重。
关闭weight augmentation(weight_augment=False),这是默认设置但对小数据集帮助有限;开启cache=True把数据集缓存到显存,能大幅减少训练过程中的磁盘IO等待。
4.3 训练过程中的实时监控和调优
训练开始后,最需要关注的指标是train/cls_loss(分类损失)和train/box_loss(回归损失)的下降曲线。如果训练集分类损失持续下降到接近0而验证集损失停滞甚至上升,那基本可以确定过拟合了。
我对过拟合的应对,第一步是增加数据增强的强度,特别是把scale(随机缩放)从0.5提高到0.9,相当于喂更多"角度不同、距离不同"的样本。第二步是加dropout来正则化网络。
另一个常见的问题是:某个类的AP(平均精度)特别低。我当时就遇到"健康叶片"AP一直在0.7左右上不去,而"病害叶片"AP已经0.9了。排查下来发现两个原因:一是数据集中健康样本占比偏低;二是健康叶片在光照充足时反光严重,部分叶片边缘和背景的差异度不足。解决方案是补充了100多张侧光条件下拍摄的健康叶片,模型的AP立刻有了改善。
训练完成后,用验证集评估模型,mAP50(IoU阈值0.5下的平均精度)在0.88,而mAP50-95(从0.5到0.95取不同阈值的综合指标)在0.7左右。对农业检测来说,mAP50这个指标更重要,因为实际场景里允许检测框有一定的偏差,框住叶片的大部分区域即可,不需要像素级的精准定位。
4.4 模型导出与测试集最终评估
训练结束后,我将训练好的权重导出为TensorRT engine格式,部署在NVIDIA Jetson Orin NX上,推理速度从PyTorch的约30ms/帧降到了约12ms/帧,满足实时检测的需求。具体可这样做:
yolo export model=best.pt format=engine device=0 half=Truehalf=True表示FP16半精度推理,精度损失可以忽略,速度提升明显。导出后可以快速验证一下:
yolo predict model=best.engine source=test_images device=0测试集的310张图在导出后的engine模型上跑一遍,mAP50和训练时的验证集评估结果接近,没有出现精度断崖式下跌。这一步很有必要——有时量化或格式转换会有精度回退,及早发现比部署上线后才发现要好得多。
5. 落地部署与真实场景适配
5.1 大棚定点监控方案
第一套落地部署方案是大棚定点监控。在温室顶部或者侧面支架上安装摄像头,每隔几秒拍摄一张高清图像,传入边缘计算盒子(比如Jetson Orin NX这一级别)执行YOLO检测。
这里有一个关键的工程细节:摄像头安装高度和角度直接影响检测效果。摄像头安装得过高,叶片在画面中占的比例太小,检测精度严重下滑;安装得过低,单株叶片遮挡严重,漏检率增加。我实测下来,摄像头距离番茄植株顶部大概1到1.5米,以俯视约45度角拍摄,单张画面能覆盖3到5株番茄,叶片尺寸在画面中占比适中,检测精度比较理想。
检测结果的输出是一条带坐标和时间戳的记录,写入数据库。如果一个检测区域内连续多帧检出病害叶片,说明这里大概率真的有了问题,系统自动推送提醒消息。单独一帧偶尔检出可能是噪声,连续多帧确认能有效降低误报率。
5.2 巡检机器人路径检测方案
另一套方案是和轨道式巡检机器人配合。机器人在温室的行间轨道上移动,每隔固定距离停下拍摄一组图像。这样一套设备就能覆盖整个大棚,单台成本远低于部署几十个固定摄像头。
机器人方案对流处理有一个额外要求:检测结果需要在本地做一次时序聚合,而不能单纯依赖单帧。具体来说,每次停靠点拍摄的5张图中,至少3张检出病害区域,才确认为阳性结果。这个阈值是我通过实地测试调出来的,既能过滤运动模糊导致的误检,又不会放过真正的病斑。
5.3 弱光与逆光场景的模型表现
实际大棚里最影响检测精度的问题是弱光和逆光。大棚薄膜会过滤部分紫外线,阴天时实测亮度只有晴天的三分之一。我在训练时加入的亮度扰动在这时发挥了作用,模型在弱光下的mAP50从初始的0.72提升到了0.85,提升幅度明显。
逆光情况更棘手。太阳低角度时,朝南一侧的叶片会处于背光状态,叶片整体发暗,病害斑点和正常叶片的亮度对比度大幅下降。我处理的办法是训练时加大对比度扰动的范围,同时在实际部署时引导摄像头尽量避免直射阳光朝向,优先选择顺光或侧光位置安装。
这里也暴露了数据集的覆盖范围不足——3100张数据中逆光样本占比不到5%,模型对此类场景的泛化能力有限。后续迭代时,我会专门补一批不同时段、不同天气、不同朝向条件下的逆光数据,把短板补上。
6. 典型问题与避坑经验速查
6.1 数据层面的五大高频问题
| 问题 | 表现 | 定位方法 | 解决办法 |
|---|---|---|---|
| 标注框错位 | AP上不去,检测框整体偏移 | 可视化标注结果,逐个检查 | 统一标注工具版本和导出格式 |
| 类别不平衡 | 某一类AP明显偏低 | 分别查看每类的PR曲线 | 补充少数类样本或调整损失函数权重 |
| 图像过曝 | 叶片高光区域被判为病斑 | 检查误检样本的分布 | 删除过曝图片,增加欠曝增强 |
| 背景干扰 | 检测框跑到地面泥土或滴灌带上 | 查看错误检测的置信度分布 | 训练数据中加入不同地面的背景样本 |
| 领域偏移 | 实验室数据好,大棚数据差 | 对比训练集与实际部署场景 | 用实际场景补充采集数据并做domain adaptation |
标注框错位算是我最常遇到的标注质量问题。很多人以为标注得差不多就行,但YOLO的anchor-free机制对标注精度还是敏感的。我重新仔细标注一遍之后,mAP50提升了约5个百分点,效果立竿见影。
6.2 训练环节的四个提醒
第一个提醒:使用预训练权重(YOLOv8官方在COCO上的预训练权重)是非常必要的。COCO数据集包含大量自然图像特征,迁移学习的收益在这个规模的数据集上非常明显。从零开始训练,同参数下mAP50会低10个百分点以上。
第二个提醒:Mosaic增强在训练末期建议关闭。YOLOv8默认最后10个epoch自动关闭Mosaic,因为拼接图与真实场景差异较大,训练后期需要回归到真实分布。手动训练时记得保留这个默认机制。
第三个提醒:保存检查点文件(epoch每50轮保存一次的权重)很有用。我遇到过训练到约200轮时显存溢出导致进程被杀,如果没有检查点就只能全部重来。
第四个提醒:验证集不能只在训练结束后跑一遍,要在训练过程中定期评估,否则很难判断是否过拟合、该不该提前停止。YOLOv8自带的val机制已经能做到这一点,别嫌麻烦,每轮训练结束的自动验证对判断训练状态极为关键。
6.3 关于数据集持续迭代的体会
3100张数据集解决了从0到1的问题,但从1到N还需要持续迭代。我的做法是将每批从大棚采集的新图像做增量标注,定期合并进训练集并重新训练。这样模型能逐渐适应季节变化、品种差异、光照模式迁移带来的新情况。
具体操作时要注意不要让旧数据被新数据淹没——每次增量训练时,新数据的采样权重适当提高,但旧数据也要保留一定比例,否则模型会遗忘之前学过的特征。我使用约3:1的采样比例(新数据:旧数据),实测效果比较理想。
7. 实操中的心得体会与后续扩展方向
这个项目做完,我最大的体会是:智慧农业的模型和数据集工作,真正难的地方不在于算法本身,而在于你是否理解农业现场的真实约束。目标检测模型在标准数据集上刷分是一回事,在大棚里的泥土、水雾、遮阳网、滴灌带组成的真实环境中稳定工作是另一回事。数据集的构建和迭代必须围绕实际部署场景持续做,才能让模型从"论文里能跑"变成"地里能用"。
另外想提醒大家的是,纯检测只是第一步。我在项目尾期尝试将健康/病害检测结果接入一个轻量级的视觉分析模块,用检出的叶片区域做进一步的病斑面积估算和颜色特征分析,从而对病害严重程度做粗略分级。这个方向很有意思,但需要更多的标注数据支撑,后续我打算扩充数据集规模,把细分病害类型和严重程度也纳入训练目标,让模型在农业生产决策中发挥更大的作用。
如果你也在做类似的数据集或者想用YOLO解决农业视觉问题,建议从我的经验出发:先聚焦作物、聚焦部位、收敛类别,把数据质量和标注一致性做扎实,再谈模型调优和应用扩展。这条路走通了,后面做任何作物和场景,都能以同样的方法复现和迁移。