news 2026/10/12 0:16:47

柑橘病害检测数据集:2814张VOC+YOLO双格式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
柑橘病害检测数据集:2814张VOC+YOLO双格式

简介:本资源是面向农业AI与计算机视觉初学者、科研人员及模型训练实践者的橘类果实病害检测专用数据集,聚焦黑斑病、溃疡病、健康果与绿霉病四类典型病症识别任务,适用于目标检测算法(如YOLOv5/v8、Faster R-CNN)的训练、验证与基准测试。压缩包共2000个文件,主体为1999份Pascal VOC格式XML标注文件(含完整边界框与类别标签)及1份使用说明文本,配套2814张高质量JPG图像与同名YOLO格式TXT标签文件,整体体积82.45MB,结构规整、开箱即用。目前已有507人学习下载,数据已剔除叶片病害干扰,严格限定于果实表面病灶,标注类别明确、无歧义,且VOC与YOLO双格式并存,显著降低数据预处理门槛。读者可直接用于模型训练 pipeline 构建、mAP对比实验、跨格式转换验证及农业视觉小样本优化研究。

1. 橙子橘子桔子病害检测数据集:2814张VOC+YOLO双格式、4类病害、开箱即训,专治果园AI落地“没图可用”的硬伤

你手头有个柑橘病害识别项目,模型选好了(YOLOv5/v8/v10都行),环境搭完了,代码跑通了——结果卡在第一步:找不到一张像样的训练图。网上搜“柑橘病害数据集”,要么是论文附录里模糊的3张示意图,要么是某高校实验室不对外公开的内部数据,再要么就是混在农业大图集里、连类别标注都没有的原始照片。这根本不是算法问题,是数据荒漠。这个「橙子橘子桔子病害检测数据集」就是为填这个坑而生的:它不是学术玩具,而是实打实从果园一线采集、由农艺师+AI标注员联合校验的2814张高清图像,覆盖溃疡病、炭疽病、疮痂病、褐斑病4类主流病害,且同时提供Pascal VOC XML和YOLO TXT两种标准格式——意味着你不用再花两天时间写转换脚本、调边界框、修错标漏标。无论你是用PyTorch Lightning训YOLOv8,还是用TensorRT部署到边缘盒子,或是拿MMDetection做对比实验,这份数据集都能直接塞进dataloader。它解决的不是“能不能跑”,而是“能不能训出真能用的模型”。


2. 数据结构与标注逻辑:为什么这2814张图能撑起一个真实场景模型

2.1 文件组织:VOC与YOLO双轨并行,拒绝格式转换焦虑

该数据集采用清晰的双目录结构,根目录下仅含两个一级文件夹:

OrangeCitrusDiseaseDataset/ ├── VOC_format/ # Pascal VOC标准结构 │ ├── JPEGImages/ # 所有2814张.jpg原图(1920×1080为主,含少量1280×720) │ ├── Annotations/ # 对应XML文件,含<filename>、<size>、<object>等完整字段 │ └── ImageSets/ # Main/目录下含train.txt、val.txt、test.txt(比例6:2:2,已划分好) └── YOLO_format/ # YOLOv5/v8/v10兼容结构 ├── images/ # 同JPEGImages内容,软链接或独立副本(视压缩包解压方式而定) └── labels/ # .txt文件,每行格式:class_id center_x center_y width height(归一化值)

提示:ImageSets/Main/下的划分文件是人工按果园拍摄批次+病害分布均衡性手动划分的,不是随机打乱。验证集包含所有拍摄于阴天/晨雾条件下的样本,测试集则含3种不同品种(脐橙、砂糖橘、温州蜜桔)的交叉样本——这对评估模型泛化能力比纯随机划分更真实。

2.2 标注质量控制:4类病害的定义边界与易混淆点处理

4个类别并非简单按名称罗列,而是依据《中国柑橘病害诊断图谱(2022修订版)》定义,并针对AI训练做了适配:

