ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

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

葡萄叶病害检测数据集: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. 葡萄叶病害检测数据集VOCYOLO双重标注1609张够不够用搞过农业视觉项目的人都有体会模型选型往往不是瓶颈真正卡脖子的是数据集——格式乱、标注不统一、类别失衡光是洗数据就能耗掉一半工期。这份葡萄叶病害检测数据集属于“小而完整”的典型1609张jpg每张图配一个Pascal VOC的xml和一个YOLO的txt4个病害类别总框数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里存的是类别的英文名比如nameBlack Rot/name。而YOLO的txt每一行的第一个数字是类别ID0到3的整数。你需要自己定义一个映射字典class_map { Black Measles: 0, Black Rot: 1, blight fungus: 2, healthy leaf: 3 }这里有个很隐蔽的坑类别名的大小写和空格必须和xml里的完全一致。原始数据集里的类别叫blight fungus全小写另一个叫Black Rot是驼峰加大写开头。如果你在映射字典里写成Blight fungus或者black fungusxml解析时就会跳过这些目标导致标注框数量对不上——明明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的写法路径与类别名的对位关系YOLOv8Ultralytics框架训练需要三个信息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 \ modelyolov8s.pt \ datagrape_leaf.yaml \ epochs100 \ imgsz640 \ batch16 \ patience20 \ augmentTrue \ project./runs \ namegrape_leaf_exp1关键参数解释epochs100是必要的小数据集通常需要更长时间才能收敛patience20是早停机制连续20个epoch验证集mAP不提升就停下防止过拟合batch16根据显存调整如果你的显卡只有8GB显存降到8imgsz640是YOLOv8的默认推理尺寸与预训练权重匹配不需要改。4.3 数据增强策略小样本场景下的关键开关小数据集最怕的是没有数据增强直接硬训。YOLOv8默认开启的马赛克增强对叶片病害这种纹理敏感型任务有奇效——它把四张图拼接成一张强制模型学习局部纹理而不是整图背景。也可以在yaml里或命令行里显式增强yolo train \ modelyolov8s.pt \ datagrape_leaf.yaml \ epochs100 \ hsv_h0.015 \ hsv_s0.7 \ hsv_v0.4 \ degrees10.0 \ translate0.1 \ scale0.5 \ fliplr0.5degrees10只做小角度旋转因为叶片病斑不存在方向不变性转90度后病斑形态会失真scale0.5缩放范围控制在0.5到1.5之间太大会让叶片边缘被裁掉fliplr0.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而不是.jpgYOLO脚本在匹配时用了小写后缀导致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, conf0.25, iou0.45, imgsz640) 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}))conf0.25是默认阈值如果现场环境复杂、误报多调到0.4如果漏检多、能接受人工复核调到0.15。iou0.45是NMS的阈值值越小抑制越强适合密集病斑场景值越大保留框越多适合稀疏场景。6.3 类别不均衡的进阶处理给少数类加权重虽然这个数据集本身均衡但迁移到你的实际场景后如果某类样本变少可以给loss加类别权重。做法是计算每类框数的逆频率作为权重接一个自定义的weight参数。YOLOv8官方不直接暴露这个参数但可以通过修改数据增强的mosaic概率或对少数类做离线复制来缓解。我个人的习惯是在数据准备阶段做一次基于类的数据综述反向检查各类别的sample_count。这个数据集四类基本均衡已经省下了这一步。总结一条经验无论标注工具是labelImg还是其他转换格式时永远保留一份原始xml副本不要只留txt——因为txt没有类别名的可读性一旦ID映射错误找回信息的成本极高。吃过大亏之后我每次做完格式整理都会先在纯CPU环境跑一遍数据加载脚本确认全部文件对上了再上GPU训练。这份数据集虽然只有1609张但胜在标注干净、类别均衡、双格式齐备复现一遍YOLO训练流程能帮你把“数据准备→训练→验证→部署”的完整链路跑通。希望帮到你。本文还有配套的精品资源点击获取
返回列表