☰
基于YOLOv11的花生霉变检测系统:从训练到部署实战解析
2026/10/19 4:13:12 网站建设 项目流程

花生这东西,看着颗粒饱满、表皮光滑,其实安全隐患很容易藏在细节里。你要是蹲在粮库或者加工厂生产线旁边待过,就会知道霉变花生筛选是个多烦人的活儿——黄曲霉毒素超标可不是小事,直接关系到食品安全,人工目检又累又慢,漏检率还不稳定。我做项目的时候刚好碰上这个需求,索性就用深度学习把这件事自动化了。这套基于YOLOv11的花生种子霉变检测系统,从模型训练到UI界面,从登录注册到源码部署,一条线全串起来做完了,今天就把它拆开聊透。

这套系统能干什么,一句话说清楚:拍一张花生种子的照片,模型自动判断每一颗是正常、霉变还是可疑级别,并且把框框和置信度直接画在图上。它适合作种植户质检工具、食品加工厂的抽检辅助,也很适合给做毕业设计的同学打底子——有完整的Python源码、模型权重和界面工程,拿去做二次开发路径非常清晰。

1. 项目到底想解决什么问题

1.1 花生霉变检测的真实痛点

花生一旦仓储环境湿度控制不好,或者采摘前后遇水,霉菌繁殖速度会超出你想象。最典型的是黄曲霉菌,它产生的黄曲霉毒素B1是公认的强致癌物,而且花生表面的霉变特征往往是渐变的——初期可能只是一小块灰白色菌丝,中期表皮开始皱缩发暗,严重的时候整颗果子都会变成深褐色甚至黑绿色。这些特征用肉眼判断主观性太强,同样的样本,两个人看可能给出完全不同的结论。

工厂流水线上最常用的办法是色选机加人工抽查。色选机对颜色差异明显的霉变颗粒效果好,但对早期霉变、表面颜色变化不明显但内部已经变质的颗粒,几乎无能为力。人工抽查呢,一小时盯下来眼睛就花了,疲劳状态下漏检率飙升。我见过一个加工厂的实际数据,人工抽检的综合漏检率大约在15%到20%之间浮动——这个数字听起来不高,但放在大规模产量下,代价就非常可观了。

所以这套系统的核心目标很明确:用机器视觉替代人眼主观判断,用深度学习的特征提取能力捕捉人眼容易忽略的细微霉变信号。它不是一个概念玩具,是要能扛住实际使用压力的工具。

1.2 为什么选视觉识别路线而不走传统图像处理

有些朋友第一反应是:花生霉变检测不就是做个颜色阈值分割吗?发黑发灰的像素点找出来,统计占比,超了就判定为霉变。听起来可行,做起来全崩。

原因是霉变的视觉表现太不规律了。花生种类本身就分红衣、白衣、黑皮,不同品种的底色都不一样;还有花生本身的纹理、光照反射、拍摄角度带来的色差,都让颜色阈值法的鲁棒性大打折扣。更麻烦的是,霉变初期跟花生正常表皮上的斑点高度相似,单靠颜色特征根本区分不了。

YOLOv11这类目标检测模型的思路完全不同。它是从大量已标注样本里自动学习霉变的纹理、色彩、形状组合模式,而不是靠人手工定规则。什么意思呢?传统方法就像你告诉一个实习生"颜色暗到多少就挑出去",而深度学习方法像是让这个实习生看了一万颗霉变花生的照片,他自己就总结出了一套判断标准,而且这套标准能处理各种复杂场景。数据喂得越多,它的判断越稳。

2. 技术方案拆解与核心原理

2.1 YOLOv11为什么是当前阶段值得选的方案

YOLO家族走到今天,已经积累了很多实质性的优化。YOLOv11在几个关键环节上做了明显改进:Backbone部分的梯度流动设计更合理,C3K2模块替换了老版本的一些结构,在高重叠目标和小目标的检测场景下提升比较显著。花生的颗粒不算大,尤其是批量检测时一堆花生挤在一起,目标互相遮挡严重,这种情况下模型对遮挡和小目标的处理能力就极其关键。

还有个容易被忽略的点是训练收敛速度。YOLOv11的比较新的结构设计让它在同样的数据量下,收敛到可用精度的轮次更少。我用下来,同样的数据,v11比v8大概能提前十个epoch达到类似的表现。这意味着你调参试错的周期变短了,对项目迭代来说是非常实的效率提升。

当然,选择它也不全是因为性能,还有一个重要因素是生态成熟度。YOLOv11的官方实现接口和v8高度兼容,网上资料丰富,部署时踩坑了能找到对应的解决方案。做项目最怕的不是技术难,而是碰到一个冷门技术栈,报错搜遍全网都没人理你。这点YOLOv11没这个问题。

