简介:这份PDF面向刚接触Matlab图像处理的初学者与工程技术人员,系统梳理图像处理常用函数与典型实例,帮助读者从读取显示到频域变换建立完整的实操认知。内容覆盖图像读取与显示、灰度转换与裁剪缩放、Canny等边缘检测、多边形区域选择与掩膜、区域滤波与填充、FFT与补零、离散余弦变换、Radon投影以及均值/中值/维纳滤波和减采样等知识点,每个环节均配有可直接运行的示例代码与结果说明。资源包共1个PDF文件,约5.94MB,篇幅紧凑、便于打印或随查随用。目前已有2004人学习,适合课程实验、项目入门与函数速查场景,读者可据此快速掌握常用函数的调用方式与参数含义,并对照示例完成自己的图像处理练习。
1. 一份能直接跑通的 MATLAB 图像处理实例集,到底值不值得翻
很多人第一次用 MATLAB 做图像处理,卡住的地方往往不是算法本身,而是函数记不住、参数顺序搞反、显示出来一片黑或者一片白。这份《matlab图像处理基础实例.pdf》就是冲着这个痛点来的:它把 imread、rgb2gray、edge、imcrop、roipoly、fft2、dct2、radon、imerode、imdilate、watershed 这些高频函数串成了一条条可以直接粘贴进命令窗口的实例,覆盖从读取显示、区域选择、频域变换到形态学分割的完整链路。适合两类人:一是刚上手 Image Processing Toolbox、需要一份能照着敲的样例清单的新手;二是平时写算法多、但 MATLAB 图像函数用得零散、想补一套系统调用习惯的从业者。下面按“先跑通、再理解、最后避坑”的顺序拆。
2. 从读图到区域选择:把实例里的调用链跑通
2.1 读图、灰度化与显示的基本骨架
实例里几乎每个例子都以imread开头,这不是凑字数,而是因为后面所有函数的输入类型都依赖读进来的数据。RGB 图是三维矩阵,灰度图是二维矩阵,很多函数对维度敏感,所以rgb2gray往往是第一步。下面这段把读取、转换、显示三件事串起来,并顺手用imfinfo看一眼图像元数据,避免拿到一张索引图却当成 RGB 处理。
f = imread('lbxx.bmp'); % 读入图像,返回 uint8 矩阵 info = imfinfo('lbxx.bmp'); % 查看位深、颜色类型、尺寸 a = rgb2gray(f); % RGB 转灰度,二维矩阵 subplot(121); imshow(f); title('原图'); subplot(122); imshow(a); title('灰度图');逻辑说明:imread返回的类型取决于文件格式,常见是 uint8;rgb2gray按亮度加权转成二维,权重接近人眼感知。参数上没什么可调的,但要注意如果读进来的是索引图,rgb2gray之前得先ind2rgb,否则维度对不上。subplot(121)是一行两列取第一个,实例里反复用这个写法做对比显示,比开多个 figure 窗口省事。
2.2 裁剪、缩放与旋转:几何操作的三件套
实例里imcrop的矩形参数是[XMIN YMIN WIDTH HEIGHT],这个顺序和很多人直觉里的[x1 y1 x2 y2]不一样,是第一个容易翻车的地方。imresize支持比例和指定尺寸两种写法,imrotate则要注意旋转后默认会扩大画布,需要crop参数才能保持原尺寸。
a = imread('onion.png'); b = imcrop(a, [75 68 130 112]); % 起点(75,68),宽130,高112 c = imresize(a, 2); % 按比例放大两倍 d = imresize(a, [33 24]); % 指定输出尺寸,注意是[行 列] e = imrotate(a, 45, 'bilinear', 'crop'); % 双线性插值并裁剪回原尺寸 subplot(221); imshow(a); title('原图'); subplot(222); imshow(b); title('裁剪'); subplot(223); imshow(c); title('放大'); subplot(224); imshow(e); title('旋转45度');参数说明:imcrop的宽高是包含起点在内的像素数,写大了会自动截断到边界;imresize的[33 24]是输出行数和列数,不是宽高,写反了图会变形;imrotate的插值方法常用'bilinear'或'bicubic','crop'让输出和输入同尺寸,不做这个的话旋转后画布会变大,后续做像素级运算时尺寸对不上。
2.3 多边形区域选择与掩膜:roipoly、poly2mask、roifilt2 的分工
实例里这一组函数是区域处理的精华。roipoly用列坐标 c 和行坐标 r 定义多边形,返回二值掩膜;poly2mask直接由坐标生成掩膜,适合脚本化批量处理;roifilt2把滤波器只作用在掩膜区域内,区域外保持原样。三者配合能做出“只对某块区域锐化”的效果。
a = imread('onion.png'); i = rgb2gray(a); c = [200 250 278 248 199 172]; % 列坐标 r = [21 21 75 121 121 75]; % 行坐标 bw = roipoly(i, c, r); % 交互式或坐标式生成掩膜 h = fspecial('unsharp'); % 锐化滤波器 j = roifilt2(h, i, bw); % 仅对掩膜区域滤波 subplot(121); imshow(i); title('灰度原图'); subplot(122); imshow(j); title('区域锐化');逻辑说明:roipoly的坐标是 (x, y) 即 (列, 行),和矩阵索引 (行, 列) 相反,这是第二个高频翻车点。roifilt2的第二个参数必须是二维灰度图,传 RGB 会报错。fspecial('unsharp')生成的是 3×3 锐化核,想调强度可以换'average'或自定义矩阵。roifill则是用区域边界像素做插值填充,适合修补小瑕疵,实例里给了坐标式调用,注意它和roifilt2一样只吃灰度图。
3. 频域变换与滤波:fft2、dct2、radon 的实例怎么改
3.1 FFT 变换、补零与象限搬移
实例里先用一个 100×100 的矩形块做fft2,再用fftshift把零频搬到中心,这个顺序是频域可视化的标准动作。补零操作fft2(f, 256, 256)改变的是变换点数,不是图像尺寸,目的是提高频率分辨率,但会带来频谱泄漏,实例里没展开讲,实际用时要注意。
f = zeros(100, 100); f(20:70, 40:60) = 1; % 构造矩形块 F = fft2(f); % 二维傅里叶变换 F2 = log(abs(F)); % 对数压缩动态范围 subplot(121); imshow(F2, []); colorbar; title('未搬移'); F3 = fftshift(fft2(f, 256, 256));% 补零到256并搬移零频 subplot(122); imshow(log(abs(F3)), []); colorbar; title('补零并搬移');参数说明:log(abs(F))是对幅度取对数,不加这一步频谱图基本是一片黑,因为直流分量比高频大几个数量级;imshow(..., [])让显示范围自动拉伸到数据最小最大值,不加的话 uint8 以外的数据会显示异常。补零到 256 后频谱更细,但矩形边缘的振铃也更明显,这是补零的固有代价,不是代码写错了。
3.2 DCT 变换与系数截断
离散余弦变换在图像压缩里用得最多,实例里用dct2变换后把绝对值小于 10 的系数置零,再idct2反变换,直观展示“丢掉高频系数图像还能看”。这个阈值就是压缩率的旋钮,调大丢得多、画质降,调小保留多、压缩比低。
a = imread('onion.png'); i = rgb2gray(a); j = dct2(i); % 二维DCT subplot(131); imshow(log(abs(j)), []); colorbar; title('DCT系数'); j(abs(j) < 10) = 0; % 阈值截断 k = idct2(j); % 反变换 subplot(132); imshow(i); title('原图'); subplot(133); imshow(k, [0 255]); title('截断后重建');逻辑说明:dct2的输出是 double,idct2重建后也是 double,显示时要给[0 255]范围,否则imshow按 double 的 0~1 处理,图会发白。阈值 10 是实例给的起点,实际做压缩可以按能量占比来定,比如保留前 10% 的系数。
3.3 Radon 变换与投影可视化
radon计算指定角度上的投影,实例里对边缘图做 0~179 度投影,用imagesc显示正弦图。这个函数在 CT 重建、直线检测里常见,参数theta是角度向量,输出r是投影矩阵,xp是投影轴坐标。
a = imread('onion.png'); i = rgb2gray(a); b = edge(i, 'canny'); % 先提边缘 theta = 0:179; [r, xp] = radon(b, theta); % 投影 figure; imagesc(theta, xp, r); colormap(hot); colorbar; xlabel('\theta (degrees)'); ylabel('x\prime');参数说明:edge的'canny'对阈值敏感,实例没给阈值,默认自动算,边缘图太密或太稀时可以手动传[low high]。imagesc的坐标轴是角度和投影位置,colormap(hot)让高值更醒目。这一步的输出可以直接喂给反投影重建,但实例只到可视化为止。
4. 形态学与分割:腐蚀膨胀、分水岭、区域生长的参数边界
4.1 腐蚀膨胀与结构元素尺寸
实例里用strel('square', 3)和strel('square', 5)对比腐蚀膨胀效果,结构元素尺寸直接决定腐蚀膨胀的强度。3×3 去细噪点,5×5 去得更狠但目标也会缩水,这个取舍是形态学处理的核心。
a = imread('football.jpg'); t = graythresh(a); % Otsu自动阈值 bw = im2bw(a, t); % 二值化 se1 = strel('square', 3); se2 = strel('square', 5); bw2 = imerode(bw, se1); % 3x3腐蚀 bw3 = imdilate(bw, se1); % 3x3膨胀 bw4 = imerode(bw, se2); % 5x5腐蚀 subplot(231); imshow(a); title('灰度原图'); subplot(232); imshow(bw2); title('3x3腐蚀'); subplot(233); imshow(bw3); title('3x3膨胀'); subplot(234); imshow(bw4); title('5x5腐蚀');逻辑说明:graythresh返回 0~1 的归一化阈值,im2bw按这个阈值二值化,输入必须是灰度图。strel除了'square'还有'disk'、'line',圆形结构元素对旋转更鲁棒。腐蚀后目标变小、膨胀后变大,先腐蚀后膨胀就是开运算,能去小噪点保大目标,实例里没显式写imopen,但两步分开跑效果一样。
4.2 分水岭分割与局部极小值
实例里的分水岭流程是:灰度图 → 梯度幅值 →watershed→ 找分水岭线 → 在原图上标出。梯度用 Prewitt 水平和垂直滤波合成,watershed直接吃梯度图,输出标签矩阵,标签为 0 的位置就是分水岭脊线。
f = imread('lbxx.bmp'); f = rgb2gray(f); 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); % 梯度幅值 l = watershed(g); % 分水岭 wr = (l == 0); % 脊线掩膜 f(wr) = 255; % 在原图标白 subplot(221); imshow(uint8(f)); title('分割结果'); rm = imregionalmin(g); % 局部极小值 subplot(222); imshow(rm); title('局部极小值');参数说明:imfilter的'replicate'处理边界,避免边缘出现黑边;watershed对噪声敏感,梯度图里每个局部极小值都会成为一个盆地,所以实际用之前通常先做平滑或imextendedmin标记前景,实例里用imregionalmin把极小值可视化出来,就是提醒这一点。直接对原始梯度跑分水岭,过分割几乎是必然的,这是血泪经验。
4.3 区域生长与彩色空间转换
实例里区域生长只给了标题没给完整代码,但彩色部分给得很足:手工构造 RGB 四象限图,再转 HSI,对 H 分量做均值模糊再转回 RGB,结论是图像变柔和;对 S 分量模糊则饱和度降低。这段代码的价值在于把 RGB↔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; h1 = filter2(fspecial('average', 25), h) / 255; % 模糊H分量 hsi = cat(3, h1, s, i); subplot(121); imshow(rgb); title('原图'); subplot(122); imshow(h, []); title('H分量');逻辑说明:im2double把 uint8 转到 0~1,后面所有公式都基于这个范围;eps防止除零;h(b > g)那段是 HSI 公式里角度修正的标准写法,漏了会导致色相在蓝绿区域翻转。filter2的 25×25 均值核模糊 H 分量,核越大过渡越平滑,但色相环是循环的,模糊到 0 和 1 交界处会出现伪色,这是 HSI 处理的固有坑。
5. 避坑与排查:这份实例里最容易翻车的五个地方
5.1 现象:imshow 出来一片黑或一片白
原因:数据类型和显示范围不匹配。double 类型默认按 0~1 显示,uint8 按 0~255 显示,log(abs(F))这类结果直接imshow必然异常。解决:double 数据用imshow(img, [])自动拉伸,或者显式给[0 255];uint8 数据正常imshow即可。实例里 DCT 重建那段给了[0 255],就是踩过这个坑之后的写法。
5.2 现象:roipoly 选出来的区域和预期完全错位
原因:坐标顺序搞反。roipoly的 c 是列坐标(x),r 是行坐标(y),而矩阵索引是先行后列。解决:画图时用plot(c, r)验证多边形位置,确认无误再传roipoly;批量处理改用poly2mask(x, y, m, n),参数顺序同样是先 x 后 y。
5.3 现象:edge 检测结果全是噪点或者什么都没有
原因:输入不是灰度图,或者 Canny 阈值不合适。edge对 RGB 三维矩阵会报错或按通道处理,结果不可控。解决:先rgb2gray;Canny 手动给阈值edge(a, 'canny', [0.1 0.3]),低阈值管弱边缘、高阈值管强边缘,两个值差距越大保留的边缘越少。
5.4 现象:分水岭分割过分割严重,目标被切碎
原因:梯度图局部极小值太多,每个极小值都成了一个盆地。解决:先对梯度图做平滑(imgaussfilt或medfilt2),再用imextendedmin加imimposemin标记前景种子,最后跑watershed。实例里用imregionalmin把极小值可视化出来,就是让你先看清过分割的来源再动手。
5.5 现象:imresize 之后图像比例不对,或者 imrotate 后尺寸变了
原因:imresize的[行 列]顺序写反,或者imrotate没加'crop'。解决:指定尺寸时记住 MATLAB 是先行后列;旋转后要做像素级运算的,一律加'crop'保持画布一致,否则后续imadd、imsubtract会因尺寸不匹配报错。
6. 把实例改成自己的验证脚本:一个可复用的检查习惯
这份实例最大的价值不是那些函数本身,而是它给了一套“输入—变换—显示”的固定节奏。我一般会把每个例子改成一个带断言的小脚本,跑完顺手检查三件事:数据类型是不是预期(class(img))、尺寸有没有被意外改变(size(img))、显示范围对不对(imshow加不加[])。这三项一过,后面算法层面的问题才好定位。
举个具体的改法:把实例里的边缘检测那段包成一个函数,输入路径和阈值,输出边缘图和耗时,这样换图测试时不用反复改命令。
function [bw, t] = check_edge(imgPath, low, high) f = imread(imgPath); if ndims(f) == 3 f = rgb2gray(f); % 统一转灰度 end tic; bw = edge(f, 'canny', [low high]); t = toc; fprintf('类型:%s 尺寸:%s 边缘像素占比:%.3f 耗时:%.3fs\n', ... class(f), mat2str(size(f)), nnz(bw)/numel(bw), t); end调用时换不同图片和阈值,看边缘占比和耗时怎么变,比对着实例一条条敲更能建立参数直觉。另外,实例里filter2做均值滤波时除了 255,是因为fspecial('average')生成的核元素和大于 1,不除会溢出;换成imfilter就不需要手动除,这个差别在混用两套函数时特别容易翻车。
还有一个习惯:凡是涉及频域的结果,先fftshift再显示,凡是涉及形态学的结构元素,先打印strel的邻域矩阵看一眼。这两步花不了几秒,但能省掉大量“为什么结果和教程不一样”的排查时间。从那以后我每次拿到一份新的图像处理实例,都强制先跑一遍数据类型和尺寸检查,再谈算法效果。希望帮到你。
本文还有配套的精品资源,点击获取