☰
MATLAB图像处理入门:读图、灰度、裁剪、滤波与边缘检测实例
2026/10/29 16:31:58 网站建设 项目流程

简介:面向Matlab图像处理初学者与课程实验需求整理的实例型PDF文档,围绕图像读取与显示、灰度转换、裁剪与子图显示、多边形区域选择及掩膜、区域滤波与填充、边缘检测、FFT与补零、离散余弦变换、Radon投影、均值/中值/维纳滤波和减采样等基础操作展开,配有可直接参考的代码片段与结果示意,便于按知识点检索并对照练习。资源包共1个PDF文件,大小5.94MB,结构紧凑,适合课堂演示、实验课复习和自学查漏补缺。已有2003人学习下载,说明其在入门实践中具有一定参考价值;读者可从中获得常用函数调用方式、图像变换与滤波的实现思路,以及区域处理、频域分析和灰度级变化等典型实例的操作脉络。

1. 先别急着敲代码:matlab 图像处理到底在电脑里干什么

很多人第一次听到 matlab 图像处理入门,脑子里冒出来的是一堆公式和满屏看不懂的矩阵,于是软件还没打开就先退了半步。换个角度想:你手机相册里那张照片,在电脑眼里既不是猫也不是风景,而是一大张写满数字的表格,每个格子记着一个像素有多亮、偏什么颜色。matlab 干的事,就是让你用几行命令去改这张表格——把彩色褪成黑白、把某个角落剪下来、把模糊的边描出来、把噪点擦掉。这份 matlab 图像处理基础实例收的就是这类小操作:读图、转灰度、裁剪、滤波、边缘检测,每一步都能马上在屏幕上看到结果。它适合完全没碰过图像处理、但愿意照着敲几行命令的新手,不需要你先学完线性代数。

2. 先把第一个画面点亮:读图、看图、看懂图像信息

2.1 为什么值得花一个下午学它:三个迟早会碰上的场景

先说清楚学它有啥用,不然敲命令很容易变成机械劳动。第一个场景是批量处理:手里有几百上千张照片,要统一裁成同样大小、统一转成灰度、统一算出某个区域的亮度,手动一张张点完全不现实,而一段十几行的循环就能跑完。第二个场景是找目标:从一堆显微照片里数出亮点个数、从零件照片里找出缺口位置,人眼看一天会累,代码不会。第三个场景是把想法验证一遍:你想到一个处理思路,想知道效果好不好,matlab 里敲两行就能出图,不用先搭一整套工程。

matlab 在这件事上的舒服之处在于,它天生就是跟矩阵打交道的语言,而图像在内存里恰好就是矩阵,所以不用做额外的数据搬运。图像处理工具箱里现成的函数也都按"输入一张图、输出一张图"的方式组织,读图是imread、显示是imshow、转灰度是rgb2gray,名字基本能猜出用途。缺点也说在前面:matlab 里写 for 循环跑大图会慢,这是后面要学的向量化话题,入门阶段不用纠结,先把流程跑通比什么都重要。

2.2 三行命令跑通第一个例子:imread 与 imshow

打开软件后先看两个地方:左边或上方的"当前文件夹"面板,以及中间的"命令行窗口"。当前文件夹决定你的代码去哪里找图片文件,命令行窗口则是你一行一行敲命令的地方。入门阶段不需要建脚本文件,直接在命令行窗口敲就行,敲一句按一次回车,错了立刻重来,这种即时反馈对新手最友好。

% 把图片从硬盘读进内存,f 拿到的是一个矩阵 f = imread('onion.png'); % 把矩阵显示成画面 imshow(f);

第一行imread做的是"解码加读入":硬盘上的 png 文件是压缩过的,读进来之后变成内存里的一张数字表,变量名随便起,这里叫f。第二行imshow把这个矩阵按图像的方式画到图上窗口。注意别用image或imagesc代替它,imshow会自动处理数据范围和坐标轴比例,显示出来的比例跟原图一致,新手用它最省心。

