news 2026/9/24 18:55:51

茶叶病害数据集VOC+YOLO格式883张8类别:从格式转换到YOLOv8训练全流程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
茶叶病害数据集VOC+YOLO格式883张8类别:从格式转换到YOLOv8训练全流程

简介:这份茶叶病害数据集面向农业图像识别、植物保护研究及深度学习目标检测方向的开发者与学习者,提供可直接用于模型训练与验证的标注数据。资源共883张jpg图片,每张仅含单片叶子,配套883个VOC格式xml与883个YOLO格式txt标注文件,另含少量说明文本,压缩包约200.5MB,总计2000个文件,兼容Pascal VOC与YOLO两种主流训练流程。标注由labelImg完成,以矩形框标出8类病害:炭疽病、藻斑病、鸟眼斑、褐斑病、灰斑病、健康叶、红叶斑及白斑,总框数884,其中红叶斑与白斑样本较多,健康叶相对偏少,便于按类别分布调整采样策略。目前已有886人学习下载,适合作为目标检测课程实验、病害分类对比或数据增强练习的现成素材,能省去从零采集与标注的成本。

1. 茶叶病害数据集 VOC+YOLO 格式 883 张 8 类别:从拿到压缩包到跑通训练

茶园里最怕的不是虫,是病。叶片上刚冒出针尖大的褐点,三五天就能蔓延成一片焦枯,等人眼看出来往往已经错过最佳防治窗口。我去年帮一个做智慧农业的团队处理过一批茶园巡检图,他们手里攒了 883 张标注好的茶叶病害图片,8 个类别,VOC 和 YOLO 两种格式都给了。这个数据集的价值不在于图片多,而在于它把「叶片病斑」这种小目标、类间差异细微的场景做成了可直接训练的形态。如果你正在找烟草病虫害数据集 yolo 那类农业检测数据,或者想拿一份真实农业场景数据练手 yolo 训练自己的数据集,这份茶叶病害数据是个不错的起点。它适合两类人:一是刚学完 yolo 环境配置、想跑通第一个非 COCO 数据集的算法新手;二是做农业巡检落地、需要快速验证检测方案可行性的工程师。下面我按拿到压缩包之后的真实操作顺序,把格式转换、环境搭建、训练调参和踩坑记录讲清楚。

2. VOC 与 YOLO 双格式到底差在哪:先搞懂再动手

2.1 两种标注格式的坐标逻辑差异

VOC 格式的标注文件是 XML,每个目标用<bndbox>记录xminyminxmaxymax四个值,这是绝对像素坐标,原点在图片左上角。YOLO 格式则是每张图对应一个.txt文件,每行一个目标,格式是类别索引 x_center y_center width height,后四个值全部是相对于图片宽高的归一化值,范围 0 到 1。这个差异决定了你不能直接把 XML 丢给 YOLO 训练,必须做一次坐标换算。换算公式很直接:x_center = (xmin + xmax) / 2 / img_widthy_center = (ymin + ymax) / 2 / img_heightwidth = (xmax - xmin) / img_widthheight = (ymax - ymin) / img_height。看起来简单,但实际转换时图片尺寸读取错误、类别名和索引映射错位是两个高频翻车点。

2.2 8 个类别与数据分布要先摸清

拿到数据集第一件事不是急着转格式,而是统计类别分布。883 张图分 8 类,平均下来每类一百来张,但农业数据集的类别不平衡往往很严重——健康叶片可能占了一大半,某些病害只有几十张。你需要先跑一遍统计脚本,看清楚每类多少张、每张图平均几个目标框。如果某类样本少于 50 张,训练时就要考虑数据增强或者类别权重调整。下面这段脚本同时完成类别统计和 VOC 转 YOLO 两件事,我一般会先跑统计部分确认分布,再执行转换。

