news 2026/9/28 6:00:43

葡萄叶病害检测数据集:VOC/YOLO双重标注与YOLOv8训练实践

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
葡萄叶病害检测数据集:VOC/YOLO双重标注与YOLOv8训练实践

简介:这份葡萄叶片病害检测数据集面向计算机视觉与农业智能识别方向的学习者,提供1609张单叶片的真实病害图像,涵盖Black Measles、Black Rot、blight fungus及healthy leaf四个类别,并同步给出Pascal VOC与YOLO两种标注格式,可直接用于目标检测模型的训练与评估。压缩包共包含2000个文件,核心为1609个XML格式的VOC标注文件及配套的YOLO格式TXT文件,使用labelImg工具完成标注,总标注框数1614,类别分布均衡,适合作为入门级植物病害检测项目的训练数据。资源包整体大小约109.12MB,文件结构简洁清晰。目前已有115人学习下载,对于需要快速开展葡萄叶病害识别实验、对比两种标注格式差异或扩充训练样本的研究者而言,这份数据集能够有效节省人工采集与标注时间,帮助聚焦模型调优与算法验证。

1. 葡萄叶病害检测数据集:VOC+YOLO双重标注,1609张够不够用?

搞过农业视觉项目的人都有体会:模型选型往往不是瓶颈,真正卡脖子的是数据集——格式乱、标注不统一、类别失衡,光是洗数据就能耗掉一半工期。这份葡萄叶病害检测数据集属于“小而完整”的典型:1609张jpg,每张图配一个Pascal VOC的xml和一个YOLO的txt,4个病害类别,总框数1614,用labelImg标注。图片全部是单个叶片的特写,背景干扰小,适合做病害分类和检测的入门训练,也适合拿来验证数据增强策略对小样本任务的提升效果。

为什么我强调“双重标注”这件事?因为VOC格式适合用labelImg继续编辑、做二次检查,YOLO格式则能直接喂给YOLOv5/v8训练。很多公开数据集只给其中一种,转换时坐标系出错是常事。这份数据集把两条路都铺好了。适合谁用?想做葡萄病害检测毕设的、打算在小数据集上跑通YOLO训练流程的、以及需要一份干净的农业检测基线数据的从业者。下面我把数据集结构、转换逻辑、训练参数和排错经验一并拆开讲。

2. 数据集构成与类别分布:先看清1609张图里有什么

2.1 四类病害与标注框数:每类四百框的均衡性

先看类别。数据集包含四个类别:Black Measles(黑麻疹)、Black Rot(黑腐病)、blight fungus(枯萎病菌)和healthy leaf(健康叶片)。框数分别是414、402、398、400,总计1614。这个分布很有意思——几乎完全均衡。

类别框数占比
Black Measles41425.7%
Black Rot40224.9%
blight fungus39824.7%
healthy leaf40024.8%

为什么这种均匀分布值得关注?因为绝大多数开源农业数据集都带有明显的长尾问题——病害多、健康叶少,或者某一种病害特别多。训练时模型会对高频类别过拟合,对低频类别欠拟合,mAP被拉低一大截。这份数据集的标注者明显做了采集控制,每类大约400框,意味着你不用在数据增强时强行做类别重采样,直接按默认比例划分train/val就能得到相对公平的基线。

2.2 文件命名与配对规则:jpg/xml/txt一图三件套

解压后你会看到一堆以firc_leaf_开头的文件,比如firc_leaf_36.txt、firc_leaf_1228.txt。注意,同名的txt是YOLO标注,但原始图片是jpg。也就是说一个样本对应三个文件:firc_leaf_XXXX.jpg、firc_leaf_XXXX.xml、firc_leaf_XXXX.txt。XML是VOC原始标注,TXT是归一化后的YOLO格式。

目录结构是扁平化的,没有像官方YOLO数据集那样预设images和labels两个文件夹。这说明拿到手后你需要自己做一次目录整理。我建议按下面的结构重排:

dataset/ ├── images/ │ ├── train/ │ ├── val/ ├── labels/ │ ├── train/ │ ├── val/

整理时注意不要只移动图片不移动标注,或者文件名对不上。这种扁平结构的坑在于:你可能会把xml、txt、jpg混在一起给训练脚本用,而YOLO训练只认images和labels的对应关系。常见做法是写一个脚本按文件名前缀批量拷贝,确保三个后缀的文件一一对应。后面我会给出这个脚本。

