
简介面向棉花病害智能检测任务这份已标注数据集提供约4,600张真实田间图像及对应YOLO标签覆盖枯萎病、卷曲、灰霉、健康植株、叶斑病等6个类别适用于目标检测算法训练、模型评估与农业视觉研究。资源共包含2,000个文件其中1,999个txt标注文件与1个show.py可视化脚本压缩包整体156.57MB标注格式可直接接入YOLO系模型训练流程。数据集已按训练、验证、测试划分完毕用户下载后无需额外整理运行show.py即可快速预览标签与图像对应关系便于核查标注质量。对于需要构建棉花病害检测基准或开展YOLO系列改进实验的开发者这份数据能有效节省采集和标注时间也可用于迁移学习与数据增强效果对比。目前已有47人浏览学习属于轻量级专用数据集适合个人项目或课程实践使用。1. 棉花病害检测卡在哪4,600 张已标注图像能直接打通哪些环节做植保视觉的人都知道棉花病害检测最耗时间的不是模型选型而是数据本身。棉叶上的病斑常常只有十几个像素角斑病和褐斑病在自然光下长得几乎没有差别田间背景又乱叶片互相遮挡拿通用目标检测数据集训练出来的模型一到田里就翻车。这份棉花植物病害图像目标检测数据约 4,600 张图像加标签全部按 YOLO 标注格式整理完毕类别、坐标、目录结构都已经对齐到能直接喂给训练脚本的状态。它解决的是从零攒数据、标注、清洗这一整段最磨人的流程适合正在做棉田病害巡检、无人机航拍识别或者想拿目标检测练手但不想在标注上耗两周的人。拿到手之后有三件事必须自己做数据校验、类别口径确认、训练参数调整。下面按这条路拆开讲。2. 数据集结构解剖YOLO 标注格式、目录划分与类别边界2.1 YOLO 标注一个框到底存了什么YOLO 标注格式的每一行是五个值类别 ID、归一化中心点 x、归一化中心点 y、归一化宽、归一化高。所有坐标都除以了图像宽高取值落在 0 到 1 之间不关心图像实际是多大。这和 VOC 那种左上角、右下角的像素坐标完全是两套逻辑很多第一次拿到 YOLO 数据集的人直接把 txt 里的数当像素用画出来的框全偏。我一般会先写一个解析脚本把归一化坐标还原成像素框叠加到原图上人工抽看。这步虽然简单却是判断标注质量最快的手段。import cv2 def parse_yolo_label(txt_path, img_path): img cv2.imread(img_path) if img is None: raise FileNotFoundError(f图像读取失败: {img_path}) h, w img.shape[:2] boxes [] with open(txt_path, r, encodingutf-8) as f: for line in f: parts line.strip().split() if len(parts) ! 5: # 非标准标签行直接跳过并留痕 print(非标准标签行:, line.strip()) continue cls, xc, yc, bw, bh parts # 归一化坐标乘以图像宽高得到像素坐标 xc, yc float(xc) * w, float(yc) * h bw, bh float(bw) * w, float(bh) * h x1 int(xc - bw / 2) y1 int(yc - bh / 2) x2 int(xc bw / 2) y2 int(yc bh / 2) boxes.append((int(cls), (x1, y1, x2, y2))) return boxes这段逻辑很直白但有三处值得注意。第一读取图像用的是 cv2这里只取 shape 算宽高BGR 通道无所谓。第二归一化坐标严格来说是中心点加宽高还原像素框时要除以 2 再加减漏了这一步框会整体偏移。第三非标准行不能静默跳过最好打印出来后面统一处理不然训练时某张图标签数量对不上排查起来很被动。参数说明txt_path 是每张图对应的同名标签文件img_path 是原图路径返回的 boxes 里每个元素是 (类别ID, (x1, y1, x2, y2)) 的像素坐标元组可以直接交给 cv2.rectangle 画框。h、w 必须用原图实际尺寸不要用缩略图或 EXIF 里的尺寸否则坐标会整体错位。2.2 目录结构与 data.yaml 的约定拿到数据集的第一步不是急着训练而是把目录结构摸清楚。YOLO 训练框架的默认约定是 images 和 labels 分开放各自再拆 train、val 子集标签文件名必须和图像文件名一一对应。路径内容images/train训练图像常见格式 jpg / pngimages/val验证图像建议按拍摄场景独立抽取labels/train与 images/train 同名的 txt 标签labels/val与 images/val 同名的 txt 标签data.yaml数据集描述文件含路径和类别清单data.yaml 里最关键的是 names 字段一行一个类别名顺序就是类别 ID。训练框架按行号映射 0、1、2如果 names 顺序和标注 txt 里的类别 ID 对不上模型学到的类别和你想的完全不是一回事。拿到手先打开 data.yaml 看一眼 names 数量是否和标注里出现的最大类别 ID 对齐例如标注里出现过 ID 3names 至少要有 4 项。训练框架一般要求 data.yaml 的 path 写数据集根目录train、val 写相对路径。这个字段容易踩坑有人把 path 写死成自己机器的绝对路径换台机器训练直接报路径找不到。我习惯把 path 留空train、val 写相对路径代码里切到数据集根目录再启动训练这样工程迁移性最好。2.3 类别边界病害种类与标注口径这份数据的类别以棉花叶部常见病害为主拿到手后首先要打开 data.yaml 逐个确认类别清单而不是直接开训。棉花病害命名在不同资料里不完全统一同一个病斑有人按角斑病标有人按褐斑病标还有人干脆只标一个叶斑病。这里的核心问题是标注口径。一份数据集里如果混用了标病斑和标病叶两种口径训练出来的模型会非常不稳定。病斑口径下框子小、数量多病叶口径下框子大、数量少两种框混在一起损失函数在大小目标之间来回摇摆。判断口径是否统一的办法很简单按类别统计框宽高的分布画出直方图。如果某个类别同时存在大量 0.05 以下的极小框和 0.4 以上的大框说明口径混了需要挑出样本重新定标准。我处理过类似的数据当时直接把两个相似病害合并成一个叶斑病类别虽然类别粒度变粗了但标注一致性立刻好转mAP 反而从 0.52 涨到 0.71。如果下游任务只关心叶片有没有病、病害面积多大合并相似类别是性价比很高的操作只有明确要做精细化分级时才值得保留细分类别。3. 从 YOLO 格式到损失收敛训练配置、参数选型与校验脚本3.1 训练前的三道体检标注数据直接开训是新手最常见的翻车点。4,600 张图不是小数目但哪怕只有一张标签越界训练都可能出现 loss 变成 NaN 或某个 batch 被静默跳过。我每次拿到数据集第一件事是跑一个全量体检脚本检查三类问题标签越界、空标签、图像与标签名不匹配。import os from pathlib import Path def check_dataset(img_dir, label_dir): problems [] for lp in Path(label_dir).glob(*.txt): stem lp.stem # 检查同名图像是否存在 imgs list(Path(img_dir).glob(stem .*)) if not imgs: problems.append((stem, no_match_image)) continue lines [ln.strip() for ln in lp.read_text(encodingutf-8).splitlines() if ln.strip()] if not lines: problems.append((stem, empty_label)) continue for line in lines: parts line.split() if len(parts) ! 5: problems.append((stem, bad_field_count, line)) continue try: cls int(parts[0]) xc, yc, bw, bh [float(v) for v in parts[1:]] except ValueError: problems.append((stem, non_numeric, line)) continue # 归一化坐标越界检查 if cls 0 or xc 0 or yc 0 or bw 0 or bh 0: problems.append((stem, non_positive, line)) if xc bw / 2 1.0001 or yc bh / 2 1.0001: problems.append((stem, out_of_image, line)) return problems这段脚本覆盖了三道体检。第一道是文件名匹配标签存在但图像缺失训练到一半会报错退出第二道是空标签文件训练框架会静默跳过空白图问题是它不提示你根本不知道哪些图没参与训练第三道是数值检查中心点加半宽超过 1 意味着框冲出图像边界这类标签在 anchor 匹配阶段会产生异常梯度这是 NaN 损失的高发来源。参数说明img_dir 和 label_dir 分别传训练或验证的 images、labels 目录脚本返回 problems 列表每项是 (文件名, 问题类型, 标签行)。越界阈值留 0.0001 容差因为个别标注工具浮点精度会导致边界刚好压在 1.0 多一点这种可以容忍超过 1.0001 的必须处理。常见做法是把越界框按图像边界裁剪或者直接删掉那一行重新标注后者更省事。3.2 训练命令参数怎么选体检通过之后我用 YOLOv8 训练这份数据。命令行方式最直接数据和配置收敛在一个目录里便于复现。yolo detect train \ datadata.yaml \ modelyolov8n.pt \ imgsz640 \ batch16 \ epochs150 \ patience30 \ lr00.01 \ projectruns/cotton \ nameexp1逐个说参数怎么定。imgsz 默认 640对棉花病害这种小目标居多的场景偏小。我把病斑尺寸统计过一遍大量目标集中在 20 到 50 像素640 输入下这些目标在深层特征图只剩两三个特征点。显存够的话建议提到 1024代价是训练时间约翻倍4,600 张图属于中等规模时间成本可以接受。参数建议值说明imgsz640 / 1024小目标多就上 1024显存不足退 640batch8 / 161024 输入用 8640 输入用 16epochs150配合 patience 提前停止patience30连续 30 轮验证指标不涨就停lr00.01配合 SGD小数据集更稳batch 主要看显存16 在消费级显卡上配合 640 输入是安全值用 1024 输入需要降到 8。epochs 给 150 并开 patience30即连续 30 个 epoch 验证集指标没有提升就提前停避免死等。lr0 保持 0.01 配 SGD数据量不算大AdamW 在小数据集上收敛快但容易过拟合这类场景我更愿意用 SGD。训练日志里重点盯三类指标box_loss 是否持续下降、验证集 mAP50-95 是否在 30 个 epoch 内还在涨、以及每个类别的 AP 分布。如果某个类别 AP 明显低于其他类大概率是该类别样本太少往下看数据增强的处理办法。注意data.yaml 的 path 字段不要写死本地绝对路径换机器训练会直接报路径错误留空或写相对路径更稳妥。3.3 类别不均衡与增强策略4,600 张图分布在多个病害类别里几乎必然存在不均衡。我一般先看训练后按类别统计的实例数量最少类和最多类可能差到 5 倍以上。YOLOv8 训练阶段没有直接按类别加权的检测损失选项常见做法是两条腿走路一是在数据侧对少样本类别做重采样二是靠增强倾斜。增强方面YOLOv8 默认开了 mosaic这对植保场景是好事可以把不同病害贴到一张图上间接增加背景多样性。但要注意棉花叶片的病害空间方向性不强翻转增强可以放开旋转增强我限制在 15 度以内旋转太多会把叶片纹理扭曲到失真。颜色增强方面hsv_v 适当调大因为田间光照强度差异很大训练时见过更多亮度区间实拍时不容易过曝丢检。少样本类别我习惯单独建一个 supplementary 列表从原图做简单复制粘贴增强把小病斑裁剪出来按随机位置贴到健康叶片图上重新生成标签。注意粘贴时避开原图已有目标区域避免框重叠导致类别混叠。这个操作在数据层面比调损失权重直观效果也更可控。4. 训练与部署避坑标签越界、小目标漏检与类别混淆的排查记录下面是实际折腾过的几个典型坑每个都按现象、原因、解决记录。这些坑和技术选型关系不大全是被数据和使用方式逼出来的血泪值很高。4.1 现象训练到第 24 个 epochbox_loss 突然变成 NaN原因排查了很久最后定位到验证集的一张图。它的标签文件里有一行 width1.2明显是标注工具导出时把像素坐标当作归一化坐标写进去了或者图片被压缩后标签没同步更新。训练框架不会对单行错误标签报错它就安静地躺在数据里等模型算到它时梯度直接爆掉。损失曲线前面一路下降谁能想到一枚坏标签能让整个训练前功尽弃。解决把第 3.1 节的体检脚本设成每次训练的前置步骤全量扫一遍再开训。处理策略我定成两条能确认原图尺寸的按正确尺寸重新归一化无法确认的一律删行并记录。删完行之后统计每张图的标签框数人工抽查 20 张确认误删率。这套流程挡住的不只是 NaN还包括训练看着正常但某类 AP 奇低的慢性病。4.2 现象验证集 mAP50 有 0.83但田间实拍时小病斑漏检一大片原因把漏检图拉出来逐张看漏掉的全是面积在 15 到 30 像素之间的早期病斑。两个因素叠加输入分辨率 640 时这些小目标在深层特征图上几乎只占几个特征点特征表达先天不足同时原始标注对小病斑本身也存在漏标模型学到的正样本不完整。mAP 虚高是因为验证集里大目标占比大小目标被平均掉了。解决第一imgsz 提到 1024小目标的像素占比直接翻倍同类场景下 recall 普遍能涨 5 到 8 个点第二对验证集按目标面积区间分别统计 recall单独盯着 32x32 以下这类指标不再被总 mAP 迷惑第三推理阶段开 TTA原图和水平翻转各推一次再融合结果小目标 recall 再涨 3 个点左右代价是单帧耗时翻倍实时巡检要评估算力再决定。4.3 现象两种叶部病害互相污染混淆矩阵一整片亮单类 AP 都卡在 0.5 以下原因这两种病害在早期症状上是渐进连续的不是非黑即白。更麻烦的是标注口径前后不一致第一批标注员只框边界清晰的斑点第二批把整片发黄区也框了进来。模型看到的同一类目标有两种形态分布决策边界根本拉不开。解决先把两类样本的框宽高分布打出来对比发现第二批框普遍大一圈。我把边界模糊的样本挑出来重新目视复核最后决定合并成一个大类叶斑病。合完之后单类 AP 从 0.5 涨到 0.75 以上。业务上只关心有没有病、病害面积多大完全够用如果确实要细分唯一靠谱的路是把边界样本单独拆成一类再补标几百张没有捷径。4.4 现象训练集指标很漂亮一换到田间实拍整体掉点接近一半原因典型的领域偏移。数据里有相当一部分是室内单叶拍摄背景干净、光线均匀田间实拍是整株冠层逆光、叶片互相遮挡、背景有土壤和杂草。模型在室内图上学到的叶片边缘锐度特征到田间完全失效。这种偏移从训练曲线里看不出来只能靠单独的场景验证集暴露。解决先统计训练图和实拍图的亮度、对比度分布确认偏移方向然后把实拍样张按 3:1 混进训练集做微调再用 copy-paste 增强把室内病斑裁下来贴到田间背景上制造混合样本。真正的关键动作是单独划出一个 field_test 集只用它做最终验收训练过程中不碰它防止模型反向过拟合到验收集。提示field_test 集只用来做最终验收不要在训练调参时反复看它的指标看一次就被它带偏一次。4.5 现象推理时预测框全部挤在图像边缘置信度普遍低于 0.3原因这批图的标签坐标整体偏移。追查后发现其中一批原图在入库时被批量压缩过一次图像尺寸变了标签里的归一化坐标却没有按新尺寸重新计算。归一化坐标理论上不随尺寸变化但压缩工具改了长宽比坐标就悬空了。解决用第 2.1 节的解析脚本把所有疑似问题图的预测框画出来目视扫一遍框全部贴边的批次直接定位。处理方式是把这批图按原始长宽比重新导出或者直接剔除出训练集。从那以后凡是经过批量图像处理的目录我都会把处理前后的尺寸记录留档标签坐标重新生成后必须再过一次体检脚本。4.6 现象训练正常收敛但导出的 ONNX 在本地推理结果和训练时预测完全不同原因导出时没有固定 imgszonnxruntime 动态输入尺寸下模型的缩放逻辑和训练时不一致另一个常见原因是导出后 NMS 参数被重置conf 和 iou 阈值回到了默认值导致输出框数量和位置都对不上。解决导出命令显式写 imgsz并在部署代码里重新声明 conf 和 iou拿训练集里同一张图对比 PyTorch 推理和 ONNX 推理的输出坐标偏差超过 2 像素就要检查预处理里的 letterbox padding。这个坑和数据集本身无关但凡是把数据集导出部署都会碰到值得记录。5. 把 4,600 张用出 10,000 张的效果数据清洗、难例挖掘与增量扩充5.1 训练结果反哺数据漏检样本就是金子第一次训练跑完不要急着部署。把训练好的模型放回到训练集和验证集上推理一遍置信度阈值调低到 0.05把所有漏检的框捞出来。这个操作叫难例挖掘。模型在训练集上漏掉的样本要么标得太差要么目标特征太隐蔽这些恰恰是下一轮训练最该补的素材。用命令行先把预测结果落盘yolo detect predict \ modelruns/cotton/weights/best.pt \ sourcedatasets/cotton/images/train \ save_txtTrue \ conf0.05 \ projecthard_examples \ nametrain_mining参数说明save_txtTrue 会让每张图生成一个同名 txt里面是预测框格式和标签一致conf0.05 是为了把低置信度的弱响应也保留下来正常推理用 0.25 到 0.3但挖掘难例必须放宽否则真阳性也被滤掉了。输出在 hard_examples/train_mining/labels 目录按图像文件名可直接和原标签做比对。拿到预测 txt 之后写一段比对脚本读取预测框和真实标签框做 IoU 匹配小于 0.1 的预测框视为模型压根没找到对应图像挑出来人工复查。IoU 计算是最基础的几何运算def iou(box_a, box_b): # box_a 和 box_b 都是 (x1, y1, x2, y2) 的像素坐标 x1 max(box_a[0], box_b[0]) y1 max(box_a[1], box_b[1]) x2 min(box_a[2], box_b[2]) y2 min(box_a[3], box_b[3]) inter max(0, x2 - x1) * max(0, y2 - y1) area_a (box_a[2] - box_a[0]) * (box_a[3] - box_a[1]) area_b (box_b[2] - box_b[0]) * (box_b[3] - box_b[1]) return inter / (area_a area_b - inter 1e-6)加了 1e-6 是为了防止分母为 0两个完全重合的空框不会触发除零。复查时重点看两件事是标注漏了还是目标本身极小看不清。前者补标后者记录成难例下一轮训练时单独加大复制粘贴增强次数。5.2 标注一致性体检重标和合并的决策数据标注的一致性直接决定模型上限。我常用的检查维度有三个框宽高分布、类别实例数分布、同图重复框数量。框宽高分布前面提过这里说后两个。类别实例数分布按类别统计所有标签的行数如果某类只有几十个实例这个类别的 AP 基本是虚的训练时会被其他大类压制。实例数少于 100 的类别我的处理惯例是要么找漏标的同类图像补标把数量拉到 300 以上要么直接合并进语义相近的大类。同图重复框两个标注员对同一张图的同一个病斑重复画了两个框一个精确一个宽松这样的重复框会让损失函数在同一个位置产生两次梯度框的回归方向互相打架。检查方法是按图像统计框数和框面积占比正常叶片病害每张 1 到 8 个框如果出现单张 20 个框且面积都小于 0.01大概率是重复标注需要人工合并。5.3 半自动增量扩充模型预标加人工校对数据不足时最常见的增量方案是拿现成模型去预标新采集的田间图片。流程是新照片丢给 best.pt 推理只保留置信度 0.6 以上的框生成初步标签然后人工用标注工具逐张校对。这一步的重点不是省标注时间而是保证新样本的标签口径和原数据集一致。预标有一个明显的坑模型会系统性地漏掉它在训练中学得差的类别。如果新图上恰好有这类病害预标结果里它没出现人工校对时容易顺手忽略导致新数据不仅没补齐短板反而强化了原有偏差。我的习惯是预标之前先列出模型单类 AP 最低的三个类别校对时要求人工专门留意这些类别只要图上出现疑似特征就手动补框不能依赖模型输出。每批增量数据加完后重新跑一次训练对比全类别 AP 变化确认短板类别是否真的在涨。6. 导出与田间验证ONNX 推理、指标复盘与一个养成习惯训练收敛后我习惯把 best.pt 导出成 ONNX再做一次独立的指标复盘才真正把这个数据集的价值兑现到现场。导出命令yolo export modelruns/cotton/weights/best.pt formatonnx imgsz640导出后用 onnxruntime 在 CPU 上跑 20 张实拍图重点不是速度而是确认导出后的输入尺寸和 NMS 输出和训练时一致。常见坑是导出后置信度阈值被重置部署代码里要重新指定 conf 和 iou不要沿用导出的默认值。指标复盘我只盯三组数验证集全类别 mAP50、单类 AP 最低值、conf0.25 时的 precision/recall 配对。前两组决定模型能不能上线最后一组决定现场阈值怎么设。如果 recall 明显低于 precision现场要把阈值下调到 0.15 左右宁可多框也不能漏植保场景漏检的代价远高于误检。配套的推理脚本、校验工具、训练配置我都和数据集放在同一个目录下命名带日期版本。这半年养成了一个固定习惯每次拿到标注数据不管对方说得多完整都强制走一遍体检脚本、类别分布直方图、抽 30 张图目视复核这三步过了才允许开训练。这个习惯帮我挡掉了至少三次本来要通宵排查的数据事故。希望这份数据能让你少走同样一段路希望帮到你。本文还有配套的精品资源点击获取