☰
番茄叶片病害检测Python深度学习资源:YOLO目标检测实战与避坑指南
2026/10/1 2:24:23 网站建设 项目流程

简介:这份资源面向具备Python与PyTorch基础、希望上手番茄叶片病害目标检测的开发者与学习者,提供从数据处理到模型训练再到可视化识别的完整代码链路。压缩包共1470个文件,约40.55MB,其中730张jpg为番茄叶片病害图像样本,358个xml与363个txt分别对应标注文件与YOLO格式标签,另有3个py脚本、3个pt权重、3个yaml配置及png、csv等训练日志与评估图表,覆盖数据、训练、推理全流程。已有109人学习下载。资源核心价值在于开箱即用的工程结构:01脚本负责将数据集转为YOLO格式并生成train.txt、val.txt与data.yaml,02脚本用于模型训练,03脚本提供PyQt可视化界面,点击加载图片与检测按钮即可完成识别;若仅调用已训练模型,直接运行03pyqt.py即可,适合快速验证与二次开发。

1. 番茄叶片病害检测这套 Python 深度学习资源,到底能省掉多少造轮子的时间

去年帮一个做智慧农业的朋友看大棚巡检方案,他手里攒了三千多张番茄叶片的手机照片,想做个能自动框出病斑、区分早疫和晚疫的检测模型。他一开始打算从零标注、从零写训练脚本,结果两周过去连数据格式都没统一。后来我给他扔了一套现成的番茄叶片病害目标检测资源包,含数据集和代码,他三天就跑通了第一版推理。这套资源解决的核心问题很具体:把「番茄叶片 + 病害区域」这个垂直场景的数据集、标注格式、训练脚本和推理入口一次性配齐,省掉的是数据清洗、格式转换和训练框架搭建这三块最耗时的脏活。它适合两类人:一类是刚接触 Python 深度学习、想拿一个真实农业场景练手目标检测的入门者;另一类是做农业物联网或植保巡检、需要快速验证检测方案可行性的从业者。关键词 python yolo 目标检测 在这里不是标签,而是这套资源的技术底座——用 Python 写训练和推理,用 YOLO 系列做检测头,数据集直接对应番茄叶片病害。

2. 数据集结构与 YOLO 标注格式:先看懂再动手

2.1 番茄叶片数据集的目录长什么样

拿到一个含数据集和代码的压缩包,第一件事不是急着跑 train.py,而是把目录结构摸清楚。常见做法是数据集按 images 和 labels 分开放,images 下再分 train、val、test,labels 下保持同名对应。番茄叶片病害这类资源,图片格式多为 jpg 或 png,标注文件是 YOLO 格式的 txt,每行五个字段:类别索引、归一化中心 x、归一化中心 y、归一化宽、归一化高。下面是我一般会先跑的目录扫描脚本,用来确认文件数量和配对情况。

import os from pathlib import Path # 数据集根目录,按实际解压路径改 root = Path("tomato_leaf_dataset") for split in ["train", "val", "test"]: img_dir = root / "images" / split lbl_dir = root / "labels" / split imgs = list(img_dir.glob("*.jpg")) + list(img_dir.glob("*.png")) lbls = list(lbl_dir.glob("*.txt")) # 检查图片和标注是否一一对应 img_stems = {p.stem for p in imgs} lbl_stems = {p.stem for p in lbls} only_img = img_stems - lbl_stems only_lbl = lbl_stems - img_stems print(f"{split}: 图片 {len(imgs)} 张, 标注 {len(lbls)} 个, 缺标注 {len(only_img)}, 缺图片 {len(only_lbl)}")

这段脚本的逻辑很直白:分别统计每个 split 下的图片和标注数量,再用集合差找出不配对的样本。参数上只需要改 root 指向解压后的数据集根目录。如果 only_img 不为零,说明有图片没标注,训练时要么剔除要么补标;如果 only_lbl 不为零,说明标注文件是孤儿,直接删掉即可。这一步不做,后面训练报「找不到标签」的错会浪费很多时间。