2.2 霉变花生在YOLO眼里长什么样

这个角度很有意思。你在标注数据的时候,不可能把"霉变"这个概念直接丢给模型,你必须把霉变转化为模型能理解的几何信息——边界框和类别标签。

模型学到的不是"霉变"这个抽象词,而是一系列特定的特征组合。我在特征可视化分析里观察到,模型对霉变的响应区域主要集中在三个部位:一是花生腰线附近的颜色突变区,二是表皮皱缩形成的纹理紊乱区,三是菌丝体覆盖形成的絮状模糊区。这说明它不是在靠某一个单一颜色通道作出判断,而是综合了边缘、纹理、颜色多个维度的信息。

这一点在实际测试中体现得很明显。我拿一款颜色接近正常的轻度霉变花生测试,色选机判断为合格,但模型给出的置信度在0.78左右,能准确识别出异常区域。后期做决策的时候,你可以把这个置信度分级利用起来——0.7到0.85之间就判为可疑,单独放一堆做二次复检,既兼顾了漏检风险又不过度打击良品。

2.3 数据集的构建与标注,偷偷告诉你几条经验

这是整个项目里决定上限的环节。模型结构再先进,喂进去的数据质量跟不上,结果就是训练时loss下不去,测试时一塌糊涂。

数据采集层面,我强烈建议不要只在理想条件下拍。光照要分强光、弱光、自然光、白炽灯、LED灯,背景要分托盘白底、传送带黑底、收纳袋杂色底,拍摄角度要覆盖俯拍、斜拍45度、侧拍30度。原因很简单——你采集时的多样性,直接决定了模型在真实使用时的鲁棒性。我见过太多项目,训练集清一色白底俯拍,一上线换成传送带灰底就彻底废掉,就是因为没有做好域泛化的准备。

标注层面的第一条铁律是:霉变区域是边界框,尽量不要用整颗花生做框。原因很实际,如果一颗花生只有30%面积霉变,你把它整颗标成霉变类,模型学习时会把健康的区域也关联到霉变特征里,导致误判率上升。正确的做法是只框住霉变那块的区域,让模型学到的特征是清晰的、局部的。

第二条铁律是:要专门建一类"背景负样本"图。就是完全没有花生的空托盘图、黑色传送带图、纯色桌面的图。这类负样本图不需要标注任何目标,但它们能显著降低模型的无中生有式误报——很多新手做检测项目完全忽略这个,结果模型动不动在空白区域画出框来,一问才发现纯背景图一张都没放进去。

我这次构建数据集总共收集了约3200张图,其中各类霉变样本占比60%,正常花生占比25%,背景负样本占比15%,标注后总共产生了接近9500个边界框目标。按8:1:1切为训练/验证/测试集,确保测试集完全独立于训练过程。

3. 系统实现与关键模块落地

3.1 整体架构要想清楚的一层关系

一个看起来不复杂的项目,真正动手时会发现牵扯的东西不少。如果连整体架构都没想清楚,先写哪个模块都会觉得错。我的经验是先把数据流画清楚:图像输入 → 预处理 → 模型推理 → 后处理 → 结果存储/展示 → 用户操作入口。每个环节的输入输出边界必须严格定义好,这样训练端和界面端才能并行开发不互相踩脚。

目录结构大致是这个思路:

peanut_detection_system/ ├── app.py # 主程序入口,启动UI界面 ├── models/ │ ├── best.pt # 训练好的YOLOv11权重文件 │ └── detector.py # 推理封装模块 ├── datasets/ │ ├── images/ # 原始图片目录 │ ├── labels/ # 标注文件目录 │ └── data.yaml # 数据集配置文件 ├── ui/ │ ├── login_window.py # 登录注册界面 │ ├── main_window.py # 检测主界面 │ └── widgets.py # 自定义控件 ├── utils/ │ ├── image_processing.py # 预处理与后处理 │ └── db_manager.py # 用户数据与检测记录管理 └── requirements.txt

UI这块选型上,我用的是PySide6,也就是Qt for Python。为什么不用tkinter?tkinter做简单的控件布局行,但你要实现图片缩放显示、拖动框选、多线程加载模型时不阻塞界面这些功能,PySide6的QThread和QGraphicsView给的支持要强得多。登录注册界面走的是本地SQLite,通过用户名密码校验后进入主界面,主界面加载训练好的best.pt进行推理。

3.2 训练环节的关键参数与调优过程

训练参数直接抄我这份可能不完全适配你的数据,但思路是可以借鉴的。我跑的基础配置是YOLOv11n规格,图像尺寸640×640,初始学习率0.01配合余弦退火调度,优化器选用SGD加动量0.937,权重衰减5e-4,批大小视显存而定——8GB显存条件下批大小设为16,batch大小不足的时候注意用梯度累积来补偿。

