ARTICLE DETAIL

资讯详情

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

葡萄叶片病害检测数据集:VOC、COCO、YOLO标签格式选型与YOLOv8训练实战

葡萄叶片病害检测数据集:VOC、COCO、YOLO标签格式选型与YOLOv8训练实战 简介这份资源面向从事农业图像识别、目标检测学习与科研的学生和开发者提供一套真实场景下的葡萄叶片病害检测数据集可直接用于YOLO系列模型训练与验证。压缩包共约2000个文件整体349.64MB以1985个xml标注文件为主另含少量txt、html与py脚本分别承担标签数据、说明文档和划分工具等用途。数据集包含10000张高质量图片经labelimg标注同时提供voc、coco和yolo三种格式标签分目录存放便于不同框架直接读取。资源还附赠YOLO环境搭建、训练案例教程以及训练集、验证集、测试集划分脚本读者可依据自身需求重新划分数据快速跑通从环境配置到模型训练的完整流程。目前已有355人学习下载适合需要现成数据与配套脚本开展课程设计、毕业项目或算法实验的读者参考使用。1. 一万张葡萄叶片病害图三种标签格式到底怎么选拿到一个农业病害数据集第一反应往往不是「数据够不够」而是「标签格式对不对」。葡萄叶片病害检测这类任务田间拍回来的原始图通常只有文件夹分类而 YOLO 训练要的是归一化坐标的 txtCOCO 要的是单文件 jsonVOC 要的是每张图一个 xml。三种格式各有各的脾气转换脚本写错一个字段训练时 loss 直接不降排查半天才发现是类别 id 从 1 开始还是从 0 开始的问题。这个数据集的核心价值在于10000 张葡萄叶片图片覆盖黑腐病、轮纹病、褐斑病等常见叶部病害同时给了 VOC、COCO、YOLO 三套标签和划分脚本。它解决的不是「有没有数据」而是「拿到数据后怎么快速对齐到自己的训练管线」。适合两类人一是刚接触 YOLO 目标检测、想找一个真实农业场景练手的工程师二是已经在做作物病害识别、需要扩充数据或对比不同标签格式影响的从业者。我见过太多人卡在第一步下载完数据集打开一看三个文件夹不知道哪个该喂给 YOLOv8哪个该喂给 Detectron2。这篇就把三种格式的差异、划分脚本的逻辑、以及从零跑通一次训练的全过程拆开讲顺带把那些「不报错但结果不对」的坑标出来。2. 三种标签格式的底层差异与选型逻辑2.1 VOC、COCO、YOLO 各自存了什么VOC 格式是「一图一文件」每张图片对应一个 XML里面用object标签记录类别名和边界框的xmin/ymin/xmax/ymax。它的优点是可读性强用文本编辑器打开就能看懂缺点是文件数量爆炸10000 张图就是 10000 个 XML拷贝和版本管理都很痛苦。COCO 格式是「全量单文件」所有图片的标注塞进一个 JSON结构分images、annotations、categories三块。annotations里的bbox是[x, y, width, height]注意这里是左上角坐标加宽高不是右下角。COCO 的类别 id 通常从 1 开始0 留给背景这个细节在转 YOLO 时经常翻车。YOLO 格式是「一图一 txt」每行class_id x_center y_center width height全部归一化到 0 到 1 之间。它最轻量训练时读取最快但可读性最差打开 txt 只能看到一堆小数。YOLO 的类别 id 从 0 开始和 COCO 差一位这是转换脚本里最容易埋雷的地方。选型上如果你用 Ultralytics 的 YOLOv5/v8/v11直接选 YOLO 格式省去转换步骤。如果你用 MMDetection 或 Detectron2COCO 格式更顺手。VOC 格式现在更多是作为中间态或者给一些老代码用。这个数据集三套都给意味着你不用自己写转换但得知道每套的边界在哪。2.2 划分脚本在做什么别让训练集和验证集串门划分脚本的核心任务是把 10000 张图按比例分成 train、val、test 三份同时保证对应的标签文件跟着走。听起来简单但有两个隐藏问题一是随机种子没固定每次跑划分结果不一样实验没法复现二是同一张图的不同病害区域被拆到不同集合导致验证集里出现训练集见过的叶片。常见做法是按 8:1:1 或 7:2:1 划分先固定random.seed(42)再对图片文件名列表做 shuffle。如果数据里有同一片叶子的多角度拍摄最好按「叶片 id」分组划分而不是按图片随机。这个数据集如果没提供叶片分组信息那就只能按图片随机但要在实验记录里写清楚避免后续对比时误判模型泛化能力。下面是一个我常用的划分脚本骨架直接改路径就能跑import os import random import shutil # 固定随机种子保证每次划分结果一致 random.seed(42) # 原始图片和标签目录 img_dir datasets/grape/images label_dir datasets/grape/labels # 输出目录 out_dir datasets/grape_split train_ratio, val_ratio 0.8, 0.1 # 只取图片文件按文件名排序后再 shuffle避免依赖文件系统顺序 imgs sorted([f for f in os.listdir(img_dir) if f.endswith((.jpg, .png))]) random.shuffle(imgs) n len(imgs) n_train int(n * train_ratio) n_val int(n * val_ratio) splits { train: imgs[:n_train], val: imgs[n_train:n_train n_val], test: imgs[n_train n_val:] } for split, files in splits.items(): img_out os.path.join(out_dir, split, images) lbl_out os.path.join(out_dir, split, labels) os.makedirs(img_out, exist_okTrue) os.makedirs(lbl_out, exist_okTrue) for f in files: shutil.copy(os.path.join(img_dir, f), os.path.join(img_out, f)) # 标签文件名和图片一致只是后缀换成 txt lbl_name os.path.splitext(f)[0] .txt src_lbl os.path.join(label_dir, lbl_name) if os.path.exists(src_lbl): shutil.copy(src_lbl, os.path.join(lbl_out, lbl_name)) else: print(f警告{f} 没有对应标签)这段脚本的关键参数是random.seed(42)和train_ratio/val_ratio。种子固定后任何人跑出来的划分结果都一样实验可复现。比例按数据集大小调10000 张图用 8:1:1 比较稳验证集和测试集各 1000 张足够评估。如果某张图没有对应标签脚本会打印警告而不是静默跳过这点很重要——静默跳过会让训练集里混入无标签图模型学会「什么都不检测」。2.3 从 COCO 转 YOLO坐标归一化和类别偏移如果你拿到的是 COCO json想转成 YOLO txt核心就两步坐标归一化和类别 id 减一。COCO 的bbox是[x_min, y_min, width, height]YOLO 要的是[x_center, y_center, width, height]且全部除以图片宽高。类别 id 方面COCO 从 1 开始YOLO 从 0 开始直接减一即可但要注意有些数据集的 COCO json 里categories的 id 不连续得先建映射表。import json import os from PIL import Image coco_json annotations/instances.json img_dir images out_dir labels_yolo os.makedirs(out_dir, exist_okTrue) with open(coco_json, r) as f: data json.load(f) # 建立 category_id 到连续 0-based 索引的映射 cat_ids sorted([c[id] for c in data[categories]]) cat_map {cid: idx for idx, cid in enumerate(cat_ids)} # 按 image_id 聚合标注 img_info {img[id]: img for img in data[images]} anns_by_img {} for ann in data[annotations]: anns_by_img.setdefault(ann[image_id], []).append(ann) for img_id, anns in anns_by_img.items(): info img_info[img_id] w, h info[width], info[height] lines [] for ann in anns: x, y, bw, bh ann[bbox] # 转中心点坐标并归一化 xc (x bw / 2) / w yc (y bh / 2) / h nw bw / w nh bh / h cls cat_map[ann[category_id]] lines.append(f{cls} {xc:.6f} {yc:.6f} {nw:.6f} {nh:.6f}) # 输出文件名和图片同名后缀换 txt name os.path.splitext(info[file_name])[0] .txt with open(os.path.join(out_dir, name), w) as f: f.write(\n.join(lines))这里cat_map是关键它把 COCO 里可能不连续的类别 id 压成 0 到 N-1。归一化时保留 6 位小数YOLO 训练时精度足够。如果图片宽高和 json 里记录的不一致以 json 为准因为标注是基于那个尺寸做的。转完后随便抽几个 txt 和原图对照看框的位置对不对这一步别省。3. 用 YOLOv8 跑通葡萄叶片病害检测训练3.1 环境配置与数据 yaml 的写法YOLOv8 的环境配置现在很成熟Python 3.8 以上装ultralytics包就行。如果你有 GPU先确认 CUDA 版本和 PyTorch 匹配不然训练时会报CUDA error。我一般用 conda 建一个干净环境避免和系统里的包打架。conda create -n grape_yolo python3.10 -y conda activate grape_yolo pip install ultralytics # 验证安装和 GPU 是否可用 yolo checksyolo checks会打印环境信息重点看CUDA那一行是不是available。如果是not available要么是没装 GPU 版 PyTorch要么是驱动版本太低。CPU 也能训但 10000 张图跑起来会很慢建议至少用一张 8G 显存的卡。数据 yaml 是 YOLO 训练的入口格式如下path: /data/grape_split train: train/images val: val/images test: test/images names: 0: black_rot 1: esca 2: leaf_blight 3: healthypath是数据集根目录train/val/test是相对路径。names里的类别顺序必须和 txt 里的 class_id 对应写反了模型会把黑腐病认成健康叶。类别名建议用英文避免中文路径在某些系统上的编码问题。如果数据集里还有「健康」这一类别忘了加进去不然健康叶片会被当成背景模型见到健康叶就乱框。3.2 训练命令与关键参数怎么调启动训练就一行命令但参数决定成败yolo detect train \ datagrape.yaml \ modelyolov8s.pt \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ patience20 \ projectruns/grape \ nameexp1modelyolov8s.pt是预训练权重小模型适合快速验证如果精度不够再换yolov8m.pt或yolov8l.pt。imgsz640是输入尺寸葡萄叶片病害的斑点有时候很小640 够用但如果病斑占比很小可以提到 1024代价是显存翻倍。batch16在 8G 显存上跑 640 尺寸比较稳爆显存就降到 8。lr00.01是初始学习率YOLOv8 默认用 SGD 时这个值合适如果用 AdamW 可以降到 0.001。patience20表示 20 轮验证指标不提升就早停省时间。训练过程中重点看三个指标box_loss应该持续下降如果震荡不降检查标签有没有问题mAP50是 IoU 0.5 时的平均精度葡萄病害检测一般能到 0.7 以上算不错precision和recall要平衡recall 太低说明漏检多可能是病斑太小或标注太松。3.3 训练完怎么验证混淆矩阵和实际推理训练结束后runs/grape/exp1目录下会有confusion_matrix.png这个图能直接看出哪类病害容易被混淆。比如黑腐病和褐斑病如果互相误判多说明两类病斑在颜色和形状上太像要么加数据要么在预处理时增强对比度。实际推理用命令行yolo detect predict \ modelruns/grape/exp1/weights/best.pt \ sourcetest_images/ \ conf0.25 \ saveTrueconf0.25是置信度阈值低于这个值的框不显示。田间图片背景复杂可以调到 0.3 减少误检。推理结果会保存在runs/detect/predict下打开图片看框的位置和类别标签对不对。如果发现某类病害总是漏检回去看训练集的标注是不是框得太紧YOLO 对边界框的宽容度有限标注时留一点边距反而有助于学习。4. 避坑与排查那些不报错但结果不对的情况4.1 类别 id 从 1 开始模型把背景当目标现象训练 loss 能降但推理时满屏都是框置信度还不低。原因标签里的 class_id 从 1 开始而 YOLO 的names从 0 开始模型学到的「1」对应的是names里的第二类第一类永远学不到背景反而被当成目标。解决检查 txt 里最小 class_id 是不是 0不是就整体减一同时确认names的键从 0 连续排列。4.2 图片和标签文件名不一致训练时静默跳过现象训练日志里train的图片数量比预期少但没有任何报错。原因YOLO 按文件名匹配图片和标签如果图片是IMG_001.jpg标签是img_001.txt大小写不一致就匹配不上该图被当成无标签样本丢弃。解决统一文件名大小写划分脚本里加一步校验打印匹配失败的列表。4.3 验证集 mAP 很高实际田间图片一塌糊涂现象验证集 mAP50 到 0.9拿手机去葡萄园拍几张模型几乎不框。原因训练集和验证集来自同一批拍摄条件光照、角度、背景都相似模型过拟合了采集环境。解决划分时按拍摄批次分而不是随机分或者在训练时加更强的数据增强比如mosaic1.0、hsv_h0.015、hsv_s0.7让模型见到更多颜色和亮度变化。4.4 显存够但训练速度极慢GPU 利用率上不去现象nvidia-smi显示 GPU 利用率只有 20% 到 30%训练一轮要很久。原因batch太小或者数据加载是瓶颈CPU 预处理跟不上 GPU。解决先把batch提到显存允许的最大值再设置workers8根据 CPU 核数调如果还是慢把图片提前 resize 到接近imgsz的尺寸减少训练时的缩放开销。4.5 混淆矩阵总合不唯一类别数对不上现象混淆矩阵的行列和实际类别数不一致或者某些类别的样本数为 0。原因验证集里某些类别一张图都没有划分时随机性导致小类别被分没了。解决划分时按类别分层抽样保证每个类别在 train/val/test 里都有一定比例。如果某类样本极少考虑过采样或在 loss 里加类别权重。5. 把 10000 张图用出复利增量训练与格式互转的省力技巧数据集的价值不在「跑通一次」而在「反复用」。我一般会做两件事一是把 YOLO 格式作为主存储因为训练读取最快二是写一个双向转换脚本需要 COCO 时从 YOLO 转过去需要 VOC 时也转而不是维护三套标签。这样新增图片时只标一套其余格式按需生成。增量训练是另一个省力点。葡萄叶片病害有季节性新拍的数据往往只包含某几种病害。这时候不要从头训用modelbest.pt加载已有权重把新数据混进训练集学习率调小到lr00.001训 20 到 30 轮就够。这样模型既保留旧类别的能力又吸收新样本。注意新数据里如果出现了旧类别标注要和旧标签的类别名一致否则模型会分裂出两个相似的类。格式互转的脚本我放在一个tools/目录下核心是「以 YOLO 为中间态」。YOLO 转 COCO 时遍历所有 txt按图片尺寸反归一化再拼成 jsonYOLO 转 VOC 时每张图生成一个 xml。反过来COCO 和 VOC 都先转 YOLO再按需转其他。这样只需要维护两个转换函数而不是六个。最后说一个验证技巧训练前先拿 10 张图跑一遍yolo detect train的--epochs 1看 loss 有没有从随机水平开始下降。如果第一轮 loss 就是 0 或者 NaN说明标签格式有问题别急着跑 100 轮。这个习惯帮我省过很多次通宵排查的时间。希望帮到你。本文还有配套的精品资源点击获取
返回列表