简介:本资源为面向农业AI研发者与计算机视觉初学者的水稻虫害检测专用图像数据集,聚焦解决农田场景下害虫目标识别模型训练的数据匮乏问题。数据集包含5212张高分辨率JPG图像及配套标注,采用Pascal VOC(XML)与YOLO(TXT)双格式并行组织,兼顾算法研究的规范性与工程部署的便捷性;6类常见水稻害虫——褐飞虱、绿叶蝉、稻纵卷叶螟、稻水象甲、茎螟、螺纹虫——均经labelImg人工矩形框标注,总计8104个高质量边界框,类别分布均衡,适配YOLOv5/v8、Faster R-CNN等主流检测框架。资源以单个2.08MB DOCX文档形式提供,内含完整数据说明、目录结构图示、标注样例截图及classes.txt类别索引,便于快速理解数据组织逻辑与使用路径。目前已有126人学习下载,是开展农业病虫害智能监测系统开发、课程实验设计或毕业课题实践的理想基础数据支撑。
1. 水稻虫害检测数据集VOC+YOLO格式5212张6类别:不是“又一个农业数据集”,而是能直接喂进YOLOv8训练管道、跳过80%格式转换血泪调试的现成燃料
你有没有试过:花三天配好labelImg环境,标注完200张图,导出YOLO格式后发现classes.txt顺序和代码里硬编码的类别索引对不上,模型训出来全是背景?或者把VOC转YOLO时xml解析脚本漏了whorl-maggot这种带连字符的类名,导致所有螺纹虫框全丢?——这个水稻虫害检测数据集VOC+YOLO格式5212张6类别,就是专治这类翻车现场的。它不只提供5212张jpg+5212个xml+5212个txt,而是每一对三件套(jpg/xml/txt)都经人工交叉校验:xml里的 字段、txt首列数字、classes.txt第N行文本、实际图像中框内目标,四者严格一一对应。6个类别名称全部按YOLO训练惯例小写+短横线标准化,无空格无大小写混用;所有txt文件首列数字从0开始连续编号,与classes.txt行号零偏差;所有xml文件的 与jpg文件名完全一致(含大小写),路径层级干净到只有images/和labels/两级。它适合两类人:一是农业AI项目刚立项、急需真实田间数据启动baseline训练的工程师;二是高校课程设计要交一个“能跑通、能展示、能讲清”的水稻虫害识别demo的学生。别被“5212张”吓住——真正卡住进度的从来不是数据量,而是格式错位、类别漂移、路径混乱这三座大山。这份资源,是把山炸平后铺好的碎石路。
2. VOC+YOLO双格式共存结构解析:为什么必须同时保留xml和txt,以及classes.txt才是唯一真相源
2.1 VOC格式xml文件:结构细节与不可替代性
Pascal VOC格式的xml文件是计算机视觉领域事实标准,其结构清晰、语义明确,尤其在跨框架迁移、可视化验证、学术论文复现时具有不可替代性。本数据集的每个xml文件严格遵循VOC 2007规范,核心字段包括:
<filename>:值为xxx.jpg,与images/目录下文件名100%一致(如IMG_00123.jpg),不含任何路径前缀;<size>:包含<width>、<height>、<depth>,其中<depth>恒为3(RGB),所有图片均为标准三通道;<object>块:每个害虫实例一个块,内含<name>(如brown-planthopper)、<bndbox>(<xmin>、<ymin>、<xmax>、<ymax>,像素坐标,左上角为原点);<truncated>与<difficult>:本数据集中二者全部设为0,无截断目标、无难例标记,降低初学者理解门槛。
提示:VOC格式是“可读性锚点”。当你发现YOLO训练结果异常(比如某类召回率极低),直接打开对应xml文件,用浏览器或VS Code查看
<name>和<bndbox>数值,能3秒确认是标注问题还是模型问题——这是txt文件做不到的。
2.2 YOLO格式txt文件:坐标归一化规则与classes.txt的绝对权威地位
YOLO格式的txt文件是训练效率的关键。本数据集每个txt文件严格遵循YOLOv5/v8官方规范:
- 每行代表一个目标框,格式为:
class_id center_x center_y width height; class_id:整数,取值范围0~5,必须且只能与labels/classes.txt文件中对应行号(从0开始)的类别名一致;center_x,center_y,width,height:全部归一化到[0,1]区间,计算公式为:center_x = (xmin + xmax) / (2 * image_width) center_y = (ymin + ymax) / (2 * image_height) width = (xmax - xmin) / image_width height = (ymax - ymin) / image_height- 所有数值保留6位小数(如
0.456789),避免浮点精度丢失引发的训练抖动。
关键点来了:classes.txt是整个YOLO流程的“宪法”。它的内容如下(逐行):
brown-planthopper green-leafhopper leaf-folder rice-bug stem-borer whorl-maggot注意:没有空行、没有BOM头、换行符为LF(Unix风格)。这意味着你在YOLO训练配置文件(如data.yaml)中定义的names字段,必须与此完全一致、顺序完全相同。常见错误是手动重排classes.txt顺序或添加中文注释,这会导致模型把whorl-maggot(第5类)当成brown-planthopper(第0类)学习——后果是模型输出全是褐飞虱。
2.3 目录结构设计:为什么images/和labels/必须同级,且labels/下不嵌套子目录
本数据集采用极简扁平化结构:
rice_pest_dataset/ ├── images/ # 所有5212张.jpg文件在此 ├── labels/ # 所有5212个.txt文件在此 │ └── classes.txt # 唯一类别定义文件 └── annotations/ # 所有5212个.xml文件在此这种设计直击工业部署痛点:
- YOLO训练脚本(如
train.py)默认读取images/和labels/同名文件(IMG_001.jpg→labels/IMG_001.txt),无需额外映射逻辑; - VOC工具链(如
pascal_voc.py)默认从annotations/读xml,路径无歧义; - 严禁将txt文件按类别分到
labels/brown-planthopper/等子目录——这会迫使你重写数据加载器,增加3小时调试成本; - 严禁在
images/下建train/val/test子目录——本数据集未做划分,划分逻辑应由训练代码控制(如torch.utils.data.random_split),而非靠文件系统隔离。
我一般会在项目初始化时执行一次校验:
# 校验images/与labels/文件名是否完全一致(忽略扩展名) diff <(ls images/ | sed 's/\.jpg$//' | sort) <(ls labels/ | sed 's/\.txt$//' | sort) # 若无输出,说明一一对应;若有差异,立即停下手头工作,先修复文件名这行命令是我写进每个农业AI项目的precheck.sh里的第一行——它比任何文档都可靠。
3. 双格式一致性校验:用Python脚本自动揪出xml与txt的3类隐性错位
3.1 校验脚本核心逻辑:从xml反推txt,再比对原始txt
光看文件数量相等(5212=5212=5212)远远不够。真正的坑藏在细节里:xml里标了3个框,txt里却只有2行;xml里<name>是whorl-maggot,txt里class_id却是4(对应stem-borer);xml坐标越界(xmax > image_width)导致归一化后width > 1。以下脚本一次性扫清这三类问题:
# validate_voc_yolo_consistency.py import os import xml.etree.ElementTree as ET from pathlib import Path def parse_xml(xml_path, class_to_id): """从xml提取所有框,返回[class_id, cx, cy, w, h]列表""" tree = ET.parse(xml_path) root = tree.getroot() size = root.find('size') img_w = int(size.find('width').text) img_h = int(size.find('height').text) boxes = [] for obj in root.findall('object'): name = obj.find('name').text.strip() if name not in class_to_id: raise ValueError(f"XML {xml_path.name}: unknown class '{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) # 坐标合法性检查 if xmin < 0 or ymin < 0 or xmax > img_w or ymax > img_h or xmin >= xmax or ymin >= ymax: raise ValueError(f"XML {xml_path.name}: invalid bbox [{xmin},{ymin},{xmax},{ymax}] for {img_w}x{img_h}") # 转YOLO格式(归一化) cx = (xmin + xmax) / (2 * img_w) cy = (ymin + ymax) / (2 * img_h) w = (xmax - xmin) / img_w h = (ymax - ymin) / img_h boxes.append([class_to_id[name], cx, cy, w, h]) return boxes def parse_txt(txt_path): """从txt提取所有框,返回[class_id, cx, cy, w, h]列表""" boxes = [] with open(txt_path, 'r') as f: for line in f: parts = line.strip().split() if len(parts) != 5: continue # 跳过空行或格式错误行 class_id = int(parts[0]) cx, cy, w, h = map(float, parts[1:5]) boxes.append([class_id, cx, cy, w, h]) return boxes def main(): dataset_root = Path("rice_pest_dataset") # 替换为你的解压路径 images_dir = dataset_root / "images" labels_dir = dataset_root / "labels" annotations_dir = dataset_root / "annotations" # 读取classes.txt构建映射 classes_path = labels_dir / "classes.txt" with open(classes_path, 'r') as f: classes = [line.strip() for line in f if line.strip()] class_to_id = {cls: i for i, cls in enumerate(classes)} errors = [] for img_path in images_dir.glob("*.jpg"): base_name = img_path.stem xml_path = annotations_dir / f"{base_name}.xml" txt_path = labels_dir / f"{base_name}.txt" # 检查文件存在性 if not xml_path.exists(): errors.append(f"Missing XML: {xml_path}") continue if not txt_path.exists(): errors.append(f"Missing TXT: {txt_path}") continue try: xml_boxes = parse_xml(xml_path, class_to_id) txt_boxes = parse_txt(txt_path) # 框数量对比 if len(xml_boxes) != len(txt_boxes): errors.append(f"Count mismatch {base_name}: XML={len(xml_boxes)}, TXT={len(txt_boxes)}") continue # 逐框比对(允许1e-5浮点误差) for i, (xml_box, txt_box) in enumerate(zip(xml_boxes, txt_boxes)): if abs(xml_box[0] - txt_box[0]) > 1e-5: # class_id errors.append(f"Class ID mismatch {base_name} box{i}: XML={xml_box[0]}, TXT={txt_box[0]}") for j in range(1, 5): # cx,cy,w,h if abs(xml_box[j] - txt_box[j]) > 1e-5: errors.append(f"Coord mismatch {base_name} box{i} dim{j}: XML={xml_box[j]:.6f}, TXT={txt_box[j]:.6f}") except Exception as e: errors.append(f"Parse error {base_name}: {str(e)}") if errors: print("=== CONSISTENCY ERRORS FOUND ===") for err in errors[:20]: # 只显示前20个,避免刷屏 print(err) print(f"... and {len(errors)-20} more errors") return False else: print("✅ All VOC and YOLO files are perfectly consistent!") return True if __name__ == "__main__": main()参数说明与使用逻辑:
dataset_root:指向解压后的根目录,脚本会自动遍历images/下所有.jpg,并推导对应的.xml和.txt路径;class_to_id映射严格依赖labels/classes.txt的行序,确保whorl-maggot永远是5;- 坐标比对采用
1e-5容差,覆盖浮点计算微小差异,但拒绝0.123456vs0.123457这种量级偏差; - 错误信息精确到
box{i},方便定位具体哪一行标注出错。
运行后若输出✅ All ... consistent!,说明你可以放心进入训练阶段;若报错,不要跳过——哪怕只有一处Class ID mismatch,也意味着整个类别的学习目标已错乱,训100轮也是白费。
3.2 为什么不能只信txt文件?——YOLO格式的三大脆弱性
YOLO格式虽高效,但天生脆弱:
- 无图像尺寸记录:txt文件里只有归一化坐标,不知道原始图像是
1920x1080还是640x480。一旦训练时imgsz参数设错(如用640训1920图),模型会学废; - 无类别语义:
class_id=3本身不告诉你这是rice-bug还是stem-borer,全靠classes.txt外部约定,而约定极易被覆盖或误改; - 无目标存在性证明:txt文件可以为空(0行),但无法告诉你“这张图里真的没有害虫”,还是“标注员漏标了”。而xml文件里
<object>块的有无,是人工标注意图的直接证据。
因此,我的工作流永远是:用xml做ground truth校验,用txt做训练输入,用classes.txt做唯一ID源。三者缺一不可,但信任权重是xml > classes.txt > txt。
4. 避坑:水稻虫害数据集实操中踩过的5个真实坑及血泪解决方案
4.1 现象:YOLO训练时Loss震荡剧烈,mAP@0.5在0.1~0.3之间反复横跳
原因:classes.txt文件末尾有多余空行,导致len(names)为7而非6,模型内部类别数错配。YOLOv8在build_targets()中按nc=7分配内存,但实际标签只有0~5,造成张量越界和梯度爆炸。
解决:用vim -b classes.txt检查二进制结尾,删除所有空行;或执行sed -i '/^$/d' labels/classes.txt(Linux/macOS);Windows用户用Notepad++ → “编辑”→“行操作”→“删除空行”。
4.2 现象:验证时大量预测框集中在图像边缘,且conf值异常高(>0.95)
原因:xml文件中<xmin>或<ymin>被误标为负数(如-5),归一化后cx/cy超出[0,1]范围,YOLO损失函数(CIoU)对越界框产生巨大惩罚,模型被迫“学会”把框打在边缘来规避惩罚。
解决:运行3.1节校验脚本,它会在parse_xml()中直接抛出ValueError;手动修复xml:将负值改为0,并确保xmax>xmin、ymax>ymin。
4.3 现象:val.py评估时提示KeyError: 'whorl-maggot',但classes.txt里明明有这一行
原因:classes.txt文件编码为UTF-8 with BOM(Windows记事本默认),Python读取时line.strip()无法清除BOM头(\ufeff),导致'whorl-maggot'实际为'\ufeffwhorl-maggot',字典匹配失败。
解决:用VS Code打开classes.txt,右下角点击编码(如“UTF-8 with BOM”),选择“Save with Encoding”→“UTF-8”;或用Python一键转换:
with open("labels/classes.txt", "r", encoding="utf-8-sig") as f: content = f.read() with open("labels/classes.txt", "w", encoding="utf-8") as f: f.write(content)4.4 现象:训练几轮后GPU显存OOM,但batch_size=8在其他数据集上正常
原因:部分jpg图片为CMYK色彩模式(常见于扫描仪直出图),OpenCV/PIL读取后自动转为4通道,YOLO数据加载器未做通道裁剪,导致显存占用翻倍。
解决:批量检查并转换:
# Linux/macOS:找出非RGB图 find rice_pest_dataset/images -name "*.jpg" -exec identify -format "%f %m %Q\n" {} \; | grep -v "RGB 8" # 对CMYK图批量转RGB mogrify -colorspace RGB rice_pest_dataset/images/*.jpg注意:
mogrify会直接修改原图,操作前务必备份!
4.5 现象:模型在测试集上对leaf-folder召回率接近0,但训练日志显示该类loss正常
原因:leaf-folder在classes.txt中拼写为leaf_folder(下划线),而xml中为leaf-folder(短横线),导致class_to_id映射失败,所有该类框在parse_xml()中被raise ValueError拦截,实际参与训练的框数为0。
解决:校验脚本3.1节已覆盖此场景,报错信息为unknown class 'leaf-folder';统一修正为短横线(与标题、摘要描述一致),并确保classes.txt、xml、训练代码names三处完全一致。
5. 训练启动与效果验证:从解压到mAP提升的完整闭环,附YOLOv8配置速查表
5.1 5分钟启动YOLOv8训练:最小可行配置
假设你已安装ultralytics(pip install ultralytics),解压数据集到./rice_pest_dataset,按以下步骤操作:
第一步:编写data.yaml
# rice_pest_data.yaml train: ../rice_pest_dataset/images # 注意:这里是相对路径,相对于yolov8/train.py所在位置 val: ../rice_pest_dataset/images # 本数据集未划分,val即全部用于验证(或自行切分) nc: 6 # number of classes names: ["brown-planthopper", "green-leafhopper", "leaf-folder", "rice-bug", "stem-borer", "whorl-maggot"]关键点:
train和val路径必须指向images/目录(不是./rice_pest_dataset),因为YOLOv8默认从images/找图、从labels/找txt(同级目录)。
第二步:启动训练(CPU/GPU自适应)
# 使用YOLOv8n(nano)快速验证流程,10分钟出结果 yolo detect train data=rice_pest_data.yaml model=yolov8n.pt epochs=50 imgsz=640 batch=16 device=0 # 若需更高精度,换yolov8m(medium) yolo detect train data=rice_pest_data.yaml model=yolov8m.pt epochs=100 imgsz=1280 batch=8 device=0imgsz=640:对水稻田间图足够,若图像细节丰富(如茎螟幼虫特写),可升至1280;batch=16:根据GPU显存调整,RTX 3090可跑batch=32,GTX 1660建议batch=8;device=0:指定GPU编号,多卡时用device=0,1。
第三步:验证与可视化
训练完成后,runs/detect/train/weights/best.pt即为最佳权重。验证:
yolo detect val model=runs/detect/train/weights/best.pt data=rice_pest_data.yaml结果生成在runs/detect/val/,关键文件:
results.csv:包含metrics/mAP50-95(B)(主指标)、metrics/mAP50(B)、各类别AP;confusion_matrix.png:直观看出whorl-maggot是否常被误判为leaf-folder;val_batch0_pred.jpg:随机抽取的预测样例,肉眼判断框准不准。
5.2 YOLOv8关键参数速查表:水稻虫害场景下的推荐值
| 参数 | 默认值 | 水稻场景推荐值 | 为什么这样设 |
|---|---|---|---|
imgsz | 640 | 640(初训)或1280(精调) | 水稻害虫常小而密集,1280能保留更多纹理细节,但显存翻倍 |
batch | 16 | 8~32(依GPU而定) | batch=16在RTX 3090上稳定,batch=8在GTX 1660上避免OOM |
epochs | 100 | 50~150 | 数据集5212张属中等规模,50轮可得baseline,100轮收敛,150轮防过拟合 |
lr0(初始学习率) | 0.01 | 0.005~0.01 | 农业数据噪声略高,稍低学习率更稳;若loss下降慢,可试0.01 |
optimizer | auto | auto(AdamW) | AdamW对小目标检测更鲁棒,无需手动切SGD |
rect(矩形训练) | False | True | 开启后batch内图像按长宽比分组填充,减少无效黑边,提升小目标密度 |
mosaic(马赛克增强) | 1.0 | 0.5~1.0 | 全开(1.0)可能破坏水稻叶片连续性,0.5更稳妥 |
提示:
rect=True是水稻数据的隐藏加速器。它让同一batch内图像按aspect_ratio分组(如所有4:3图一组),填充时只补短边,避免1920x1080图被压成640x360导致害虫变糊。
5.3 效果验证三板斧:不止看mAP,更要盯住农业场景真需求
mAP只是起点,农业落地要看三件事:
- 单图推理速度:用
yolo detect predict测time(ms),田间设备要求<100ms/图(30FPS); - 小目标召回率:重点看
whorl-maggot和brown-planthopper的AP@0.5,它们体长常<20像素; - 误报容忍度:打开
val_batch0_pred.jpg,检查是否有大量“把叶脉当害虫”的误框——这反映模型是否学到本质特征。
我每次训完必做:
- 在
val_batch0_pred.jpg上用红圈标出所有conf>0.7但明显错的框; - 统计这些框的
class_id分布,若rice-bug误报最多,说明数据集中rice-bug与leaf-folder的形态相似样本不足,需针对性增补; - 用
cv2.resize()把预测图缩放到手机屏大小(如1080x2340),模拟农户手持查看效果——框太小看不清,就是不合格。
从那以后我每次拿到新农业数据集,都强制走一遍3.1节的校验脚本+4.1~4.5的避坑清单,再启动训练。省下的不是时间,是半夜三点对着loss曲线发呆的崩溃感。希望帮到你。
本文还有配套的精品资源,点击获取