新闻详情

新闻详情

首页 / 资讯中心 / 详情

植物萌芽检测数据集全流程:从解压校验到YOLO训练

发布时间:2026/10/2 8:59:42来源:尧图网络
植物萌芽检测数据集全流程:从解压校验到YOLO训练
简介植物萌芽检测数据集.zip 是一套面向精准农业与植物表型研究的 YOLO 格式目标检测数据集适用于农业科研人员、算法工程师及农林院校师生开展萌芽期识别模型训练与生长阶段自动监测。数据集包含训练集 1177 张、验证集 302 张、测试集 5 张以 budding 为唯一类别标注框严格遵循中心坐标加宽高的 YOLO 规范并涵盖多视角图像及旋转、裁剪、噪声处理等增强版本便于提升模型鲁棒性。压缩包内含 2000 个文件其中 1484 个 txt 标签、514 个 jpg 图像、1 个 yaml 配置及 1 个 docx 说明文档整体大小约 133.71MB结构清晰可直接接入主流 YOLO 系列算法流程。目前已有 101 人学习浏览适合用于智能温室管理、作物生长周期预测及农业物联网设备中的萌芽状态识别也可作为农林院校相关课程的教学实践数据。1. 植物萌芽检测数据集.zip 在解决什么问题自动出苗计数前的最后一块拼图做农业视觉或者植物表型分析的人大概都经历过同一种疲劳育苗盘里冒出一百多棵芽要数清楚哪几个孔位还没出苗人工数到第三盘就分不清刚才数到哪了。植物萌芽检测数据集.zip 这类资源就是把「数苗」这件事前置成一份可以直接喂给目标检测模型的训练数据——压缩包里整理好了苗期图像和对应的萌芽标注框用来训练模型自动定位每一棵芽再做计数和长势统计。它能帮你绕开最耗时的人工标注环节直接从出苗检测、萌芽率统计这些结果开始入手。这份数据适合用 YOLO、Faster R-CNN 这类检测框架做农业落地的开发者也适合课程设计里需要真实农业图像数据、又不想自己蹲在温室拍半个月照片的同学。2. 解压前的 10 分钟体检识别数据集结构与标注格式下载完这份 zip第一反应别是双击解压。压缩包里的数据一旦被解到磁盘文件一多结构是否合理、标注是否齐全反而不容易看出来。我通常先花十分钟对压缩包本身做个体检把三个问题问清楚里面有几类文件、标注是哪种格式、类别标签是什么。这三个问题直接决定后面要不要写转换脚本以及训练脚本里的 data.yaml 该怎么写。2.1 用 Python 只读目录不改动压缩包Python 标准库的 zipfile 可以直接读 zip 的中央目录不需要把整个压缩包解出来几百 MB 的包也就是几秒钟的事。先看一眼顶层结构和文件后缀分布import zipfile from collections import Counter zip_path plant_seedling_detection.zip with zipfile.ZipFile(zip_path) as zf: names zf.namelist() print(总条目数:, len(names)) exts Counter(name.rsplit(., 1)[-1].lower() for name in names if . in name) for ext, cnt in exts.most_common(): print(f{ext}: {cnt})这段代码不会改动压缩包里的任何文件只是列出条目。重点看两个比例图片数量和标注数量是否接近标注后缀是 xml、txt 还是 json。如果图片 1200 张、xml 也有 1200 个大概率是 VOC 风格如果出现一个体积明显偏大的 json多半是 COCO 格式如果 txt 数量和图片数量一致那就是 YOLO 系列可以直接吃的格式。另外注意有没有混进来 README、exe、pdf 之类的无关文件——混入说明这份数据曾经被人手工整理过后面的校验要做得更细。2.2 VOC、COCO 与 YOLO先认准标注格式再动手萌芽检测数据集里最常见的标注格式是三种它们的坐标体系和文件组织完全不同认错了后面转换脚本会写得很痛苦。格式文件组织一张图的标注内容框的坐标VOC XML每张图一个 .xmlobject里写类别名和bndbox绝对像素 xmin ymin xmax ymaxCOCO JSON整个数据集一个 JSONannotations数组按image_id关联图片绝对像素 x y w hYOLO txt每张图一个 .txt每行一个框class_id cx cy w h归一化到 0~1判断方法很直接文件清单里 xml 和 jpg 一一对应就是 VOC有一个大 json、里面还有_annotations.coco.json这种名字就是 COCOtxt 每行五个数字就是 YOLO。很多做农业的数据集发布方会同时给 xml 和 txt因为知道实际使用的人大多跑 YOLO 系。COCO 格式的结构固定是 images、annotations、categories 三块转格式时要以这个结构为基准读而不是靠猜字段名。2.3 标签体系与检测任务对齐单类、多类、背景框还是旋转框接下来看类别清单。萌芽检测的类别名可能是 seedling、sprout、emerged、background 这些压缩包里通常有 README 或者 classes.txt 说明。先把类别名全部列出来再决定训练任务的设置。如果只有 seedling 一类模型学的是「这里有没有萌芽」如果细分成「刚出土子叶」和「真叶展开」那就是生长阶段判定任务输出类别数变成两类后处理逻辑也要跟着改。还有一种常见情况数据里标了背景框也就是把空盆、石子、育苗盘边缘框出来当 background 类。这类框在 YOLO 训练里通常直接删掉不要把它当单独类别训否则类别数虚高推理时模型还会费力去区分「不是芽的东西到底是石头还是土」。如果数据里的标注不是水平矩形、而是带旋转角度的框说明芽出土方向不规则、水平外接框会包进太多背景常见做法是先按水平外接框近似用着等计数误检明显偏多时再考虑 mmrotate 这类旋转框框架。3. 解压、校验与配对把 zip 变成可训练目录的完整步骤体检完就该落地了。解压这件事看起来简单但数据集压缩包经常在这三步翻车解压中途报错、图片文件损坏、标注和图片对不上。我的流程是安全解压 → 检查图像 → 配对标注三步都过了才认为这份 zip 可以进入训练环节。3.1 解压时把 zip 伪加密和坏包挡在门外尽量不要用extractall()一把梭。压缩包里如果被人塞了../这种相对路径extractall 会直接把文件写到目标目录之外而且 extractall 遇到第一个坏文件就抛异常后面全部停住。用逐条解压更稳import zipfile from pathlib import Path def safe_extract(zip_path, out_dir): out_dir Path(out_dir) out_dir.mkdir(parentsTrue, exist_okTrue) with zipfile.ZipFile(zip_path) as zf: for info in zf.infolist(): if info.is_dir(): continue target (out_dir / info.filename).resolve() if not str(target).startswith(str(out_dir.resolve())): raise RuntimeError(f路径越界: {info.filename}) target.parent.mkdir(parentsTrue, exist_okTrue) with zf.open(info) as src, open(target, wb) as dst: dst.write(src.read()) print(解压完成:, out_dir)zf.open()在读取每个文件时都会校验 CRC32哪个文件坏了会精确报在哪个文件上不会让整个解压过程死在一半。路径越界检查是为了防../覆盖别处文件这在网上下载的数据集里不是没见过。还有一种很玄学的情况解压时每个文件都提示需要密码但发布说明里根本没给密码。先用脚本确认加密标志位def check_encrypted(zip_path): with zipfile.ZipFile(zip_path) as zf: for info in zf.infolist(): if info.flag_bits 0x1: print(标记为加密:, info.filename)zip 格式的 general purpose bit flag 第 0 位是加密位。如果所有文件都显示加密、压缩软件又能直接列出文件列表多半是伪加密打包工具误置了标志位文件内容本身并没有真加密。处理方式是用能修正伪加密标志的工具重写一遍 zip 的中央目录再解压修正后内容原样可读。要注意这只是修复损坏的元数据不是破解授权如果确认是真加密老老实实去数据发布页找口令说明别在本地做无意义的尝试。3.2 图像完整性检查损坏、0 字节与 EXIF 方向解压完先跑一遍图像体检别直接开训练。目标检测训练时遇到一张损坏图轻则跳过重则让整个训练进程崩掉。用 Pillow 的 verify 模式只校验文件结构速度很快from PIL import Image from pathlib import Path img_dir Path(images) for p in sorted(img_dir.iterdir()): if p.suffix.lower() not in {.jpg, .jpeg, .png}: continue try: im Image.open(p) im.verify() # 只校验文件结构不加载全部像素 with Image.open(p) as im2: # verify 后需要重新打开 w, h im2.size if w 100 or h 100: print(尺寸异常:, p.name, w, h) except Exception as e: print(无法读取:, p.name, type(e).__name__)除了损坏还要留意 EXIF 方向。手机和部分相机直出的 jpg 会带 Orientation 信息图片在查看器里是正的但原始像素其实是横的。标注框如果按「显示方向」标的训练框架读取原始像素时框就全偏了。稳妥做法是在预处理阶段统一转正图像再重新生成标注坐标不要赌训练框架会自动处理 EXIF。jpg 转正时注意保存质量别为了省事把原图压缩得面目全非。3.3 标注与图片配对缺漏、空标注和多余文件最后做配对检查。训练目录里 images 和 labels 的同名文件必须一一对应这一步漏掉的问题等到训练时报「no labels found」再去查返工成本高得多from pathlib import Path img_dir Path(images) ann_dir Path(labels) imgs {p.stem: p for p in img_dir.iterdir() if p.suffix.lower() in {.jpg, .jpeg, .png}} anns {p.stem: p for p in ann_dir.iterdir() if p.suffix.lower() .txt} missing sorted(set(imgs) - set(anns)) orphan sorted(set(anns) - set(imgs)) empty [p for p in anns.values() if p.stat().st_size 0] print(缺少标注的图片:, len(missing), missing[:10]) print(没有图片对应的标注:, len(orphan), orphan[:10]) print(空标注文件:, len(empty))缺失标注的图要补否则训练时要么报错要么被当背景孤儿标注要查是不是文件名改过。空标注文件在萌芽场景里往往不是错误——育苗盘大量未出苗的孔位就是天然负样本YOLO 支持空 txt但要在验证集里也保留一部分空标注否则部署时模型会对空盘乱报。如果缺失数量特别大先怀疑文件名不是普通后缀DJI_0234.jpg的标注常被写成DJI_0234.jpg.txt按stem匹配就会全丢这时候要用p.name.replace(.jpg, )做键再来一轮。4. 从 zip 到模型YOLOv8 训练萌芽检测的最小流程数据校验通过接下来就是出结果的部分。用 YOLOv8 做萌芽检测是最常见、最不折腾的路线几百张图不需要从零预训练直接用 COCO 预训练权重迁移跑一两个晚上就能看到像样的检测框。这一章按我实际跑项目时的顺序来划分数据、转格式、定训练参数、看验证指标。4.1 数据划分按育苗盘分组别按文件名随机切很多新手上来就random.shuffle然后切 80/20这是栽培类数据的常见坑。萌芽数据往往是同一个育苗盘在几天里连续拍的同一个盘的不同照片之间光照、角度高度相似。随机划分会让同一个盘的照片同时出现在训练集和验证集验证指标虚高等模型拿去数真正的新盘子立刻现原形。正确做法是按「盘」或者按「拍摄批次」分组import random from pathlib import Path from collections import defaultdict random.seed(42) imgs list(Path(images).glob(*.jpg)) groups defaultdict(list) for p in imgs: key p.name.split(_)[0] # 假设文件名是 tray01_001.jpg 这种 groups[key].append(p) group_keys list(groups.keys()) random.shuffle(group_keys) train_keys group_keys[: int(len(group_keys) * 0.8)] val_keys group_keys[int(len(group_keys) * 0.8):] train_files [p for k in train_keys for p in groups[k]] val_files [p for k in val_keys for p in groups[k]] print(ftrain {len(train_files)} 张, val {len(val_files)} 张, 分组 {len(train_keys)}/{len(val_keys)})key 的取法取决于文件名命名规则没有盘 id 就按时间戳切前几天的图归 train后几天的归 val模拟「模型去数一批新拍的苗」。这样切出来的验证结果才真实是从一次验证集 mAP 0.9、上线直接翻车的血泪经验换来的。4.2 转成 YOLO 格式时的四个参数细节如果拿到的是 VOC XML先用脚本统一转成 YOLO txt。关键是坐标转换公式要写对import xml.etree.ElementTree as ET def voc_to_yolo(xml_path, img_w, img_h, class_map): root ET.parse(xml_path).getroot() lines [] for obj in root.findall(object): name obj.find(name).text if name not in class_map: print(跳过未登记类别:, name) continue b obj.find(bndbox) x1 float(b.find(xmin).text) y1 float(b.find(ymin).text) x2 float(b.find(xmax).text) y2 float(b.find(ymax).text) cx (x1 x2) / 2.0 / img_w cy (y1 y2) / 2.0 / img_h w (x2 - x1) / img_w h (y2 - y1) / img_h lines.append(f{class_map[name]} {cx:.6f} {cy:.6f} {w:.6f} {h:.6f}) return \n.join(lines)四个细节容易出错。第一是坐标系起点VOC 的 xmin 常见从 1 开始直接相减得到的宽会偏小 1 像素对大目标无所谓对只有十几像素的芽就是百分之几的误差。第二是越界处理人工标注偶尔会标出图像边界归一化后的 cx 或 w 可能小于 0 或大于 1建议算完统一 clamp 到 [0,1]。第三是类别 idclass_map 从 0 开始排COCO 的 category_id 往往从 1 开始转 YOLO 时记得减一否则类别整体错位。第四是空 xml没有对象的 xml 转出来是空内容保留空文件本身不要删除。4.3 训练命令与保守起步参数数据目录整理成 images/train、images/val 和 labels/train、labels/val 之后写一个 data.yamlpath: /home/user/seedling_data train: images/train val: images/val names: 0: seedling然后跑训练。我一般用这组保守参数起步yolo detect train \ modelyolov8n.pt \ dataseedling.yaml \ epochs100 \ imgsz640 \ batch16 \ lr00.01 \ mosaic0.5 \ close_mosaic10 \ patience20 \ projectruns/seedling \ nameexp1参数建议值说明modelyolov8n.pt / yolov8s.pt几百张图用 n 起步目标极小再试 s模型过大在数据量少时只会过拟合imgsz640芽只有 10~20px 时先跑通流程再试 1280分辨率翻倍显存占用约翻四倍mosaic0.5对萌芽这种小目标mosaic 把四张图拼一起会把芽缩到更小不建议超过 0.5密集场景直接关close_mosaic10最后 10 个 epoch 关掉 mosaic让模型回到真实分布微调patience20萌芽类间差异小、loss 波动大早停阈值给宽松一点batch168GB 显存能跑显存小就降到 8 并保持 imgsz640先跑通一次再调参不要一上来就 1280 加 mosaic1.0。如果数据里自带旋转框标注YOLOv8 的 obb 任务也能处理但常规萌芽计数用水平框就够只有出现「框内背景太多导致同一个芽被重复计数」时才值得切换到旋转框路线。4.4 验证指标不要只看 mAP还要算计数误差训练结束别只看 mAP 绿了就高兴。mAP0.5 反映的是「框和类别对不对」而做萌芽检测的最终目的是数苗。出苗计数更关心两个数字F1 分数以及计数相对误差(预测数 - 人工数) / 人工数。我在验证集里固定挑三五张育苗盘照片人工数一遍再拿模型推理结果对比。如果单帧 mAP 很高但计数误差超过 10%问题通常出在同一个芽被多次触发或者多个芽被框进同一个大框这时候要回头调 NMS 阈值和面积过滤而不是继续堆训练轮数。5. 植物萌芽检测数据集的避坑指南5 个高频翻车点这一章把我在萌芽检测数据上踩过的坑按「现象 → 原因 → 解决」整理出来。每一条都来自真实跑数据时遇到的问题新手照着排查能省下大半天。5.1 解压提示需要密码但文件其实没加密zip 伪加密现象解压时每个文件都弹密码框发布说明里却没给密码压缩软件能正常列出所有文件名甚至能预览部分图片。原因打包工具写坏了 general purpose bit flag 的第 0 位形成伪加密文件内容实际是明文。解决先跑 3.1 里的check_encrypted确认加密位状态伪加密用能修正 zip 标志位的工具重写中央目录后即可正常解压。如果确认是真加密直接去发布页找口令说明不要浪费时间在本地尝试。5.2 训练 loss 正常、验证没有检测框类别编号从 0 还是 1 开始的错位现象训练过程 loss 稳步下降但验证结果里完全没有检测框或所有框的类别标签都显示成同一类。原因YOLO txt 的 class_id 必须从 0 开始很多 COCO 风格数据的 category_id 从 1 开始转换时没有减一如果背景被误标成 0模型直接把芽全学成背景。解决解压后先读五个 txt打印每行第一列的最大值再对照 data.yaml 里的 names 数量。类别 id 不在 0 到 C-1 范围内的写个脚本统一重映射。5.3 图片和标注数量对不上格式转换时悄悄丢了的样本现象images 目录 1200 张 jpglabels 目录只有 1140 个 txt凭空少了 60 个。原因最常见的原因不是漏标而是双后缀命名。DJI_0234.jpg的标注常被写成DJI_0234.jpg.txt按普通stem匹配时这 60 个文件全部对不上。解决配对脚本里用p.name.replace(.jpg, )代替p.stem做键处理完还缺的再考虑是不是原图本身没标注。5.4 小目标召回率极低mosaic 与归一化坐标的双重陷阱现象验证 mAP 不低但数苗时漏掉大量刚露头的芽长开叶子的苗全检出来了土缝里几毫米的芽丢了。原因mosaic 增强把四张图拼在一起原本 15px 的芽被缩到 8px 以下特征直接糊掉或者 imgsz 太小输入分辨率本身就喂不进去。解决先关掉 mosaic 看召回是否回升再用 imgsz640 起步、目标极小就试 1280。对小目标来说提高输入分辨率往往比换更大的模型更直接。5.5 解压后中文文件名乱码GBK 与 UTF-8 的编码错位现象解压后图片名、标注名出现一串乱码配对脚本里set(imgs) - set(anns)几乎全部不匹配。原因zip 格式对文件名编码的标记是 flag bit 第 11 位Windows 下用 GBK 压缩的文件在 Linux 或默认 UTF-8 的 Python 环境下读出乱码。解决解压时判断info.flag_bits 0x800不带 UTF-8 标记的条目用 gbk 编码尝试解码。更省事的做法是解压后把所有文件统一重命名为img_0001这种纯 ASCII 名字标注名同步替换后续任何训练框架都不会再编码翻车。6. 从检测框到出苗数面积筛选与跨帧去重的小技巧模型训好只是第一步落到「这一盘出了多少苗」才是终点。直接把所有检测框当芽数往往多头几个因为训练时的正样本框有大有小推理时背景里的石子、育苗盘边缘也可能被框出来。我一般加两道后处理面积筛选和跨帧去重。面积筛选基于一个朴素观察萌芽框在 640 分辨率下极少小于 30×30 像素而真正的误检要么是几像素的石子要么是育苗盘边缘的大块背景。跨帧去重则利用固定机位拍摄时真芽不动的特性多帧推理后合并距离过近的中心点from ultralytics import YOLO model YOLO(runs/seedling/exp1/weights/best.pt) image_area 640 * 640 centers [] for r in model.predict(tray_photos, conf0.3, imgsz640): if r.boxes is None: continue for box in r.boxes: x1, y1, x2, y2 map(float, box.xyxy[0].tolist()) area (x2 - x1) * (y2 - y1) if area 30 * 30 or area image_area * 0.02: continue centers.append(((x1 x2) / 2, (y1 y2) / 2)) merged [] for c in centers: if all((c[0] - m[0]) ** 2 (c[1] - m[1]) ** 2 20 ** 2 for m in merged): merged.append(c) print(估计出苗数:, len(merged))30×30 是 640 图上芽的最小经验框2% 面积上限挡育苗盘边缘的大块误检20px 距离阈值按实际芽间距调整密植的育苗盘可以缩到 12~15px。这套流程走顺后几百张图的萌芽数据集足够把「数苗」这件重复劳动交出去。我自己的习惯是每次训练完留三五张盘照片人工数一遍计数误差超过 5% 就回头查数据增强和面积阈值而不是急着换模型结构。希望这个思路帮到你少踩几个坑。本文还有配套的精品资源点击获取
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