# 训练命令参考 yolo detect train \ data=peanut_mold/data.yaml \ model=yolo11n.pt \ epochs=200 \ imgsz=640 \ batch=16 \ lr0=0.01 \ optimizer=SGD \ momentum=0.937 \ weight_decay=0.0005 \ patience=30 \ cache=True

训练过程没有一帆风顺的。第一个版本的模型在验证集上的mAP50大约在0.72左右,听上去好像还行,但一检查混淆矩阵就发现问题了——正常花生被误识别为霉变的比率高得吓人。排查后发现是数据不均衡的锅:霉变样本太多,正常样本偏少,训练过程反复拉偏模型。

解决的办法是重新调整了数据集配比,增加正常花生样本数量,同时给霉变样本做随机颜色抖动增强来增加类内多样性。调整后重跑训练,mAP50升到了0.84,mAP50-95也有0.71,这个指标在花生颗粒这种不算太小的目标上已经能打了。

推理侧的速度表现,我实际测下来差不多是这样:

硬件环境推理耗时/张备注
RTX 3070 (8GB)约25ms满足实时检测要求
RTX 3060 (6GB)约32ms正常流畅
CPU纯推理 (i7-12700)约300ms脱机模式可用但不太实时

3.3 UI界面与登录注册模块的实现细节

登录注册界面初看像小儿科,但细节做得不好真会影响整套系统的第一印象。我的实现大概分三块:密码存储用的是哈希加盐,不是明文存库——这个细节很多人会踩坑,直接明文存密码一旦数据库泄露就是灾难,加了盐能显著提升安全性;注册页面做了两次密码校验和弱密码拦截;登录成功跳转主界面,失败会弹原因提示。

主界面的功能布局围绕一个核心使用流程来转:上传图片 → 自动检测 → 查看结果 → 保存报告。左侧放导航和信息区,右侧放图像预览区。加载模型的过程看不到任何提示,用户会以为程序卡死了,所以我在程序启动后用一个后台线程加载权重,加载过程中显示"模型加载中,请稍候"的进度条,这个交互细节强烈建议加上,体验差了好几档。

图像预览区用了QGraphicsView来支持放大镜级别的拖动和缩放,检测结果的框和标签直接以浮层形式绘制在图像上。旁边还有一个统计表格,列出每颗花生的检测编号、类别判定和置信度数值,一键导出CSV的功能也补上了。

4. 训练与部署阶段的高频问题排查

4.1 损失不下降或收敛过慢,从哪几步排查

模型训练时loss卡住不动是新手最常见的噩梦。这事本身不可怕,可怕的是不知道从哪里排查。按我的经验,排查顺序是:先看数据配置,再调学习率,再看Backbone是否冻结,最后检查标签是否对齐。

第一个要确认data.yaml里的类别编号和标注文件内容一致。我第一次跑自己的数据时就出过这问题,标注软件导出的类别是从1开始的,但data.yaml里面类别编号是从0开始的,导致模型学了一个完全错位的映射,loss直接原地起飞。这个错误最诡异的地方在于它不会报错——程序正常跑,就是效果全错。

第二个常见问题是学习率设置不当。很多人的习惯是照着别人的参数抄,完全没想过自己的数据量和问题复杂度不一样。数据量小的时候学习率设太高,loss曲线会出现典型的"先降后升再震荡"形态。数据量大的时候学习率设太小,loss下降会慢得让人怀疑人生。我的建议是先用默认学习率跑50个epoch观察趋势,loss降了就继续,没降就按倍数下调再试。

第三个是冻结Backbone的问题。很多人为了省显存把Backbone全部冻结,只训练检测头,这种做法在数据量很少的情况下也许有效,但如果你的数据量超过1500张,冻结Backbone会明显限制模型上限。因为Backbone层学到的底层特征不够贴合你的霉变数据分布,而训练时把它冻住等于放弃了自适应调整的机会。

4.2 标注易踩的几个坑,以及检测精度提升的实战技巧

标注工作枯燥且容易出错,但恰恰是这里最容易拉开项目差距。

标注中一个极易踩的坑是边界框过大。很多新手标注时习惯沿着一整颗花生的轮廓画框,但这样会让框内既有霉变区域又有健康区域。前边我已经说过,这会混淆模型学到的特征。正确的做法是精确框定霉变区域,哪怕每个目标分多个框标注,也不要怕麻烦。