2.2 类别索引和 data.yaml 的对应关系

YOLO 训练依赖一个 data.yaml 文件,里面写清楚 train、val 路径和类别名称列表。番茄叶片病害常见类别包括早疫病、晚疫病、叶霉病、健康叶片等,具体以资源包里的 classes.txt 或 data.yaml 为准。这里有个容易翻车的地方:标注 txt 里的类别索引是从 0 开始的整数,而 data.yaml 里 names 列表的顺序必须和索引严格对应。我见过有人把 names 写成字典顺序,结果模型把早疫病识别成健康叶片,推理结果全乱。下面是一个标准的 data.yaml 写法。

# data.yaml train: ./tomato_leaf_dataset/images/train val: ./tomato_leaf_dataset/images/val test: ./tomato_leaf_dataset/images/test nc: 4 # 类别数量,按实际改 names: 0: 早疫病 1: 晚疫病 2: 叶霉病 3: 健康叶片

参数说明:nc 是类别数,必须和 names 长度一致;train/val/test 路径可以是相对路径也可以是绝对路径,相对路径以训练脚本执行目录为基准。如果资源包里已经带了 data.yaml,先打开核对一遍,别直接信。类别名用中文还是英文不影响训练,但推理后处理时要注意编码一致,避免显示乱码。

2.3 标注质量快速抽检:别让脏数据毁掉训练

数据集再大,标注质量不行也是白搭。我一般会抽 20 张图做可视化检查,看框是否贴合病斑、有没有漏标、有没有把整片叶子框成一个大框。下面这段代码用 OpenCV 把标注画回原图,存到临时目录肉眼过一遍。

import cv2 from pathlib import Path root = Path("tomato_leaf_dataset") img_dir = root / "images" / "train" lbl_dir = root / "labels" / "train" out_dir = Path("check_vis") out_dir.mkdir(exist_ok=True) # 只抽前20张,避免全量可视化太慢 for img_path in sorted(img_dir.glob("*.jpg"))[:20]: img = cv2.imread(str(img_path)) h, w = img.shape[:2] lbl_path = lbl_dir / (img_path.stem + ".txt") if not lbl_path.exists(): continue with open(lbl_path) as f: for line in f: cls, cx, cy, bw, bh = map(float, line.split()) # YOLO 归一化坐标转像素坐标 x1 = int((cx - bw / 2) * w) y1 = int((cy - bh / 2) * h) x2 = int((cx + bw / 2) * w) y2 = int((cy + bh / 2) * h) cv2.rectangle(img, (x1, y1), (x2, y2), (0, 255, 0), 2) cv2.putText(img, str(int(cls)), (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2) cv2.imwrite(str(out_dir / img_path.name), img) print("可视化结果已存到 check_vis 目录")

逻辑说明:读取每张图的标注文件,把归一化坐标还原成像素坐标,画框并标类别号。参数上只改 root 和抽样数量。重点看三种情况:框明显偏大或偏小、同一病斑被重复标注、健康叶片被误标成病害。发现超过 10% 的样本有问题,建议先清洗再训练,否则模型学到的就是错误边界。

3. 训练脚本拆解:从 train.py 到超参数怎么调

3.1 训练入口和关键参数含义

资源包里的训练脚本通常基于 ultralytics 的 YOLO 接口,常见写法是 from ultralytics import YOLO,然后 model.train()。但直接跑默认参数在番茄叶片这种小目标密集场景下效果往往一般,需要针对性调几个参数。下面是一个我常用的训练配置,基于 YOLOv8 风格接口,YOLOv5 或更新版本思路类似。

