资讯动态

基于Matlab和机器学习的水果缺陷分选实战

发布时间:2026/10/23 3:28:08 来源:尧图企业网站定制
接手这个项目之前我一直觉得水果分选不是什么高科技无非是传送带上拍张照片把颜色不对、形状不对的果子踢出去。真等动手做起来才发现问题多得很。同一批苹果早上采的和下午采的底色都不一样运输出来的轻微碰伤前期根本看不出颜色变化等到了客户手里才发黑还有果皮上的蜡质高光反光点能直接把相机参数带偏。单纯用阈值分割调一组参数只能在一堆果子里活下去换一批样本就崩。后来我把方案改成“图像特征提取 机器学习分类器”全程用Matlab做原型验证总算是把缺陷水果分选这件事从玄学变成了工程。这套流程做下来我觉得值得整理成一篇完整的记录。1. 先厘清边界分选问题到底要解决什么很多人一听到“缺陷检测”就想着用深度学习把病害区域框出来。但在实际产线上尤其是中小规模的加工厂问题往往更简单也更直接他们只需要把果子分成“能卖的”和“不能卖的”最多再加一档“可以降级处理”。所以我在项目一开始做的事不是让模型去数有几个虫眼而是和需求方把标准和优先级定下来。1.1 缺陷类型和检测难点的初步拆解常见的水果缺陷大体分几类机械损伤磕碰、挤压、划痕、病理缺陷腐烂、霉变、果锈、虫害虫眼、蛀洞、还有形态异常畸形、裂果。每一类在图像上的表现完全不同。磕碰伤早期在颜色上变化很小可能只是轻微凹陷光线一变就看不见腐烂区域则是从一个小点开始向外蔓延颜色不均匀边缘模糊划痕是线状结构形状细长果锈这类表面纹理变化颜色和正常果皮差别不大但质感不一样。这就意味着单一特征很难覆盖所有缺陷。颜色特征对腐烂和褪色敏感但对早期碰伤基本无效纹理特征能抓住果皮表面粗糙度变化却容易受果实品种影响形状特征又能排除一些畸形果但对斑点类缺陷无能为力。所以特征融合是必须的而不是找到某一个“神奇特征”然后一劳永逸。检测难点的第二个维度是环境。产线不是实验室自然光和日光灯混在一起传送带背景颜色可能跟果皮接近果子还会滚动旋转同一个缺陷在不同姿态下的形状会有很大变化。假如只采集“摆正了拍”的样本训练出来的模型到了现场几乎没法用。项目一开始我吃过大亏就是在这里用固定角度拍摄的图做测试准确率有98%换成传送带随机角度一测直接掉到82%。后来才把空间翻转和旋转增强加进去。1.2 为什么传统阈值分割在这里不够用传统机器视觉做人机分选最经典的做法是在某个颜色空间里做阈值分割。比如把RGB转换到HSV或者Lab然后在色调通道上设一个区间把超出区间的像素标记为缺陷。这在单一背景、恒定光源下很有效也是很多教科书里的入门案例。但真实水果分选要面对的信息不是一块简单的色块而是一颗果实的局部区域。原因有几层。第一果皮的颜色不是均匀色不同品种、不同成熟度、甚至同一颗果子的阴阳面都存在连续的渐变阈值只能画一条硬线很容易把正常的深色区域归为缺陷。第二高光导致的过曝区域在HSI空间里会拉低饱和度而这些区域的色调值不稳定用固定阈值没法稳定识别。第三阈值分割没有形状和纹理的概念。一块碰伤可能颜色只深了一点点面积也不大但是在固定阈值下它可能和果萼阴影混在一起只有加入形态学先验才能分开。机器学习方法不一样的地方在于它用多个特征共同构造一个分类边界而不是靠一两个通道的绝对数值。同样是碰伤颜色特征给一个弱的信号纹理特征给一个弱的信号形状特征再给一个提示三个弱信号合并起来分类器就能学出一个比“颜色等于某个值”稳健得多的判断边界。这是它在缺陷水果分选里能站住脚的根本原因。2. 数据准备与标注整个项目最容易翻车的地方模型训练花的时间其实不长真正把进度拖慢的是数据。我得说实话如果你打算在Matlab里跑通这条流程请把七成精力放在数据采集和标注上。模型好不好一开始就由数据决定了。很多刚接触机器学习的开发者想不明白觉得算法才是核心结果数据标的乱七八糟后面怎么调都救不回来。2.1 图像采集阶段就要考虑产线约束相机选型不用刻意追求超高分辨率关键是要让最小的目标缺陷在图像上至少占据几个像素。比如你要求检测1毫米的瑕疵视野宽度是100毫米相机分辨率是1000像素那么1像素对应0.1毫米理论上够了但要考虑运动模糊和镜头畸变实际最好让最小缺陷占5个像素以上也就是分辨率再大两到三倍。光源是另一个高优先级问题。水果表面多半有蜡质或绒毛容易产生镜面反射。刚开始我用了环形LED直射光拍出来的苹果每个都有两个刺眼的白点那个区域的颜色信息完全丢失触发了大量误报。后来参考果品行业常见做法改用低角度漫射光并加偏振镜才把高光压下去。如果是在传送带场景还必须注意曝光时间要短否则运动模糊会抹掉细小的划痕。一个比较稳的参数组合是曝光时间控制在1/1000秒以内相机离果面30-40厘米光圈调小一点保证景深够用传送带速度不要超过每秒0.5米。数据集划分也要讲究。同一颗果实多次拍摄的图像应该全部放进同一个集合要么都在训练集要么都在测试集。否则模型在训练阶段“见过”某一颗果子的不同角度测试时又碰到同一颗果子的另一个角度造成数据泄露测试准确率虚高。很多项目报告里写的99%准确率就是这么灌水灌出来的一到现场就露馅。2.2 标注规范、样本均衡和数据增强标注本身不复杂但要有统一规范。Matlab自带的Image Labeler可以用来框选缺陷区域也可以直接用文件夹方式把正常果实和缺陷果实的整图分别放在train/normal、train/defect里用图像级标签做分类。对于分选需求整图级二分类往往已经足够不需要做像素级分割。但是要明确一条标注规则一张图只要存在任意一处明显缺陷就标记为缺陷类不要因为缺陷小就犹豫。标准不一致标签噪声会严重影响模型效果。类别不平衡是这个项目里几乎必然遇到的问题。正常果实数量多缺陷果实数量少比例可能到10比1。如果直接训练分类器会倾向于把所有样本都判成正常因为这样正确率也高。解决思路有三种一是对缺陷样本做重采样把少数类复制几份二是对多数类做欠采样但会丢失信息三是做离线数据增强对缺陷样本进行旋转、平移、缩放、亮度抖动然后在训练中过采样。实测下来先用数据增强把缺陷样本数量补到正常样本的六到七成再配合SVM的代价敏感学习效果最好。数据增强在Matlab里可以自己写也可以直接用图像增强工具函数。旋转角度最好覆盖±30度因为传送带上的果实姿态随机亮度抖动范围设在±15%左右模拟不同光照水平翻转和轻微缩放也可以加。要注意的是增强只能用于训练集测试集必须保持现场采集的原始分布否则评估结果不真实。我习惯在增强之后人工抽样看几十张图确认增强没有把缺陷特征给扭曲掉。3. 特征工程从像素到可学习向量的核心环节机器学习分类器输入的不是图像本身而是一个固定长度的特征向量。特征工程的任务就是想办法把图像里的物理差异量化成数值。这一步做得好不好直接决定分类器的上限。传统机器学习领域有句话叫“Garbage in, garbage out”特征就是那个输入。3.1 颜色特征从RGB转换到HSV和LabRGB是最原始的颜色表示但它三个通道之间相关性强而且受光照强度影响很大。同样是红色苹果暗处拍出来的R值可能和亮处的G值差不多。所以更合适的做法是把图像转换到HSV或Lab色彩空间。HSV中H表示色相跟亮度关系小适合用来区分果皮颜色异常S表示饱和度腐烂区域往往伴随饱和度降低V表示明度高光和暗影都反映在V上。Lab色彩空间的a分量在绿色和红色之间变化对于苹果这类红色水果红很容易判断成熟度和底色偏差。我常用的流程是% 读取图像并转换到HSV空间 img imread(sample.jpg); hsvImg rgb2hsv(img); H hsvImg(:,:,1); S hsvImg(:,:,2); V hsvImg(:,:,3); % 统计H通道基础指标 hMean mean(H(:)); hStd std(H(:)); hP95 prctile(H(:), 95); hP05 prctile(H(:), 5);这里之所以用分位数而不是最大最小值是因为单个像素噪声很容易让最大值失真。取5%到95%的分位数能描述主要像素的分布过滤掉极端反光点。对S和V通道也同样统计均值、标准差和分位数这样一个果实就能得到一组颜色描述子。缺陷区域在颜色上通常表现为色相偏移、饱和度异常或明度突变这三类信息必须一起喂给分类器。3.2 纹理与形状特征捕捉颜色看不出的问题早期碰伤和果锈这种缺陷颜色变化很弱但表面纹理会有明显的粗糙度变化。灰度共生矩阵是一种经典的纹理描述方式。Matlab里用graycomatrix和graycoprops可以快速计算对比度、能量、相关性和同质性。对比度反映纹理的深浅差异能量反映纹理的均匀性相关性反映纹理方向性。对果实缺陷来说正常果皮纹理相对均匀能量较高碰伤区和腐烂区纹理杂乱对比度上升能量下降。局部二值模式同样常用。它的核心思想是给每个像素点周边做二进制编码统计整个图像中不同编码模式的频率直方图。Matlab从某个版本开始提供了extractLBPFeatures可以直接得到LBP特征向量。如果版本较低也可以自己写一个函数网上类似实现很多但要注意边界像素处理。% 灰度图像上的GLCM特征 grayImg rgb2gray(img); offset [0 1; -1 1; -1 0; -1 -1]; % 四个方向 glcm graycomatrix(grayImg, Offset, offset, Symmetric, true); textureStats graycoprops(glcm, {Contrast,Correlation,Energy,Homogeneity});形状特征也是不可忽略的一环。在特征提取之前需要先把果实区域从背景中分割出来最简单的做法是用Otsu阈值分割或者K-means把图像分成前景和背景然后取面积最大的连通域作为果实。随后用regionprops计算面积、周长、离心率、致密性等几何属性。圆形度可以这样算circularity 4*pi*Area/(Perimeter^2)。正常果实的圆形度接近1畸形果或严重裂纹果的圆形度会明显下降。把这些形状指标和颜色、纹理特征拼接在一起就得到了每张图像的特征向量。3.3 特征标准化和降维不同特征量纲差别很大面积可能是几千色相均值是0到1对比度可能是几万。这种差异会让SVM在高维空间里被量纲大的特征主导。所以训练前必须做Z-score标准化让每个特征均值为0、标准差为1。Matlab里一句[X, mu, sigma] zscore(X)就搞定。训练时保存mu和sigma预测时用同样参数对测试数据做标准化。特征数量要控制。如果只有几十个特征通常不需要降维。但如果把LBP的全部直方图bin都纳入维度可能到几百这时候可以做PCA或者用relieff选择有效的特征子集。我实际走下来颜色统计量大约五六个、GLCM四个、LBP二三十个、形状三四个总共不超过五十维配合样本量几百张已经足够训练出稳定的模型。特征越多越要小心过拟合模型在训练集上表现好不代表在明天新采的果子上表现好。4. 分类器训练与评估选择合适的机器学习算法有了特征向量和标签接下来就是选分类器。Matlab的Statistics and Machine Learning Toolbox里提供了SVM、随机森林TreeBagger、决策树、KNN、朴素贝叶斯、判别分析等多种选择。我没有一开始就全试一遍而是先定了两个主力候选SVM和随机森林。4.1 SVM和随机森林怎么选SVM的优势在于小样本下泛化能力强尤其在高维空间里它只依赖支持向量来构建边界不容易被远处无关样本干扰。它的核心参数是核函数、BoxConstraint和KernelScale。核函数我用的是RBF高斯核因为它能刻画非线性边界对特征之间的关系没有强线性假设。BoxConstraint控制误分类惩罚越大越容易过拟合KernelScale控制核的宽度越小越能拟合复杂边界但也越容易过拟合。随机森林的思路正好相反它是一堆决策树的集成。每棵树在数据子集和特征子集上随机训练最后对输出做投票。它对特征相关性和异常值没有那么敏感还能量化每个特征的重要性。在样本不均衡的时候随机森林通常比普通SVM表现得稳。但它的模型文件偏大预测速度稍慢不过在单张图片级别完全够用。下面是一个简单的对比表我在选型时主要参考这几个维度模型非线性能力调参难度训练速度预测速度可解释性小样本表现SVM(RBF核)强中中快弱好随机森林强低快中较强较好决策树中低快快强容易过拟合KNN取决于距离低无训练慢弱样本多才好我在实际项目里的选择是先用SVM做主线因为它在Matlab里的接口清晰、超参搜索方便而且模型小容易部署随机森林作为交叉验证的对比项用来确认SVM的性能没有异常。如果换一个数据规模更大的场景我会更倾向于随机森林或者直接考虑深度学习。4.2 Matlab训练流程、交叉验证和超参搜索SVM训练代码很简单。假设特征矩阵是X每一行是一张图的特征向量标签是Y0表示正常1表示缺陷可以这样训练% 拟合并做5折交叉验证 rng(42); SVMModel fitcsvm(X, Y, ... KernelFunction, rbf, ... BoxConstraint, 1, ... KernelScale, auto, ... Standardize, true, ... ClassNames, [0 1]); CVSVMModel crossval(SVMModel, KFold, 5); loss kfoldLoss(CVSVMModel); fprintf(5折交叉验证错误率: %.2f%%\n, loss * 100);如果第一版效果不够好可以用贝叶斯优化自动搜索超参数。Matlab的fitcsvm支持OptimizeHyperparameters选项但要注意搜索过程会反复训练模型样本量大的时候会等很久。为了节省时间我会固定核函数为RBF只优化BoxConstraint和KernelScale两个参数目标函数是交叉验证损失。optimizedSVMModel fitcsvm(X, Y, ... KernelFunction, rbf, ... OptimizeHyperparameters, {BoxConstraint,KernelScale}, ... HyperparameterOptimizationOptions, struct(... AcquisitionFunctionName, expected-improvement-plus, ... MaxObjectiveEvaluations, 30, ... Kfold, 5));评估阶段不要只看准确率。在分选场景里漏掉一个坏果流出到市场比误杀一个好果的代价大得多。所以我更关心召回率也就是所有真实缺陷样本中有多少被正确识别出来。用confusionchart可以清楚展示混淆矩阵然后手工计算精确率、召回率和F1分数。精确率是机器判定为缺陷的样本中有多少真的是缺陷召回率是确实有缺陷的样本中有多少被判出来。分选系统的目标通常是高召回率即使牺牲一点精确率让误杀率稍微高一点也比漏检亡羊补牢强。如果需要调整阈值SVM默认阈值是0.5可以通过fitcsvm的ScoreTransform和predict输出来调整。5. 实际部署与现场调试从正确率到稳定性的距离模型在实验台上跑出95%的准确率只代表故事刚开了个头。现场环境的变化会让精度掉得你怀疑人生。我在这部分要写的是如何把一个看上去还行的模型变成一个真正能在产线上连续工作的分选逻辑。5.1 打包部署方案与实时性预算Matlab模型部署有几个可选路线。如果工厂的工控机装了Matlab运行环境可以通过Application Compiler打包成独立程序界面做成简单的实时检测窗口。如果后续要嵌入到小型设备里可以用MATLAB Coder将特征提取和SVM预测的代码转换成C/C部署在ARM板卡或工业计算机上。我建议从一开始就把特征提取和分类器封装成独立函数输入是图像路径或图像矩阵输出是标签和置信度这样后续不管走哪条部署路线都方便。实时性要提前算好。比如传送带速度是每秒0.5米相机视野宽度是30厘米那么每张图有效时间大约是0.6秒。图像采集、预处理、特征提取和分类加起来必须小于这个时间。传统特征提取加SVM通常在几十毫秒内完成压力不大。如果用深度学习做端到端检测单张图在普通CPU上可能到几百毫秒必须上GPU否则跟不上产线。这也是我坚持用传统机器学习的一个重要原因成本低部署简单。5.2 现场最常见的两类翻车问题和修复方法第一个翻车点是高光。水果表面有一层天然蜡质进入分选现场后光源角度和输送带振动会让高光位置不断变化。高光区域的像素几乎饱和颜色特征完全失真SVM可能把这些区域当成异常。应对办法有两种一种是在光源设计阶段加偏振片物理上消除镜面反射另一种是在算法上检测高光区域如果高光占比过高就把该区域从特征统计中剔除或者单独把高光比例作为一个特征加入模型让模型学会处理它。第二个翻车点是品种和产地的底色变化。同一批模型的测试数据是某个产地的红富士下一次来的是山东栖霞产的颜色更红更深模型的误报率立刻就上去了。这说明模型并不是学会了“缺陷是什么”而是记住了“当前数据里缺陷长什么样”。解决办法不是重新开发而是维护一个增量样本库。现场每次人工抽检发现误报或漏检就把对应图片归档每周重新训练一次模型测试集里保留一批固定样本来验证模型是否回退。这比一次性交付模型然后甩手不管要实用得多。5.3 一条更稳妥的迭代路线如果现在让我重新做一个水果分选项目我不会急着堆特征或者直接套深度网络。我会先搭一个最小闭环用最基础的颜色和形状特征训练一个SVM放到几段真实视频里跑一跑看看失败案例集中在哪。是光线问题还是标注问题还是特征不足以区分根据失败案例再决定加纹理特征、调超参数、或者换模型。每一个调整都用历史回归测试集验证避免修好一个错引出另一个错。最后分享一个习惯我在每轮实验后都会保留一份模型配置文件里面记录特征列表、采集日期、图像预处理参数、分类器参数、测试集组成和混淆矩阵结果。这样过了两个月再打开项目还能快速复现当时的实验而不是面对着十几个不同版本的脚本发呆。做工程不是写论文可复现性和鲁棒性才是真正让分选项目从实验室走向产线的关键。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