2.3 标注质量与图像特点:单叶片特写的利与弊

数据集的图片内容是单个叶片的特写,这意味着检测目标和图像边界的相对关系比较稳定——叶片基本居中,占画面比例大,病害区域清晰。这对训练来说是好事,模型容易学到纹理特征而不是位置特征。

但也要注意一个代价:单叶片特写意味着每张图只有一个主目标(偶尔有多个病斑框),模型在推理时如果遇到多叶片交叠的现场照片,泛化能力可能下降。这是所有“实验室级数据集”的通病。你需要在后续部署时补充实拍数据做微调,或者至少把推理时的置信度阈值调低,容忍更多的候选框输出。图像尺寸方面,VOC的xml里有width和height字段,不同图片尺寸可能不一致,喂给YOLO时需要注意resize策略。

3. VOC转YOLO的五个要点:从xml到txt的坐标归一化

3.1 坐标系的本质差异:绝对像素 vs 归一化浮点

Pascal VOC的xml记录的是绝对像素坐标,四个关键字段是xmin、ymin、xmax、ymax,单位是像素。而YOLO格式的txt要求的是归一化后的中心点坐标和宽高,全部是0到1之间的浮点数。转换公式如下:

x_center = (xmin + xmax) / 2 / width y_center = (ymin + ymax) / 2 / height box_width = (xmax - xmin) / width box_height = (ymax - ymin) / height

这个公式看起来简单,但很多人会顺手把xmin除以width、xmax除以width,直接存成xmin_width_xmax_width的模式——这在某些工具里能跑,但是format不对。YOLO必须用中心点和宽高,顺序是class_id x_center y_center width height。如果你自己写转换脚本,建议把表达式拆开写,不要省略括号,否则很容易出边界错误。

3.2 类别ID映射与txt行格式:从字符串到数字的陷阱

VOC的xml里存的是类别的英文名,比如<name>Black Rot</name>。而YOLO的txt每一行的第一个数字是类别ID,0到3的整数。你需要自己定义一个映射字典:

class_map = { 'Black Measles': 0, 'Black Rot': 1, 'blight fungus': 2, 'healthy leaf': 3 }

这里有个很隐蔽的坑:类别名的大小写和空格必须和xml里的完全一致。原始数据集里的类别叫blight fungus,全小写,另一个叫Black Rot,是驼峰加大写开头。如果你在映射字典里写成Blight fungus或者black fungus,xml解析时就会跳过这些目标,导致标注框数量对不上——明明xml里有400个框,转出来txt里只有398个,你还在纳闷哪里丢了。

3.3 解析脚本:同时输出验证信息的转换工具

我一般会写脚本时顺手加一个校验逻辑:每转完一个xml,就对比xml里<object>的数量和txt行数。这个习惯能帮你快速定位漏转的文件。

import xml.etree.ElementTree as ET import os def convert_voc_to_yolo(xml_path, out_path, class_map): tree = ET.parse(xml_path) root = tree.getroot() img_w = int(root.find('size/width').text) img_h = int(root.find('size/height').text) objects = root.findall('object') lines = [] for obj in objects: name = obj.find('name').text if name not in class_map: print(f"[skip] unknown class {name} in {xml_path}") continue class_id = class_map[name] bndbox = obj.find('bndbox') xmin = int(bndbox.find('xmin').text) ymin = int(bndbox.find('ymin').text) xmax = int(bndbox.find('xmax').text) ymax = int(bndbox.find('ymax').text) x_center = (xmin + xmax) / 2.0 / img_w y_center = (ymin + ymax) / 2.0 / img_h w = (xmax - xmin) / img_w h = (ymax - ymin) / img_h lines.append(f"{class_id} {x_center:.6f} {y_center:.6f} {w:.6f} {h:.6f}") with open(out_path, 'w') as f: f.write('\n'.join(lines)) if len(lines) != len(objects): print(f"[warn] {xml_path}: xml has {len(objects)} objects, txt has {len(lines)} lines")

这段脚本的核心是解析size/width和size/height作为归一化分母,然后逐个object提取bndbox字段。{: .6f}的精度对YOLO训练足够用,浮点数位数太多反而会让文件体积变大。运行后如果看到warn信息,优先检查类别名映射,其次检查xml里是否嵌套了<segmented>标签导致解析偏移。这个数据集本身是labelImg标注的,xml结构比较标准,一般不会出现嵌套问题。