from ultralytics import YOLO # 加载预训练权重,没有预训练权重就从 yaml 初始化 model = YOLO("yolov8n.pt") model.train( data="data.yaml", # 数据集配置文件 epochs=100, # 训练轮数,小数据集可适当增加 imgsz=640, # 输入尺寸,病斑小可提到 800 batch=16, # 批大小,显存不够就降到 8 lr0=0.01, # 初始学习率 lrf=0.01, # 最终学习率系数 patience=20, # 早停耐心值,20轮没提升就停 device=0, # 用 GPU 就写 0,CPU 写 cpu workers=4, # 数据加载线程数 project="runs/train", # 训练结果保存目录 name="tomato_exp1" # 实验名 )

参数逐个说:epochs 不是越大越好,番茄叶片数据集通常几千张,100 轮足够,再大容易过拟合;imgsz 默认 640,如果病斑在图中占比很小,提到 800 或 1024 能提升小目标召回,但显存占用会明显上升;batch 根据显存调,16 是 8G 显存的保守值;lr0 初始学习率 0.01 是 YOLO 系列常用值,如果 loss 震荡厉害可以降到 0.001;patience 是早停,防止无效训练。device 写 0 表示第一块 GPU,多卡用 0,1。workers 在 Windows 下建议设 0 或 2,设大了容易报共享内存错误。

3.2 训练过程看什么指标

训练启动后,控制台会输出每轮的 box_loss、cls_loss、dfl_loss 和 mAP。box_loss 是边界框回归损失,cls_loss 是分类损失,dfl_loss 是分布焦点损失。这三个 loss 整体趋势应该是下降的,如果某个 loss 一直不降或者反弹,说明对应部分有问题。mAP50 和 mAP50-95 是评估指标,mAP50 表示 IoU 阈值 0.5 时的平均精度,番茄叶片病害检测一般能到 0.85 以上算不错。我一般会重点看 mAP50-95,它更严格,能反映框的精准度。如果 mAP50 高但 mAP50-95 低,说明框大致位置对但不够贴合,可以检查标注质量或调整 imgsz。

训练结束后,runs/train/tomato_exp1 目录下会有 weights 文件夹,里面 best.pt 是验证集上表现最好的权重,last.pt 是最后一轮权重。推理优先用 best.pt。results.csv 记录了每轮指标,可以用 pandas 画曲线看趋势。confusion_matrix.png 能直观看到哪些类别容易混淆,比如早疫病和晚疫病如果互相误判多,说明这两类病斑特征接近,需要更多样本或更强 backbone。

3.3 推理脚本和结果后处理

训练完拿到 best.pt,下一步是写推理脚本,对单张图或整个文件夹做检测。下面这段代码支持单图和批量推理,并把结果保存下来。

from ultralytics import YOLO from pathlib import Path model = YOLO("runs/train/tomato_exp1/weights/best.pt") # 单张推理 results = model.predict( source="test_leaf.jpg", conf=0.25, # 置信度阈值,低于此值的框丢弃 iou=0.45, # NMS IoU 阈值,控制重叠框合并 imgsz=640, save=True, # 保存带框图片 save_txt=True # 保存检测结果 txt ) # 批量推理整个文件夹 model.predict( source="tomato_leaf_dataset/images/test", conf=0.25, iou=0.45, save=True, project="runs/predict", name="batch_test" )

参数说明:conf 是置信度阈值,调低会检出更多框但误检增加,调高则漏检增加,番茄叶片病害建议从 0.25 起步试;iou 是 NMS 的 IoU 阈值,病斑密集时适当调低到 0.4 能减少框重叠;save_txt 会输出每个框的类别和坐标,方便后续统计病害面积占比。推理结果默认存在 runs/detect 下,批量推理会按文件名逐个保存。

后处理阶段,我一般会统计每张图的病害类别分布和病斑总面积占比,作为大棚巡检的量化指标。比如某张图检出三个早疫病框,总面积占叶片区域 15%,就可以触发预警。这部分逻辑用 OpenCV 读原图和检测 txt 就能算,不复杂但很实用。

4. 避坑与排查:番茄叶片检测最容易翻车的五个地方

4.1 训练 loss 不降反升

