资讯动态

MATLAB水果识别实战:传统图像处理实现颜色分割与分类

发布时间:2026/10/23 21:07:44 来源:尧图企业网站定制
简介这是一份面向MATLAB初学者与图像识别入门者的水果识别程序源码包通过图像处理与机器学习技术实现对不同种类水果的自动分类可应用于课程设计、学术研究及农业自动化、超市果蔬分类等场景。压缩包共11个文件包含5张jpg水果样本图、4个m脚本文件、1个txt说明文档和1个fig图形文件整体约77KB其中m文件承载预处理、特征提取与分类识别的核心流程jpg提供青椒、西红柿、香蕉、梨等测试样本txt为运行指引fig保存界面或结果图形。程序覆盖灰度化、二值化、边缘检测等预处理步骤并涉及颜色直方图、LBP、HOG等特征提取方法以及SVM、决策树等分类器训练与测试评估思路。目前已有2679人学习下载适合希望理解图像识别基本流程、提升MATLAB编程技巧的读者参考借鉴。1. 从一堆烂水果照片到能跑的识别程序这个 MATLAB 项目到底能干什么实验室的桌子上堆着三十多张用手机拍的水果照片苹果、香蕉、橘子混在一起光照忽明忽暗有的还带着阴影。带我的师兄丢过来一句“你试试用 MATLAB 把这些分出来别用深度学习就传统图像处理。”我当时的第一反应是——这能行吗后来翻到这个 MATLAB 水果识别程序才发现它正好就是为这种场景写的不依赖任何深度学习工具箱纯靠颜色空间转换、形态学操作和区域特征做分类把一张随手拍的水果图变成带标签的识别结果。它适合谁如果你正在上数字图像处理、模式识别这类课需要交一份能演示、能改参数的课程设计或者你手头有工业分拣、农产品初筛的小需求想先用轻量方案验证可行性这个项目就是很好的起点。整个程序围绕 MATLAB 的 Image Processing Toolbox 展开核心文件不多但把“读图—预处理—分割—特征提取—分类—可视化”这条链路走得很完整拿来当骨架改比从零写要省太多事。2. 技术选型与整体架构为什么用传统图像处理而不是深度学习2.1 选型逻辑轻量、可解释、不挑机器这个项目最核心的决策就是放弃深度学习路线。原因很实际水果识别在颜色和形状上的区分度本来就高苹果偏红、香蕉偏黄、橘子偏橙用 HSV 颜色空间做阈值分割就能拿到相当干净的区域没必要上卷积网络。传统方法的另一个好处是可解释——每一步处理完你都能 imshow 出来看哪一步翻车了一眼就知道不像神经网络那样是个黑匣子。从依赖上看整个项目只要求 MATLAB 基础环境加 Image Processing Toolbox不需要 Deep Learning Toolbox也不需要 GPU。这意味着在普通办公电脑甚至老旧的实验室机器上都能跑起来对课程设计这种交付场景非常友好。常见做法是配合 App Designer 做一个简单的 GUI把图片加载、识别按钮和结果显示框拼在一起演示的时候点两下就行。2.2 模块划分六个函数各管一段项目按处理流程拆成了几个独立函数主脚本负责串联。典型的目录结构长这样fruit_recognition/ ├── main.m % 主入口串联整个流程 ├── load_image.m % 读图与尺寸归一化 ├── preprocess.m % 滤波、增强、去噪 ├── segment_fruit.m % 颜色空间分割 形态学 ├── extract_features.m % 提取颜色/形状/纹理特征 ├── classify_fruit.m % 基于规则的分类器 ├── show_result.m % 结果可视化与标注 └── dataset/ % 存放测试图片 ├── apple_01.jpg ├── banana_01.jpg └── orange_01.jpg这种拆法的好处是每个环节可以单独调试。比如分割效果不好你只需要改 segment_fruit.m不用动分类逻辑想换分类器也只影响 classify_fruit.m 一个文件。我一般会在每个函数开头加一段参数注释写清楚输入输出和可调阈值后面改起来不用来回翻。2.3 数据流一张图从进入到出结果主流程的数据流很清晰读入 RGB 图像后先统一缩放到固定尺寸常见是 256×256避免大图拖慢处理接着做中值滤波去噪再转 HSV 空间在 HSV 上用阈值把水果区域和背景分开得到二值掩膜对掩膜做开闭运算去掉小噪点和填补空洞然后用掩膜抠出原图里的水果区域提取颜色直方图、面积、圆度、长宽比等特征最后送进规则分类器判断类别把结果和置信度画回原图上。提示尺寸归一化这一步别省。不同手机拍出来的分辨率差异很大不统一尺寸的话后面基于像素数的面积特征会完全失去可比性。3. 核心模块拆解分割、特征提取与分类的代码实现3.1 图像预处理滤波和颜色空间转换预处理的目标是把噪声压下去、把颜色信息整理成更容易分割的形式。代码大致是这样function img_hsv preprocess(img_rgb) % 统一尺寸兼顾速度和细节 img_rgb imresize(img_rgb, [256, 256]); % 中值滤波去椒盐噪声窗口别开太大否则边缘糊 img_filt medfilt2(img_rgb(:,:,1), [3 3]); img_filt(:,:,2) medfilt2(img_rgb(:,:,2), [3 3]); img_filt(:,:,3) medfilt2(img_rgb(:,:,3), [3 3]); % 转 HSVH 通道对光照变化更鲁棒 img_hsv rgb2hsv(img_filt); end这里有几个参数值得说。imresize 的目标尺寸 256×256 是速度和精度的折中如果你要识别的水果在画面里占比很小可以提到 512×512但处理时间会明显上升。medfilt2 的窗口用 [3 3] 是常规选择窗口越大去噪越狠但边缘也越糊水果轮廓本来就不算复杂3×3 够用。转 HSV 是关键一步RGB 三个通道都和亮度耦合光照一变阈值就失效而 HSV 的 H 通道基本只反映颜色种类对阴影和反光容忍度高得多。3.2 颜色分割与形态学处理分割是整个项目里最需要调参的环节。思路是在 H 通道上给每个水果设一个色相区间落在区间内的判为水果function mask segment_fruit(img_hsv, fruit_type) H img_hsv(:,:,1); S img_hsv(:,:,2); V img_hsv(:,:,3); % 按水果类型设定色相范围H 取值 0~1 switch fruit_type case apple % 红色系H 在 0 附近或接近 1 mask (H 0.05 | H 0.95) (S 0.4) (V 0.2); case banana % 黄色系 mask (H 0.12 H 0.18) (S 0.4) (V 0.4); case orange % 橙色系 mask (H 0.05 H 0.12) (S 0.5) (V 0.4); end % 形态学开运算去小噪点闭运算填内部空洞 se strel(disk, 5); mask imopen(mask, se); mask imclose(mask, se); % 只保留最大连通区域去掉背景干扰 mask bwareafilt(mask, 1); end色相阈值是这套方法的核心参数。苹果的红色在 H 上跨越 0 边界所以要写成H 0.05 | H 0.95这种双区间香蕉和橘子的区间相对集中。S 和 V 的下限用来排除灰白背景和过暗区域。形态学那两行的顺序不能反——先开后闭开运算先把零星噪点清掉闭运算再把水果内部因为反光造成的空洞补上。bwareafilt 保留最大连通域是个实用技巧能自动丢掉画面边缘的杂物。注意如果你的测试图背景是纯白或纯黑这套阈值很好用但背景里有其他暖色物体时分割会误判这时候要么换背景要么加一步基于位置或形状的二次筛选。3.3 特征提取颜色、形状、纹理三路并进分割出掩膜后就可以在水果区域上算特征了。项目里主要用了三类function feats extract_features(img_rgb, mask) % 颜色特征H 通道均值反映主色调 img_hsv rgb2hsv(img_rgb); feats.hue_mean mean(img_hsv(:,:,1), all, omitnan); % 形状特征面积、圆度、长宽比 stats regionprops(mask, Area, Perimeter, ... BoundingBox, Centroid); feats.area stats.Area; feats.circularity 4 * pi * stats.Area / (stats.Perimeter^2); bbox stats.BoundingBox; feats.aspect_ratio bbox(3) / bbox(4); % 纹理特征灰度共生矩阵的对比度 gray rgb2gray(img_rgb); glcm graycomatrix(gray, NumLevels, 8); props graycoprops(glcm, Contrast); feats.contrast props.Contrast; end颜色特征用 H 均值最直接苹果、香蕉、橘子的 H 均值天然分得开。形状特征里圆度4πA/P²对苹果和橘子这种接近圆形的物体取值高香蕉因为细长会明显偏低长宽比进一步强化这个区分。纹理特征用灰度共生矩阵的对比度香蕉表面的纹理比苹果光滑表皮要丰富一些可以作为辅助判据。regionprops 返回的 stats 是结构体字段名要和调用时写的一致写错了 MATLAB 会直接报错这点新手容易踩。3.4 规则分类器用 if-else 也能分得准分类部分没有用任何机器学习工具箱就是基于阈值的规则判断function [label, score] classify_fruit(feats) % 按优先级依次判断命中即返回 if feats.circularity 0.75 feats.hue_mean 0.1 label apple; score feats.circularity; elseif feats.aspect_ratio 1.8 label banana; score feats.aspect_ratio / 3; elseif feats.hue_mean 0.05 feats.hue_mean 0.15 label orange; score 1 - abs(feats.hue_mean - 0.1) * 10; else label unknown; score 0; end end规则顺序有讲究。圆度加色相先判苹果因为苹果的圆形特征最稳定长宽比判香蕉细长形状几乎不会误判剩下的橙色系归橘子。score 是个粗略的置信度用特征值离阈值的距离估算方便在界面上显示“像不像”。这套规则在背景干净、光照均匀的图片上准确率不错但阈值是硬编码的换一批数据可能就要重新调。4. 跑起来环境准备、运行步骤与参数调试4.1 环境要求和启动方式跑这个项目需要 MATLAB R2018b 或更高版本以及 Image Processing Toolbox。检查工具箱是否安装在命令行敲ver看列表里有没有 Image Processing Toolbox 就行。没有的话通过附加功能管理器装一下。启动方式有两种。命令行方式最直接% 在 MATLAB 命令行里执行 cd(fruit_recognition); % 进入项目目录 img imread(dataset/apple_01.jpg); result main(img); % 主函数返回识别结果 disp(result.label);如果项目带了 GUI直接运行main.m或者对应的 App 文件界面上会有“加载图片”和“开始识别”两个按钮点完结果会标注在原图上。第一次跑建议先用 dataset 里自带的图确认流程通了再换自己的照片。4.2 关键参数怎么调调参是这个项目绕不开的环节几个最常动的参数和它们的调整方向参数位置作用调大效果调小效果目标尺寸preprocess.m归一化分辨率细节多、速度慢速度快、细节少滤波窗口preprocess.m去噪强度更平滑、边缘糊保边缘、噪点多色相区间segment_fruit.m分割范围纳入更多像素分割更严格形态学半径segment_fruit.m开闭运算核去噪强、可能吞细节保留细节、噪点多圆度阈值classify_fruit.m苹果判据更严格更宽松调参的顺序建议从分割开始。先把 mask 用 imshow 显示出来看水果区域是不是完整、背景有没有残留分割对了再去看分类结果。分割不对的情况下调分类阈值是白费功夫。4.3 用自带数据验证流程验证流程是否正常可以写个小脚本批量跑一遍 dataset% 批量测试统计识别情况 files dir(dataset/*.jpg); for i 1:length(files) img imread(fullfile(dataset, files(i).name)); result main(img); fprintf(%s - %s (score: %.2f)\n, ... files(i).name, result.label, result.score); end跑完看输出如果大部分图片都能给出合理标签说明流程没问题。有个别识别错的先别急着改代码把那张图的中间结果mask、特征值打出来看看是哪一步出的问题定位清楚再动手。5. 避坑与常见问题那些让我重跑好几遍的坑5.1 分割结果全是噪点现象mask 显示出来是一片散点完全看不出水果轮廓。原因通常是色相阈值设得太宽把背景里的杂色也纳入了。解决方法是先把原图转 HSV用impixelinfo在图上点几个水果像素和背景像素看它们的 H 值分别是多少据此收窄区间。另外 S 和 V 的下限也要检查背景如果是浅色S 值低加个 S 下限就能滤掉。5.2 苹果被识别成橘子现象红色苹果的识别结果偶尔跳到 orange。原因是苹果的 H 值在 0 附近而橘子的区间从 0.05 开始边界处有重叠。解决办法是在分类规则里把苹果的判断放在前面并且给苹果的色相条件加上H 0.95这个分支确保跨 0 边界的红色被苹果先接住。规则分类器的顺序本质上就是优先级把最不容易混淆的判据放前面。5.3 换一批图片后准确率暴跌现象自带数据跑得好好的换成自己拍的照片就大面积识别错误。这几乎都是光照和背景差异导致的。传统阈值方法对成像条件敏感这是它的固有短板。应对办法有两个方向一是拍摄时尽量用纯色背景、均匀光照从源头减少变量二是在预处理里加一步白平衡或直方图均衡把不同图片的亮度和对比度拉到相近水平减小域偏移。5.4 处理大图时卡到怀疑人生现象用几千万像素的手机原图跑每一步都要等好几秒。原因是所有操作都是逐像素的图越大越慢。解决很简单在 preprocess 第一步就 imresize 到 256×256后面所有计算都在小图上做。如果确实需要高分辨率输出可以只在小图上算 mask 和特征最后把 mask 放大回原尺寸再叠加显示。5.5 regionprops 报字段错误现象调用 regionprops 后取 stats.Circularity 报错说字段不存在。原因是 regionprops 的属性名要用它支持的字符串圆度对应的属性名是 Circularity 没错但如果你在调用时没把它写进参数列表返回的结构体里就不会有这个字段。检查regionprops(mask, Area, Perimeter)这行需要哪些属性就显式列哪些别指望它全返回。6. 二次开发从规则分类器升级到可训练的分类流程规则分类器跑通之后最自然的改造方向就是把它换成可训练的分类器让阈值从数据里学出来而不是手调。这一步不需要动前面的分割和特征提取只替换 classify_fruit.m 就行接口保持不变——输入特征结构体输出标签和分数。具体做法是先用 extract_features 把 dataset 里所有图片的特征批量算出来存成一个特征矩阵标签单独存一列。然后用 MATLAB 自带的分类器应用或者 fitcknn、fitcsvm 这类函数训练一个模型% 批量提取特征构建训练集 files dir(dataset/*.jpg); X []; Y {}; for i 1:length(files) img imread(fullfile(dataset, files(i).name)); mask segment_fruit(preprocess(img), apple); % 分割逻辑复用 feats extract_features(img, mask); X [X; feats.hue_mean, feats.circularity, ... feats.aspect_ratio, feats.contrast]; Y{end1} extract_label(files(i).name); % 从文件名解析标签 end % 训练 KNN 分类器并做交叉验证 mdl fitcknn(X, Y, NumNeighbors, 3); cvmdl crossval(mdl, KFold, 5); fprintf(交叉验证准确率: %.2f%%\n, ... (1 - kfoldLoss(cvmdl)) * 100);这样改的好处是分类边界由数据决定换一批图片时只要重新标注、重新训练不用再手动调那一堆 if-else 阈值。特征维度也可以扩展比如把 H 通道的直方图分箱后拼进去或者加上 Hu 矩这类形状不变量。验证方法上交叉验证的准确率比单次划分更可靠样本少的时候尤其明显。我自己的习惯是每次改完分类器都先把混淆矩阵打出来看哪个类别容易被误判一目了然。有一次苹果和橘子互相误判得厉害查了半天发现是特征里 hue_mean 的区分度不够加了一维 H 直方图特征之后就分开了。从那以后我每次动特征或分类器都强制走一遍混淆矩阵加交叉验证不再只看总准确率那个数。希望这个项目能帮到你把传统图像处理这条链路真正跑通、改顺。本文还有配套的精品资源点击获取

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

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

免费获取报价 →
↑