苹果叶片病害图像识别数据集:1700张标注数据YOLOv8实战
2026/9/24 18:15:49 网站建设 项目流程

简介:苹果叶片病害图像识别数据集面向计算机视觉与农业智能识别方向的学习者和研究者,用于训练和评估叶片病害分类模型。数据已专业标注,共分健康、生锈、痂三个类别,并预先划分训练集与验证集,方便直接开展模型训练与泛化能力检验。压缩包共1733个文件,以1730张jpg图像为主体,另含1个json标注文件、1个py可视化脚本和1个png示例图,整体约354.45MB,目录按训练与验证分别存放同类图片,结构清晰。运行包内show脚本可快速可视化数据分布,便于检查样本质量与类别特征。资源同时适配CNN分类网络与基于YOLOv5的分类方案,配套项目链接可辅助搭建和优化识别系统。目前已有340人学习下载,适合希望快速上手苹果叶片病害分类任务、验证模型效果的读者参考使用。

1. 苹果叶片病害图像识别数据集:1700 张已标注数据能跑出什么结果

果园里最怕的不是虫,是叶子先出问题。斑点落叶、褐斑、灰斑、锈病、黑星病,早期症状在叶片上只占几个像素,等人眼看出大面积枯黄,防治窗口已经过了。这也是为什么「苹果叶片病害图像识别数据集」这类资源一直有人找:它把田间拍到的叶片图整理成带标签的样本,让检测或分类模型能直接吃进去训练。约 1700 张、已标注,这个体量不算大,但足够跑通一条从数据检查到模型验证的完整链路,适合做课程设计、小课题验证、或者给果园巡检设备做原型。真正决定成败的不是模型选得多新,而是这 1700 张里类别是否均衡、框是否贴边、有没有重复图。下面按我实际处理这类数据集的顺序讲清楚。

2. 先看清数据长什么样:类别、标注格式与划分策略

拿到一个「已标注」的数据集,第一件事不是写训练脚本,而是把标注文件打开看。苹果叶片病害常见的标注形态有两种:一种是整图分类标签(一张图一个类别),一种是目标检测框(一张图里多个病斑位置)。这两种决定了后面完全不同的技术路线,选错了模型再强也白搭。

2.1 分类标注与检测标注的判断方法

判断方法很直接:看标注文件里有没有坐标。如果每张图对应一个类别名或类别编号,就是分类数据集;如果标注里出现xmin, ymin, xmax, ymax或归一化的cx, cy, w, h,就是检测数据集。苹果叶片病害里,早期病斑小且分散,检测框能定位到具体病斑,对精准施药更有价值;但如果标注只到叶片级别,硬做检测就是给自己找麻烦。

我一般会先统计每个类别的图片数量,用一段脚本跑出来:

import os from collections import Counter # 假设标注是 YOLO 格式的 txt,每行: class_id cx cy w h label_dir = "labels/train" counter = Counter() for name in os.listdir(label_dir): if not name.endswith(".txt"): continue with open(os.path.join(label_dir, name), "r", encoding="utf-8") as f: for line in f: line = line.strip() if not line: continue cls_id = line.split()[0] counter[cls_id] += 1 # 输出每个类别的标注框数量,判断是否严重不均衡 for cls_id, num in sorted(counter.items(), key=lambda x: -x[1]): print(f"class {cls_id}: {num} boxes")

这段脚本做的是逐文件读取标注、按类别累计框数。label_dir指向存放 txt 标注的目录,cls_id是类别编号。跑完你会看到类似「class 0 有 900 个框,class 4 只有 60 个框」的结果,这就是后面要处理的不均衡信号。如果某个类别框数不到总数的 5%,训练时几乎必然被忽略。

2.2 训练集、验证集、测试集怎么切才不翻车

1700 张的体量,常见做法是 7:2:1 或 8:1:1。但苹果叶片数据有个坑:同一片叶子可能被连拍多张,或者同一棵树不同角度拍了很多。如果随机切分,训练集和验证集里出现几乎相同的图,验证指标会虚高,上线就露馅。

我的习惯是按「拍摄批次」或「叶片编号」分组切分,而不是按图片随机切。具体做法是给每张图打一个 group id(比如文件名前缀),同一 group 的图只能进同一个集合。下面是一个按前缀分组的切分脚本:

import os import random from collections import defaultdict img_dir = "images" groups = defaultdict(list) # 用文件名前缀作为分组依据,例如 "leaf012_03.jpg" -> "leaf012" for name in os.listdir(img_dir): if not name.lower().endswith((".jpg", ".png", ".jpeg")): continue group_id = name.split("_")[0] groups[group_id].append(name) group_ids = list(groups.keys()) random.seed(42) random.shuffle(group_ids) n = len(group_ids) train_end = int(n * 0.8) val_end = int(n * 0.9) split_map = {} for g in group_ids[:train_end]: split_map[g] = "train" for g in group_ids[train_end:val_end]: split_map[g] = "val" for g in group_ids[val_end:]: split_map[g] = "test" # 打印每个集合的图片数,确认比例合理 for split in ["train", "val", "test"]: count = sum(len(groups[g]) for g in groups if split_map[g] == split) print(split, count)

random.seed(42)保证切分可复现,group_id取文件名下划线前的部分。跑完看三个集合的图片数,如果 test 少于 100 张,指标波动会很大,可以考虑改成 8:1:1 并把 test 合并进 val 做交叉验证。这一步做完,数据才算真正可用。

3. 用 YOLOv8 跑通苹果叶片病害检测的最小闭环

数据集检查完,接下来就是训练。苹果叶片病害检测目前最省事的路线是 YOLOv8,安装简单、文档全、对小目标有专门优化。1700 张的规模,单卡消费级显卡就能跑,不需要多机多卡。这一章从环境到训练到推理,给一条能直接抄的路径。

3.1 环境安装与数据目录组织

先建一个干净的 Python 环境,避免和系统里的包打架:

conda create -n apple_leaf python=3.10 -y conda activate apple_leaf pip install ultralytics opencv-python

ultralytics包里已经带了 YOLOv8 的训练和推理接口,opencv-python用于后面做可视化和数据增强检查。装完可以用yolo checks确认环境正常。

数据目录按 YOLO 的标准结构放:

apple_leaf_dataset/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ └── data.yaml

data.yaml是训练入口,内容如下:

path: ./apple_leaf_dataset train: images/train val: images/val test: images/test names: 0: alternaria_leaf_spot 1: brown_spot 2: gray_spot 3: rust 4: scab

path是数据集根目录,train/val/test是相对路径,names里按你的实际类别改。类别名建议用英文,避免训练时编码问题。如果标注里类别编号和这里对不上,训练会直接报错或学出乱七八糟的结果,务必核对。

3.2 训练命令与关键参数怎么设

最小训练命令:

yolo detect train \ data=apple_leaf_dataset/data.yaml \ model=yolov8s.pt \ epochs=100 \ imgsz=640 \ batch=16 \ lr0=0.01 \ patience=20 \ project=runs/apple_leaf \ name=exp1

逐项说明:model=yolov8s.pt是预训练权重,1700 张数据从零训练容易过拟合,用预训练权重收敛更快;epochs=100配合patience=20,20 轮验证指标不提升就早停,省时间;imgsz=640是默认输入尺寸,如果病斑特别小可以提到 960,但显存占用会明显上升;batch=16在 8GB 显存上比较稳,显存不够就降到 8;lr0=0.01是初始学习率,数据量小的时候可以降到 0.005 减少震荡。

训练过程中重点看mAP50mAP50-95两个指标。苹果叶片病害这种小目标场景,mAP50到 0.7 以上算可用,mAP50-95通常低不少,别拿它当唯一标准。如果训练 loss 一直不降,先检查标注框有没有越界或宽高为 0。

3.3 推理与结果可视化

训练完用最好的权重跑推理:

from ultralytics import YOLO import cv2 model = YOLO("runs/apple_leaf/exp1/weights/best.pt") results = model.predict( source="apple_leaf_dataset/images/test", conf=0.25, iou=0.45, save=True, project="runs/predict", name="test_result" ) # 打印每张图的检测框数量,快速判断漏检情况 for r in results: print(r.path, len(r.boxes))