import os import xml.etree.ElementTree as ET from collections import Counter from PIL import Image # 类别列表,按你的数据集实际类别顺序填写 classes = ['病斑A', '病斑B', '病斑C', '病斑D', '病斑E', '病斑F', '病斑G', '健康'] class_to_id = {name: i for i, name in enumerate(classes)} def convert_voc_to_yolo(xml_dir, img_dir, out_dir): os.makedirs(out_dir, exist_ok=True) counter = Counter() for xml_file in os.listdir(xml_dir): if not xml_file.endswith('.xml'): continue tree = ET.parse(os.path.join(xml_dir, xml_file)) root = tree.getroot() # 图片文件名,VOC 里通常在 filename 节点 img_name = root.find('filename').text img_path = os.path.join(img_dir, img_name) # 用 PIL 读真实尺寸,不要信 XML 里的 size 节点 with Image.open(img_path) as im: w, h = im.size lines = [] for obj in root.findall('object'): cls_name = obj.find('name').text.strip() if cls_name not in class_to_id: continue counter[cls_name] += 1 bbox = obj.find('bndbox') xmin = float(bbox.find('xmin').text) ymin = float(bbox.find('ymin').text) xmax = float(bbox.find('xmax').text) ymax = float(bbox.find('ymax').text) # 归一化并限制在 0-1,防止标注越界 xc = min(max((xmin + xmax) / 2 / w, 0), 1) yc = min(max((ymin + ymax) / 2 / h, 0), 1) bw = min(max((xmax - xmin) / w, 0), 1) bh = min(max((ymax - ymin) / h, 0), 1) lines.append(f"{class_to_id[cls_name]} {xc:.6f} {yc:.6f} {bw:.6f} {bh:.6f}") # 输出同名 txt txt_name = os.path.splitext(xml_file)[0] + '.txt' with open(os.path.join(out_dir, txt_name), 'w') as f: f.write('\n'.join(lines)) print("类别分布:", counter) convert_voc_to_yolo('./Annotations', './JPEGImages', './labels')

这段代码的关键点有三个。第一,图片尺寸用 PIL 实时读取,而不是用 XML 里<size>节点记录的值,因为标注工具偶尔会写错尺寸,用错尺寸会导致所有框偏移。第二,归一化后做了min(max(...))截断,防止个别越界标注产生大于 1 的坐标,YOLO 训练时遇到这种值会直接报错。第三,类别名到索引的映射必须和后续训练时的data.yaml完全一致,顺序错了模型学出来的类别就是乱的。转换完成后,你会得到和图片同名的.txt文件,放在labels目录下。

2.3 目录结构要按 YOLO 约定摆好

YOLO 训练对目录结构有固定要求,常见做法是建一个数据集根目录,下面分imageslabels,各自再分trainval,有时候还有test。图片和标注文件必须同名,只是扩展名不同。我一般按 8:1:1 切分,883 张图大约训练集 706 张、验证集 88 张、测试集 89 张。切分时要注意同一片茶园、同一批次拍的图不能同时出现在训练和验证集里,否则验证指标会虚高。下面这段脚本完成切分和目录搬运。

import os import shutil import random random.seed(42) # 固定随机种子,保证可复现 img_dir = './JPEGImages' lbl_dir = './labels' out_root = './tea_dataset' all_imgs = [f for f in os.listdir(img_dir) if f.lower().endswith(('.jpg', '.png', '.jpeg'))] random.shuffle(all_imgs) n = len(all_imgs) n_train = int(n * 0.8) n_val = int(n * 0.1) splits = { 'train': all_imgs[:n_train], 'val': all_imgs[n_train:n_train + n_val], 'test': all_imgs[n_train + n_val:] } for split, files in splits.items(): img_out = os.path.join(out_root, 'images', split) lbl_out = os.path.join(out_root, 'labels', split) os.makedirs(img_out, exist_ok=True) os.makedirs(lbl_out, exist_ok=True) for f in files: shutil.copy(os.path.join(img_dir, f), os.path.join(img_out, f)) txt = os.path.splitext(f)[0] + '.txt' src_txt = os.path.join(lbl_dir, txt) if os.path.exists(src_txt): shutil.copy(src_txt, os.path.join(lbl_out, txt)) else: print("缺失标注:", txt) print("切分完成:", {k: len(v) for k, v in splits.items()})

跑完这段,数据集就摆成了 YOLO 能直接吃的形态。如果打印出「缺失标注」,说明有图片没有对应的 txt,要么是原数据集漏标,要么是转换时类别名没匹配上被跳过了,需要回去检查。

3. 用 YOLOv8 在本地跑通茶叶病害训练的最小流程

3.1 环境配置与依赖安装

YOLOv8 对环境的要求不算苛刻,Python 3.8 到 3.11 都能跑,PyTorch 版本跟 CUDA 匹配就行。我一般用 conda 建一个干净环境,避免和系统里的包打架。如果你搜 yolo v8 anaconda 环境配置要求,核心就是三件事:Python 版本、PyTorch 与 CUDA 对应、ultralytics 包。下面这套命令是我在 Ubuntu 和 Windows 上都验证过的。

conda create -n tea_yolo python=3.10 -y conda activate tea_yolo # 根据你的 CUDA 版本去 PyTorch 官网选对应命令,这里以 CUDA 11.8 为例 pip install torch torchvision --index-url https://download.pytorch.org/whl/cu118 pip install ultralytics opencv-python pillow

装完之后跑一句yolo checks,它会打印出 PyTorch 版本、CUDA 是否可用、设备信息。如果显示CUDA:0说明 GPU 能用,显示CPU就说明 CUDA 没配好,训练会慢几十倍。CPU 训练 883 张图跑 100 轮大概要几个小时,GPU 上十几分钟就能出结果,所以能上 GPU 尽量上。