3.4 验证转换结果:四则运算检查边界框

转换完不要急着训练。先在任意一类图片上做一次可视化验证——把txt里的坐标反算回像素,画框看是否贴合病斑。反算公式就是上面公式的逆运算:

xmin = int((x_center - w/2) * img_w) ymin = int((y_center - h/2) * img_h) xmax = int((x_center + w/2) * img_w) ymax = int((y_center + h/2) * img_h)

如果你看到框偏移、出血、或者框内根本不是病斑区域,别怀疑是数据集有问题——99%的情况是你在解析xml时把xmin和ymin的顺序弄反了。VOC的坐标顺序固定是xmin、ymin、xmax、ymax,但有些人会因为看多了COCO的x1 y1 x2 y2而成功绕晕自己。这个验证步骤不能省,尤其是打算微调YOLO预训练权重的时候,一个错误的标注框会把整个损失曲线带偏。

4. 用YOLOv8训练这个数据集:格式目录yaml三件套

4.1 数据集yaml的写法:路径与类别名的对位关系

YOLOv8(Ultralytics框架)训练需要三个信息:train/val图片路径、类别数量nc、类别名字names。yaml文件如下:

path: /your/dataset/root # 改成你的实际路径 train: images/train val: images/val nc: 4 names: 0: Black Measles 1: Black Rot 2: blight fungus 3: healthy leaf

注意path字段是相对的根路径,YOLO会自动拼接{path}/{train}和{path}/{val}。如果你把图片放在dataset/images/train下,那么path填dataset的绝对路径,train填images/train。此外,names列表的顺序必须和训练时txt里第一个数字的语义一致——如果之前转换脚本里class_map的顺序是0123,这里就按同样的顺序写。

4.2 训练命令与参数:小数据集的保守配置

1609张图不算多。假设按8:1:1划分训练/验证/测试,训练集大概有1287张。用YOLOv8s或者YOLOv8m比较合适,YOLOv8l容易过拟合。命令如下:

yolo train \ model=yolov8s.pt \ data=grape_leaf.yaml \ epochs=100 \ imgsz=640 \ batch=16 \ patience=20 \ augment=True \ project=./runs \ name=grape_leaf_exp1

关键参数解释:epochs=100是必要的,小数据集通常需要更长时间才能收敛;patience=20是早停机制,连续20个epoch验证集mAP不提升就停下,防止过拟合;batch=16根据显存调整,如果你的显卡只有8GB显存,降到8;imgsz=640是YOLOv8的默认推理尺寸,与预训练权重匹配,不需要改。

4.3 数据增强策略:小样本场景下的关键开关

小数据集最怕的是没有数据增强直接硬训。YOLOv8默认开启的马赛克增强对叶片病害这种纹理敏感型任务有奇效——它把四张图拼接成一张,强制模型学习局部纹理而不是整图背景。也可以在yaml里或命令行里显式增强:

yolo train \ model=yolov8s.pt \ data=grape_leaf.yaml \ epochs=100 \ hsv_h=0.015 \ hsv_s=0.7 \ hsv_v=0.4 \ degrees=10.0 \ translate=0.1 \ scale=0.5 \ fliplr=0.5

degrees=10只做小角度旋转,因为叶片病斑不存在方向不变性,转90度后病斑形态会失真;scale=0.5缩放范围控制在0.5到1.5之间,太大会让叶片边缘被裁掉;fliplr=0.5水平翻转对叶片病害检测是安全的增强手段。HSV扰动值调小,因为植物病害的颜色是弱特征,但色调偏移过大反而会误导模型。

4.4 训练过程中的观察点:loss曲线与验证指标

训练启动后重点看两个指标:box_loss和cls_loss。box_loss下降说明定位在变准,cls_loss下降说明分类在变对。如果看到box_loss降得很慢而cls_loss已经收敛,大概率是标注框的边界不贴合病斑——叶片病害的边缘是渐变的,标注员打框时往往偏大或偏小半毫米。处理方式不是重标,而是在损失函数里对box分支加权太小的情况下,换用CIoU或SIoU。YOLOv8默认用CIoU,一般够用。