企业微信机器人openclaw配置避坑:TaoToken统一Key接入少走弯路 2026/10/2 10:35:44

企业微信机器人openclaw配置避坑:TaoToken统一Key接入少走弯路

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
Python连接Impala并获取数据:TaoToken统一Key通道下的完整配置与验证 2026/10/2 10:35:43

Python连接Impala并获取数据:TaoToken统一Key通道下的完整配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
VS Code + EIDE 构建系统与多调试器配置深度实战:TaoToken 统一 Key 打通 OpenOCD 与 J-Link 2026/10/2 10:35:42

VS Code + EIDE 构建系统与多调试器配置深度实战:TaoToken 统一 Key 打通 OpenOCD 与 J-Link

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
八款降AI率工具实测:从检测原理到论文改写避坑指南 2026/10/2 10:35:35

八款降AI率工具实测:从检测原理到论文改写避坑指南

2026年专科生毕业季,我身边好几个朋友都在为同一件事头疼:论文写完了,AI检测那一关却过不去。学校的AIGC检测报告里,整段整段标红,AI疑似率直接飙到百分之七八十。我因为常年帮人改稿,最近一个月几乎把市面…

阅读更多 →
curl库64位bin选型与排错:从LNK1112到CMake完整落地 2026/10/2 10:35:35

curl库64位bin选型与排错:从LNK1112到CMake完整落地

简介:一个为六十四位Windows环境准备的CURL二进制库,由微软二零一七版工具编译,面向需要将网络请求集成到应用中的C/C开发者。CURL支持HTTP、HTTPS、FTP等协议,能完成文件上传下载、Cookie会话管理、请求重定向及多种身份认证&…

阅读更多 →
AI 辅助研发内部复盘(5/5):验证体系、产品协作与行动项(含硬核实战案例)——TaoToken 统一 Key 通道下的落地拆解 2026/10/2 10:35:35

AI 辅助研发内部复盘(5/5):验证体系、产品协作与行动项(含硬核实战案例)——TaoToken 统一 Key 通道下的落地拆解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