3.2 data.yaml 的写法与类别顺序

YOLOv8 靠一个data.yaml文件找到数据和类别。这个文件里names的顺序必须和转换脚本里的classes列表完全一致,差一个位置模型就学错。path写数据集根目录,trainvaltest写相对路径。下面是我这份茶叶病害数据集的配置。

path: ./tea_dataset train: images/train val: images/val test: images/test nc: 8 names: 0: 病斑A 1: 病斑B 2: 病斑C 3: 病斑D 4: 病斑E 5: 病斑F 6: 病斑G 7: 健康

nc是类别数,这里 8 类就写 8。names可以用列表形式也可以像上面这样用字典,字典形式更直观,不容易数错。写完存成tea.yaml,放在项目根目录。

3.3 启动训练与关键参数含义

训练命令本身很短,但参数怎么设决定了你能不能跑出可用模型。下面这条是我在茶叶病害数据上常用的起手配置。

yolo detect train \ data=tea.yaml \ model=yolov8s.pt \ epochs=150 \ imgsz=640 \ batch=16 \ lr0=0.01 \ patience=30 \ project=runs/tea \ name=exp1

model=yolov8s.pt用的是预训练权重,小目标检测场景下 s 版本比 n 版本召回更好,又不像 m 那么吃显存。imgsz=640是输入尺寸,茶叶病斑在叶片上占比小,如果你显存够,可以提到 800 甚至 1024,小目标召回会明显改善。batch=16在 8G 显存上比较稳,显存不够就降到 8。lr0=0.01是初始学习率,用预训练权重时这个值合适,如果你从头训练可以降到 0.001。patience=30表示验证指标 30 轮不提升就早停,避免过拟合。训练过程中重点看mAP50mAP50-95两个指标,前者宽松后者严格,农业检测里 mAP50 到 0.85 以上基本可用。

3.4 训练完怎么验证和推理

训练结束后权重存在runs/tea/exp1/weights/best.pt。验证用yolo detect val,推理单张图用yolo detect predict。下面这条命令对测试集跑一遍,输出每类的精确率和召回率。

yolo detect val model=runs/tea/exp1/weights/best.pt data=tea.yaml split=test

如果某类召回特别低,比如某个病斑类只有 0.4,先别急着调模型,回去看这类样本是不是太少,或者标注框是不是画得太松。农业病害的类间差异本来就小,标注质量对结果的影响比模型结构大得多。

4. 训练茶叶病害模型最容易踩的五个坑

4.1 类别索引错位导致模型全学偏

现象:训练 loss 正常下降,但验证时所有预测框的类别都是错的,或者某一类永远不出现。原因:VOC 转 YOLO 时的classes列表顺序和data.yaml里的names顺序不一致,比如转换时「健康」排第 8,yaml 里排第 1。解决:转换脚本和 yaml 用同一份类别列表,最好把类别定义抽成一个单独的classes.txt,两边都读这个文件,从源头杜绝不一致。

4.2 图片尺寸读错导致框整体偏移

现象:训练能跑,但预测框位置系统性偏移,比如都往左上角偏。原因:转换时用了 XML 里<size>节点记录的宽高,而实际图片尺寸和记录值不符,归一化分母错了。解决:一律用 PIL 或 OpenCV 实时读取图片真实尺寸,不要信任标注文件里的尺寸字段。转换完可以抽几张图用可视化脚本画框检查,框和病斑对齐才算过。

4.3 小目标病斑在 640 尺寸下召回低

现象:大块病斑检测很准,针尖大的小病斑大量漏检。原因:输入尺寸 640 时,原图上几十像素的病斑缩到特征图上只剩几个像素,特征太弱。解决:把imgsz提到 800 或 1024,同时开启 YOLOv8 的mosaiccopy_paste增强,让模型多见小目标。如果显存不够,用yolov8myolov8s不一定有用,优先提输入尺寸。

4.4 验证集指标虚高但实际部署翻车

现象:验证集 mAP 很高,拿到新茶园图片上检测效果差很多。原因:切分数据时没有按拍摄批次或茶园分组,同一片叶子的相似图同时进了训练和验证集,模型其实在「背答案」。解决:切分前先按拍摄时间、地点、批次分组,整组进训练或验证,保证验证集和训练集来自不同分布。这个坑在农业数据集里极其常见,血泪经验。

4.5 标注框过松导致定位不准

现象:类别分类对了,但框比病斑大一圈,IoU 上不去。原因:标注时框画得太随意,把周围健康组织也框进去了。解决:农业病害标注要贴着病斑边缘画,宁可略紧不要过松。如果数据集已经这样了,训练时把box损失权重适当调高,或者用yolov8close_mosaic在最后几轮关掉增强,让模型更关注精确定位。