验证集mAP50和mAP50-95的差值是另一个信号。如果mAP50有0.92但mAP50-95只有0.6,说明模型能检测到目标,但定位精度不够,可能病斑区域小、边界模糊。这种情况在叶片病害里非常常见,后处理时可以考虑调整NMS的IoU阈值到0.3左右,保留更多候选框。

5. 避坑记录:五条关于格式与训练的血泪经验

5.1 只看txt不看xml,遗漏类别名大小写差异

现象:训练时提示Class 2 not in names list或者检测结果里blight fungus的准确率特别低。

原因:数据集的xml里类别名是blight fungus,全小写;而有的人在写yaml的names列表时习惯性写成Blight Fungus或blight_fungus。类别ID对不上,模型把真实的类别2当成了错误类别的监督信号。

解决:写个脚本扫描所有xml的<name>字段,把去重后的列表打印出来,直接复制粘贴到yaml里。不要手打。

5.2 图片路径大小写不一致导致找不到文件

现象:训练刚开始就报Image not found: /path/to/Firc_leaf_36.jpg。

原因:Windows和Linux文件系统对大小写敏感度不同。解压数据的机器是Windows,部署训练的机器是Linux,文件夹或文件名的首字母大小写变了。

解决:解压后先执行一遍find . -name "*.JPG" -exec rename 's/\.JPG$/.jpg/' {} \;全部转小写,同时把所有路径写相对路径。纠正后再改yaml里的path字段为绝对路径。

5.3 某些图片的jpg和xml标注对不上

现象:训练时报No labels found in labels/xxx.jpg,但xml文件确实存在。

原因:扁平结构下,个别图片的文件名后缀是.JPG而不是.jpg,YOLO脚本在匹配时用了小写后缀,导致label关联失败。

解决:用一条bash命令检查后缀不一致的文件,然后统一重命名。同时确认train.txt里是否混入了没有对应xml的孤儿图片。

5.4 验证集mAP高但实际检测效果差:单叶片特写的过拟合

现象:训练时mAP50达到0.95,但拿到田间拍摄的多叶片照片上,检测框乱跳、误报率高。

原因:数据集是单叶片特写,模型学到了叶片占满整个画面的先验。多叶片场景下目标占比变小,模型适应不了。

解决:推理时把输入尺寸从640改成800,让模型看到更多小目标;同时把置信度阈值从0.25降到0.15,宁可多输出候选框再做NMS。后续如果有条件,采集一批多叶片的实拍图微调。

5.5 训练到一半loss变成nan

现象:训练到第30个epoch时total_loss突然变成nan,然后验证集mAP归零。

原因:常见原因是学习率过大导致梯度爆炸,或者batch内出现了全黑的图片(叶片背面阴影)导致BN层方差异常。小数据集偶尔会有破损图片混入。

解决:先把lr0从0.01降到0.005,再把batch从16降到8。如果还不行,用yolo val单独跑一遍数据,看有没有无法解码的图片,找到后删除或替换。

6. 进阶验证与部署技巧:从mAP到实际应用

6.1 用混淆矩阵看类别间的混淆模式

训练结束后,YOLO会自动生成confusion_matrix.png。这个图的价值远超mAP数字——它告诉你哪些类别被模型混在一起。葡萄叶病害中,Black Measles和blight fungus在视觉上很接近:都是深色斑块,只有纹理细节不同。如果混淆矩阵里这两个类别的互相误判率超过10%,说明仅靠这1609张图不足以区分它们。此时优先做法是采集局部特写图,把病斑区域裁出来单独做分类,而不是盲目加大模型。

6.2 推理脚本:输出类别名而不是ID

部署时最容易翻车的点:训练时类别ID是0到3,但在业务系统里你需要输出Black Rot这样的中文或英文可读名称。写推理脚本时不要直接打印class_id,做一个映射输出。

from ultralytics import YOLO model = YOLO('runs/grape_leaf_exp1/weights/best.pt') result = model.predict('test_image.jpg', conf=0.25, iou=0.45, imgsz=640) class_names = ['Black Measles', 'Black Rot', 'blight fungus', 'healthy leaf'] for r in result: for box in r.boxes: cls_id = int(box.cls[0]) conf = float(box.conf[0]) x1, y1, x2, y2 = map(int, box.xyxy[0].tolist()) print(f'{class_names[cls_id]} {conf:.3f} ({x1},{y1})-({x2},{y2})')