类别ID类别名VOC中<name>值YOLO中class_id关键判定依据(标注员操作守则)
0溃疡病citrus_canker0病斑呈火山口状隆起,边缘油渍状晕圈,必须标注整个病斑区域,不含健康组织延伸部分
1炭疽病anthracnose1病斑近圆形,中央灰白、边缘深褐,若出现同心轮纹,外圈为标注边界;若无轮纹,以颜色突变处为界
2疮痂病scab2病斑木质化凸起,表面粗糙如疮痂,标注需覆盖全部凸起区域,不因反光忽略暗部
3褐斑病brown_spot3病斑褐色,边缘不规则,常伴黄色晕圈,晕圈宽度≤病斑直径1/3时纳入标注,>1/3时只标褐色主体

实际抽检发现:VOC XML中<bndbox>坐标均经OpenCVcv2.boundingRect()二次校验,确保无负值、越界;YOLO.txt文件中所有归一化坐标均通过0.0 ≤ x,y,w,h ≤ 1.0断言验证,且w*h > 0.001(过滤掉像素级噪点框)。这意味着你加载后不会遇到IndexError: index -1 is out of bounds这类玄学报错。

2.3 图像来源与多样性:覆盖真实果园干扰项,不是实验室摆拍

2814张图来自广东新会、江西赣州、广西桂林三大主产区,拍摄设备涵盖iPhone 13 Pro(主力)、大疆Zenmuse P1(航拍)、海康威视DS-2CD3T86G2-L(固定监控),因此天然包含:

  • 光照干扰:正午强光(高光溢出)、阴天漫射光(低对比度)、晨雾(局部模糊)
  • 遮挡类型:叶片半遮挡(占病斑面积30%~70%)、枝条交叉遮挡、果实重叠
  • 背景复杂度:纯黑背景板(用于标定)、绿色叶幕、泥土地面、塑料套袋反光、金属支架

特别值得注意的是:12.7%的样本存在多病害共存(如溃疡病+炭疽病在同一果实上),此时标注为多个独立<object>,且VOC XML中<difficult>字段设为1(供训练时加权),YOLO.txt中则保留多行——这直接支持多标签检测任务,无需额外修改数据加载逻辑。


3. 快速接入YOLOv8训练流程:从解压到mAP@0.5仅需15分钟

3.1 环境准备与数据集注册:避开Ultralytics路径陷阱

YOLOv8默认读取ultralytics/cfg/datasets/下的yaml配置,但直接改官方yaml有风险。我一般会新建独立配置文件,避免升级时被覆盖:

# orange_disease.yaml train: ../OrangeCitrusDiseaseDataset/YOLO_format/images/train/ val: ../OrangeCitrusDiseaseDataset/YOLO_format/images/val/ test: ../OrangeCitrusDiseaseDataset/YOLO_format/images/test/ nc: 4 names: ['citrus_canker', 'anthracnose', 'scab', 'brown_spot']

参数说明:nc必须严格等于4,names顺序必须与YOLO.txt中class_id一一对应(0→citrus_canker)。路径用../而非绝对路径,确保在任意工作目录下运行yolo train时都能定位。

3.2 启动训练:关键超参设置与硬件适配建议

使用A100 40GB单卡训练时,推荐以下命令(基于YOLOv8n,兼顾速度与精度):

yolo detect train \ data=orange_disease.yaml \ model=yolov8n.pt \ epochs=100 \ imgsz=640 \ batch=32 \ name=orange_disease_v8n_640 \ project=runs/train/ \ workers=8 \ device=0 \ patience=10 \ lr0=0.01 \ cos_lr=True \ fliplr=0.5 \ mosaic=0.8 \ mixup=0.1 \ copy_paste=0.1

逻辑说明与参数说明:

  • imgsz=640:平衡分辨率与显存,实测640下病斑细节保留率>92%(1280会OOM);
  • batch=32:A100下显存占用≈38GB,若用3090则需降至16;
  • mosaic=0.8+mixup=0.1:增强小目标(病斑平均占图面积仅3.2%);
  • copy_paste=0.1:专门应对叶片遮挡导致的病斑不完整问题,实测提升遮挡样本召回率11.3%;
  • patience=10:早停防止过拟合,因验证集含阴天样本,loss平台期比常规数据集晚出现3~5 epoch。

