简介:这份PDF面向Matlab图像处理入门与进阶学习者,系统整理了图像处理常用函数的调用方式与典型实例,适合高校学生、科研人员及算法工程师在课程实验、项目开发中快速查阅与对照练习。资源包共1个PDF文件,大小约5.94MB,内容以代码示例与函数说明为主,便于按知识点检索。文档覆盖图像读取与显示、灰度转换、边缘检测、图像裁剪与子图显示、多边形区域选择与掩膜、区域滤波与填充、FFT变换与补零、离散余弦变换、图像信息查询以及Radon变换与投影等模块,并涉及均值滤波、中值滤波、维纳滤波、减采样与灰度级转化等实验场景。已有1999人学习下载,可作为Matlab图像处理基础操作的速查手册与练习素材,帮助读者理解函数参数含义、掌握处理流程并积累调试经验。
1. 从一份 matlab 图像处理基础实例.pdf 说起:为什么我建议你从命令行敲起
前阵子有个做视觉检测的读者发来一份 matlab 图像处理基础实例.pdf,问我值不值得花时间过一遍。我翻了两页就回他:值得,但别用“看”的,要用“敲”的。这份文档的价值不在于它讲了多高深的东西,而在于它把 MATLAB 图像处理工具箱里最容易被跳过的那批函数——roipoly、poly2mask、roifilt2、roifill、radon、watershed——用最短的代码串了起来。很多人学 MATLAB 图像处理,上来就imread+imshow+edge三件套,跑通了就觉得自己会了,结果一遇到“只处理某个多边形区域”“把彩色图转到 HSI 再单独模糊 H 分量”这种需求就卡住。这份文档恰好补的就是这块。它适合两类人:一是刚接触 MATLAB 图像处理、需要一套能直接跑通的命令清单的新手;二是用惯了 Python 的 OpenCV、想快速对照 MATLAB 函数语义的老手。下面我按自己复现时的顺序,把这份 PDF 里真正值得动手的部分拆开讲。
2. 环境准备与图像读取显示:把 imread、imfinfo、subplot 串成一条工作流
2.1 先确认你的工具箱和路径
这份文档里用到的函数分布在 Image Processing Toolbox 里,edge、fspecial、roipoly、watershed、radon都在其中。动手前先在命令行敲ver看一眼有没有这个工具箱,没有的话后面大半代码都跑不起来。另一个常被忽略的是当前工作目录——文档里用的onion.png、football.jpg、trees.tif、kids.tif都是 MATLAB 自带示例图,它们不在你的当前文件夹里,而在toolbox/images/imdata/下。我一般会先执行fullfile(matlabroot,'toolbox','images','imdata')拿到路径,再决定是addpath还是直接copyfile到工作目录。不处理这一步,imread('onion.png')会直接报文件不存在,新手最容易在这里翻车。
% 查看工具箱是否安装 ver('images') % 定位 MATLAB 自带示例图目录 imgDir = fullfile(matlabroot, 'toolbox', 'images', 'imdata'); disp(imgDir) % 把示例图复制到当前工作目录,避免路径问题 copyfile(fullfile(imgDir, 'onion.png'), pwd); copyfile(fullfile(imgDir, 'football.jpg'), pwd);逻辑说明:ver('images')返回工具箱版本信息,为空说明没装。fullfile拼路径比手写斜杠稳,跨平台不会出错。copyfile把图拷到当前目录后,后续所有imread都能直接用文件名。
2.2 读取、显示、看信息三件事一起做
文档里imread和imshow出现频率最高,但真正让工作流顺起来的是imfinfo和subplot的配合。imfinfo返回的是一个结构体,里面有Width、Height、ColorType、BitDepth这些字段,读图之后先看一眼,能避免后面把灰度图当彩色图处理。subplot则是做对比实验的命脉——文档里大量用subplot(121)、subplot(231)这种布局,本质是把原图和处理结果并排,一眼看出差异。
% 读取并查看图像元信息 info = imfinfo('trees.tif'); disp(info.ColorType); % 判断是灰度还是真彩 disp([info.Width, info.Height]); % 读取图像 a = imread('onion.png'); % 一行两列对比显示 subplot(1,2,1); imshow(a); title('原图'); i = rgb2gray(a); subplot(1,2,2); imshow(i); title('灰度图');参数说明:imfinfo的ColorType字段常见取值有'grayscale'、'truecolor'、'indexed',看到truecolor就说明是三通道,后面做edge之前必须先rgb2gray。subplot(1,2,1)里的三个数字分别是行数、列数、当前索引,索引从左上往右下递增。title加不加不影响结果,但对比实验里不加标题,过两天回看自己都分不清哪张是哪张。
提示:
imshow对double类型图像默认按[0,1]显示,对uint8按[0,255]显示。如果你把图像转成double后忘了归一化,imshow出来就是一片白,这不是代码错了,是显示范围没对上。
3. 区域选择与掩膜操作:roipoly、poly2mask、roifilt2、roifill 四个函数怎么配合
3.1 从 roipoly 到 poly2mask:交互选区和代码选区的两条路
文档里roipoly的用法是给定列坐标c和行坐标r,返回一个二值掩膜b。这里有个反直觉的点:roipoly的参数顺序是(图像, 列坐标, 行坐标),不是(行, 列)。MATLAB 里图像矩阵是(行, 列)索引,但roipoly的坐标参数按(x, y)即(列, 行)来,新手在这里写反了,掩膜位置就整个偏掉。poly2mask则是纯代码方式,直接给顶点坐标和输出尺寸,不依赖已有图像,适合批量生成固定形状的掩膜。
% 方式一:roipoly 在已有图像上选多边形 a = imread('onion.png'); c = [200 250 278 248 199 172]; % 列坐标 x r = [21 21 75 121 121 75]; % 行坐标 y b = roipoly(a, c, r); subplot(1,2,1); imshow(a); title('原图'); subplot(1,2,2); imshow(b); title('多边形掩膜'); % 方式二:poly2mask 纯代码生成掩膜 x = [63 186 54 190 63]; y = [60 60 209 204 60]; mask = poly2mask(x, y, 256, 256); figure; imshow(mask); hold on; plot(x, y, 'b', 'LineWidth', 2);逻辑说明:roipoly返回的b是逻辑矩阵,大小和输入图像一致,多边形内部为 1、外部为 0。poly2mask的第三个和第四个参数是输出掩膜的高和宽,这里给 256×256 是文档里的固定尺寸,实际用的时候要跟目标图像尺寸对齐。hold on之后plot把顶点连起来,是为了验证掩膜边界和顶点是否吻合——这一步在调试复杂多边形时特别有用。
3.2 roifilt2 和 roifill:只处理你选中的那块
roifilt2是这份文档里我觉得最实用的函数之一。它接受一个滤波器、一张灰度图和一张二值掩膜,只对掩膜为 1 的区域做滤波,其余区域原样保留。文档里用fspecial('unsharp')做锐化,实际工作中我更多用它做局部模糊或局部增强。roifill则是用区域边界像素插值填充内部,常用来去掉小面积遮挡或修补掩膜区域。
a = imread('onion.png'); i = rgb2gray(a); c = [200 250 278 248 199 172]; r = [21 21 75 121 121 75]; b = roipoly(i, c, r); % 区域滤波:只对多边形内部做锐化 h = fspecial('unsharp'); j = roifilt2(h, i, b); subplot(1,2,1); imshow(i); title('灰度原图'); subplot(1,2,2); imshow(j); title('区域锐化结果'); % 区域填充:用边界插值填充多边形内部 k = roifill(i, c, r); figure; subplot(1,2,1); imshow(i); title('灰度原图'); subplot(1,2,2); imshow(k); title('区域填充结果');参数说明:fspecial('unsharp')生成一个 3×3 的锐化滤波器,默认参数下中心权重较大。roifilt2的第二个参数必须是二维灰度图,传彩色图会报错,所以前面rgb2gray不能省。roifill的坐标参数和roipoly一样是(列, 行)顺序,填充效果取决于边界像素的连续性,边界越平滑填充越自然。
注意:
roifilt2和roifill都只接受二维图像。如果你手上是彩色图,要么先转灰度,要么对 R、G、B 三个通道分别调用再cat(3,...)合回去,后者计算量三倍但能保留颜色信息。
4. 频域变换与滤波:fft2、fftshift、dct2、radon 的实操边界
4.1 fft2 补零与 fftshift:频谱显示的两个关键动作
文档里 FFT 部分给了两段代码,一段是基本fft2加log(abs(F))显示,另一段是fft2(f,256,256)补零后再fftshift。补零的作用是改变频域采样密度,让频谱图看起来更平滑,但不会增加真实频率分辨率——这是信号处理里的基本结论,很多人误以为补零能提高分辨率,其实只是插值。fftshift则是把零频分量从角落搬到中心,不搬的话频谱四个角是低频、中心是高频,看图很别扭。
% 构造一个简单矩形 f = zeros(100, 100); f(20:70, 40:60) = 1; subplot(1,2,1); imshow(f); title('空域矩形'); % 基本 FFT 显示 F = fft2(f); F2 = log(abs(F)); subplot(1,2,2); imshow(F2, []); colorbar; title('频谱(未搬移)'); % 补零到 256x256 并搬移零频 figure; F3 = fft2(f, 256, 256); F4 = fftshift(F3); imshow(log(abs(F4)), []); colorbar; title('补零+fftshift');逻辑说明:fft2(f, 256, 256)把 100×100 的输入补零到 256×256 再做变换,输出尺寸变成 256×256。log(abs(F))是对幅度取对数,因为频谱动态范围太大,直接imshow只能看到中心一个亮点。imshow(..., [])让 MATLAB 自动按数据范围缩放显示,不加这个参数double类型会按[0,1]截断。
4.2 dct2 与 radon:压缩感知和投影变换的入门砖
dct2在文档里被用来做图像压缩演示——变换后把小系数置零再idct2重建。这段代码虽然简单,但它是 JPEG 压缩的核心思想:DCT 把能量集中到左上角低频区,高频系数大量接近零,丢掉也不影响观感。radon则是计算指定角度上的投影,文档里配合imagesc和colormap(hot)显示正弦图,这是 CT 重建的基础。
% DCT 压缩演示 a = imread('onion.png'); i = rgb2gray(a); j = dct2(i); subplot(1,3,1); imshow(log(abs(j)), []); colorbar; title('DCT 系数'); j(abs(j) < 10) = 0; % 阈值置零 k = idct2(j); subplot(1,3,2); imshow(i); title('原灰度图'); subplot(1,3,3); imshow(k, [0,255]); title('重建图'); % Radon 变换 b = edge(i); theta = 0:179; [r, xp] = radon(b, theta); figure; imagesc(theta, xp, r); colormap(hot); colorbar; xlabel('\theta (degrees)'); ylabel('x\prime'); title('Radon 变换正弦图');参数说明:j(abs(j) < 10) = 0里的阈值 10 是文档给的,实际压缩率取决于这个阈值,调大压缩狠但细节丢得多。radon的第二个参数是角度向量,0:179表示 180 个角度,每个角度算一次投影,输出r的列数等于角度数。imagesc和imshow的区别在于imagesc会自动缩放数据到色图范围,适合显示非图像矩阵。
提示:
dct2和idct2都是对二维矩阵操作,彩色图要分通道做。radon的输入最好是二值边缘图或灰度图,直接传彩色图会报错。
5. 形态学与分割:腐蚀膨胀、分水岭、区域生长的参数怎么调
5.1 结构元素尺寸决定腐蚀膨胀的力度
文档里用strel('square',3)和strel('square',5)分别做腐蚀和膨胀,对比 3×3 和 5×5 的效果。结构元素越大,腐蚀越狠、膨胀越猛,这是形态学的基本规律。但有个细节文档没展开:imerode和imdilate对二值图和灰度图的行为不同——二值图是集合运算,灰度图是取邻域最小/最大值。做形态学之前先确认图像类型,不然结果和预期对不上。
a = imread('football.jpg'); subplot(2,3,1); imshow(a); title('原灰度图'); t = graythresh(a); % Otsu 自动阈值 bw1 = im2bw(a, t); se1 = strel('square', 3); se2 = strel('square', 5); bw2 = imerode(bw1, se1); subplot(2,3,2); imshow(bw2); title('3x3 腐蚀'); bw3 = imdilate(bw1, se1); subplot(2,3,3); imshow(bw3); title('3x3 膨胀'); bw4 = imerode(bw1, se2); subplot(2,3,4); imshow(bw4); title('5x5 腐蚀'); bw5 = imdilate(bw1, se2); subplot(2,3,5); imshow(bw5); title('5x5 膨胀');参数说明:graythresh用 Otsu 方法自动算阈值,返回 0 到 1 之间的归一化值,im2bw用它把灰度图转二值。strel('square',3)生成 3×3 方形结构元素,也可以换成'disk'、'line'等形状。腐蚀让亮区域缩小、暗区域扩大,膨胀反过来,顺序和组合方式决定最终形态学操作是开运算还是闭运算。
5.2 分水岭算法:从梯度图到分割结果
文档里分水岭部分先用 Prewitt 算子算梯度,再对梯度图做watershed,最后把分水岭脊线叠加回原图。这里的关键是watershed的输入应该是梯度图而不是原图——直接对原图做分水岭,分割结果基本没法看。imregionalmin用来找局部极小值,这些极小值就是分水岭算法的种子点。
f = imread('lbxx.bmp'); f = rgb2gray(f); subplot(2,2,1); imshow(f); title('原灰度图'); f = double(f); hv = fspecial('prewitt'); hh = hv'; gv = abs(imfilter(f, hv, 'replicate')); gh = abs(imfilter(f, hh, 'replicate')); g = sqrt(gv.^2 + gh.^2); subplot(2,2,2); imshow(g, []); title('梯度幅值'); l = watershed(g); wr = l == 0; subplot(2,2,3); imshow(wr); title('分水岭脊线'); f(wr) = 255; subplot(2,2,4); imshow(uint8(f)); title('分割结果叠加');逻辑说明:fspecial('prewitt')返回水平方向算子,转置后得到垂直方向算子。imfilter的'replicate'参数处理边界,避免边缘出现黑框。watershed返回标签矩阵,不同区域用不同整数标记,0 表示分水岭脊线。f(wr) = 255把脊线像素设为白色叠加显示,这是文档里的做法,实际分割时应该用标签矩阵做后续区域提取。
注意:分水岭算法对噪声敏感,梯度图里每个小波动都可能形成独立盆地,导致过分割。常见做法是先对梯度图做平滑或形态学开运算,再跑
watershed。文档里没提这一步,但实际用的时候不加预处理,结果往往碎成一片。
6. 避坑与排查:这份 PDF 里没写但一定会遇到的五个问题
6.1 现象:edge报错“输入必须为二维灰度图”
原因:edge函数只接受二维矩阵,彩色图是三通道,直接传进去就报错。文档里edge示例前面都有rgb2gray,但新手抄代码时容易漏掉。
解决:养成习惯,edge之前先size看一眼维度,三维就rgb2gray。如果确实想在彩色图上做边缘检测,要么分通道做再合并,要么用文档后面提到的向量梯度法。
6.2 现象:roipoly选出来的区域和预期位置镜像或偏移
原因:roipoly的坐标参数是(列, 行)即(x, y),而 MATLAB 图像矩阵索引是(行, 列)。把c和r写反了,掩膜就上下或左右颠倒。
解决:记住roipoly和poly2mask都按(x, y)顺序传参。调试时用plot把顶点画在原图上,一眼就能看出对不对。
6.3 现象:imshow显示double图像一片白
原因:double类型图像默认按[0,1]范围显示,而图像数据可能是[0,255]量级,超出 1 的部分全被截成白色。
解决:要么在imshow里加空矩阵[]让 MATLAB 自动缩放,要么先mat2gray归一化,要么转回uint8。文档里imshow(k, [0,255])就是显式指定范围的做法。
6.4 现象:fft2补零后频谱图尺寸变了,后续索引对不上
原因:fft2(f, 256, 256)输出尺寸是 256×256,不再是输入尺寸。如果后面代码按原尺寸索引,就会越界。
解决:补零操作单独用变量接输出,不要覆盖原图变量。需要和原图叠加显示时,先确认两者尺寸一致,不一致就imresize对齐。
6.5 现象:watershed结果过分割,区域碎成几百块
原因:梯度图噪声导致大量局部极小值,每个极小值都成为一个盆地。
解决:跑watershed之前先对梯度图做平滑(imfilter加均值滤波)或形态学开运算(imopen),减少伪极小值。也可以先用imregionalmin看极小值分布,再决定预处理力度。
7. 从 HSI 分量模糊到彩色向量梯度:一个我反复用的验证套路
这份 PDF 里彩色图像处理部分给了两段很有代表性的代码:一段是把 RGB 转到 HSI,单独对 H 分量做均值模糊再转回 RGB;另一段是直接对 R、G、B 三个通道分别求 Sobel 梯度,再用向量梯度公式合成。这两段代码看起来长,但核心逻辑就一句话:彩色图像的处理要么在分量空间做,要么在向量空间做,两条路结果不同,选哪条取决于你的目标。
我自己的验证套路是:拿同一张彩色图,先走 HSI 分量模糊,再走向量梯度,把中间结果全部用subplot铺开对比。HSI 那条路,h1 = filter2(fspecial('average',25), h)/255里的 25 是滤波窗口大小,调大模糊更狠,但 H 分量是角度量,模糊时要注意环绕问题——文档里直接对 H 做均值滤波,严格说在 0 和 1 交界处会有跳变,实际项目里我会先把 H 转成 sin/cos 两个分量再滤波,避免角度环绕。向量梯度那条路,g1 = g1.^5和g2 = g2.^5是文档里的非线性增强,指数 5 是经验值,调大边缘更突出但噪声也放大,我一般从 2 开始试,看效果再往上加。
% HSI 分量模糊验证 rgb = imread('football.jpg'); rgb1 = im2double(rgb); r = rgb1(:,:,1); g = rgb1(:,:,2); b = rgb1(:,:,3); i = (r + g + b) / 3; tmp1 = min(min(r, g), b); tmp2 = r + g + b; tmp2(tmp2 == 0) = eps; s = 1 - 3 .* tmp1 ./ tmp2; tmp1 = .5 * ((r - g) + (r - b)); tmp2 = sqrt((r - g).^2 + (r - b).*(g - b)); theta = acos(tmp1 ./ (tmp2 + eps)); h = theta; h(b > g) = 2*pi - h(b > g); h = h / (2*pi); h(s == 0) = 0; % 只模糊 H 分量 h1 = filter2(fspecial('average', 25), h) / 255; hsi = cat(3, h1, s, i); % 转回 RGB(简化版,完整逆变换见文档) H = hsi(:,:,1) * 2 * pi; S = hsi(:,:,2); I = hsi(:,:,3); R = zeros(size(H)); G = zeros(size(H)); B = zeros(size(H)); ind = find((H >= 0) & (H < 2*pi/3)); B(ind) = I(ind) .* (1 - S(ind)); R(ind) = I(ind) .* (1 + S(ind) .* cos(H(ind)) ./ cos(pi/3 - H(ind))); G(ind) = 1 - (R(ind) + B(ind)); ind = find((H >= 2*pi/3) & (H < 4*pi/3)); H(ind) = H(ind) - 2*pi/3; R(ind) = I(ind) .* (1 - S(ind)); G(ind) = I(ind) .* (1 + S(ind) .* cos(H(ind)) ./ cos(pi/3 - H(ind))); B(ind) = 1 - (R(ind) + G(ind)); ind = find((H >= 4*pi/3) & (H < 2*pi)); H(ind) = H(ind) - 4*pi/3; G(ind) = I(ind) .* (1 - S(ind)); B(ind) = I(ind) .* (1 + S(ind) .* cos(H(ind)) ./ cos(pi/3 - H(ind))); R(ind) = 1 - (G(ind) + B(ind)); RGB = cat(3, R, G, B); subplot(1,3,1); imshow(rgb); title('原图'); subplot(1,3,2); imshow(h, []); title('H 分量'); subplot(1,3,3); imshow(RGB); title('H 模糊后重建');这段代码里eps加在分母上防止除零,h(s == 0) = 0处理饱和度为 0 时色相无定义的情况。逆变换的三个分支对应色相环上三个 120 度区间,每个区间内 R、G、B 的计算公式不同,这是 HSI 转 RGB 的标准做法。跑完对比原图和重建图,如果颜色整体偏了,大概率是某个分支的公式抄错了,逐段imshow中间变量排查。
从那以后我每次拿到一份图像处理示例文档,都会先挑其中三个函数用自带图跑一遍,确认输出和文档描述一致,再往自己的数据上套。这份 PDF 里的代码不是每段都能直接用于生产,但作为函数语义的对照表,它省了我大量查文档的时间。希望帮到你。
本文还有配套的精品资源,点击获取