conf=0.25是默认阈值,如果现场环境复杂、误报多,调到0.4;如果漏检多、能接受人工复核,调到0.15。iou=0.45是NMS的阈值,值越小抑制越强,适合密集病斑场景,值越大保留框越多,适合稀疏场景。

6.3 类别不均衡的进阶处理:给少数类加权重

虽然这个数据集本身均衡,但迁移到你的实际场景后,如果某类样本变少,可以给loss加类别权重。做法是计算每类框数的逆频率作为权重,接一个自定义的weight参数。YOLOv8官方不直接暴露这个参数,但可以通过修改数据增强的mosaic概率或对少数类做离线复制来缓解。我个人的习惯是:在数据准备阶段做一次基于类的数据综述,反向检查各类别的sample_count。这个数据集四类基本均衡,已经省下了这一步。

总结一条经验:无论标注工具是labelImg还是其他,转换格式时永远保留一份原始xml副本,不要只留txt——因为txt没有类别名的可读性,一旦ID映射错误,找回信息的成本极高。吃过大亏之后,我每次做完格式整理都会先在纯CPU环境跑一遍数据加载脚本,确认全部文件对上了再上GPU训练。这份数据集虽然只有1609张,但胜在标注干净、类别均衡、双格式齐备,复现一遍YOLO训练流程能帮你把“数据准备→训练→验证→部署”的完整链路跑通。希望帮到你。

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/28 6:00:26

微服务认证授权实战:Spring Security 6 + OAuth2 + JWT 完整方案

从单体到微服务之后&#xff0c;很多团队第一个被搞崩的不是业务&#xff0c;而是登录。原来在单体应用里一套HttpSession躺平搞定的事&#xff0c;拆成十几个服务后立刻变得尴尬&#xff1a;Session在哪个服务里&#xff1f;用户明明登录了&#xff0c;另一个服务怎么不认识&a…

作者头像 李华
网站建设 2026/9/28 5:58:44

SSM社区居民便民服务关怀系统实战:从需求设计到面试亮点全解析

做这个项目的时候&#xff0c;我其实已经带过不少学生完成类似的 Java 课程设计了&#xff0c;但“社区居民便民服务关怀系统”这个名字背后要做的事&#xff0c;比一开始预想的多不少。它不只是一个 CRUD 练习&#xff0c;而是把“便民”和“关怀”落到了具体的业务场景里&…

作者头像 李华
网站建设 2026/9/28 5:58:32

VMware Workstation安装CentOS全流程:镜像下载到系统优化

做运维这些年&#xff0c;我几乎每天都要跟虚拟机打交道。尤其CentOS&#xff0c;哪怕到了2026年还是绕不开它&#xff1a;新人在练Linux基本功&#xff0c;开发要搭测试环境&#xff0c;老项目要复现生产配置&#xff0c;动不动就要先搞一台虚拟机。而vmware workstation加cen…

作者头像 李华
网站建设 2026/9/28 5:57:42

M.2 Key类型与协议兼容性深度解析:从NVMe SSD到AI加速卡选型实战

1. 项目概述&#xff1a;M.2不是一块板子&#xff0c;而是一套精密的“插头-插座-协议”协同系统你拆开笔记本、台式机或者工控盒子&#xff0c;看到那块细长的黑色小板子&#xff0c;第一反应可能是“哦&#xff0c;这是个M.2固态硬盘”。但如果你真这么想&#xff0c;就等于把…

作者头像 李华
网站建设 2026/9/28 5:57:42

贷中风险预测模型全流程实战:样本、特征与LightGBM落地要点

简介&#xff1a;这是面向金融风控场景的机器学习贷中风险预测项目包&#xff0c;源自“江苏银行杯”金融大数据建模挑战赛初赛方案&#xff0c;适合高校人工智能、金融科技相关专业学生、教师及从业者学习参考。压缩包共49个文件&#xff0c;约10.97MB&#xff0c;包含19个Pyt…

作者头像 李华
网站建设 2026/9/28 5:56:35

SSM在线教育系统实战:从课程设计到毕业设计的Java Web完整方案

1. 项目定位与技术选型拆解1.1 这是一个什么项目“ssm基于的青春追梦在线教育系统mv59t”这个名字看着像课程设计或者毕业设计的选题&#xff0c;但它本身的定位非常清晰&#xff1a;一个基于SSM框架的在线教育平台。说白了&#xff0c;就是把线下的培训机构、课堂教学场景搬到…

作者头像 李华