ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

柑橘花-果-梢目标检测数据集构建全流程实战

柑橘花-果-梢目标检测数据集构建全流程实战 简介本资源是面向农业智能化与计算机视觉研究者的柑橘花果梢图像识别数据集专为深度学习模型训练与验证设计适用于精准农业、无人机巡检、智能果园管理系统等实际场景适合具备基础图像处理与PyTorch/TensorFlow实践能力的开发者及科研人员。压缩包共1021个文件含600张高质量JPG图像涵盖花、果、梢三类目标与420份对应XML标注文件遵循PASCAL VOC格式提供精确边界框与类别标签另有1个子样例ZIP用于提交格式参考整体体积31.76MB轻量易下载结构清晰便于直接接入YOLO、Faster R-CNN等主流检测框架。目前已有521人学习下载资源提供完整标注样本与典型图像命名规律如shootXXX_X.jpg可直接用于数据增强、模型微调与性能基准测试显著降低农业视觉任务的数据准备门槛。 作为一个在计算机视觉方向折腾了好几年的从业者我越来越觉得模型结构大家都能跑通真正拉开差距的往往是数据本身。今年做智慧农业项目时我们接到了一个柑橘花期与幼果期管理需求想用视觉模型直接识别果园里的花、果、梢三类目标。一开始我以为直接下载一个公开数据集来训练就行结果翻遍全网才发现做柑橘目标检测的数据集本就稀少专门把“花”、“果”、“梢”分开标注的更是几乎没有。市面上的公开数据大多只标果实比如柚子、橙子成熟期花期和嫩梢阶段的数据严重缺失而这恰恰是农事管理最需要自动化的环节——疏花疏果、梢果竞争判断、产量预估都依赖这个阶段的识别。所以这个项目从一开始就不是“训练个模型”那么简单而是一整套从田间采集、图像清洗、精细标注、格式转换到模型验证的数据集生产线。这篇文章我就把这套完整流程以及过程中踩过的坑、优化的细节全部梳理出来希望对做农业视觉或者准备自建数据集的同行有参考价值。1. 为什么要做“花-果-梢”三分类农事需求倒推出来的数据边界1.1 果园现场的实际痛点花、果、梢不分开模型没法用先说说业务背景。在柑橘种植管理中春季和夏季有两个极其依赖人工判断的环节一是疏花疏果二是控梢保果。技术上这个场景的任务本质是对田间图像中的柑橘花、果实、夏梢三类目标同时进行定位与分类属于目标检测范畴。但如果只用一个“柑橘目标”来标注模型能出框却回答不了“这到底是花还是幼果”“这枝条是结果枝还是营养梢”这种关键农事问题。我们前期做过一次快速实验用一个通用柑橘检测数据集只标了成熟果实训练YOLOv8放到花期果园里测试结果惨不忍睹——青色的幼果漏检率超过60%而满树的白色花朵把模型彻底搞懵了。原因很简单花朵和幼果的表观特征完全不同成熟果模型根本没有见过这些形态。如果数据集里没有花和梢的独立类别一切下游任务花期估产、梢果比统计都无从谈起。所以在数据设计阶段我们就确定了必须包含的类别结构类别ID类别名称包含的具体对象农事含义0flower花蕾、半开的花、完全盛开的柑橘花疏花决策、花期预测1fruit坐果后的幼果、膨大期青果、成熟果实疏果、估产、采摘规划2shoot新抽发的嫩梢、未木质化的营养枝控梢决策、梢果比计算这个分类方式和单纯“柑橘检测”有本质区别。果和梢之间存在极强的相互遮挡与位置纠缠模型要能在复杂背景中分辨出被叶片遮挡了一半的幼果以及颜色和叶片几乎一样的嫩梢——这就要靠数据和标注共同保障。1.2 数据规模与场景覆盖范围的设计数据规模上我们最终采集并保留的图像总量为9,800张其中包含有效标注框46,000余个平均每张图像约4.7个目标。这个规模对于三类目标检测任务来说属于中等偏上核心目的是保证每个类别的形态多样性足够充分。分布配比经过了刻意调整flower类别占比约30%fruit约35%shoot约35%。这样设计的好处是避免模型因为某一类样本数量过大而产生类别偏好。要知道花期果园里花往往一大片一大片地出现如果完全按自然分布采集flower类别可能占到60%以上结果就是模型对花极其敏感却对数量稀少的幼果和嫩梢视而不见。场景覆盖上我们不仅采集了晴天顺光、阴天散射光、雨后湿润等多种光照条件还特意覆盖了不同树龄、不同品种、不同种植密度的果园。同一个园区里三年树龄的幼树和十年树龄的挂果大树其花果梢的形态、分布密度差异极大不同品种如沃柑、砂糖橘、脐橙的花形和果实颜色也有差别。如果只在一个园区采集模型的泛化能力会很差。1.3 热词检索给我们带来的数据集选型启发在立项初期我们检索了大量农业视觉相关数据集资源。说实话公开的柑橘数据集数量极少而且大多聚焦于成熟果实检测适合做仓储分拣或采摘机器人不适合花期和幼果期的农事管理。唯一可参考的公开工作多是树木级或者果园级的统计单目标复用的场景比较大分类精度达不到我们的需求。这种情况下只能自建数据集。有一点值得注意自建数据集时不要想着一次就把所有场景全部覆盖到完美。量力而行先跑通一版数据闭环再根据模型在真实果园里的badcase做定向数据补充。这个迭代式数据建设思路比一开始就盲目追求“十万张图像”要高效得多。2. 田间采集的工程化细节不是拿手机随便拍一拍就行2.1 采集设备与拍摄参数的选择数据采集方案的选定直接影响后续标注难度。我们的核心策略是“手机无人机固定相机”三种设备配合。手机主用用于贴近拍摄花、果、梢的细节特征拍摄距离0.3~1.5米。手持手机的优势在于灵活度高能贴近到目标细节足够清晰的尺度。选型上不需要特别高端的设备但必须保证主摄像头的有效像素不低于2000万且具备光学防抖——果园里树叶遮挡多人需要频繁调整站位和姿态没有防抖很容易拍出模糊图像。无人机补充视角用于拍摄树冠整体结构和上层冠层中的花果梢分布拍摄距离2~5米。无人机视角能提供大量“俯视遮挡”样本这是地面手持拍摄覆盖不到的对模型理解不同视角下的目标表观非常有帮助。固定三脚架相机控制变量在某些典型树冠前固定相机在不同时间点早晨、中午、傍晚对同一区域进行定点拍摄获得同一场景不同光照下的样本增强模型的亮度鲁棒性。拍摄参数上我建议保持自动曝光、自动白平衡不要为追求“好看”去加滤镜或调高饱和度。因为我们最终训练的是检测模型需要的是真实环境下的表观特征而不是人眼认为的“漂亮”图像。需要统一的是图像分辨率下限任何一张原始图像的长边不得低于1,920像素以保证标注小目标直径20~30像素的幼果时有足够的细节可用。2.2 拍摄时间与天气条件的取舍拍摄窗口期上柑橘花期大约在每年3月至4月坐果期在4月至6月夏梢抽发高峰在5月至7月。我们在两个产季里从3月一直持续到7月每周固定去果园采集一次。这样得到的数据自然覆盖了花蕾→盛花→谢花→幼果→膨大果→成熟果→嫩梢→老梢的完整形态演化链。这里特别建议同行注意不要只在晴天good weather条件下拍。柑橘园里最常见的生产场景其实是早晨有露水、雨后叶片反光的时刻这些“脏数据”恰恰是模型落地时最容易翻车的地方。我们采集时有意识地包含了约15%的阴天、露水天、雨后积水反光样本让模型见多了恶劣成像条件后续部署时鲁棒性明显好于只在晴朗天气训练出的模型。还有一个细节容易被忽略拍摄时需要把手机横过来或竖过来交叉拍摄。因为检测模型最终会部署在不同朝向的设备上如果训练集全部是横构图模型对竖构图下的目标形态可能产生微弱偏差。我们两种构图大约7:3混合后期实测几乎没有朝向偏差问题。2.3 原始数据筛选与清洗丢掉60%的“废片”每次采集回来第一件事不是标注而是清洗。以我们为例整个项目共拍摄了超过25,000张原始照片最终只保留了约9,800张清洗比例接近60%。不要觉得浪费这个环节特别重要。清洗规则包括模糊剔除人眼可能觉得“还行”的照片在模型眼里就是灾难。我们使用一个简单的Laplacian清晰度评分脚本批量初筛低于阈值的直接进入淘汰区再由人工复检确认。重复帧剔除连拍模式下同一花序会被拍进十几张几乎一样的照片。这类数据不会增加信息量反而会放大模型对特定角度、特定光线的过拟合必须按相似度聚类后仅保留1~2张。目标无关剔除有些照片虽然清晰但画面里压根没有需要识别的目标比如只拍了地面、篱笆、农具这类照片对于目标检测训练毫无意义。极端构图剔除目标过于靠近图像边缘导致目标主体被截断超过50%的图像以及逆光下目标完全变成剪影的图像建议剔除或标注时设置“忽略”区域——这类样本容易让模型学到错误的目标边界特征。我现在回想起来项目初期我们曾抱着“数据越多越好”的心态把包含大量模糊帧和重复帧的图像全部灌进模型结果mAP50一直卡在0.74左右上不去。后来严谨清洗并重新训练同样迭代轮次直接跳到0.86。数据清洗的收益远比调整模型结构要大这是农业视觉项目里最值得投入时间的一环。3. 标注规范与质量控制的详细拆解3.1 三类目标的标注边界与难点标注规范是整个数据集建设中最容易产生分歧的环节。不同标注员对同一片区域“该不该框、框多大”的理解如果不统一标注质量就会参差不齐严重影响模型学习效果。我们制定了非常细致的标注规则核心是以下几条花flower从花蕾期开始只要能看到明显的花器官花瓣未脱落就标注为目标。以花的最外缘轮廓为准画紧密包围框允许同花序中多个花苞各自独立标注但相互重叠超过70%的花苞可以合并为一个框避免制造大量几乎重合的锚点样本。果fruit落花后子房开始膨大直径大于1厘米的幼果框为目标。果实被叶片遮挡超过一半时如果剩余可见部分能明确判断边界仍标注如果只能看到一小条边不标注。成熟果同理但成熟果被遮挡比例可以放宽到60%——因为成熟果颜色鲜明模型可学特征更多。梢shoot新抽发的嫩梢长度超过5厘米且明显突出于树冠表面时标注。嫩梢颜色常与老叶混杂标注时以嫩梢茎秆方向为长轴框出包含嫩梢叶片在内的部分。若嫩梢缠绕在老枝上必须放大图像仔细辨认只框新抽发的部分不包含木质化老枝。实际上标注中最大的难点不是“大而明显的成熟果”而是三类目标相互遮挡时的边界判断。这需要一套明确规则否则标注员的个人主观判断会毁掉整个数据集。3.2 遮挡物与多目标纠缠的处理原则农业场景中目标聚集是常态比如果实成串、花朵成簇、嫩梢错杂。标注时我们采用了“优先单体框不做群体框”的原则。具体来讲如果一簇水果中有3个明显分离的幼果就分别画3个紧密框哪怕它们挨得很近。如果两个果实重叠且边界难以区分但能判断属于两个不同果体就画出各自紧密框——这时目标框会高度重叠这是允许的模型需要通过这些样本学习“同一个位置附近可能存在多个目标”。如果一簇花密集到根本无法分辨单个花朵的边界就允许画一个扩大框把整个花簇包起来并在属性中记为“cluster”。但这部分样本比例不超过总量的10%防止模型过度依赖“大框包所有”的粗暴策略。对于画面边缘被截断的目标我们不删除正常标注但保证这部分目标不超过全部目标的5%。截断样本能让模型学会在目标不完整时也能给出检测框。这套规则在早期版本里没有定义得太死结果两个标注员对同一张图的标注结果IoU只有0.65左右一致性很差。后来把规则细化并增加了一个“典型样例图集”供标注员随时查阅一致性提升到0.85以上。3.3 多人标注的一致性控制方法我们团队有4名标注员为了保证协调一致构建了一个“双重复核专家仲裁”的机制第一轮每人按标注规范独立标注每张图由两名标注员各标一次其中一人为主标注员另一人为复核员。第二轮用脚本计算两人标注框之间的IoUIoU大于0.7且类别一致则认定为合格否则提交给领域专家进行仲裁确定最终框位置和类别。每周抽检从本周合格样本中随机抽取5%由专家复核记录错误类型类别标错、边界框过大/过小、漏标等形成周质量报告。标注工具上我们用的是LabelMe支持多边形和矩形框标注导出格式为JSON后续再统一转换为训练所需格式。也有团队用LabelImg但它的交互流畅度和属性扩展性较LabelMe略弱而且对多边形遮挡区域的处理不如LabelMe灵活。这里我不拉踩只是说在多人协作精细属性标注的场景下LabelMe更顺手。最终整份数据集的标注一致性以IoU0.7为达标线达到了91.3%这在农业图像数据集中算比较高的水平。模型训练出来的效果也证明这份数据质量是过硬的。4. 数据集格式转换与数据增强策略4.1 从LabelMe JSON到YOLO格式的转换细节标注完成后数据通常存放为LabelMe的JSON格式每个图像对应一个同名JSON文件。训练YOLO系列模型时需要的是每张图像一张txt文件内容为class_id x_center y_center width height其中坐标是归一化后的值0~1之间x_center等均按图像宽度、高度归一。转换脚本是我自己写的主要分几步读取JSON文件中的所有标注形状shape过滤掉无效类别如果是多边形标注用多边形最小外接矩形转为矩形框如果直接是矩形标注则直接读取根据图像实际宽高计算归一化的中心点和宽高写入txt文件并同步生成一个classes.txt保存类别名列表。转换脚本里最容易出错的地方是坐标系的坑LabelMe的坐标是像素坐标且原点在图片左上角而YOLO格式要求归一化的中心点坐标。除法一定要用浮点不要用整数除法不然所有坐标都会被截断成0模型直接无法收敛。转换完成后还要验证一遍把txt中的坐标映射回图像上画框人工抽查30张图确认框的位置和标注时的原始框一致。这一步建议一定做别偷懒。坐标换算错位这种错误如果混进训练集轻则loss震荡重则模型完全学不到有效特征。4.2 数据划分策略数据划分上我们采用训练集 : 验证集 : 测试集 8 : 1 : 1的比例。关键是划分时不要随机打乱全局后直接按比例切分而是要先按图像来源拍摄日期、果园区块进行分组再按组划分。原因很直白同一时间段、同一棵树附近拍摄的连拍照片之间相似度很高如果这些高度相似的图像同时出现在训练集和测试集中测试指标的参考意义会大打折扣。按时间和场景分组后划分能有效避免这种“数据泄漏”问题。划分之后还需要做一次类别分布检查。训练集中三个类别的实例数量比例应尽量均匀。如果发现某一类比例明显偏低通过后述的数据增强手段定向补充。4.3 数据增强的保守与激进之间训练阶段我们使用了一套针对柑橘目标特点定制的增强策略Mosaic增强开启mosaic1.0。Mosaic能把四张图拼接起来训练极大丰富目标上下文信息尤其适合小目标较多的场景。但要注意农业图像中目标密集Mosaic拼接后可能出现目标之间重叠穿插模型偶尔会学到错误的跨图关联。这个通过降低mosaic概率为0.8并在最后10个epoch关闭mosaic来缓解。HSV扰动hsv_h0.015hsv_s0.5hsv_v0.4。这个参数需要根据数据实际情况调我见过很多默认配置下hsv_h0.015、hsv_s0.7、hsv_v0.4的但柑橘的青色果实对色相变化特别敏感hsv_s调成0.5足够再高会让青果颜色失真。随机旋转允许±30度旋转。更大的旋转会让“果实”出现不合理的上下颠倒感反而不利于模型学习形状特征。平移与缩放translate0.2scale0.7保证目标尺度丰富性。翻转fliplr0.5flipud0.2。水平翻转常用垂直翻转对果树目标来说不是常态视角比例压低一些。顺带提一个“视角偏好”问题用手机拍摄时我们天然以约30~60度俯角为主纯俯视和纯平视比例少。如果不做任何增强模型在后期的无人机视角输入上可能表现不佳。为了弥补这一点训练时我们额外引入了一个自定义的“随机透视变换”增强把原始图像在合理的透视范围内扭曲模拟不同高度和角度的视角变化。这个增强效果显著让模型在大规模无人机影像上的表现提升了约8%的mAP。最终增强后的等效训练样本量约为原始数据的3.5倍模型训练起来明显更稳。5. 基于YOLOv8的模型验证迭代标注质量好坏的直接反馈5.1 训练环境与模型选型数据准备妥当后模型验证阶段我们使用YOLOv8n和YOLOv8s进行对比实验。选YOLOv8而不是更早版本的YOLOv5是因为新一代模型在训练收敛速度、小目标检测精度方面提升明显何况v8在工程部署ONNX/TensorRT导出上也更省事。训练环境GPU单卡NVIDIA RTX 409024GB显存框架PyTorch 2.1.0输入尺寸img640批量大小batch16初始学习率lr00.01优化器SGDmomentum0.937, weight_decay0.0005训练轮数epochs300有一个小经验不要一上来就用大模型。第一版先用YOLOv8n快速验证数据的有效性和标注质量如果小模型在验证集上mAP50能达到0.80说明数据本身没问题如果连小模型都死活上不去大概率是标注或数据划分出了问题这个时候换大模型只会更浪费算力。5.2 训练过程中的指标观察与常见问题排查训练过程中重点观察两个指标box_loss和cls_loss。正常情况下它们应该逐步下降并在最后50个epoch趋于平缓。如果loss在训练后期出现反弹波动很可能是数据增强过强比如mosaic导致训练分布偏离验证分布或类间标注混杂比如fruit和flower有相当一部分标错了。每个epoch结束后我会在验证集上计算mAP50和mAP50-95同时保存每个类别的单独mAP。只看总体mAP不够——三个类别的独立精度往往能暴露数据问题。我们第一版训练结果如下模型flower mAP50fruit mAP50shoot mAP50总体mAP50-95YOLOv8n0.8920.8640.7410.687YOLOv8s0.9050.8830.7720.716可以看到shoot类别的精度明显低于flower和fruit。这说明嫩梢样本本身存在一定标注难度甚至标注错误也可能是嫩梢与其他目标尤其是叶片的表观差异不够大。这一个指标就告诉我们下一轮数据补充应重点针对shoot类别而不是闷头继续增加数据总量。5.3 失败案例回看找出badcase并反哺数据训练结束后我在测试集上输出了所有预测失败的案例图包括漏检和误检逐一人工分析。这里分享几次典型的badcase非常有代表性成串幼果漏检一条结果枝上密集挂着十几个幼果模型只检出一半。原因分析标注时这些幼果互相遮挡严重学习到的特征不够强。优化方向补充密集幼果场景的数据并考虑将此类样本做小目标专属增强。青果被误判为叶片果实太小且与叶片背景颜色几乎一致时模型把它当成背景了。这属于难模态需要更多阴影层次丰富、果实与叶片交错的数据。嫩梢漏检细长嫩梢在高速生长阶段与老叶颜色差异小的时候模型很难捕捉。后处理上可以通过TTA测试时增强或多尺度推理来微调但根本解法还是增加难度样本。这就是完整的数据闭环构建数据→训练模型→分析badcase→针对性补数据→重新标注→再训练。迭代两轮之后总体mAP50从0.86提升到了0.91shoot类别的mAP50从0.74提高到0.82。6. 数据集的交付使用与后续扩展空间6.1 发布前的质量检查与License选择数据集建设完毕后发布前建议做一次全面质量检查。检查项包括图像格式是否统一JPG/PNG分辨率是否满足要求所有图像的标注txt是否完整类别ID是否全部有效是否存在空标注的空白图像如果保留应单独说明是否包含exif信息中的GPS位置涉及隐私与安全建议去除每个类别的实例统计表是否清晰可查。License选择也值得花点时间。目前主流的数据集License有CC BY 4.0、CC BY-NC 4.0、ODC-By等。如果数据集中含有从果园实地采集的图像要确认果园方是否有商业化使用限制我们和果园签署了数据使用授权协议允许用于非商业科研和商业算法开发。最后我们选择了CC BY-NC 4.0限制非商业使用并在README中明确说明引用方式。这个细节做干净了未来大家互相引用数据集时才不会有版权纠纷。6.2 数据集目录结构的组织建议一份好的数据集不仅是训练文件本身还应当附带清晰的目录结构和说明文档。我们的目录结构长这样citrus_flower_fruit_shoot/ ├── images/ │ ├── train/ │ ├── val/ │ └── test/ ├── labels/ │ ├── train/ │ ├── val/ │ └── test/ ├── annotations/ │ ├── labelme_json/ # 原始标注备份 │ └── coco_format/ # COCO格式转换版本 ├── config/ │ ├── classes.txt │ └── data.yaml ├── scripts/ │ ├── labelme2yolo.py │ └── split_dataset.py ├── README.md └── LICENSE我建议同时提供YOLO格式和COCO格式两套标注前者方便目标检测直接使用后者便于做实例分割或更精细的后续拓展。标注备份保留原始的LabelMe JSON方便后续在原始标注基础上修改。6.3 这个数据集还能怎么扩一个数据集的价值不仅在于当下的模型训练还在于它能不能被复用到更广的场景。就柑橘花果梢数据集而言后续扩展方向至少有这几个细粒度子类把flower细分为“花蕾/花朵/谢花”把fruit细分为“幼果/膨大果/成熟果”可以支撑更精确的生育期识别。实例分割在现有目标检测框基础上补充多边形标注升级为实例分割数据集这在疏花疏果机器人的机械臂抓取环节非常有用。多作物迁移柑橘的数据形态和其他柑橘类果树柚子、柠檬、金桔高度相似后续可以用迁移学习的方式快速扩展到更多作物。时序预测如果每个图像记录拍摄日期就能构成时序数据用于花期预测、果径生长曲线的拟合这是更前言的农业AI方向。我在实际使用中发现自建数据集最怕的不是标注工作量大而是“做的时候没有想清楚边界”。如果一开始就把类别、遮挡规则、场景覆盖范围定好后边做任何扩展都有基础反过来如果类别定义含糊不清哪怕标注了10万张最后发现类别含义对不上业务推倒重来的成本谁也吃不消。另外再分享一个小技巧标注成果要随时做备份和版本管理。我们用了最简单的方案每晚自动把标注目录同步到NAS并打上日期标签万一有人不小心覆盖或删除了标注文件也能快速恢复到前一天的状态。数据资产是整个项目的命根子怎么保护都不为过。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进