FEATURED · 精选文章

芒果害虫检测数据集VOC+YOLO双格式:从解压清洗到YOLOv8训练

发布时间 / 2026/9/15 3:43:22
来源 / 创域科博编辑部
栏目 / 资讯中心
芒果害虫检测数据集VOC+YOLO双格式:从解压清洗到YOLOv8训练 简介一份面向农业害虫检测与目标检测模型训练的高质量数据集涵盖芒果生长过程中常见的10类害虫包括象鼻虫、甲虫、蚱蜢、芒果叶蝉、芒果粉蚧、蛾、锯蝇、蛞蝓、钻心虫及黄蜂等。数据采用Pascal VOC与YOLO两种主流标注格式每张图片均配套对应的xml与txt标注文件共3575对可直接用于YOLO、Faster R-CNN等常见检测框架的训练与验证。包内共2000个文件以xml标注文件为主另附使用说明txt全部内容压缩为191.04MB的7z包结构简洁便于下载后快速迁移至项目目录。目前已有222人学习使用适合计算机视觉方向的开发者、农业科研人员及算法入门者用来完成害虫识别模型训练、数据增强实践或模型性能对比等任务。整理方按统一命名规则组织图片与标注方便构建自定义数据集或扩展新类别具有较强的实用性与复用价值。1. 芒果害虫检测数据集VOCYOLO双标注一份能直接衔接YOLO训练的数据资产第一次拿到芒果害虫检测数据集VOCYOLO格式3575张10类别.7z时别急着解压。文件名里已经把最有价值的信息写在第一行数据量3575张、类别数10、标注格式同时给了Pascal VOC和YOLO。这意味着你大概率不需要从零开始做转换也能直接把它喂给YOLOv5/YOLOv8。这类数据集在农业害虫检测项目里的典型场景是果园部署摄像头对疑似害虫做实时告警先跑通一个最小可用的检测逻辑。下面按“解压确认格式 → 重新划分数据 → 训练调参 → 验证迭代”的顺序讲每步都有能直接复制的命令。2. 解压、盘点和理清格式芒果害虫检测数据集的VOC与YOLO目录结构2.1 先解压 7z 包Linux 和 Windows 下最不容易出错的命令# 先装 p7zipDebian/Ubuntu 系 sudo apt install p7zip-full 7z x 芒果害虫检测数据集VOCYOLO格式3575张10类别.7z7z x会保持压缩包里的目录结构解出来的路径和打包时一致。如果手误写成7z e所有文件会被平铺到当前目录JPEGImages 和 labels 里的同名文件就会互相覆盖所以统一用x。解压前可以先用7z l 包名.7z看一眼顶层目录心里有数后再操作。Windows 下用 7-Zip 图形界面右键“提取到当前文件夹”即可也可以用同一套 7z 命令行。挂载在共享目录时如果遇到中文文件名乱码先把包名改成mango_pest.7z再解压能少踩一个坑。2.2 VOC 与 YOLO 标注体系一份图两种坐标语言格式文件位置每张图对应文件坐标定义VOCAnnotations/xxx.xmlobjectname类名/namebndbox…/bndbox/objectxmin/ymin/xmax/ymax单位是像素坐标原点在图像左上角YOLOlabels/xxx.txt每行一个目标class_id cx cy w h中心点坐标、宽高全部除以图像宽高归一化到 0~1VOC 格式便于可视化、转 COCO也适合直接用 LabelImg 二次编辑YOLO 格式则可以被 darknet、Ultralytics 等训练框架直接读取省去每次训练前的转换。题目里同时提供两种格式意味着你可以随时用 VOC 标注反向校验 YOLO 标签是否被改坏这是很多单格式数据集不具备的便利。2.3 写一个盘点脚本3575 张图、10 个类别是否真的能对上import os from collections import Counter labels_dir labels classes_file classes.txt with open(classes_file) as f: names [line.strip() for line in f if line.strip()] print(类别数:, len(names)) print(类别列表:, names[:10]) targets Counter() images 0 empty 0 total_boxes 0 for fn in os.listdir(labels_dir): if not fn.endswith(.txt): continue images 1 path os.path.join(labels_dir, fn) lines [line.strip() for line in open(path) if line.strip()] if not lines: empty 1 for line in lines: parts line.split() if len(parts) 5: continue cls_id int(parts[0]) if cls_id len(names): print(f越界类别: {fn} - {cls_id}) targets[cls_id] 1 total_boxes 1 print(含标注图片数:, images) print(空txt数:, empty) print(总目标框数:, total_boxes) for i in range(len(names)): print(f {names[i]}: {targets.get(i, 0)})classes.txt 的行号就是 YOLO 类别 idYOLO 标注第一列必须是整数类别 id。脚本统计了空 txt 和越界 id能快速发现划分错误。如果解压后的 labels 目录同时包含train/labels和val/labels要把代码里的labels_dir改成对应路径分别运行或者合并统计。图像数量可以用find Images -type f | wc -l核对如果图像数和含标注图片数不一致说明有一部分图没有标签训练前需要单独处理。3. 从VOC转YOLO到跑通训练YOLOv8训练芒果害虫检测的最小方案3.1 为什么有了YOLO标注仍要保留VOC转YOLO的能力这个数据集虽然给了双格式但 YOLO 目录可能只按 train/val 粗分类别顺序也可能被重构过或者 labels 里带有历史脏数据。保留转换脚本可以随时从干净的 XML 重建 YOLO 标签避免被已有错误标签带偏。VOC 转 YOLO 的数学本质是归一化先读出xmin,ymin,xmax,ymax再计算cx(xminxmax)/2/widthcy(yminymax)/2/heightw(xmax-xmin)/widthh(ymax-ymin)/height。归一化之后同一份标签可以在不同分辨率下训练模型不会因为输入尺寸变化而重新标框。3.2 写一个最小可用的VOC转YOLO脚本import os import xml.etree.ElementTree as ET # 从classes.txt读类别名保证和YOLO id一致 with open(classes.txt) as f: classes [line.strip() for line in f if line.strip()] def voc_to_yolo(xml_file, out_file): tree ET.parse(xml_file) root tree.getroot() img_w int(root.find(size/width).text) img_h int(root.find(size/height).text) lines [] for obj in root.findall(object): name obj.find(name).text if name not in classes: continue obj_id classes.index(name) box obj.find(bndbox) xmin float(box.find(xmin).text) ymin float(box.find(ymin).text) xmax float(box.find(xmax).text) ymax float(box.find(ymax).text) xmin max(0, min(xmin, img_w)) ymin max(0, min(ymin, img_h)) xmax max(0, min(xmax, img_w)) ymax max(0, min(ymax, img_h)) if xmax xmin or ymax ymin: continue cx (xmin xmax) / 2.0 / img_w cy (ymin ymax) / 2.0 / img_h w (xmax - xmin) / img_w h (ymax - ymin) / img_h lines.append(f{obj_id} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) with open(out_file, w) as f: f.write(\n.join(lines)) for xml in os.listdir(Annotations): if not xml.endswith(.xml): continue voc_to_yolo(os.path.join(Annotations, xml), os.path.join(labels, xml.replace(.xml, .txt)))这里的关键参数是classes的顺序classes.index(name)直接依赖 classes.txt 的行顺序如果顺序和 VOC 的name标签不匹配会整类串位。所以脚本跑完后不要直接训练先做一次反向校验读回几个 YOLO txt把中心点坐标还原成像素框去和原 XML 比对。越界裁剪用max/min限制在图像范围内宽高为负的框会被过滤避免后续训练步骤报“boxes have zero size”之类的错误。3.3 配置 mango.yaml 并跑起 YOLOv8 训练# mango.yaml path: /绝对路径/解压目录 train: images/train val: images/val nc: 10 # 类别名按 classes.txt 实际内容替换顺序不能乱 names: 0: class0 1: class1 2: class2 3: class3 4: class4 5: class5 6: class6 7: class7 8: class8 9: class9yolo detect train datamango.yaml modelyolov8s.pt epochs100 imgsz640 batch16 projectruns_mango nameexp1参数建议值原因modelyolov8s.pt3575 张图不算多s 比 n 准比 m 快先跑通再升级epochs100 左右观察 mAP 不再涨就可以停不必硬跑完imgsz640 或 1280害虫通常偏小1280 对小目标友好但显存占用翻倍batch16 或 32根据显卡显存调整16G 显存用 16 更稳训练日志里会实时打印 box_loss、cls_loss、dfl_loss这三项对应 YOLO 损失函数的回归损失、分类损失和 DFL 分布损失。如果三者持续下降但 mAP 不动先检查数据划分如果 loss 震荡明显把 lr0 从默认 0.01 降到 0.005或者把 mosaic 关闭到后 20 个 epoch。如果你还不确定现在 YOLO 已经出到第几代不影响这个流程v5 到 v8 的配置文件写法基本一致数据集本身不会因为模型版本失效。4. 芒果害虫检测数据集的样本质量分析统计、清洗与增强4.1 统计每类目标数、目标尺寸和长宽比定位10类别的不平衡import glob import numpy as np class_count np.zeros(10) size_list [] wh_ratio [] img_count 0 for txt in glob.glob(labels/*.txt): img_count 1 for line in open(txt): parts line.strip().split() if len(parts) 5: continue cls int(parts[0]) w float(parts[3]) h float(parts[4]) class_count[cls] 1 size_list.append((w h) / 2) wh_ratio.append(w / max(h, 1e-6)) print(每张图平均目标数:, class_count.sum() / img_count) print(相对面积均值:, np.mean(size_list)) for i in range(10): print(fclass {i}: {class_count[i]})size_list存的是归一化后目标宽高的平均值数值 0.02 意味着目标面积只占原图的千分之几级别很典型的小目标场景。长宽比极端的目标说明叶片上的害虫姿态细长训练时不能只靠随机缩放。如果某个类只有几十个框而其他类有上千个框后面的类别 AP 会被严重拖低不要只用总 mAP 判断数据好坏。4.2 清洗坏标签越界框、空文件、类id越界import os for name in os.listdir(labels): path os.path.join(labels, name) lines [] for line in open(path): parts line.split() if len(parts) ! 5: continue cls int(parts[0]) cx, cy, w, h map(float, parts[1:]) if w 0 or h 0: continue cx max(0.0, min(1.0, cx)) cy max(0.0, min(1.0, cy)) w max(1e-6, min(1.0, w)) h max(1e-6, min(1.0, h)) lines.append(f{cls} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) with open(path, w) as f: f.write(\n.join(lines))这个清洗脚本会把所有坐标 clip 到 [0,1] 区间过滤掉宽高为负的行。注意 clip 只能保证训练不崩如果原始框本身就错位clip 后仍然错位。建议在执行前先备份 labels 目录清洗后挑几张图把 YOLO 框画回原图人眼确认不是大面积错框。4.3 用数据增强和超参数放大3575张图的价值参数典型值对芒果害虫场景影响hsv_h0.015模拟不同光照下的叶色变化hsv_s0.7应对清晨阳光导致的饱和度偏移hsv_v0.4模拟逆光和遮阴degrees15摄像头安装角度随机旋转translate0.1目标在画面中的位置变化scale0.5模拟摄像头远近fliplr0.5镜像翻转不影响害虫语义mosaic1.0四图拼接有利小目标训练yolo detect train datamango.yaml modelyolov8s.pt epochs150 imgsz1280 batch8 hsv_h0.02 degrees10 scale0.8数据增强不是越大越好。degrees30以上会把芒果叶片旋得不像自然场景scale1.5会把目标放大到覆盖全图模型学到的是“大虫”而非“虫”。建议先按表里的典型值训练一个 baseline再逐项调大观察验证集 mAP。如果训练时间充足把mosaic1.0保留到最后一个 epoch 前关闭能让模型适应正常构图。如果显卡显存不够跑imgsz1280可以把原图切块后再训练效果通常比强制缩小全图更好。5. 验证芒果害虫检测模型从混淆矩阵到类别AP再切入工检查5.1 训练结束后先跑一次 val把混淆矩阵和人眼抽查放在同一屏yolo detect val datamango.yaml modelruns_mango/exp1/weights/best.pt跑完看runs_mango/exp1/下的confusion_matrix.png和confusion_matrix_normalized.png。别只看最后输出的整体 mAP50混淆矩阵里对角线之外的亮块才是真正需要关心的最亮的非对角格代表哪两个类互相认错。同时翻出val_batch1_pred.jpg人眼扫一遍能区分是标注错、小目标漏检还是遮挡。5.2 用类别 AP 列表定位拖后腿的类再决定下一步from ultralytics import YOLO model YOLO(runs_mango/exp1/weights/best.pt) metrics model.val(datamango.yaml, splitval) # 每个类别的 mAP50 存在 box.maps 里顺序与 data.yaml 中 names 一致 for i, name in enumerate(model.names.values()): print(fAP50 {name}: {metrics.box.maps[i]:.3f})不同版本字段名可能从box.maps变成box.ap但思路不变。如果两个类的 AP 都低且混淆矩阵显示互相错认说明视觉特征接近优先考虑把这两个类合并成一个超类重新训练如果只有某个类 AP 低且目标数很少回到第 4 章对该类做针对性增强或者单独切大图训练一个二分类模型再融合。5.3 一个能提升小目标漏检的验证技巧切 patch 后重新预测对 3575 张原始图训练出的模型常常在果蝇这类小目标上漏检。常见做法是验证时先把大图切成不重叠的 patch对每个 patch 预测再按坐标拼回原图mAP 能提升好几个点。切 patch 的边长取训练时imgsz的 1.5 到 2 倍重叠率 0.2先把置信度低却可能是目标的框留下来最后用 NMS 合并。本文还有配套的精品资源点击获取
RELATED — 相关阅读

相关资讯

LATEST — 最新资讯

最新发布

TODAY — 本日精选

新闻

WEEKLY — 本周精选

新闻

MONTHLY — 本月精选

新闻