简介:这份资源面向图像处理入门者与农业自动化方向的开发者,聚焦苹果成熟度检测这一典型应用场景,提供一套可运行的编码分析示例。包内共10个文件,以8张jpg图像素材和2个m脚本为主,压缩包约196KB,图像素材覆盖原图、单取苹果图、灰度图、面积图、色差移除图及含青苹果样本,脚本则对应成熟度分析流程,便于直接对照调试。已有275人学习下载,说明该案例在图像分割、特征提取与色彩分析等基础技能训练中具有一定参考价值。读者可借助这些素材理解如何从色泽变化、表皮光泽等视觉指标判断成熟状态,并在此基础上尝试引入机器学习或卷积神经网络建立成熟度模型,同时体会结合近红外光谱等非视觉信息做综合评估的思路,为农业自动化与食品质量控制场景下的算法实践提供可复用的起点。
1. 从一张青红相间的苹果照片说起:这套 MATLAB 脚本到底能跑出什么
手里有一张两个苹果的照片,一个偏红一个带青,想用代码判断它们谁更熟——这就是apple_test.rar要解决的事。压缩包里是几个.m脚本加一串中间过程图:apple_test.m、apple_test_ysh.m,还有原图、单取苹果图、灰度图、面积图、色差移除图、含青苹果图等。它不是深度学习那套重装备,而是用 MATLAB 做经典的图像分割加色彩分析,把「成熟度」这个模糊概念落到像素和面积上。适合两类人:一是做 MATLAB 图像处理大作业、需要一份能跑通、能看到每一步中间结果参考实现的学生;二是想用 OpenCV 或 MATLAB 快速搭一个农产品分选原型的工程师,先拿它验证色彩阈值这条路走不走得通。它不承诺识别精度,但把从读图到出结论的链路完整摊开了。
2. 拆开压缩包:脚本分工、图像分割与色彩通道的选型逻辑
2.1 文件清单背后的处理流水线
先别急着运行,把包里的文件按名字过一遍,基本就能还原作者的思路。原图.jpg是输入,两个苹果.jpg和两个苹果含青.jpg是不同样本,单取苹果图.jpg说明做了目标提取,灰度图.jpg是中间转换,面积图.jpg大概率是分割后统计像素面积的可视化,色差移除.jpg则是把背景或光照干扰去掉的结果。这条链路对应图像处理的四个标准动作:读取、分割、特征提取、量化输出。
| 文件 | 在流程中的角色 | 常见处理手段 |
|---|---|---|
| 原图.jpg / 两个苹果.jpg | 原始输入 | imread 读入,检查尺寸与通道 |
| 单取苹果图.jpg | 目标分割结果 | 阈值分割、形态学去噪 |
| 灰度图.jpg | 中间转换 | rgb2gray,用于面积或轮廓 |
| 面积图.jpg | 量化可视化 | 统计目标像素数,映射成熟度 |
| 色差移除.jpg | 预处理 | 色彩空间转换后剔除背景色 |
这张表不是让你背,而是让你在跑脚本前先建立预期:如果某一步的输出图和你想象的不一样,问题多半出在分割阈值或色彩空间选择上,而不是代码写错了。
2.2 为什么用 HSV 而不是死磕 RGB
苹果从青到红,RGB 三个通道都在变,但变化不同步,直接拿 R 减 G 设阈值,换一张光照不同的图就翻车。HSV 把色相(H)、饱和度(S)、明度(V)拆开,成熟度主要反映在 H 上——青苹果 H 偏绿区,红苹果 H 偏红区,而光照强弱主要影响 V。这意味着你可以对 H 设阈值判断颜色类别,对 V 做归一化抵抗光照,两个维度互不干扰。
常见做法是先把图像转到 HSV,再对 H 通道做直方图,看双峰分布:一个峰对应青果,一个峰对应红果,阈值取两峰之间的谷底。这比拍脑袋定一个 RGB 差值稳得多。下面这段是色彩空间转换和 H 通道提取的最小骨架:
% 读取图像并转换到 HSV 空间 img = imread('两个苹果.jpg'); hsvImg = rgb2hsv(img); % 分离三个通道,H 决定颜色类别 H = hsvImg(:,:,1); S = hsvImg(:,:,2); V = hsvImg(:,:,3); % 查看 H 通道直方图,辅助确定分割阈值 figure; imhist(H); title('H 通道直方图');逻辑说明:rgb2hsv把 0-255 的 RGB 映射到 H 的 0-1 范围,红色大约在 0 和 1 附近(环形),绿色在 0.33 左右。参数上,如果你发现直方图两个峰挨得太近,说明样本颜色差异小,这时候要么换更严格的 S 和 V 约束,要么承认这张图不适合纯色彩法。imhist的 bin 数默认 256,对 H 通道够用,不用改。
2.3 分割与面积统计:把「熟不熟」变成一个数
分割出苹果区域后,成熟度可以粗略量化为红色像素占比。做法是:在 H 通道上分别对红色区间和绿色区间做逻辑掩膜,统计各自像素数,红色占比越高越熟。这一步的关键是掩膜之后要做形态学处理,否则苹果表面的高光点、阴影会被误判成背景,面积统计直接偏。
% 红色区间掩膜(H 接近 0 或 1) redMask = (H < 0.05 | H > 0.95) & S > 0.4 & V > 0.2; % 绿色区间掩膜(H 在 0.25-0.45) greenMask = (H > 0.25 & H < 0.45) & S > 0.3 & V > 0.2; % 形态学闭运算填补孔洞,去除小噪点 se = strel('disk', 3); redMask = imclose(redMask, se); redMask = bwareaopen(redMask, 50); % 统计红色像素占比 redRatio = sum(redMask(:)) / (sum(redMask(:)) + sum(greenMask(:))); fprintf('红色像素占比:%.2f\n', redRatio);逻辑说明:S > 0.4和V > 0.2是为了排除灰白背景和过暗阴影,这两个阈值要根据你的实际图片调,背景越杂,S 门槛越高。strel('disk', 3)的半径 3 适合几百像素宽的苹果,图更大就加大。bwareaopen去掉小于 50 像素的连通域,防止反光点被算成红色区域。redRatio就是这套脚本给出的成熟度代理指标,0.5 以上基本可判为偏熟。
3. 从脚本到可复现流程:运行顺序、参数调试与结果验证
3.1 正确的运行顺序与依赖检查
拿到.m文件别一个个乱点,按数据流顺序跑:先跑预处理脚本(对应色差移除、灰度转换),再跑分割脚本(单取苹果图),最后跑统计脚本(面积图)。apple_test.m和apple_test_ysh.m大概率一个是主流程、一个是带颜色空间转换的版本,先看哪个脚本里调用了rgb2hsv,从它入手。
运行前确认三件事:MATLAB 版本不低于 R2016b(imclose、bwareaopen这些函数老版本也有,但strel的写法在更早版本略有差异);Image Processing Toolbox 已安装,否则imread之后的形态学函数全部报错;当前工作目录切到脚本所在文件夹,因为脚本里大概率用的是相对路径读图。
% 检查工具箱是否可用 ver('images') % 切换工作目录到脚本所在位置 cd('你的解压路径/apple_test') % 按顺序运行 run('apple_test.m')逻辑说明:ver('images')会打印 Image Processing Toolbox 的版本信息,没有输出就是没装。cd到解压目录是为了让imread('两个苹果.jpg')能找到文件,很多人翻车就翻在路径上,报错「文件不存在」其实图就在旁边。
3.2 阈值怎么调:从直方图到试错
色彩阈值没有万能值,必须对着你的图调。我一般会先跑一遍imhist(H),看红色峰和绿色峰的位置,把阈值设在两峰之间的谷。如果直方图只有一个大峰,说明这张图里苹果颜色太单一,要么换样本,要么引入 S 通道做二次判断。
调参时建议把中间结果都imshow出来,别只看最后那个比例数字。红色掩膜图如果把背景也框进去了,说明 S 或 V 门槛太低;如果苹果上出现大量空洞,说明门槛太高或者形态学半径不够。这个过程没有捷径,就是看图、改数、再看图,三五轮下来就能找到适合当前样本的参数组。
提示:把调好的阈值写回脚本时,顺手加一行注释记下对应的图片名和光照条件,下次换图能省一半时间。
3.3 结果验证:面积图和肉眼判断对得上吗
面积图.jpg是验证环节的关键。它通常是把分割后的掩膜叠加回原图,或者用不同颜色标出红色区和绿色区。你要做的是拿它和原图对照:红色掩膜覆盖的区域是不是真的偏红,绿色掩膜是不是真的偏青,有没有把苹果梗、背景桌面误算进去。
如果面积图和肉眼判断一致,那redRatio这个数就有参考价值;如果不一致,先别怀疑算法,回头查分割那一步。常见的不一致是苹果高光被算成背景,导致红色面积偏小,成熟度被低估。解决办法是在 V 通道上放宽上限,或者对高光区域做单独处理。
4. 避坑与排查:这套脚本最容易翻车的五个地方
4.1 现象:运行报错「未定义函数 imclose」
原因:没装 Image Processing Toolbox,或者 MATLAB 安装时没勾选该组件。解决:在命令行输入ver查看已安装工具箱列表,没有的话通过安装程序补装,别去网上找野路子函数替换,形态学操作的边界行为差异很大。
4.2 现象:分割结果全是黑色或全是白色
原因:阈值设到了极端值,比如 H 通道阈值写成了 0 到 1 全范围,或者 S 门槛高到没有任何像素满足。解决:先把掩膜条件逐个拆开看,单独跑H < 0.05看有多少像素,再叠加S > 0.4,一步步收紧,别一次性写一长串条件。
4.3 现象:换一张图后红色占比完全不对
原因:光照条件变了,V 通道整体偏移,原来调好的 S、V 阈值失效。解决:对 V 通道做归一化,或者改用自适应阈值方法(如graythresh对 V 通道自动求阈值),别指望一组固定参数打天下。
4.4 现象:苹果边缘被啃掉一圈,面积偏小
原因:形态学闭运算的半径太大,把边缘腐蚀掉了,或者bwareaopen的最小面积设得过高,把边缘碎片滤掉了。解决:把strel半径降到 1 或 2,bwareaopen的阈值从 50 降到 20 试试,宁可保留一点噪点也别丢真实边缘。
4.5 现象:脚本跑完没有任何输出图
原因:脚本里imshow后面没加figure,或者用了set(0,'DefaultFigureVisible','off')把窗口隐藏了。解决:在每个imshow前显式加figure;,并检查脚本开头有没有关闭图形显示的设置,有就注释掉。
5. 把这套流程用活:从单张图到批量分选的进阶改法
单张图跑通只是起点,真正有用的是把它改成能批量处理的函数。我一般会把核心逻辑封装成一个接收图片路径、返回成熟度比例的function,然后用dir遍历文件夹里所有.jpg,把结果写进表格。这样你手里有一批苹果照片时,不用一张张手动跑。
function ratio = appleRipeness(imgPath) % 封装成熟度计算,输入图片路径,输出红色像素占比 img = imread(imgPath); hsvImg = rgb2hsv(img); H = hsvImg(:,:,1); S = hsvImg(:,:,2); V = hsvImg(:,:,3); redMask = (H < 0.05 | H > 0.95) & S > 0.4 & V > 0.2; greenMask = (H > 0.25 & H < 0.45) & S > 0.3 & V > 0.2; se = strel('disk', 3); redMask = imclose(redMask, se); redMask = bwareaopen(redMask, 50); ratio = sum(redMask(:)) / (sum(redMask(:)) + sum(greenMask(:)) + eps); end逻辑说明:eps加在分母上防止除零,这是批量处理时容易忽略的边界。函数化之后,主脚本只需要三行就能处理整个文件夹:
files = dir('*.jpg'); for i = 1:length(files) r = appleRipeness(files(i).name); fprintf('%s 成熟度:%.2f\n', files(i).name, r); end参数上,dir('*.jpg')只抓 jpg,如果你的图是 png 就改后缀。输出格式可以改成writetable存成 CSV,方便后续做统计或喂给其他工具。
验证批量结果是否可信,有个笨但有效的办法:挑三张图,一张明显青、一张明显红、一张青红各半,看输出的比例是不是依次递增。如果顺序乱了,说明阈值对某类光照不适应,得回头补预处理。这套方法不追求学术级精度,但作为 MATLAB 图像处理大作业的完整闭环,或者农产品分选原型的起点,它把该踩的坑都摆在了明面上。从那以后我每次拿到这类色彩分析脚本,都强制先跑一遍中间结果图再信最后的数字,希望帮到你。
本文还有配套的精品资源,点击获取