这里有个容易忽略的点:imread只认当前文件夹里的相对路径,或者你写全的绝对路径。第一次跑报"文件不存在",九成不是函数写错了,而是当前文件夹没切到图片所在的位置。原料里的示例图用的是onion.png、football.jpg、kids.tif这类名字,你自己练的时候把文件名换成手头任意一张图就行,路径写全或者先把图拖进当前文件夹都可以。

2.3 图像在 matlab 里到底是什么:size、whos 与 imfinfo

跑通显示只是第一步,真正让你后面不迷糊的,是搞清楚这个变量里装了什么。在命令行里接着敲:

size(f) % 返回 [行数 列数 通道数],例如 384 512 3 whos f % 看数据类型和占用内存,一般是 uint8 info = imfinfo('trees.tif') % 返回结构体,含宽高、位深、色彩类型

size返回三个数,第一个是行数也就是图像高度,第二个是列数也就是宽度,第三个是颜色通道数,3 表示红绿蓝三通道,没有第三个数说明是灰度图。这个"行在前、列在后"的顺序要刻进脑子里,后面裁剪、取区域、画坐标全都按这个来,搞反了就是新手最常见的翻车点之一。

whos告诉你数据类型,绝大多数读进来的图是uint8,也就是每个数字取值范围 0 到 255。这个信息非常关键,因为后面做加减乘除时,uint8会产生截断,255 加 1 不会变成 256 而是卡在 255,很多人算出来的图一片惨白就是这个原因。imfinfo则是查文件本身的属性,不读像素,只告诉你这张图多宽多高、几位色深、是不是索引色,处理来源不明的图片时先查一下能省不少事。

想看两张图并排对比,用subplot划格子就行:subplot(1,2,1)表示把画面分成一行两列,接下来画的图放在第一格,再subplot(1,2,2)画第二张。这个函数后面每一章都会用到,先记住它接受三个参数:行数、列数、当前第几格,编号是从左到右、从上到下数的。

3. 把图改造成能用的样子:灰度、裁剪与缩放旋转

3.1 为什么第一刀几乎都砍在颜色上:rgb2gray 与 imadjust

彩色图是三层数字叠起来的,做边缘检测、阈值分割这些操作时,三层各算一遍再合并会很麻烦,所以绝大多数流程的第一步都是转灰度,把三层压成一层。函数就一个:

a = imread('onion.png'); i = rgb2gray(a); % 三通道压成单通道 subplot(1,2,1); imshow(a); title('原图'); subplot(1,2,2); imshow(i); title('灰度图');

rgb2gray不是简单把三个通道取平均,而是按人眼对红绿蓝敏感度的不同加权,绿色权重大一些,所以转出来的灰度看起来更接近你肉眼感受到的明暗。这一步之后size(i)只返回两个数,后面的滤波、边缘检测函数大多要求输入是这种二维灰度矩阵。

转完灰度经常还要调对比度,因为有些照片整体偏暗或者偏灰,细节全挤在中间一小段亮度里。imadjust就是干这个的:

% 把输入亮度 0.3~0.6 这一段拉伸到 0.1~0.9,暗的更暗、亮的更亮 j = imadjust(i, [0.3 0.6], [0.1 0.9]); imshow(j);

两个区间分别对应"输入范围"和"输出范围",都是 0 到 1 的归一化值。你把输入区间写窄一点,等于只取中间那段亮度来拉伸,对比度提升更明显;写太窄会出现大片死黑死白,这就得靠试。我第一次调这个参数时连着试了七八组才满意,别指望一次就对。

3.2 剪下你要的那一块:imcrop 的矩形参数与 subplot 排版

只想看图像某个角落的细节时,用imcrop把那一块切出来:

a = imread('onion.png'); % 矩形写成 [XMIN YMIN WIDTH HEIGHT],即左上角列、左上角行、宽、高 b = imcrop(a, [75 68 130 112]); subplot(1,2,1); imshow(a); title('原图'); subplot(1,2,2); imshow(b); title('裁剪结果');

