
简介面向农业害虫监测、生态研究与目标检测方向学习者这套小绿叶蝉目标检测标注数据以VOC与YOLO两种主流格式整体交付免去自行转换与整理标注的环节可直接用于Faster R-CNN、SSD等模型训练、验证及mAP指标评估。压缩包共274个文件约12.81MB其中134张jpg图像、67个xml标注、71个txt标签、1个yaml配置文件及1个cache文件VOC格式下JPEGImages与Annotations对应存放YOLO格式下images与labels配套齐全并已划分好train.txt、val.txt方便直接送入训练框架。目前已有92人学习下载适合需要标准数据集开展计算机视觉入门实践、迁移学习微调或农业害虫自动识别实验的开发者可基于标注内容确认小绿叶蝉的类别与边界框快速搭建完整训练流程。1. 小绿叶蝉目标检测数据集.zip解压前先想清一个问题“小绿叶蝉目标检测数据集.zip”这个标题翻译过来其实是一句话给我一批茶园里拍的图像图像里标注好小绿叶蝉的位置我要拿它训练一个目标检测模型。小绿叶蝉是茶园里最难缠的害虫之一成虫体长也就三毫米嫩绿色喜欢吸食茶树嫩梢的汁液测报员顶着太阳数黄板上的虫口数又累又容易数漏。这个数据集要解决的就是把“数虫”这件事自动化虫情测报灯拍照、模型自动检测、统计虫口数量再决定要不要用药。适合读这篇文章的人是准备拿这类农业数据集训练模型的工程师、做虫情监测设备的开发者以及想把计算机视觉落到田间的学生。数据集的坑不比模型的坑少从压缩包里文件怎么组织到小目标为什么漏检每一步都有容易翻车的细节。2. 拆开小绿叶蝉数据集.zip目录、标注格式与校验三步拿到任何一个目标检测数据集压缩包我一般不会急着解压后直接开训练。先花半小时理清目录结构和标注格式能省后面好几天。小绿叶蝉数据集这类农业检测包最典型的交付形态有两种一种是按YOLO格式整理好的三件套解压就能用另一种是把图片和标注文件混在一起需要自己划分数据集并做格式转换。不管哪种形态核心都是 images 加 labels 的配对关系。2.1 “三件套”目录是最省心的基线先按这个核对按 YOLO 惯例组织的目标检测数据集解压后长这样dataset/ ├── images/ │ ├── train/ │ │ ├── 20250714_tea_001.jpg │ │ ├── 20250714_tea_002.jpg │ │ └── ... │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ │ ├── 20250714_tea_001.txt │ │ └── ... │ ├── val/ │ └── test/ ├── classes.txt └── data.yaml三件套的含义很直白images 里放原始图片labels 里放与图片同名的 .txt 标注文件classes.txt 按行写类别名。如果解压出来的结构和这个基线一致恭喜你省掉了最麻烦的整理环节。但更常见的情况是压缩包里只有一堆 jpg 和一个 annotations 文件夹里面是 XML 格式的标注那就得先做格式转换再谈训练。下表是我处理过几种常见数据包结构后的判断依据交付形态目录特征训练前要做的处理YOLO三件套images/train 与 labels/train 配对可直接使用先做校验VOC 单目录JPEGImages Annotations写一次 voc2yolo 转换脚本未划分混合图片和标注按拍摄场次分散先按批次划分 train/val/test多类混杂除小绿叶蝉外还有其他害虫类别决定保留下全部类别还是只取目标类还有一种容易踩的情况压缩包解压后第一层是一个同名文件夹路径变成小绿叶蝉目标检测数据集/data/...。这个不影响训练但在写 data.yaml 时容易把路径里多写或少写一层。我习惯先把数据集路径提炼成环境变量后面所有脚本都从同一个变量取路径避免因为路径问题查半天。2.2 两种标注格式VOC XML 和 YOLO txt转换就一个公式农业目标检测数据集里VOC 格式出现频率相当高。小绿叶蝉的标注如果是 Pascal VOC每个目标存的是左下角和右下角坐标文件结构大概这样annotation object namesmall_green_leafhopper/name bndbox xmin352/xmin ymin480/ymin xmax387/xmax ymax502/ymax /bndbox /object /annotation而 YOLO 训练要的格式是归一化后的中心点坐标和宽高一行一个目标0 0.1924 0.4593 0.0182 0.0214两个格式之间的坐标转换不需要任何深度学习知识就一个公式cx (xmin xmax) / 2 / image_width cy (ymin ymax) / 2 / image_height w (xmax - xmin) / image_width h (ymax - ymin) / image_height转换脚本我一般这么写import xml.etree.ElementTree as ET from pathlib import Path def voc2yolo(xml_path: Path, out_path: Path): root ET.parse(xml_path).getroot() w float(root.find(size/width).text) h float(root.find(size/height).text) lines [] for obj in root.iter(object): name obj.find(name).text # 只保留小绿叶蝉类别其他标注当作背景 if name ! small_green_leafhopper: continue box obj.find(bndbox) x1 float(box.find(xmin).text) y1 float(box.find(ymin).text) x2 float(box.find(xmax).text) y2 float(box.find(ymax).text) cx, cy (x1 x2) / 2 / w, (y1 y2) / 2 / h bw, bh (x2 - x1) / w, (y2 - y1) / h lines.append(f0 {cx:.6f} {cy:.6f} {bw:.6f} {bh:.6f}) out_path.write_text(\n.join(lines))逻辑说明脚本先读取图片宽高然后遍历 XML 里所有标注框只保留类别名为small_green_leafhopper的目标把角点坐标换算成归一化的中心坐标。这里特别注意类 ID 的写法我默认把类别 ID 写死为 0前提是整份数据集只有小绿叶蝉一类。如果压缩包里还包含其他害虫类别必须先把所有类别名列出来生成 classes.txt再给每个类别分配固定 ID否则后面训练时类别错位就会全乱。2.3 解压后先做三件事CRC校验、缺图检查、中文路径处理压缩包传输过程中可能出现文件损坏或缺失不要等训练报错才回头检查。拿到“小绿叶蝉目标检测数据集.zip”后我习惯按下面三步做第一轮体检。第一步校验压缩包完整性。Python 的 zipfile 可以直接跑测试from zipfile import ZipFile with ZipFile(小绿叶蝉目标检测数据集.zip, r) as zf: bad_file zf.testzip() print(压缩包完整 if bad_file is None else f文件损坏: {bad_file})testzip()会逐个解压内部文件并比对 CRC 校验值返回第一个损坏的文件名。这个检查能提前发现图片缺损避免后期训练到一半报“图像解码失败”。第二步核对图片和标注文件名是否一一对应from pathlib import Path img_names {p.stem for p in Path(images/train).glob(*.jpg)} label_names {p.stem for p in Path(labels/train).glob(*.txt)} print(缺少标注的图片, img_names - label_names) print(缺少图片的标注, label_names - img_names)小绿叶蝉数据集如果拍摄时连拍多张很容易出现某张图片因为模糊被人工删掉了但标注文件没删导致 label 文件比 image 文件多。训练时 YOLO 读取标签时会跳过无标注图片但如果一张图片有标注文件而图片本身缺失训练直接报错。第三步处理中文文件名乱码。zipfile 默认用 cp437 解码文件名如果发布方用 UTF-8 写入Windows 下解压就会出现乱码。兜底方案是用 Python 重新解压并修正编码import zipfile with zipfile.ZipFile(小绿叶蝉目标检测数据集.zip, r) as zf: for item in zf.infolist(): raw_name item.filename try: new_name raw_name.encode(cp437).decode(utf-8) except UnicodeDecodeError: new_name raw_name zf.extract(item, dataset) if new_name ! raw_name: (Path(dataset) / new_name).parent.mkdir(parentsTrue, exist_okTrue) Path(dataset) / new_name # 实际解压后再重命名注意这里只是给出修正思路实际写成代码时要在解压前先创建目录再把解压出来的文件移动到修正后的路径。农业数据集里带中文路径的压缩包比例不低提前处理这一层能省很多莫名其妙的“文件不存在”报错。3. 小绿叶蝉为什么难检小目标、密虫口与绿背景三重夹击很多第一次做农业害虫检测的人会拿通用目标检测的思路直接套下载预训练权重、图片缩放到 640、训练几十个 epoch、看 mAP。放在小绿叶蝉数据集上这套流程大概率翻车。原因不在模型在于这个检测任务本身的三个特殊性。3.1 三毫米的虫体在1920px照片里只有不到二十个像素虫情测报常用的图像分辨率是 1920×1080相机视野大约 30 厘米宽。小绿叶蝉成虫体长约 3 毫米按比例算它在图像里只占 19 个像素左右。这个尺寸是什么概念YOLOv8 的检测头在不同下采样倍数的特征层上工作P3 层 stride 是 8输入 640 像素时特征图是 80×80每个格点要负责原图 8×8 的区域。一只 16×16 像素的虫子在 80×80 特征图上只有 2×2 个格点能响应这意味着检测器能用来判断“这是不是虫”的语义信息非常有限。如果把输入尺寸从 640 提高到 1280同样一只虫子对应特征图上的响应区域会变大漏检率会显著下降。这也是我处理这类小目标数据集时第一个调参方向永远是 imgsz 的原因。对比一下通用目标检测和农业小目标检测的输入设置任务类型典型目标尺寸推荐 imgsz备注通用场景检测100×100 以上640默认配置就够小绿叶蝉检测15~30 像素1280 或原图切片分辨率是首要瓶颈黄板高密度虫口10~20 像素且大量重叠原图 1:1 切片推理配合 SAHI 类工具3.2 黄板上的密集虫口会让 NMS 把相邻目标一锅端黄板诱虫是茶园测报的主流办法。一张黄板上可能粘着上百只小绿叶蝉虫体之间挨得很近框与框的 IoU 经常超过 0.5。模型推理阶段要经过非极大值抑制简单来说就是两个高度重叠的框只保留分数更高的那个。密集虫口场景下相邻虫子的检测框重叠度高后一个直接被抑制掉输出的计数就低于真实虫口数。这是我们做虫口计数时最容易忽略的问题因为 mAP 只衡量检测框画得准不准不直接反映“该数 30 只却只数出 20 只”。解决思路有两个方向一是在训练阶段增加密集场景的样本权重确保标注完全覆盖重叠目标二是在推理阶段调整 NMS 的 IoU 阈值一般从默认的 0.45 提到 0.5 或 0.55让相邻目标更容易同时保留下来。黄板场景还要注意有些虫子被粘住后翅面展开姿态和自然状态差异很大数据标注时要单独把这部分作为一类样本不能完全只取自然姿态。3.3 拟态背景嫩绿虫体长在嫩绿叶上对比度低小绿叶蝉体色淡黄绿茶树嫩芽也是黄绿系。在 RGB 空间里虫体和叶片的颜色距离可能只差十几个灰度级加上自然光的偏色模型很容易把虫身和叶子背景混在一起。这会直接引出数据增强里一个很容易踩的配置HSV 色彩扰动。通用目标检测训练里hsv_h0.015这类参数用来增强颜色鲁棒性但在小绿叶蝉数据集里色相扰动调太大会把本来就和叶子同色系的虫子变得更难区分。我一般会把hsv_h调成 0 或接近 0保留hsv_s和hsv_v的轻微扰动让模型更依赖轮廓和纹理边缘去识别而不是只靠颜色。3.4 叶片边缘、卷曲、阴影都会冒充目标另一个隐藏难点是负样本太像正样本。茶树嫩芽的尖端往往卷曲形状像虫子的侧影叶片反光的水珠在高光下呈现半透明椭圆叶缘阴影也可能在二值化时形成一个“虫形”。如果训练数据里正样本全是背景干净的图像模型很容易学成一个“看到绿色小团块就报警”的误检器。缓解办法是训练集里混入一定比例的背景图也就是不带任何标注框的纯背景图像或者用裁剪干扰物的方式构造负样本。目标检测对负样本的需求不像分类任务那么严格但纯背景图能让模型减少很多低置信度的假正例。4. 用 YOLOv8 把小绿叶蝉数据集跑通划分、yaml 与必调参数数据集结构和难点都摸清楚了接下来是真正的动手环节。我用 YOLOv8 走一遍最小可复现流程按这个顺序做能避开大部分新手踩过的坑。4.1 数据集划分要按拍摄批次不能随机切小绿叶蝉图像通常来自同一批拍摄设备、同一段连续监测时间。如果直接随机划分训练集和验证集同一个黄板同一分钟里拍的几张照片可能一张在训练集、一张在验证集模型相当于看着“参考答案”考试验证集分数虚高换一批实地照片立刻现原形。正确的做法是按拍摄批次划分比如每张照片的文件名带拍摄时间前缀那就按前缀分组再切分from pathlib import Path import random, shutil img_dir Path(origin_images) imgs list(img_dir.glob(*.jpg)) batch_ids {p.stem.split(_)[0] for p in imgs} batch_ids list(batch_ids) random.shuffle(batch_ids) n_val max(1, int(len(batch_ids) * 0.2)) val_ids, train_ids set(batch_ids[:n_val]), set(batch_ids[n_val:]) train_imgs [p for p in imgs if p.stem.split(_)[0] in train_ids] val_imgs [p for p in imgs if p.stem.split(_)[0] in val_ids] print(f训练集 {len(train_imgs)} 张验证集 {len(val_imgs)} 张)逻辑说明先把所有照片按文件名的批次前缀分组再把整个批次随机分到训练区或验证区而不是把单张照片随机打散。这个操作对农业时序数据尤其重要能让验证结果更接近真实部署环境。代码里的split(_)[0]是按“时间戳 序号”的命名规则提取批次号具体分隔符和位置要按你实际的文件命名调整。目录结构准备成下面这样即可leafhopper_tea/ ├── images/ │ ├── train/ │ ├── val/ ├── labels/ │ ├── train/ │ ├── val/ └── data.yaml4.2 一份能直接跑的 data.yaml数据集的类别信息写在一个 yaml 文件里YOLOv8 的训练入口读它来定位图片、标签和类别名称。最小配置如下path: /mnt/data/leafhopper_tea train: images/train val: images/val test: images/test names: 0: small_green_leafhopper注意几个容易出错的点path指数据集根目录train和val是相对path的子目录。如果压缩包解压后目录层级比这个多一层path一定要指到包含 images 和 labels 的那一层。names下面的类 ID 必须从 0 开始连续如果 classes.txt 里小绿叶蝉不是第 0 类要和标注文件里的 ID 对齐而不是看类别名来猜。4.3 训练启动imgsz 提到 1280batch 按显存调节准备好数据和配置后训练命令如下yolo detect train \ dataleafhopper_tea.yaml \ modelyolov8n.pt \ imgsz1280 \ batch8 \ epochs200 \ patience50 \ cacheTrue \ projectleafhopper_exp参数说明参数值说明modelyolov8n.pt先用 nano 跑通确认数据没问题再升级到 s/mimgsz1280小目标数据集的关键参数低于 640 基本不可用batch8按显存调整显存不足降到 4epochs200农业数据集不一定跑满配合早停patience50验证集指标连续 50 轮不涨就自动停cacheTrue内存足够时缓存图像大幅加速小数据集迭代我一般先拿yolov8n跑通流程看训练曲线能不能正常收敛再决定要不要换更大的模型。小绿叶蝉这类目标不大、场景相对固定的数据集nano 和 small 之间的差距没有通用场景里那么明显数据质量的影响远大于模型大小。数据增强参数也要针对性改一下特别是 HSV 扰动yolo detect train \ dataleafhopper_tea.yaml \ modelyolov8n.pt \ imgsz1280 \ batch8 \ epochs200 \ hsv_h0.0 \ hsv_s0.2 \ hsv_v0.2 \ fliplr0.5逻辑说明把色相扰动关掉保留一定比例的饱和度和明度扰动避免“绿虫变黄虫”这种颜色溢出干扰模型学习。左右翻转保留 0.5因为小绿叶蝉的姿态没有左右不对称性这组增强能提升模型对朝向变化的鲁棒性。训练完成后验证时同样要用 1280 的输入尺寸yolo detect val \ modelleafhopper_exp/weights/best.pt \ dataleafhopper_tea.yaml \ imgsz1280如果验证和训练不是同一个 imgsz得到的结果没有参考意义。4.4 小目标漏检严重的补救办法切片推理即使把 imgsz 提高到 12801920 像素的原图里 20 像素的小虫子在缩放后仍然信息不足。常见做法是先切片再推理把一张大图切成几块有小幅重叠的小图分别跑模型再把结果按坐标合并回原图。这个过程不需要重新训练用 Python 的 PIL 就能实现from PIL import Image def detect_on_tiles(model, img_path, tile640, overlap64): img Image.open(img_path) w, h img.size detections [] step tile - overlap for y0 in range(0, h - tile 1, step): for x0 in range(0, w - tile 1, step): crop img.crop((x0, y0, x0 tile, y0 tile)) res model.predict(crop, imgsztile, conf0.25) for box in res[0].boxes: x1, y1, x2, y2 box.xyxy[0].tolist() detections.append((x0 x1, y0 y1, x0 x2, y0 y2, box.conf.item())) return detections逻辑说明遍历原图按 tile 尺寸和 overlap 重叠步长切块每个切块单独推理最后把框坐标偏移回原图坐标系。重叠区域里同一只虫子可能被检测两次后面还要做一次合并按 IoU 超过 0.5 的框取置信度更高的那个。这是小目标检测最实用的一招不需要改模型结构付出的代价只是推理时间成倍增加适合测报场景离线推理。5. 小绿叶蝉目标检测实战避坑解压到部署的四个记录点这一章是我最想让你先看的部分。小绿叶蝉数据集从解压到上线的路上下面这四个坑几乎每个项目都会遇到每一条都按现象、原因、解决三步写清楚。5.1 坑一Windows 下解压压缩包文件名全部乱码现象解压“小绿叶蝉目标检测数据集.zip”后图像文件名变成一串ä¸Â之类的乱码数据加载时报找不到文件。原因压缩包内文件名是 UTF-8 编码写入的Windows 自带解压工具默认按本地语言位 GBK 解码导致文件名彻底错乱。文件本身没有损坏只是路径对不上。解决不要用 Windows 右键的“全部解压缩”改用 7-Zip 解压它能正确识别 UTF-8 标记。如果你已经解压出乱码可以用 Python 把错误编码的文件名修正回来import os for old in os.listdir(.): if à in old: new old.encode(cp437).decode(utf-8) os.rename(old, new)这个操作只处理解压后乱码的文件名。路径修复完成后再用 2.3 节的脚本核对一下图片和标注文件是否一一对应。5.2 坑二classes.txt 和标注里的类别名不一致模型训练了也等于白练现象训练 loss 正常下降但验证阶段模型变成“检测什么都没有”precision 和 recall 全在低位抖动。原因标注文件里写的是tea_leafhopperclasses.txt 里写的是small_green_leafhopper转换脚本按名字过滤后把所有目标都过滤成背景了模型学了个寂寞。解决在训练前写一个类别白名单检查脚本凡是 XML 里的类别名不在预期列表里的直接打印警告并终止而不是静默跳过。同时把 VOC 转 YOLO 脚本里的类别名和 classes.txt 严格绑定不要写死allowed [small_green_leafhopper, tea_leafhopper] for name in allowed: class_id allowed.index(name)这段代码的核心是类别 ID 必须从一个明确的映射表生成不允许标注里冒出新名字。如果数据集里原本混入了其他昆虫类别要么保留全部类别并在 yaml 中补全要么统一过滤不能让过滤行为变成隐式的丢目标。5.3 坑三小目标漏检模型只认大虫子现象训练时 mAP50 到了 0.7但实际部署时对 20 像素以下的小虫基本漏检黄板上的计数误差超过 40%。原因输入尺寸训练时用了 640小虫缩小后特征在深层特征图里只剩 1~2 个格点响应。还有一个常见原因是验证集里大尺寸目标占了多数mAP 指标被大目标拉高了小目标的表现被掩盖。解决训练和推理统一把 imgsz 提到 1280如果还是不够对 1920 宽度的原图做切片推理。切图时 overlap 建议设成 64~128 像素太小会切断目标太大则切块数量翻倍。黄板图像的上下文相对一致overlap64 已经够用。另外评估时单独统计小目标类别的 AP把目标和尺寸分组计算这个指标比总 mAP 更能反映真实可用性。5.4 坑四训练 loss 一路下探但模型在全新照片上基本失效现象训练集和验证集的 loss 都在下降最后验证集 mAP 也不差但拿一批新拍的茶园照片测试检测效果明显变差。原因这是数据泄漏问题。同一个黄板同一时间段拍的连续照片在随机划分时被同时分到了训练集和验证集验证集相当于“开卷考试”。小绿叶蝉是时序拍摄数据这种问题非常隐蔽。解决回到第 4.1 节按拍摄批次划分数据而不是按单张随机划分。特点是把一批连续拍摄的照片看作一个整体整体归属训练集或验证集不允许一批照片内拆散。再进一步如果数据量够最好留出一个跨时间段的测试集例如完全用另一个月的拍摄照片做测试这样可以验证模型在时间维度上的泛化能力。最后拿切片推理后的结果在纯背景图上跑一遍误检率过高的模型大概率要回到数据层面补负样本。6. 从检测框到虫口计数把小绿叶蝉模型用在测报上训练出能用的检测模型只是第一步植保端真正要的是“这块黄板今天有多少只虫”不是一张画满框的图。把检测框转成虫口计数的脚本非常简单import csv from ultralytics import YOLO model YOLO(leafhopper_exp/weights/best.pt) results {} for img_path in sorted(glob(test_imgs/*.jpg)): res model.predict(img_path, imgsz1280, conf0.25, iou0.5) count len(res[0].boxes) results[img_path.stem] count with open(count_result.csv, w, newline) as f: writer csv.writer(f) writer.writerow([image_name, count]) for name, count in results.items(): writer.writerow([name, count])但要注意这个 counts 是“检测到的虫子数量”不是“真实虫口数”。两者之间的差距是漏检加误检。验证方法很直接人工数 10 张图上看到的虫数再对比模型输出算出误差率。小绿叶蝉密集场景下误差率在 20% 以内可接受超过这个数就回到第 5.3 节去调输入尺寸和重叠框合并策略。我自己习惯在跑完任何训练后都做一件事拿 3 张训练集里没有的出图肉眼数一遍框里的目标数量再对照模型输出。这套数下来比看任何 log 曲线都更能判断这个数据集能不能上线。黄色诱虫板这类高密度场景模型输出的计数往往偏小因为没有处理重叠框的抑制问题这类误差不是简单调阈值能救的要在后处理里合并相邻检测框按中心点距离和框尺寸做聚类才能把计数误差压下来。希望这篇笔记能帮你把“小绿叶蝉目标检测数据集.zip”里的数据真正用起来少走几趟弯路。本文还有配套的精品资源点击获取