conf=0.25是置信度阈值,低于它的框不输出;iou=0.45控制重叠框合并,病斑密集时可以调到 0.5 以上减少误合并;save=True会把画框后的图存到runs/predict/test_result。跑完翻几张图看,如果框明显偏大或偏小,多半是标注时框没贴紧病斑边缘,需要回标注环节修。

提示:推理结果里如果出现同一病斑被多个框重复标注,先调iou,再考虑用 NMS 后处理,不要直接改模型结构。

4. 数据增强与不均衡处理:让 1700 张发挥出 3000 张的效果

1700 张在深度学习里属于小数据集,直接训练容易过拟合,少数类别还会被多数类别淹没。这一章讲两个实操方向:增强策略怎么选,以及类别不均衡怎么补。

4.1 适合叶片病害的增强方式与参数

YOLOv8 内置了增强参数,在训练命令里直接加:

yolo detect train \ data=apple_leaf_dataset/data.yaml \ model=yolov8s.pt \ epochs=100 \ imgsz=640 \ batch=16 \ hsv_h=0.015 \ hsv_s=0.7 \ hsv_v=0.4 \ degrees=15 \ translate=0.1 \ scale=0.5 \ fliplr=0.5 \ mosaic=1.0 \ mixup=0.1

hsv_h/s/v控制色调、饱和度、亮度扰动,田间光照变化大,这三个值可以适当放大;degrees=15允许小角度旋转,叶片方向不固定时有用;scale=0.5做随机缩放,模拟不同拍摄距离;fliplr=0.5水平翻转,叶片左右对称,翻转不会改变类别;mosaic=1.0是 YOLOv8 默认的四图拼接增强,对小目标检测帮助明显;mixup=0.1做图像混合,比例别太高,否则病斑边界会糊。

要注意的是,垂直翻转(flipud)对叶片病害不一定合适,因为叶片正反面症状不同,翻过来可能变成另一个类别。我一般保持flipud=0.0

4.2 少数类别过采样与损失加权

如果统计发现某个类别框数特别少,有两种补法。第一种是过采样:在训练时让包含少数类别的图片被重复采样。YOLOv8 不直接提供按类别采样,但可以复制图片和标注文件到临时目录,人为提高比例:

import os import shutil src_img = "apple_leaf_dataset/images/train" src_lbl = "apple_leaf_dataset/labels/train" dst_img = "apple_leaf_dataset/images/train_oversample" dst_lbl = "apple_leaf_dataset/labels/train_oversample" os.makedirs(dst_img, exist_ok=True) os.makedirs(dst_lbl, exist_ok=True) rare_class_id = "4" # 假设类别 4 是少数类 repeat = 3 for name in os.listdir(src_lbl): if not name.endswith(".txt"): continue with open(os.path.join(src_lbl, name), "r") as f: lines = f.readlines() has_rare = any(l.strip().startswith(rare_class_id + " ") for l in lines if l.strip()) shutil.copy(os.path.join(src_img, name.replace(".txt", ".jpg")), dst_img) shutil.copy(os.path.join(src_lbl, name), dst_lbl) if has_rare: for i in range(repeat - 1): shutil.copy(os.path.join(src_img, name.replace(".txt", ".jpg")), os.path.join(dst_img, f"os{i}_" + name.replace(".txt", ".jpg"))) shutil.copy(os.path.join(src_lbl, name), os.path.join(dst_lbl, f"os{i}_" + name))

这段脚本把包含少数类的图片复制多份,文件名加前缀避免冲突。repeat=3表示少数类图片出现三次。过采样后要重新生成data.yaml指向新目录,并注意验证集不要过采样,否则指标失真。

第二种是损失加权,YOLOv8 的分类损失默认按类别频率计算,可以在自定义训练时调整cls权重,但改动成本较高。对 1700 张这个量级,过采样通常够用。

注意:过采样后训练集图片数会变多,epochs可以适当减少,否则训练时间线性增长。

5. 苹果叶片病害数据集常见问题与排查清单

这一章是我处理这类数据集时踩过的坑,按「现象 → 原因 → 解决」写,遇到问题可以直接对号入座。

5.1 训练 loss 正常但 mAP 一直是 0

现象:训练日志里 box_loss、cls_loss 都在降,但验证集 mAP50 始终为 0 或极低。