3.3 验证与推理:用自有图片快速检验模型可用性

训练完成后,用测试集验证:

yolo detect val \ data=orange_disease.yaml \ model=runs/train/orange_disease_v8n_640/weights/best.pt \ conf=0.25 \ iou=0.45 \ save_json=True

关键输出解读:

  • results.csv中metrics/mAP50(B)值>0.78即达标(行业验收线);
  • confusion_matrix.png需检查scab→brown_spot误判率<8%,否则需加强两类纹理差异增强;
  • val_batch0_pred.jpg中若出现大量“病斑框漂移至叶脉”现象,说明lr0过高,需重训并降为0.005。

对新采集的果园图片推理:

yolo detect predict \ model=runs/train/orange_disease_v8n_640/weights/best.pt \ source=/path/to/your/orchard_photo.jpg \ conf=0.3 \ iou=0.5 \ save=True \ show_labels=True \ show_conf=True

生成的predict/目录下会输出带置信度的标注图,注意conf=0.3是经过验证的阈值——低于此值漏检率陡增(尤其溃疡病早期水浸状病斑),高于0.4则误报率翻倍(把叶面水珠当病斑)。


4. 常见问题排查:那些让模型在果园现场翻车的隐蔽坑

4.1 现象:训练时loss震荡剧烈,val_map停滞在0.1~0.2之间

原因:YOLO.txt文件中存在坐标归一化错误(如x=1.05),导致yolo detect train内部坐标校验失败,自动跳过该样本但不报错,实际有效样本量锐减。
解决:用以下脚本批量校验labels:

import os from pathlib import Path label_dir = Path("OrangeCitrusDiseaseDataset/YOLO_format/labels") for txt in label_dir.rglob("*.txt"): with open(txt, "r") as f: for i, line in enumerate(f): parts = list(map(float, line.strip().split())) if len(parts) != 5: print(f"Line {i} in {txt}: wrong field count") continue x, y, w, h = parts[1:] if not (0 <= x <= 1 and 0 <= y <= 1 and 0 < w <= 1 and 0 < h <= 1 and w * h > 0.001): print(f"Invalid bbox in {txt}, line {i}: {parts}")

运行后发现17个.txt文件含x=1.001类错误,手动修正即可。

4.2 现象:推理时大量病斑被框在相邻健康果上,定位偏移>50像素

原因:VOC转YOLO时未按图像实际尺寸计算归一化,而是统一用640×640假设——但数据集中有1280×720图像,导致坐标缩放失真。
解决:重生成YOLO labels,用真实尺寸:

from PIL import Image import xml.etree.ElementTree as ET def voc_to_yolo(voc_xml, img_path, yolo_txt): tree = ET.parse(voc_xml) root = tree.getroot() img = Image.open(img_path) w, h = img.size with open(yolo_txt, "w") as f: for obj in root.findall("object"): cls = obj.find("name").text bbox = obj.find("bndbox") xmin = int(bbox.find("xmin").text) ymin = int(bbox.find("ymin").text) xmax = int(bbox.find("xmax").text) ymax = int(bbox.find("ymax").text) # 关键:用真实w,h归一化 x_center = (xmin + xmax) / 2.0 / w y_center = (ymin + ymax) / 2.0 / h width = (xmax - xmin) / w height = (ymax - ymin) / h cls_id = ["citrus_canker", "anthracnose", "scab", "brown_spot"].index(cls) f.write(f"{cls_id} {x_center:.6f} {y_center:.6f} {width:.6f} {height:.6f}\n")

4.3 现象:测试集mAP@0.5达标,但部署到田间摄像头时漏检率>40%

原因:测试集图片均为静态拍摄,而田间摄像头存在运动模糊(尤其无人机巡检),YOLO默认augmentation未覆盖此场景。
解决:在训练时加入运动模糊增强(需安装albumentations):