重点在那个四元组:前两个是左上角的列和行,不是先行后列,这跟矩阵索引的顺序正好相反;后两个是宽度和高度,不是右下角坐标。新手最常犯的错就是把右下角坐标填进去,结果裁出来的区域大小完全不对。实在记不住就在命令行敲help imcrop,官方的参数说明就在第一屏。

subplot的用法这里再巩固一次,subplot(2,2,3)是把画面分成两行两列、当前用第三格,编号顺序是从左上开始横向数。如果你发现图画到了上一张图上、或者只剩一张,八成是figure没开新的,画之前先敲一句figure就能另起一个窗口。

3.3 放大缩小转角度:imresize 与 imrotate 怎么给参数

尺寸变换有两个常用函数,imresize管缩放,imrotate管旋转:

i = imread('football.jpg'); % 按比例放大两倍 big = imresize(i, 2); % 按指定行列数缩放到 33 行 24 列,注意是 [行 列] small = imresize(i, [33 24]); % 逆时针旋转 45 度,双线性插值,并裁掉旋转后多出来的黑边 rot = imrotate(i, 45, 'bilinear', 'crop');

imresize的第二个参数给一个数就是比例,给两个数就是目标尺寸,而这两个数的顺序是行在前列在后,跟size的返回顺序一致。imrotate的角度是逆时针为正,第三个参数是插值方式,默认最近邻会让斜边出现明显锯齿,改成'bilinear'会平滑很多;第四个参数'crop'表示输出保持和原图一样大,不加的话旋转后画布会扩大,四周填黑。

除了整张图缩放,还有一种常见需求是"只处理我圈出来的那一块",这时用roipoly交互式地点出多边形顶点,它会返回一个同尺寸的逻辑掩膜,掩膜里为 1 的地方就是选中区域。掩膜这个概念可以理解成一张镂空卡纸:把它盖在图上,只有镂空的地方能透出来。后面做局部滤波、局部填充都靠它。

4. 让机器看出轮廓:滤波与边缘检测的第一批实例

4.1 先糊一层:fspecial 造模板,filter2 做均值滤波

滤波听着玄,其实就是拿一个小方阵在图上逐格滑动,每滑到一个位置就把周围像素按权重加起来,得到新像素值。这个小方阵叫模板或者核,fspecial负责造它,filter2负责滑:

i = rgb2gray(imread('onion.png')); imshow(i); % 造一个 3×3 的均值模板,里面每个元素都是 1/9 h3 = fspecial('average', 3); % 卷积后结果被放大到 0~255,除 255 归一化到 0~1 再显示 k3 = filter2(h3, i) / 255; figure, imshow(k3);

fspecial('average', 3)里的 3 是模板边长,改成 5 就是 5×5,改成 7 就是 7×7。边长越大,参与平均的邻居越多,图像越糊,细节丢得越多。这就是一个典型的取舍:想压噪点就得糊一点,想保细节就压不干净。参数怎么选没有标准答案,一般从 3 开始试,看效果再往上加。

那个/255是新手最容易漏的一步。filter2对uint8输入算完会返回double类型,数值范围还是 0 到 255,而imshow看到double会默认按 0 到 1 来解释,于是整张图看起来一片白。除以 255 把它压回 0 到 1 就正常了。另一种写法是imshow(k3, []),让函数自己按最大最小值拉伸,也能看,但数值本身没变,后面接着算容易出偏差,建议养成显式归一化的习惯。

同一套流程换成fspecial('unsharp')就是锐化模板,换成fspecial('sobel')就是求横竖方向的梯度,用法完全一样,变的只是那 9 个数字。理解到这一层,你就明白滤波并不是什么黑匣子,本质就是一组权重的排列组合。

4.2 噪点太多怎么办:medfilt2 中值滤波

有一类噪声很讨厌:画面上随机散布着一些特别亮或特别暗的小点,像撒了盐和胡椒,业内就叫椒盐噪声。均值滤波对这种噪声效果一般,因为它是取平均,一个极端亮点会把周围一圈都拉偏。中值滤波换了个思路,取邻域内的中间值,极端值直接被排掉:

i = rgb2gray(imread('football.jpg')); % 3×3 邻域取中值,边界用对称填充,避免边缘发黑 m = medfilt2(i, [3 3], 'symmetric'); subplot(1,2,1); imshow(i); title('含噪原图'); subplot(1,2,2); imshow(m); title('中值滤波后');

三个参数分别是输入图、邻域大小、边界处理方式。邻域必须给成[行 列]的形式,太小去不干净,太大会把细小结构一起抹平。'symmetric'是边界填充策略,不加的话默认补零,图像四周会有一圈暗边,这是很多人第一次跑中值滤波时发现的"怪现象"。

中值滤波要求输入是二维灰度图,彩色图要先转灰度,或者对 R、G、B 三个通道分别做再合并。另外它对细线条、小角点不太友好,如果你后面要做边缘检测,通常先中值去噪再做边缘,顺序反了会把噪点当边缘留下来。

4.3 描边第一步:edge 里 canny 与 sobel 的差别

边缘检测是整个流程里最有成就感的一步,一行代码就能把物体轮廓勾出来:

a = imread('kids.tif'); % canny 会自动估算双阈值,第二个返回值 t 就是它算出来的阈值 [g, t] = edge(a, 'canny'); subplot(1,2,1); imshow(a); title('原图'); subplot(1,2,2); imshow(g); title('canny 边缘'); % sobel 也可以手动指定阈值,不指定就用自动值 c = edge(a, 'sobel', 0.1); figure, imshow(c);

edge的第二个参数是算子名字,常用的有'sobel'、'prewitt'、'canny'、'log'。sobel 和 prewitt 都是用一个固定的小模板算梯度,速度快但边缘偏粗、抗噪一般;canny 做了高斯平滑、非极大值抑制和双阈值连接三步,出来的边缘细而且连续,代价是参数更多、稍微慢一点。入门阶段建议直接用 canny,等你能看出问题在哪再回头调 sobel。

第三个参数是阈值,给一个 0 到 1 之间的数,越大留下的边缘越少、越"干净",越小越容易把噪点也当成边。前面例子里的t就是 canny 自动算出来的阈值,想看它具体是多少,在命令行敲一下变量名就行。边缘检测之前最好先做一次中值滤波,噪点少一点,出来的线条就干净很多,这个顺序别搞反。

5. 新手排查清单:五种最常见的翻车与修法

5.1 图和数对不上:类型、范围、显示方式惹的祸

第一种:图是全白的或者全黑的。现象是imshow之后一片惨白或者一片漆黑,但变量明明有值。原因基本是数据类型和显示范围没对上——double类型的图imshow默认按 0 到 1 解释,你手上那份数据可能是 0 到 255 的,超出 1 的部分全被当成最亮。解决办法是先看一眼whos或class(变量名),如果是double且最大值明显大于 1,用imshow(图, [])自动拉伸,或者显式除以 255 归一化。想做加减乘除运算前,也建议先im2double转一下,避免uint8的截断。

第二种:滤波之后整体发灰或者对比度变差。现象是做完filter2输出的图比原图"脏",灰蒙蒙一层。原因是卷积运算本身就会让数值范围收窄,再加上模板没有归一化(比如模板元素加起来不等于 1),整体亮度就被拉偏了。解决办法是确认模板是否归一化,fspecial('average', n)自带的模板和已经为 1,自己手写模板时记得除以元素和;显示时用imshow(结果, [])也能救回来。

第三种:edge出来全是点,没有连续线条。现象是边缘图密密麻麻全是白点,看不出物体形状。原因有两个方向,要么原图噪点太多,要么阈值给太低。解决办法是先medfilt2做一次中值滤波再检测,然后把阈值往上调,或者干脆不指定阈值让 canny 自己算。如果还不行,回头看看输入是不是彩色三通道图,edge对三维矩阵的处理结果会和预期不一样,先rgb2gray再说。

5.2 文件和坐标的坑:路径、名字、行列顺序