原因:最常见的是data.yaml里的names和标注文件里的类别编号对不上,或者标注文件路径写错,模型实际在学空标签。另一个可能是图片和标注文件名不一致,YOLO 按同名匹配,找不到标注就当成背景。

解决:先跑一遍数据检查脚本,确认每张图都有对应 txt,且 txt 里类别编号不超过names的长度。再打印几张图的标注框,看坐标是否在 0 到 1 之间。归一化坐标如果写成像素值,框会全部跑到图外。

5.2 验证集指标很高,换一批图就崩

现象:验证集 mAP 0.85,拿果园新拍的图测试,漏检严重。

原因:切分时没有按叶片或拍摄批次分组,训练集和验证集里有大量近似重复图,模型记住了背景而不是病斑特征。

解决:回到 2.2 节的分组切分,用文件名前缀或拍摄时间做 group,确保同一片叶子的图只出现在一个集合。如果已经训练完,重新切分后再训一次,指标会降但更真实。

5.3 小病斑全部漏检

现象:大块病斑能检出,早期小斑点一个都框不出来。

原因:imgsz=640下,原图里几十像素的病斑缩到几个像素,特征太弱。另外默认 anchor 尺寸偏向中大目标。

解决:把imgsz提到 960 或 1280,显存不够就减小batch;同时检查标注框的宽高,如果大量框小于 10 像素,考虑在标注阶段放大病斑区域或改用分类+分割方案。YOLOv8 的mosaic增强对小目标有帮助,保持开启。

5.4 类别混淆严重,锈病被认成褐斑

现象:混淆矩阵里锈病和褐斑互相误判比例高。

原因:这两个类别在早期颜色接近,标注时边界模糊,不同标注人员标准不一致。1700 张里如果混了多个来源的标注,风格差异会放大这个问题。

解决:抽 50 张混淆最多的图,人工复核标注,统一标准。训练时提高hsv_hhsv_s扰动,让模型更关注纹理而不是颜色。如果仍然分不开,考虑把两个类合并成「叶斑病」一个大类,先保证检出率。

5.5 训练到一半显存爆了

现象:前几个 epoch 正常,后面突然 CUDA out of memory。

原因:mosaic增强在拼接时会产生尺寸不一致的中间张量,某些批次占用显存波动大。另外如果开了cache=True把图片缓存到内存,数据量大时也会挤占显存。

解决:把batch降到 8 或 4,关闭cache,或者设置amp=False排除混合精度带来的波动。如果还是爆,把imgsz从 960 降回 640,先跑通再逐步加。

6. 从 1700 张到可用模型:验证方法与一个提点技巧

训练完不是终点,怎么判断这个模型能不能用,比训练本身更重要。我一般会做三件事:看混淆矩阵找系统性错误、用 t-SNE 看特征聚类、拿真实果园图做盲测。混淆矩阵在runs/apple_leaf/exp1/下,重点看对角线以外的值,如果某个类别被大量误判到另一个类别,说明标注或特征有问题。t-SNE 可以把 backbone 输出的特征降维可视化,类别分得开说明模型学到了判别性特征,混在一起说明特征空间没拉开。

盲测是最实在的。从果园随机拍 30 到 50 张图,不挑角度、不挑光照,直接跑推理,人工数漏检和误检。如果 mAP 掉到 0.5 以下,说明数据集和真实场景差距大,需要补拍数据。补拍时优先拍模型错得多的类别和光照条件,不要平均用力。

一个提点技巧是测试时增强(TTA)。YOLOv8 推理时加augment=True,会对输入做多尺度翻转再合并结果,小目标召回通常能提几个点:

results = model.predict( source="test_images", conf=0.2, iou=0.5, augment=True, save=True )

augment=True会成倍增加推理时间,适合离线批量处理,不适合实时巡检。conf可以比训练时低一点,配合 TTA 把漏检压下去,误检靠后续人工复核兜底。

我自己做这类项目的习惯是:先把数据切分和标注检查做扎实,再谈模型。1700 张不算多,但标注质量高、切分合理的话,YOLOv8s 在苹果叶片病害上跑到可用水平完全没问题。最怕的是一上来就换模型、调超参,最后发现是标注文件里类别编号写错了。希望帮到你。

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

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

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

立即咨询