# 在ultralytics/utils/ops.py中找到letterbox函数,在return前插入: if random.random() < 0.3: # 30%概率应用 import albumentations as A transform = A.MotionBlur(blur_limit=7, p=1.0) im = transform(image=im)['image']

实测将运动模糊样本的召回率从52%提升至89%。

4.4 现象:导出ONNX后TensorRT推理结果全为背景类(class_id=-1)

原因:YOLOv8导出ONNX时默认--dynamic,但TRT引擎构建时未指定profile,导致输入shape不匹配。
解决:导出时固定shape,并TRT构建时显式声明:

# 导出固定shape ONNX yolo export model=best.pt format=onnx imgsz=640 dynamic=False # TRT构建时(Python API) config.set_flag(trt.BuilderFlag.STRICT_TYPES) profile = builder.create_optimization_profile() profile.set_shape("images", (1, 3, 640, 640), (1, 3, 640, 640), (1, 3, 640, 640)) config.add_optimization_profile(profile)

5. VOC格式深度利用:用原生Pascal VOC工具链做农业场景分析

5.1 VOC eval脚本定制:计算病害面积占比与空间分布密度

Pascal VOC自带eval_detection_voc.py只能算mAP,但果园管理需要知道“溃疡病在树冠上层占比多少”。我们改造评估逻辑,输出病害空间热力图:

# custom_voc_eval.py import numpy as np from voc_eval import voc_eval def eval_with_density(detpath, annopath, imagesetfile, classname, cachedir, ovthresh=0.5): # 原voc_eval逻辑... # 新增:统计每个bbox在图像中的相对位置 density_map = np.zeros((10, 10)) # 10×10网格 for i, (fname, bb) in enumerate(detections): img = cv2.imread(f"VOC_format/JPEGImages/{fname}.jpg") h, w = img.shape[:2] # 将bbox映射到10×10网格 grid_x = int((bb[0] + bb[2]) / 2 / w * 10) grid_y = int((bb[1] + bb[3]) / 2 / h * 10) grid_x = max(0, min(9, grid_x)) grid_y = max(0, min(9, grid_y)) density_map[grid_y, grid_x] += 1 # 归一化为密度百分比 density_pct = (density_map / density_map.sum() * 100).round(2) return ap, density_pct ap, density = eval_with_density( detpath="results/", annopath="VOC_format/Annotations/{}.xml", imagesetfile="VOC_format/ImageSets/Main/test.txt", classname="citrus_canker", cachedir="cache/" ) print("溃疡病空间密度分布(%):") print(density) # 输出类似:[[0.2, 1.8, ...], [3.1, 0.9, ...]]

价值点:该密度矩阵可直接导入GIS系统,叠加果树GPS坐标,生成“溃疡病高发区热力图”,指导精准喷药——这才是农业AI该有的闭环。

5.2 VOC XML转COCO:对接MMDetection做实例分割预研

虽然当前任务是检测,但病害严重程度需靠病斑面积判断,实例分割更优。用voc2coco.py转格式时,必须保留<difficult>字段作为COCO的iscrowd:

# voc2coco.py关键段 for i, obj in enumerate(objs): difficult = int(obj.find("difficult").text) if obj.find("difficult") is not None else 0 # COCO中iscrowd=1表示难例,参与loss计算但不计入mAP ann = { "id": ann_id, "image_id": image_id, "category_id": class_to_idx[name], "segmentation": [], # 此处留空,后续用mask R-CNN生成 "area": float((xmax-xmin)*(ymax-ymin)), "bbox": [xmin, ymin, xmax-xmin, ymax-ymin], "iscrowd": difficult # 关键!保留difficult语义 } annotations.append(ann)

这样在MMDetection中训练Mask R-CNN时,iscrowd=1的样本会参与mask loss计算,但不参与bbox mAP统计,符合农业场景“宁可漏检难例,不可误标健康果”的安全逻辑。

5.3 VOC数据增强:针对果园特有噪声的定制Aug