第四种:报"文件不存在",可文件名明明是对的。现象是imread直接报错退出。原因几乎都是当前文件夹没对,matlab 只在当前文件夹和搜索路径里找文件。解决办法是看一眼界面上的当前文件夹路径,用cd切过去,或者把图片复制到当前文件夹;也可以用which 文件名确认它到底找没找到。另外注意文件名大小写,有些系统区分大小写,Onion.png和onion.png是两回事。

第五种:裁剪和取区域的位置总是偏。现象是imcrop裁出来的不是你想要的角落,或者用坐标点选区域时整个偏移了半张图。原因是行列顺序搞反了——imcrop的矩形是[XMIN YMIN WIDTH HEIGHT],先列后行,而矩阵索引是先行后列。解决办法很简单,记住"给函数的矩形是给画图软件看的,先横后竖;给矩阵的索引是给内存看的,先行后列",两种写法不要混着用,实在不确定就先裁一小块验证一下再批量跑。

排查的时候有个通用顺序:先确认文件路径对不对,再确认数据类型是不是double且范围在 0 到 1,然后确认输入是灰度还是彩色,最后才怀疑参数。这个顺序走一遍,九成的报错都能自己定位,比到处问人快得多。

6. 跑通之后往哪走:一条能自己往前推的练习路线

这批例子跑完,你手上其实已经有一整套零件了:读图、转灰度、裁剪、缩放、滤波、边缘。接下来最忌讳的是继续漫无目的地翻函数文档,看十个忘九个。比较实在的做法是按"能做出一个完整小流程"为目标往前推,下面这条路线是我自己踩过一圈之后觉得最省力的顺序。

阶段练什么练到什么程度算过
第一周把读图、灰度、裁剪、缩放、滤波、边缘串成一条脚本换一张自己的图,脚本不用改一行也能跑通
第二周加二值化和形态学:graythresh、im2bw、imerode、imdilate能把目标区域单独抠出来,噪点用腐蚀膨胀清掉
第三周加区域统计:regionprops数目标个数、量面积能输出"这张图里有几个目标、各自多大"
第四周加批处理:把脚本改成能遍历整个文件夹一次跑完几十张图并输出结果表

第三周的regionprops是很多人忽略但特别有用的一步,它能直接告诉你每个连通区域的重心、面积、外接矩形,做计数类任务基本够用了。第四周的批处理则是把"会敲命令"变成"能干活"的分水岭,模式大概是这样:

files = dir('*.png'); % 拿到当前文件夹所有 png 文件 for k = 1:numel(files) img = imread(files(k).name); if size(img, 3) == 3 % 彩色才转灰度,灰度图跳过 g = rgb2gray(img); else g = img; end bw = im2bw(g, graythresh(g)); % 自动阈值二值化 fprintf('%s 白色像素占比 %.2f%%\n', files(k).name, 100 * mean(bw(:))); end

dir返回的是结构体数组,用files(k).name取文件名,numel数一共几个。中间那个if判断是为了兼容彩色和灰度两种输入,不加的话对灰度图调rgb2gray会报警告。graythresh用大津法自动算阈值,比手动指定省事,但遇到光照不均的图会失准,那时候再回头手动调。mean(bw(:))是把矩阵拉成一列求平均,二值图里非零就是 1,所以这个平均值正好是白色像素占比,比自己写循环快得多。

再往后如果想深入,方向大概是频域变换(fft2、dct2)和彩色空间转换,那两块数学味更重,建议等你能把上面四个阶段的东西随手拼起来之后再碰,否则很容易卡在公式上看不下去。

我第一次学的时候图省事,所有例子都拿示例图片跑一遍就算完,结果换自己的照片立刻各种报错,折腾了大半天才明白是数据类型和路径的问题。从那以后我每次开新脚本,都强制先把"读图、看size、看class、imshow一遍"这四步走完再往下写,后面省下的时间远比这四行多。希望帮到你。

本文还有配套的精品资源,点击获取

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

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

立即咨询