5. 把 883 张用到极致:小样本农业检测的进阶技巧

883 张 8 类,平均每类一百出头,这个量级做检测属于小样本。想把效果再往上推,我一般从三个方向下手。第一是离线增强,训练时 YOLO 自带的增强是随机的,你可以在转换阶段额外生成一批增强图,比如随机旋转、亮度扰动、局部裁剪,把训练集扩到两三千张。注意增强只对训练集做,验证集保持原样。第二是迁移学习策略,先用 COCO 预训练权重跑 50 轮冻结 backbone,再解冻全量微调 100 轮,这样小样本下收敛更稳。第三是推理阶段的技巧,部署时把置信度门限从默认 0.25 调到 0.35 到 0.4,能过滤掉大量低置信度假阳性,农业场景里误报比漏报更让人头疼。

验证模型是否真的可用,我习惯做一个混淆矩阵加 PR 曲线的组合检查。YOLOv8 验证时会自动生成confusion_matrix.pngPR_curve.png,重点看两类:健康叶片有没有被误判成病斑,以及两个症状相近的病斑类之间有没有互相混淆。如果健康类误报多,说明模型对健康叶片的特征学得不够,需要补健康样本;如果两个病斑类互相混淆,说明类间差异太小,要么合并类别,要么在标注时把区分特征标得更明确。

最后说个我自己的习惯:每次训完模型,我都会挑 20 张验证集里预测最差的图,一张张看是标注问题还是模型问题。十次里有六七次是标注框画歪了或者类别标错了。农业数据集的质量参差不齐,与其反复调参,不如先把标注清洗一遍。这个习惯帮我省下的时间,比换模型结构多得多。希望帮到你。

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

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

OpenCV+Dlib人脸识别门禁系统源码解析与避坑指南

简介&#xff1a;这是一套面向高校计算机相关专业学生的Python毕业设计项目源码&#xff0c;主题为基于OpenCV与Dlib的人脸识别门禁系统&#xff0c;适合作为毕业设计、期末大作业或课程设计的参考方案&#xff0c;难度适中&#xff0c;兼顾算法实现与界面交互&#xff0c;对想…

作者头像 李华
网站建设 2026/9/24 18:54:42

OpenCV+MediaPipe+CNN:手势控制鼠标的完整实现指南

简介&#xff1a;这套基于OpenCV、MediaPipe与CNN的手势识别项目&#xff0c;面向计算机视觉和人机交互学习者&#xff0c;用指尖的相对移动和运动速度控制鼠标指针&#xff0c;通过特定指尖动作完成点击、滚动页面&#xff0c;并支持手势触发快捷键与虚拟键盘输入。项目提供可…

作者头像 李华
网站建设 2026/9/24 18:54:30

Servlet+J2EE构建网格化社区管理系统:从原理到实操

做完计算机毕设里那种“管理系统”&#xff0c;最常见的坑就是你辛辛苦苦写了几千行代码&#xff0c;结果选型本身就成了答辩老师的第一攻击点。社区网格化管理系统这类题目&#xff0c;很多同学第一反应就是冲Spring Boot&#xff0c;但如果你用的是ServletJ2EE这套经典Java W…

作者头像 李华
网站建设 2026/9/24 18:53:58

用Hadess集成钉钉打造企业统一认证登录体系

做过企业内部平台的同学&#xff0c;大概率都有过这种经历&#xff1a;OA 一套账号、财务系统一套账号、项目管理工具再注册一次&#xff0c;再加上各种内部服务后台&#xff0c;光记住密码就能把人的耐心磨没。更麻烦的是&#xff0c;每个系统还得单独做密码找回、账号禁用、离…

作者头像 李华
网站建设 2026/9/24 18:53:39

Vim实战:在终端高效完成图像分类训练与调参

简介&#xff1a;这份资源面向希望上手视觉Mamba模型的深度学习开发者与图像分类实践者&#xff0c;围绕Vim这一计算与内存效率高、擅长高分辨率图像的视觉骨干网络&#xff0c;提供一套可直接运行的图像分类训练方案。压缩包共约2000个文件&#xff0c;整体971.94MB&#xff0…

作者头像 李华
网站建设 2026/9/24 18:52:52

杭州SPC地板品牌供应商企业全景分析:用户力荐的源头工厂

为什么选SPC地板?搞懂这几个核心原理再装修不踩坑很多杭州业主在做家装、工装方案时&#xff0c;都会纠结地板材质的选择&#xff1a;传统实木地板怕潮、强化地板甲醛难控、竹地板受温湿度影响大&#xff0c;而SPC地板凭借防水防潮、零醛环保的特点&#xff0c;正在成为杭州本…

作者头像 李华