通用Aug(如HSV变换)对病斑纹理破坏大。我们基于VOC XML开发果园专用增强:

增强类型实现方式农业价值
叶脉模拟在图像上叠加半透明叶脉纹理图(从真实叶脉扫描图提取),opacity=0.15防止模型把叶脉当病斑
露珠扰动在病斑区域随机添加高斯核(σ=1.2)模拟晨露反光提升早期水浸状病斑鲁棒性
套袋反光在图像底部1/3区域添加渐变白色高光(强度随y坐标线性衰减)应对塑料套袋果园场景

这些增强已打包为agri_aug.py,调用方式:

from agri_aug import LeafVeinAug, DewDropAug, BaggingGlareAug transform = Compose([ LeafVeinAug(p=0.7), DewDropAug(p=0.5, disease_classes=[0,1]), # 仅对溃疡/炭疽生效 BaggingGlareAug(p=0.3) ])

6. 模型轻量化部署实战:Triton+TensorRT在Jetson AGX Orin上跑满10路1080p视频流

6.1 TensorRT引擎构建:针对Orin的INT8校准与显存优化

Orin 32GB内存有限,必须用INT8且禁用动态shape:

# 1. 生成校准缓存(用VOC val集前200张) trtexec --onnx=yolov8n_orange.onnx \ --int8 \ --calib=test_calib.cache \ --saveEngine=yolov8n_orange_int8.trt \ --workspace=4096 \ --optShapes=images:1x3x640x640 \ --minShapes=images:1x3x640x640 \ --maxShapes=images:1x3x640x640 # 2. 验证引擎 trtexec --loadEngine=yolov8n_orange_int8.trt \ --shapes=images:1x3x640x640 \ --iterations=1000

血泪经验:校准图必须包含所有4类病害,且test_calib.cache需用IInt8EntropyCalibrator2(非IInt8MinMaxCalibrator),否则炭疽病轮纹纹理丢失率达63%。实测--workspace=4096是Orin上限,设更大反而OOM。

6.2 Triton配置:10路并发的关键参数调优

config.pbtxt中必须显式限制GPU内存与实例数:

platform: "tensorrt_plan" max_batch_size: 16 input [ { name: "images" data_type: TYPE_FP32 dims: [ 3, 640, 640 ] } ] output [ { name: "output0" data_type: TYPE_FP32 dims: [ 84, 8400 ] } ] instance_group [ [ { kind: KIND_GPU gpus: [0] # 关键:每个实例独占显存,防10路争抢 profile: ["default"] count: 10 } ] ] # 关键:关闭动态batch,强制10路各占1个batch dynamic_batching [ { max_queue_delay_microseconds: 100 } ]

验证方法:用perf_analyzer压测:

perf_analyzer -m yolov8n_orange -b 1 -u localhost:8000 --concurrency-range 1:10 --input-data inputs.json

当concurrency=10时,avg_latency_ms稳定在85±3ms,request_throughput达117.6 req/s——即每路11.76 FPS,满足1080p@25fps需求。

6.3 边缘端推理流水线:从RTSP拉流到病害预警的完整代码

# infer_pipeline.py import cv2, numpy as np, tritonclient.http as httpclient from threading import Thread, Event class VideoInferPipeline: def __init__(self, rtsp_url, triton_url="localhost:8000"): self.client = httpclient.InferenceServerClient(url=triton_url) self.cap = cv2.VideoCapture(rtsp_url) self.stop_event = Event() def preprocess(self, frame): # 统一resize+归一化,与TRT输入一致 frame = cv2.resize(frame, (640, 640)) frame = frame.astype(np.float32) / 255.0 frame = np.transpose(frame, (2,0,1)) # HWC→CHW return np.expand_dims(frame, axis=0) # NCHW def postprocess(self, output): # 解析TRT输出:[1, 84, 8400] → [boxes, scores, classes] pred = output.reshape(84, 8400).T boxes = pred[:, :4] scores = pred[:, 4:].max(axis=1) classes = pred[:, 4:].argmax(axis=1) # NMS indices = cv2.dnn.NMSBoxes(boxes, scores, 0.25, 0.45) return boxes[indices], scores[indices], classes[indices] def run(self): while not self.stop_event.is_set(): ret, frame = self.cap.read() if not ret: continue input_data = self.preprocess(frame) # Triton推理 inputs = [httpclient.InferInput("images", input_data.shape, "FP32")] inputs[0].set_data_from_numpy(input_data) outputs = [httpclient.InferRequestedOutput("output0")] result = self.client.infer("yolov8n_orange", inputs, outputs=outputs) output = result.as_numpy("output0") boxes, scores, classes = self.postprocess(output) # 病害预警逻辑 for i, cls in enumerate(classes): if scores[i] > 0.5 and cls == 0: # 溃疡病高置信 print(f"[ALERT] 溃疡病 detected at {boxes[i]} with score {scores[i]:.2f}") # 触发短信/APP推送(此处省略集成) # 启动10路 pipelines = [] for i in range(10): p = VideoInferPipeline(f"rtsp://cam{i}/stream") t = Thread(target=p.run) t.start() pipelines.append((p, t))

关键技巧:cv2.dnn.NMSBoxes必须用OpenCV 4.8+,旧版对小目标NMS效果差;scores[i] > 0.5是实测阈值——低于此值误报率飙升(把反光当溃疡),高于0.6则漏检早期病斑。

从那以后我每次部署果园AI系统,都强制走一遍这10路并发压测+单路延迟验证,哪怕客户说“先跑一路看看”。因为病害蔓延不会等你“先跑一路”,它按小时计。希望帮到你。

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

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

华为IPD培训PPT实战拆解:研发管理落地的五大支柱

简介&#xff1a;本资源为华为IPD&#xff08;集成产品开发&#xff09;体系专项培训课件&#xff0c;面向企业研发管理者、流程优化负责人及希望系统提升产品研发效能的中高层技术骨干。课件深入剖析IPD核心理念与落地路径&#xff0c;直击产品研发中常见的九大痛点——如缺乏…

作者头像 李华
网站建设 2026/10/12 0:03:20

大规模MIMO混合波束成形Matlab仿真:从预编码设计到误码率验证

简介&#xff1a;这份资源面向通信工程、电子信息等专业的高年级本科生与研究生&#xff0c;以及从事大规模MIMO系统仿真验证的科研人员&#xff0c;聚焦发射端混合波束成形这一关键技术&#xff0c;帮助读者理解并复现模拟与数字波束成形的联合设计流程。压缩包共4个文件&…

作者头像 李华
网站建设 2026/10/11 23:59:21

AI病虫害识别后端实战:ONNX推理与高并发架构设计

“后端&#xff1a;05-AI病虫害识别”&#xff0c;一看就是连续项目里的第五个环节。前四个大概率是用户体系、设备接入、数据上报、基础管理之类的活儿&#xff0c;到05这里终于轮到了核心算法业务的接入。这个模块做得好不好&#xff0c;直接决定了产品是“演示Demo”还是“能…

作者头像 李华
网站建设 2026/10/11 23:58:43

Q-Learning中用伴随法精准优化标量指标

1. 这个标题到底在讲什么&#xff1a;剥离数学包装后的本质还原“Q-Learning with Scalar Adjoint Matching”——第一次看到这个标题&#xff0c;我下意识停顿了两秒。不是因为看不懂每个词&#xff0c;而是因为这几个词被强行拧在一起后&#xff0c;散发出一种典型的“论文式…

作者头像 李华
网站建设 2026/10/11 23:58:39

RaaS结果即服务模式解析:从SaaS到按结果付费的销售服务架构

1. RaaS的基本面&#xff1a;为什么“卖结果”比“卖工具”更能打动企业这几年做销售域的服务&#xff0c;绕不开一个词&#xff1a;RaaS&#xff08;Result as a Service&#xff0c;结果即服务&#xff09;。在iSales的整个商业体系里&#xff0c;RaaS不只是营销术语&#xf…

作者头像 李华