现象:训练前几轮 loss 正常下降,后面突然飙升或者震荡剧烈。原因通常是学习率过大,或者数据集中有大量错误标注导致梯度方向混乱。解决:先把 lr0 从 0.01 降到 0.001 试一轮,如果还不行,用 2.3 节的可视化脚本抽检标注,重点看有没有框到背景或框错类别的样本。另外检查 batch 是否过大,小数据集用大 batch 容易导致泛化差。

4.2 推理时类别名显示乱码

现象:推理结果图上类别标签显示成方框或问号。原因是 OpenCV 的 putText 不支持中文,而 data.yaml 里 names 写的是中文。解决:要么把 names 改成英文,要么在推理后处理时用 PIL 的 ImageDraw 配合中文字体渲染。我一般建议数据集标注阶段就用英文类别名,显示层再做中文映射,避免训练和推理编码不一致。

4.3 显存不足报 CUDA out of memory

现象:训练启动几秒后报显存溢出。原因可能是 imgsz 设太大、batch 设太大,或者 workers 过多导致数据加载占用显存。解决:按 imgsz、batch、workers 的顺序逐个降。640 降到 512,batch 16 降到 8,workers 4 降到 2。如果还不行,检查是不是同时跑了多个训练任务。另外 YOLO 的 AMP 混合精度默认开启,如果显卡不支持可以手动关掉。

4.4 验证集 mAP 很高但实际推理效果差

现象:训练日志里 mAP50 到 0.9,但拿新拍的叶片照片推理,漏检严重。原因是验证集和训练集同分布,而实际照片的光照、角度、背景和数据集差异大。解决:从实际场景补拍一批图,标注后加入训练集重新训练;或者在推理前做图像增强,比如直方图均衡化、白平衡校正,缩小域差距。这个问题在农业场景特别常见,因为大棚光照变化大。

4.5 标注文件坐标越界

现象:训练时提示坐标超出 0-1 范围,或者可视化时框跑到图外。原因是标注时用了绝对坐标没归一化,或者归一化时除错了尺寸。解决:写个校验脚本遍历所有标注文件,检查每个字段是否在 0 到 1 之间,宽高是否大于 0。发现越界的样本要么重新标注,要么直接剔除。这个检查放在训练前做,比训练中途报错再回头查省事得多。

5. 进阶技巧:用检测结果做病害面积占比统计

训练和推理跑通之后,这套资源真正的价值在于把检测框转成可量化的植保指标。我一般会加一步后处理:读原图和检测 txt,算病斑总面积占叶片区域的比例,再按阈值分级预警。下面这段代码演示怎么从推理结果算占比。

import cv2 from pathlib import Path img_path = Path("test_leaf.jpg") txt_path = Path("runs/detect/predict/labels/test_leaf.txt") img = cv2.imread(str(img_path)) h, w = img.shape[:2] leaf_area = h * w # 简化处理,实际可用分割模型抠出叶片区域 disease_area = 0 with open(txt_path) as f: for line in f: cls, cx, cy, bw, bh = map(float, line.split()) # 框面积换算成像素面积 box_area = (bw * w) * (bh * h) disease_area += box_area ratio = disease_area / leaf_area print(f"病斑面积占比: {ratio:.2%}") if ratio > 0.15: print("预警:病害面积超过 15%,建议处理") elif ratio > 0.05: print("关注:病害面积超过 5%,持续观察") else: print("正常:病害面积较低")

逻辑说明:读取检测 txt 里每个框的归一化宽高,乘以图像宽高得到像素面积,累加后除以叶片区域面积。参数上 leaf_area 这里用整图面积简化,更准的做法是用分割模型或颜色阈值抠出叶片实际区域。阈值 15% 和 5% 是我在几个大棚项目里用的经验值,具体按作物品种和病害类型调整。这段代码可以批量跑整个测试集,输出每张图的占比和预警等级,直接对接巡检报表。

从那以后我每次拿到新的检测数据集,都强制先跑一遍标注可视化抽检和坐标越界校验,再开始训练。这两步花不了十分钟,但能省掉后面几小时的排查。希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询