还有一个坑是类别不平衡下的人工修正。用自动标注工具搞了个初版标注之后,必须做人工抽检和修正。我这次标注完第一版后,随机抽了200张图做回查,发现3%左右的标签存在框偏移或者类别错漏的问题。如果不修正直接训练,这些错误会被模型当成"标准答案",以讹传讹。

精度提升这块,我推荐一个很多人不知道的技巧:适当加入Mosaic增强时,把增强概率提高到训练前期的80%以上,后期再降到50%左右。这样做的目的是前期快速增加数据多样性、加快特征学习,后期减少过度复杂的合成图像、让模型回归到真实分布的精细拟合上。效果上,同条件下能提升大约2到3个百分点的mAP,不算夸张但很实用。

重要提示:训练集的图像不要全部用一种分辨率。如果条件允许,混合使用540×540、640×640、768×768的输入尺寸来训练,等于免费做了一步尺度增强,对识别不同距离拍摄的花生图像有明显的泛化改善。

4.3 模型部署到CPU环境的一个加速神器

如果最终要交付给没有独显的单位电脑使用,CPU推理速度就是硬伤。跑一次推理要300毫秒不是不能用,但谈不上优雅。这里分享一个确定有效但很多人没做过的技巧:把PyTorch模型转成ONNX,再用ONNX Runtime加载,并且开启int8量化推理模式。

量化后的模型体积变小,从约45MB压到约13MB,推理速度在CPU上大概能提升到100毫秒左右,精度只有2%以内的轻微回退。对花生这种安全检测场景来说,逻辑上还是建议保留一个高速筛选和一个精准复核的双通道。先用量化模型快速筛查,凡置信度落在0.6到0.8区间的再走一遍全精度模型复核,这样速度和精度就都兼顾上了。

转ONNX的命令很简单:

yolo export model=best.pt format=onnx opset=12 simplify=True dynamic=False

不过要提醒一句,转了ONNX之后如果还想改类别或者再训练,就不如在原PyTorch权重上操作方便了,所以部署到最后阶段再做这个转换,不要过早转。

5. 从项目交付角度多说几句

这类视觉检测项目看起来是纯技术活,实际走到交付阶段,就会发现不少和算法本身无关但同样要命的细节。

一个是检测记录的留存。实际的质检场景里,每一次检测的可追溯性很重要。不做记录留存的系统,本质上只是一把高级一点的放大镜,无法真正嵌入业务流程。所以我在系统里把每次检测的图片、时间、各类别数量、检测结果摘要都存进SQLite里了,并且支持按时间范围查询历史记录和导出汇总报告。别小看这个功能,真去现场调研一圈就会发现,使用方对这功能的需求远比预期强烈。

还有一点是我的真实体会:演示用的得意样本和评估时的困难样本,效果是两回事。别因为几个效果炸裂的演示图就以为模型已经完备了。我做测试的时候坚持故意挑了一批最难处理的样本——光照不均的、花生高度重叠的、霉变区域极小的、甚至还有轻微运动模糊的图,就为看看模型在恶劣条件下会坏成什么样。有了这份认知底账,后面做算法迭代时才知道该往哪个方向使劲。

模型的类间定义也值得花时间想清楚。我最终定了三个类别:Mold(霉变)、Suspicious(可疑)、Normal(正常)。这个三分类设计比单纯的二分类好用很多很多。因为实际质检动作并不是只有"扔"和"留"两个选项,而是"直接扔掉"、"复检确认"、"继续流通"三个操作。一个Suspicious中间类别,让这套系统能贴合人工质检的真实工作方式。

6. 最后分享一条个人觉得最值的经验

回过头来看整套系统的开发过程,最让我想强调的不是YOLOv11用的多熟练,也不是界面写得多顺滑,而是"在动手之前,把问题定义清楚"这件事。

什么时候才算把问题定义清楚?不是你觉得"我要做花生霉变检测"的时候,而是你能写出——输入图片有哪些预期拍摄条件、输出结果要分几类、每一类对应什么后续操作、模型误判的代价方向是什么、运行环境的硬件上下限是多少。这些问题只要有一条含糊其辞,后面必然翻车。

我早期做项目的时候,就吃过这种亏:上来就攒数据、标数据、训模型,忙忙碌碌好几周,到最后部署才被问"你这给的结果我们生产线怎么用"——直接懵住。后来我学乖了,第一步永远是先把这些使用场景问题聊透,再做任何技术动作。

这套YOLOv11花生霉变检测系统,代码结构、模型权重和使用文档都是齐全的,想做类似项目的朋友在网上能直接拿到全部材料。如果你要按照自己的场景改造它,优先从收集贴合自己现场条件的图像开始,然后把界面上的类别名称和企业实际的质检术语对齐,很快就能用起来。技术在变,但做事的方法和经验是通用的,希望对你有实实在在的帮助。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询