
简介数据来自葡萄不同生长阶段覆盖发育进程中的多种外观形态可用于训练生长阶段识别或果实检测模型。v0.1 含 1212 张 1280×720 图片、3993 个边界框v0.2 增至 2099 张图片、6641 个边界框两版分辨率一致便于复用现有模型输入尺寸也能对比数据规模对效果的影响。压缩包共 2000 个文件整体约 314.1MB主要包含 JPG 原图、TXT 标注文本和 XML 标注文件其中 JPG 为原始图像TXT 与 XML 记录目标框信息便于转入 YOLO 或 VOC 等常用检测框架。已有 180 人学习下载。样本以唯一编号命名图像与标注可快速配对适合训练集/验证集划分对深度学习初学者而言可直接用于练习数据预处理、目标检测训练与结果评估也可为葡萄长势分析、果园智能监测提供数据基础已有检测基础的开发者还可先用 v0.1 快速跑通流程再用 v0.2 验证模型鲁棒性。1. 葡萄在不同生长阶段的图像数据集先搞清楚“长到哪了”再谈估产和病害预警做果园视觉的人都会碰到一个尴尬网上搜“葡萄图像”出来一大片成熟果穗的精修图真要拿来训练一个“分清葡萄当前长到哪个阶段”的模型数据立刻成了瓶颈。这个标题所指的图像数据集不是随手拍的相册而是严格按生长阶段组织、统一拍摄条件、带明确标注的作物图像数据集。它和常见的病害图像数据集有本质区别——病害数据集聚焦病斑特写而这个数据集要回答的是“时间序列上的形态变化”。它能直接支撑三类任务生长阶段分类、果穗检测与计数、基于物候期的农事决策。适合谁做植物表型分析的算法工程师、果园数字化团队、以及想用视觉模型替代人工巡园的一线农技人员。2. 生长阶段怎么定用 BBCH 编码把九个阶段钉死图像数据集的灵魂不是像素是标签体系。葡萄在不同生长阶段的划分农学上有一套现成的通用语言——BBCH 编码。这套体系把葡萄生命周期拆成 0 到 9 共十个主阶段从芽萌发一路走到休眠每个阶段都有明确的形态学判据。做图像数据集如果不先定这套标准标注员会在同一张图上吵起来。2.1 为什么选 BBCH果园拍照的“公共语言”BBCH 是欧洲植物保护组织推广的物候学编码标准广泛用于小麦、玉米、果树和葡萄。它的好处有三点第一阶段边界清晰每个主阶段都能对应到一个肉眼可辨的形态事件第二不是葡萄领域自造的分类后续想和气象数据、农事记录合并分析时能直接对上数据库里的物候字段第三论文和农业软件里普遍使用你标注出来的数据集别人拿来就能用不存在“这个阶段你叫花期我叫开花期”的语义混乱。实际采集时我一般不会把 9 个休眠阶段收进数据集。原因很直接——落叶后的光杆枝条在视觉上几乎没有辨识度模型学不到可迁移的特征徒增背景噪声。数据集覆盖 0 到 8 阶段即可。2.2 九个阶段的视觉判据从芽绒到果穗成熟光有编码不够标注员需要知道“每个阶段在图里长什么样”。这九个阶段的形态差异不是均匀分布的——有些阶段隔两天就大变样有些阶段能持续两周却没明显变化。做标注规范时我会给每个阶段配上三句话一句描述整体形态、一句点出最关键的判别部位、一句说明最容易和相邻阶段混淆的点。下面这个表是标注规范的核心也是所有标注员共用的一套“看图说话”标准BBCH 主阶段阶段名图像中的视觉判据拍摄重点0芽萌发芽鳞裂开绿色芽尖或绒球状结构露出枝蔓节位特写1叶发育第一片叶平展叶面积明显增大新梢顶部俯视角3花序出现花穗在叶间可见小穗紧密抱合新梢中段侧视5开花花帽脱落可见花瓣掉落痕迹花穗整体与特写6果实膨大果粒如绿豆至黄豆果串下垂果穗侧面 45 度7转色红品种果粒变红白品种变透明果穗与背景叶对比8成熟果粒颜色稳定可采收果穗全貌与果粒细节我给每个阶段配了“最小可分辨特征”——比如开花期你优先看花帽脱落而不是数花瓣。这样即使两个标注员水平不同看到的关键部位一致标注就不会跑偏。2.3 用代码把阶段字典定下来标注规范要落地不能只写文档得变成代码里的字典。这个字典是后续所有脚本的“金标准”数据整理、标签检查、模型类别映射都从它出发。GROWTH_STAGES { 0: {name: budbreak, cn_name: 芽萌发, discriminant: 芽鳞裂开、绿色芽尖外露}, 1: {name: leaf_development, cn_name: 叶发育, discriminant: 第一片叶平展、新梢伸长}, 3: {name: inflorescence_emergence, cn_name: 花序出现, discriminant: 花穗可见、小穗簇生}, 5: {name: flowering, cn_name: 开花, discriminant: 花帽脱落、可见落花痕迹}, 6: {name: berry_swelling, cn_name: 果实膨大, discriminant: 果粒黄豆大小、果串下垂}, 7: {name: veraison, cn_name: 转色, discriminant: 红品种转红/白品种转透明}, 8: {name: maturity, cn_name: 成熟, discriminant: 果粒颜色稳定、果梗木质化}, }这段字典的作用是让“阶段”从自然语言变成程序可用的枚举。注意我把开花期放在 5、果实膨大放在 6中间跳过了 2、4 和 9——2 和 4 是过渡性细分图像上区分度太低收集了只会让模型学到噪声9 是休眠期对农事决策没有价值。类别定义里最关键的是discriminant字段它在后面做标签复核时会被自动读取作为人工检查的提示语。3. 数据采集与整理拍多少、怎么拍、目录怎么组织标签体系定了接下来是数据集建设的体力活。很多团队在这个环节翻车不是因为算法不行而是因为拍回来的图没法用。图像数据集和工业图像数据集不一样它在自然光照下拍摄环境变量完全不可控采集策略决定了数据集的天花板。3.1 先算账一个能训练的数据集要拍多少张先别急着架相机把数量账算清楚。对于生长阶段分类任务每个阶段至少 300 到 500 张图七个阶段共需要 2000 到 3500 张如果还要做果穗检测建议每个阶段翻倍因为检测任务需要覆盖不同角度、不同距离、不同遮挡程度。算上筛选时剔除的模糊和过曝图实际拍摄量要按目标量的 1.5 倍准备。这里有个常见误区同一株葡萄每隔三天拍一张拍十次就以为有十张不同样本。错这是同一株同一果穗的时间序列不是独立样本。模型会把背景的枝条纹理当作特征换一株葡萄就失效。独立样本的定义是不同植株、不同位置、不同朝向的果穗。采集时一定要“打一枪换一个地方”而不是蹲在同一棵树下按快门。3.2 拍摄设备与选型手机也能用但有三条底线设备选择上一台 1200 万像素以上的主流手机完全够用前提是满足三条底线。第一图像不得压缩过度关闭省电模式下的“智能压缩”保证长边不低于 2000 像素第二不得开美颜或任何场景增强滤镜这会改变果粒的真实颜色分布直接影响转色期的分类第三拍摄时保持果穗在画面中占比超过三分之一远景图留作辅助数据不作为主样本。如果预算充足可以用一台带 GPS 和光谱传感器的工业相机做补充采集。GPS 能记录株行位置后续和产量数据做空间分析时非常有用。但多光谱不是必需——生长阶段识别依赖的是形态和颜色特征普通 RGB 已经能覆盖绝大部分判别信息。3.3 目录结构与批量整理脚本采集回来的原始文件名是IMG_20240602_163000.jpg这种格式直接扔给训练脚本会让人崩溃。整理时先人工粗筛把模糊的、过曝的、果穗占比过低的删掉再按阶段归类到以 BBCH 码命名的目录里。下面这段脚本把散落在多个子目录里的原始图统一改名并归入标准结构是每次采集完之后的例行操作#!/bin/bash # organize_grapes.sh # 用法: ./organize_grapes.sh 原始目录 阶段码 输出根目录 # 例如: ./organize_grapes.sh ./raw_0601 7 ./grapes_dataset RAW_DIR$1 STAGE$2 OUT_ROOT$3 STAGE_DIR$OUT_ROOT/${STAGE}_$(echo stage_$STAGE) mkdir -p $STAGE_DIR COUNT1 for img in $RAW_DIR/*.jpg; do # 按拍摄日期和序号重命名避免不同设备文件重名 ts$(stat -c %y $img | cut -d -f1) newnamestage${STAGE}_${ts}_${COUNT}.jpg cp $img $STAGE_DIR/$newname COUNT$((COUNT1)) done echo 放入 $STAGE_DIR 的图片共 $((COUNT-1)) 张这段脚本的核心逻辑是输入原始目录和阶段码把图片复制到标准目录并重新命名。注意我用stat -c %y提取了文件修改日期这是为了给每张图打上时间戳采集时如果相机时间设置乱了后期还能靠文件名里的日期字段补做时间序列分析。实际使用时有个细节cp改成mv可以省一半磁盘空间但我建议保留cp原始文件在筛错时是后悔药。4. 标注方案与格式转换从边界框到 YOLO/COCO 的三条路线图像整理完成下一步是标注。这是整个数据集建设中最耗人工的环节也是决定模型上限的关键。很多人在这里省功夫最后模型精度上不去回头查才发现是标注标准没定清楚。4.1 标注三选一分类标签、边界框还是分割掩膜一个常见的疑问是“我这个数据集该标成什么样”答案是取决于下游任务。三种情况第一种整张图只标一个阶段标签适合做生长阶段分类器比如判断当前果园处于转色期还是成熟期这是成本最低的方案一张图一次点击就能完成。第二种在整图标签之外再加边界框框出花穗或果穗的位置适合做检测计数能同时回答“是什么阶段”和“有多少串”。第三种像素级分割标出果穗的轮廓掩膜适合做果穗尺寸测量、估产模型。第三种标注成本最高一张图可能要十分钟。从数据集的通用性考虑我强烈建议至少做到第二种——分类加检测。因为有了边界框你随时可以裁出单个果穗的样本把一个数据集拆成“整体场景”和“果穗特写”两份数据来用。只标分类标签的数据集后期想做检测还得回头补标返工成本极高。4.2 从 LabelImg 到 YOLO/COCO 的转换脚本标注工具我习惯用 LabelImg边界框或 Labelme多边形分割两者导出格式不同——LabelImg 默认输出 VOC XMLLabelme 输出 JSON。训练时常用的 YOLO 和 COCO 格式都不是它们的默认格式所以需要一小段转换脚本。以 LabelImg 输出的 XML 为例转为 YOLO 格式时最容易出错的就是坐标换算。XML 里是左上角和右下角的绝对像素坐标YOLO 需要的是中心点坐标加宽高并且要全部归一化到 0 到 1 区间。import xml.etree.ElementTree as ET import os def voc_to_yolo(xml_path, out_path, class_names): tree ET.parse(xml_path) root tree.getroot() w int(root.find(size/width).text) h int(root.find(size/height).text) yolo_lines [] for obj in root.iter(object): cls_name obj.find(name).text if cls_name not in class_names: continue cls_id class_names.index(cls_name) bbox obj.find(bndbox) xmin float(bbox.find(xmin).text) ymin float(bbox.find(ymin).text) xmax float(bbox.find(xmax).text) ymax float(bbox.find(ymax).text) # 中心点坐标 宽高全部除以图像宽高做归一化 x_center (xmin xmax) / 2 / w y_center (ymin ymax) / 2 / h box_w (xmax - xmin) / w box_h (ymax - ymin) / h yolo_lines.append(f{cls_id} {x_center:.6f} {y_center:.6f} {box_w:.6f} {box_h:.6f}) out_file os.path.join(out_path, os.path.splitext(os.path.basename(xml_path))[0] .txt) with open(out_file, w) as f: f.write(\n.join(yolo_lines)) class_names [flower_cluster, grape_bunch] for xml in os.listdir(annotations_xml): if xml.endswith(.xml): voc_to_yolo(os.path.join(annotations_xml, xml), labels_yolo, class_names)转换逻辑本身不难真正的坑藏在几个细节里。第一size/width和size/height必须从 XML 里读不能假设原始图像文件还在——标注完如果图像被压缩过像素对不上所有框都会错位。第二class_names的顺序一旦定了就不能改因为 YOLO 的标签用数字索引改顺序等于把所有标注重标一遍。第三归一化后保留 6 位小数就够了过多位数不会提升精度只会让文件变大。这套脚本跑完后建议做一次可视化检查把 YOLO 格式的框画回原图上肉眼抽查二十张。格式转换没有报错不等于坐标正确这是血泪经验。4.3 数据划分按果园划分而不是按图像随机划分数据划分是个看着简单、实际决定成败的步骤。很多数据集翻车就翻在这里按图像随机 8:2 划分训练集和验证集验证集精度 0.95一到真实果园就掉到 0.7。原因是同一株葡萄的连续时间序列图像被同时分进了训练和验证。模型相当于“见过”这些背景了。正确做法是按拍摄地点或植株编号划分同一株或同一行的所有图像必须进同一边。这样才能测试模型的泛化能力。5. 标注与训练的五个经典坑现象、原因、对策做这个方向几年踩过的坑比成功经验值钱。挑五个最高频的按“现象 → 原因 → 解决”写清楚这些钱你们不用再交一遍。5.1 同一幅图里有多个阶段标签到底归谁现象一张图里两串果穗一串已经开始转色另一串还在果实膨大期标注员 A 标了转色期标注员 B 标了膨大期反复返工。原因数据集规范只定义了“阶段长什么样”没定义“同一画面里有多个阶段时怎么处理”标注规则存在真空区。解决明确规则——分类标签以画面中占比最大或处于画面中心的果穗为准检测标签则分别对每串果穗标注各自的阶段类别。也就是分类用“主要对象投票”检测用“逐个指定”。定规则后两类任务都不会出现歧义。5.2 开花期和果实膨大初期长得太像模型一直混淆现象训练出的模型在开花期和果实膨大初期之间频繁错判混淆矩阵里这两个类别的互相误判率超过三成。原因花帽脱落后的幼果和刚坐果的形态差异极小肉眼尚且需要凑近看普通分辨率下模型更难区分。解决有两个方向的补救。一是数据补采在两个阶段的过渡期专门加拍一组 200 张的高重叠度样本二是修改标签粒度把过渡期的图像单独收一个“transition”类让模型先学会区分稳定状态再学边界状态。5.3 模型在正午拍摄的图像上严重掉点现象验证集精度正常但部署到现场上午十一点到下午两点之间拍的图像识别准确率骤降。原因数据集中绝大部分图像是在清晨和傍晚拍摄的因为那个时段光线柔和、果穗颜色还原度高、摄影师也舒服。正午的顶光在果穗表面形成高光和硬阴影模型从未见过这种光照分布。解决采集计划强制加入正午时段的视频帧抽取和补拍每个阶段至少保证 10% 的样本来自正午时段。拍摄时不需要在意过曝让果穗处于真实光照条件下的状态模型要学的就是这个。5.4 同一张图标注两次两次得到不同标签现象做标注一致性检查时发现同一张图像隔一周标注两次结果不一致率高达 15%个别阶段超过 20%。原因标注标准里没有指出“看哪里”标注员凭借整体观感做判断。果穗位置、大小、颜色在不同图片中差异巨大整体观感并不可靠。解决在标注界面的每个阶段旁边固定展示一个“参考部位截图”——例如转色期固定展示“果粒中部颜色变化”这样操作时注意力有锚点。这个措施通常能把不一致率从 15% 压到 5% 以内。5.5 验证集精度高一上真实果园就崩现象训练集和验证集划分用随机划分模型在测试集上准确率 0.93但部署到另一个产区后准确率不足 0.6。原因数据划分时没有按果园分组。同一株葡萄的图像被随机拆散训练时把某一株的枝条纹理作为特征换到另一产区后特征失效。这是典型的数据泄漏问题。解决划分按“拍摄批次/地块”维度进行一个地块的图像全部进同一侧。另外如果面向多产区部署采集时就至少覆盖三个不同地区的果园单园数据集训练出来的模型注定泛化力有限。6. 用数据集微调一个阶段分类器迁移学习的最小实验有了结构化的葡萄生长阶段图像数据集第一个验证实验我建议从迁移学习分类器做起。以 PyTorch 为例用 ResNet18 在 ImageNet 预训练权重上微调七分类任务输入尺寸 224输出七类。import torch import torchvision.models as models from torch import nn model models.resnet18(weightsmodels.ResNet18_Weights.IMAGENET1K_V1) num_classes 7 # 0,1,3,5,6,7,8 共七个阶段 model.fc nn.Linear(model.fc.in_features, num_classes) # 只微调最后两层前面的冻结权重保留通用特征 for name, param in model.named_parameters(): if layer4 not in name and fc not in name: param.requires_grad False optimizer torch.optim.AdamW(filter(lambda p: p.requires_grad, model.parameters()), lr1e-3) scheduler torch.optim.lr_scheduler.CosineAnnealingLR(optimizer, T_max30) criterion nn.CrossEntropyLoss()这里的关键参数学习率 1e-3 不算小但因为冻结了大量前层实际更新的参数量很少这个学习率是安全的。layer4和fc开放微调是因为这些层负责高层语义特征和葡萄的果穗颜色、形态最相关。如果数据量超过 3000 张可以再放开layer3一起微调通常能再提 2 到 3 个点的准确率。训练 30 个 epoch 后除了看 top-1 准确率一定要输出混淆矩阵。如果数据集质量过关混淔主要集中在前一章 5.2 提到的开花期和膨大期。这个结果反过来能指导补采方向形成“采集-标注-训练-分析-再采集”的闭环。我自己的经验是数据集的价值不在图像数量在标签一致性经不经得起交叉验证。标准统一、采集覆盖光照和地域多样性、标注规则可复查三点做到了这个数据集就能持续产生价值。希望这套流程能帮你在自己的果园数据上少走一段弯路。本文还有配套的精品资源点击获取