基于YOLOv26的哈密瓜花朵识别:雄花雌花与花瓣状态分类实战
做农业视觉项目最怕的不是算法选不对而是你对地里那堆花的理解不够。去年我接到一个哈密瓜花朵识别与分类的项目目标物说复杂也复杂说简单也简单——检测出画面里的哈密瓜花区分雄花和雌花再对花瓣结构状态做细分识别。就这三件事把从数据采集到边缘部署的全链路都趟了一遍。如果你也想在田间地头做细粒度花朵识别尤其要分雄花雌花、看花瓣开合状态这篇文章值得你看完能少走不少弯路。1. 做一个哈密瓜花朵识别模型到底解决什么问题1.1 项目背景授粉季节的人工巡检痛哈密瓜是雌雄同株异花植物一朵花上面只有雄蕊或者只有雌蕊没有两性花。种大棚哈密瓜的人都知道授粉窗口期就那么几天每天天刚亮就要进棚子巡检看到雌花开了就赶紧人工点花雄花用来采粉。一个几十亩的大棚一个人从头走到尾弯着腰一朵一朵看两个小时起步费腰不说还容易漏。农户手里的相机也好、手机也好拍完照片还是靠人眼去数根本没有把看到的信息变成能用的数据。所以这个项目最直接的目标就是做一个能跑在边缘设备上的识别模型摄像头或者手机扫过去实时告诉我这是雄花还是雌花花瓣展开到什么程度了能不能用来授粉或者接受授粉。这里有个容易被外行忽视的细节棚里湿度大、光线杂花朵容易被叶子挡住哈密瓜花本身又不大直径大概三四厘米。要在这样的画面里做到稳定的雌雄区分不是一个分类模型能搞定的必须检测加分类联动。这也是我后来选YOLOv26而不是单纯用分类网络的原因。1.2 雄花雌花区分到底难在哪里很多人第一次听说这个需求第一反应是雄花和雌花不是长得不一样吗看图分类不就行了。真拍回来你看一眼就明白了难的不是品种差异而是状态差异。雄花的特征是有细长的花柄、花蕊明显雌花最大的区别是花托部位有一个明显膨大的子房花朵下方的小瓜形态已经能看出来。但在花没完全张开的时候雄花和雌花的区别非常小尤其是花瓣还包着的时候你远远拍过去看到的全是黄色的花瓣子房完全被遮挡。等到花瓣快凋谢的时候雌花的子房已经膨大得很明显了反而不容易认错。真正难的是开花初期和半开期。花瓣结构识别就更细了。同一个雄花花药没散粉的时候适合采粉散粉之后粉的质量下降雌花的花瓣张开角度直接决定能不能授粉。所以项目里把花瓣结构分成未开放、半开放、完全开放、开始衰败四个状态。这四个状态的边界是连续的模型稍微不严谨就会把半开放判成完全开放。1.3 项目的整体技术目标整个项目的技术链路可以拆成这么几层检测层用目标检测模型在田间图像里框出每一朵花类目先粗分成花这一类。分类层对框出来的花朵图像再做雌雄二分类。细粒度层在分类基础上对花瓣结构状态进行四分类。把三件事串起来才算完整的哈密瓜花朵识别与分类。如果只做检测不做雌雄分类农户拿到手还是一个框没有任何决策价值如果只做分类不做检测图像里只要有两三朵花就全乱了。所以我的做法是检测阶段用YOLOv26把花朵位置找出来然后针对每个检测框再做一次精细分类。这样做的好处是检测模型不用背区分雌雄的包袱专心把花找出来分类模型也不用关心花在哪、有几朵专心看花瓣结构两个模型各干各的准确率反而比端到端单个模型更高。2. 方案选型为什么是YOLO而且是YOLOv262.1 目标检测框架的候选对比做花朵检测摆在桌面上的方案其实不少。老牌的Faster R-CNN精度还行但推理速度在边缘设备上不够看SSD快是快小目标检测能力一般哈密瓜花在画面里经常只占几十个像素容易漏YOLO系列一直在速度和精度的平衡上做得比较好加上生态成熟社区资料多遇到问题好排查。我之前在别的农业项目里用过YOLOv5和YOLOv8对YOLO系的训练流程已经很熟。YOLOv26是这套系列延续下来的新版本官方仓库在训练、导出、部署这一条链路上做得非常省心而且针对小目标和密集场景做了一些结构性优化。对于田间花朵这种小目标群体分布的场景YOLO系的anchor-free检测头配合多尺度特征融合确实比传统两阶段模型更合适。2.2 YOLOv26对比前代的核心改进整个项目的方案选型也不是拍脑袋。YOLOv26这一版我个人最看重的改进有三个第一主干网络在特征提取时加强了对小目标的响应。花朵在640分辨率图像里通常只有30×30到60×60像素前代模型在浅层特征图上的小目标召回率一般稍远一点的镜头就容易漏检。v26在浅层特征融合上做了调整小目标召回率有明显提升。第二训练阶段的动态标签分配更稳。不知道你有没有遇到过这种问题花朵密集的时候两个检测框挨得特别近模型把两朵花并成一朵或者一朵花重复输出两个框。v26的动态匹配机制在训练时会根据预测框与真实框的重合度动态分配正样本密集场景下的重叠框问题比前代少。第三模型结构上加入了更轻量的注意力模块用来增强对花朵局部细节的感知。这对后期的雄花雌花分类是有直接帮助的检测框能更准确地框住子房区域分类模型就能拿到更好的输入。2.3 为什么不直接使用现成作物识别模型接项目的时候也有人问网上的开源模型里不就有草莓花识别、番茄花识别的吗改改不就能用我说不行。哈密瓜花和草莓花的结构差异很大更关键的是开源模型大多只做开花/未开花两级分类根本没有人做过雄花雌花加花瓣结构的四状态细粒度分类。你要拿一个通用植物识别模型来跑它最多告诉你这是花告诉不了你这是雄花还是雌花更看不出来花瓣是半开还是全开。农业视觉项目的经验法则就是同一个区域的模型只能当作特征提取器不能当作业务模型直接上线。所以我还是老老实实从数据采集做起用YOLOv26重新训练。3. 数据准备首要是质量其次才是数量3.1 田间采集的实操要点数据采集是在一个合作大棚里做的前后去了四趟分布在不同的开花阶段。这里有一个很多人容易忽略的点不是一次性拍够数量就行而是要覆盖整个花期的不同状态。开花的第1天、第2天、第3天花朵的外观差异非常大。如果只在盛花期拍模型根本没见过衰败期和未开放期的花测试时准确率直接崩。我当时的采集方式是手机横拍、竖拍各一部分模拟不同安装角度。分别在晴天上午、阴天上午、傍晚各采一批覆盖不同光照。同一朵花从正面、侧面、俯视三个角度各拍一张尤其要拍侧面因为雌花的子房膨大特征在侧面最明显。拍摄时混入一部分叶片遮挡、双花重叠、虚焦的样本这些是实际的困难样本模型后面能不能扛住就看训练集里有没有这些坏样本。采集总量最后是九千多张原始图像去掉模糊和重复的剩下八千张左右。这个量级对二分类加四分类的任务来说是够用的重点是每一类都要有足够的正样本。3.2 标注规范雄花、雌花、花瓣状态怎么定义标注这一步最容易翻车。问题在于你觉得这个花是雌花标注师傅觉得是雄花。所以在动笔标注之前我先把标注规范文档写出来了保证不同的人标出来的结果一致。检测层的标注很简单只要是哈密瓜花不管雌雄、不管花瓣状态统一框成flower。框要贴近花朵的外轮廓不要包进去太多叶子也不要切掉花瓣边缘。分类层的标注是重头戏。每张图里的每一朵花除了检测框还要记录两个属性性别和花瓣状态。性别三分类male雄花、female雌花、unknown看不清。花瓣状态四分类closed未开放、half_open半开放、full_open完全开放、wilting衰败。这里有个容易踩的坑标注时看到被叶子遮了一半的花不要硬标。我一开始要求所有花都必须标清性别结果标注员开始猜导致训练集里有大量错误的隐性标签。后来改成看不清就标unknown。训练时把这些unknown样本排除在分类损失之外只参与检测训练准确率反而上来了。3.3 数据增强策略和数量估算八千张原始图像对YOLO系模型来说不算多所以增强策略直接决定模型过不过拟合。我用的增强参数是在YOLOv26默认增强基础上针对花朵场景调过的翻转mosaic四图拼接开0.5增加上下文多样性。旋转角度限制在±15度。这个很有讲究花朵是朝上的角度过大模型会把斜着的花当成一个对抗样本反而学坏。亮度调节±20%区间随机调整。棚内光照变化大这个增强非常关键。色彩抖动hsv饱和度±30%。哈密瓜花是黄色黄色通道在RGB空间里对光照特别敏感不抖动模型容易被同一个棚的颜色分布带偏。模糊少量高斯模糊模拟手机对焦不准的情况。增强后的有效训练样本大概到了三万张左右训练轮数可以适当延长而不过拟合。我记得最终训练时验证集上的mAP0.5稳定在92%上下雄花和雌花的分类精确率都在90%以上花瓣状态四分类的宏平均F1在85%左右。4. 模型训练实操从云服务器到命令行部署4.1 环境准备与依赖安装训练环境我用的是云上的带显卡服务器RTX 4090 24G显存Ubuntu系统CUDA跟PyTorch版本匹配好之后直接拉YOLOv26官方仓库的最新代码。创建环境的时候建议用Python 3.10以上的虚拟环境然后安装requirements。踩过一次坑直接用全局环境装依赖结果numpy版本跟torch冲突训练到一半报shape error排查了半天。所以哪怕你觉得麻烦也一定要用venv或者conda隔离环境。安装完依赖之后先跑一次自带的预训练权重推理确认整个推理链路是通的再开始训练。这一步能帮你排除很多环境层面的低级问题。4.2 训练参数设置与关键解释我最终训练用的参数是这样的python train.py \ --data data/hami_flower.yaml \ --weights yolov26s.pt \ --img 640 \ --batch 16 \ --epochs 300 \ --device 0 \ --optimizer AdamW \ --amp这里几个参数背后的考虑值得说一下。模型规模选的是yolov26ssmall版没有选最大的x版本。理由很简单最终要部署到边缘设备上x版本精度高但推理时间不达标s版本在精度和速度之间最均衡。数据侧已经靠增强补够了模型不需要用参数量硬抗。batch设置为16是基于24G显存的实际考虑。batch太小BN层的统计量不稳定batch太大显存与训练时间都吃紧。16这个值在单卡上比较稳妥。epochs设为300配合早停机制。花朵分类任务的特征差异性没有自然图像那么大训练到150轮左右验证集损失就趋于平稳继续训练到300轮主要为了让细粒度特征更稳定。如果不开早停后面容易过拟合所以我在训练命令里加了patience30。4.3 训练过程监控与调优训练过程中我习惯同时盯着两套指标loss曲线和混淆矩阵。loss曲线方面box_loss和cls_loss在前50轮下降得很快150轮之后基本是慢慢磨。如果cls_loss突然反弹大概率是学习率太高或者某个类别的样本太少这时候先检查数据分布再考虑调学习率。混淆矩阵一定要在验证集上生成不要看训练集的。我用best.pt权重跑了一遍验证集发现花瓣状态里半开放和完全开放的混淆比较严重有不少半开的花被分到了full_open里。这个结果符合预期因为半开和全开在视觉上本身就相近。解决办法是把训练集里半开花的图像数量补到和其他类持平同时增加了一部分贴近花瓣边缘的裁剪图让模型更关注花瓣张开的边缘形状。整个训练过程耗时大约12个小时300轮跑完。没有做太多超参数搜索现在的YOLO系模型对参数不敏感只要数据靠谱默认配置已经能出不错的结果。5. 雄花雌花区分效果评估从指标到可视化5.1 核心指标mAP、精确率、召回率怎么解读评估阶段我用验证集约八百张图两千三百朵花做了一轮完整的测试。主要看这几个指标mAP0.5检测框和真实框IOU超过0.5算正确这个指标稳定在92%。mAP0.5:0.95更严格的指标能看出框的精准度稳定在78%。这个数值对花朵这种小目标来说已经不错。雄花分类精确率预测为雄花的结果里真实是雄花的比例92.1%。雌花分类精确率91.6%。花瓣状态四分类宏平均F185.4%。很多人只看mAP实际上这个项目里雌雄分类精度比检测框的mAP更重要。因为检测框有点偏差花瓣边缘少框一两毫米问题不大但如果雌雄分错了后面整个决策就错了。所以我把分类层的指标单独拿出来跟踪不代表检测层的置信度。5.2 混淆矩阵里的关键错误从混淆矩阵看主要错误来源有三个第一个是雌花和unknown之间的混淆。被叶子遮住子房的雌花模型确实很难判断会输出unknown或者干脆给一个不稳定的分类。这是很正常的换成是人也看不出来。第二个是半开放和完全开放的混淆。两个状态的边界是连续的模型的概率输出经常在0.5附近徘徊。解决办法是在后处理里加一层规则如果模型输出半开放的概率小于0.6且完全开放概率在0.3到0.5之间就再裁剪花朵中心区域做一次局部放大判断。这个二次判断把半开和全开的F1提升了差不多三个百分点。第三个是密集花朵下的重叠框。两朵花离得近时检测框会相互覆盖导致分类器输入里混入了旁边花的像素。针对这个问题我在后处理里加了非极大值抑制的阈值调节把IOU阈值从默认的0.45调到0.35重叠框的产生少了很多。5.3 花瓣结构识别的具体实现花瓣结构识别不是一个单独模型而是在检测框基础上加的一个多头分类分支。训练时每个检测框除了对应性别标签还对应一个花瓣状态标签。推理时同一个检测框会同时输出性别和状态这样整个流程只需要一次前向传播效率很高。具体实现上我在分类层对花朵中心区域做了一次cutout也就是把花朵中心的子房区域随机遮挡一部分再训练逼模型去关注花瓣边缘的弧度信息。这个trick是我在训练花瓣状态时临时加上的效果出乎意料地好直接让完全开放的精确率提升了四个多点。可以这么理解完全开放的花花瓣外翻的弧度跟半开的花有明显区别但模型很容易偷懒只看花朵中心的黄色像素量不看花瓣边缘形状。cutout把中心区域遮掉以后模型只能靠边缘形状去判断反而学得更准了。6. 部署到田间边缘设备上的实时识别6.1 模型导出与端侧适配训练完成后模型要下放到田间设备上跑。我这里的目标设备是Jetson的一台边缘计算盒子算力比训练服务器差一大截所以要做一次模型压缩。第一步是把PyTorch权重导出为ONNX。YOLOv26官方仓库自带导出脚本导出时固定输入尺寸为640×640开启动态轴会拖慢TensorRT的优化效果固定尺寸在边缘设备上更友好。第二步是用TensorRT把ONNX转成engine文件开启FP16半精度推理。实测下来FP16在花朵识别这个任务上几乎不掉点mAP损失不到0.5%推理延迟从纯PyTorch的每帧90毫秒降到了25毫秒左右完全满足15帧每秒的实时识别需求。需要注意TensorRT的engine文件和具体的GPU型号绑定换一台设备要重新转换不要直接拷贝.engine文件过去。6.2 实时视频流识别与触发逻辑部署端我用了一个非常简单的架构摄像头通过RTSP协议拉流。解码后的帧送入TensorRT推理线程。推理结果写到共享内存队列。另一个业务线程从队列里取结果判断是否触发告警或记录。花朵识别的触发逻辑设计成一个状态机。默认状态下持续检测所有花朵记录每一朵花的性别和花瓣状态。当检测到一朵雌花处于完全开放状态并且附近5秒内没有匹配到授粉记录时就触发一次提醒推送照片和位置编号给工作人员。雄花则是当它处于半开放或完全开放状态时标记为可采粉方便工人集中采集花粉。这个逻辑说起来简单但实际部署时有一个很坑的点连续视频帧里同一朵花会被检测很多次如果每次检测都触发提醒授粉员会被提示轰炸。所以我在业务层做了目标跟踪匹配用IoU加位置信息把连续帧里的同一朵花关联起来只有状态的连续帧计数超过8帧时才真正触发。相当于去抖效果从每分钟十条提示降到了每天主动提醒该棚哪几朵花该处理。6.3 弱网与断网环境下的本地存储大棚里的网络条件相信去过的人都有数信号时好时坏断网是常态。所以在部署设计里所有视频流解析和识别都必须跑在本地云端只承担统计报表的功能。本地识别结果的日志先落盘用SQLite存一份结构化数据每天夜里网络好的时候再同步到云端。这里有一个重要的经验不要在视频处理链路里直接依赖云端接口。我在初期试过把每一帧识别结果实时上传断网三秒整个识别线程就卡死了因为网络请求阻塞了处理循环。后来改成本地队列加异步上传断网只会让队列堆积不会影响核心识别流程。农业物联网项目稳定性优先数据及时性可以妥协。7. 常见问题与排查实录7.1 雌雄标注不一致导致的训练偏见项目中期出现过一次训练指标看起来很好但一到新棚验证就掉点的情况。排查了很久最后发现在标注阶段不同标注员对雌花子房是否明显膨大的判断标准模糊导致一部分雌花样本实际是雄花模型学到了一堆相互矛盾的特征。解决办法是把争议样本全部抽出来重新标注并且给了明确的判定标准子房直径明显大于花瓣直径的三分之一时才算雌花否则全部标为雄花或unknown。这类标准一定要在项目开始时就定好否则后期返工成本很大。7.2 小目标漏检与遮挡漏检花朵在画面里占的比例小加上叶子遮挡漏检问题在整个开发中一直存在。主要优化手段有三个一是把输入分辨率从640提到768小幅提升了小目标的召回率代价是推理速度下降约15%二是在训练数据里专门加入遮挡样本和远距离小目标样本让模型见过这类场景三是在后处理阶段对低置信度的候选框降低阈值再补检一次用非极大值抑制的阶段过滤掉重复框。补检这个技巧值得说一下。主检测阈值设在0.3输出置信度在0.15到0.3之间的框先不丢等主检测框做完全局抑制之后再单独处理这些低置信度框如果它们跟高置信度框完全没有重叠就保留下来。这样漏检率降了两个百分点左右代价是会有少量误检需要在场景里权衡。7.3 花瓣边缘的过拟合问题有一版模型在训练集上的F1很高验证集上也能看但一拿到另一个大棚就明显变差。分析后发现是过拟合了当前棚的光照和背景花瓣边缘的颜色和纹理特征被过度放大。解决方案是引入更多样的背景。我从不同大棚、不同光照条件下补采了一批图像同时在增强阶段加入了更强的色彩扰动让模型不依赖于单一的黄色色相。最终版本在多个棚的跨域测试中花瓣状态分类的F1下降控制在3%以内算是可以接受的范围。8. 最后说几句实际操作的感受这个项目从数据采集到部署跑通前后大概两个多月。最大的体会是农业视觉项目的天花板不在模型结构而在数据质量和对业务细节的理解。你算法再强不知道雄花的子房在哪里、不知道花瓣开合状态的连续边界做出来的东西就是花架子。另外一个重要心得是不要把检测、分类、决策耦合得太死。像我最后做成的架构检测模型输出花朵框分类模型输出性别和花瓣状态业务层再根据连续帧做决策。每一层都能单独调试出问题的时候排查起来特别快。最后我想提醒一点边缘设备上做目标检测性能优化的收益往往比调模型结构更大。同样的YOLOv26s权重PyTorch直接跑和TensorRT FP16跑速度差距是三倍以上。先把部署链路打通再去抠那几个点的精度效率会高得多。如果你正要开始类似的花朵识别项目我的建议是先拿手机对着地里的花拍一周把各个状态、各个角度的照片收集齐了再谈训练。数据齐了后面都是水到渠成的事情。