首页 / 资讯中心 / 文章详情

MATLAB图像处理30个实例:从读图到频域变换的完整指南

MATLAB图像处理30个实例:从读图到频域变换的完整指南 ★ FEATURED ARTICLE
简介这份资源是面向Matlab图像处理初学者与工程实践者的基础实例文档围绕图像读取显示、预处理、边缘检测、区域选择与掩膜、滤波变换、FFT与DCT、Radon投影等常见任务给出可直接运行的代码示例与参数说明帮助读者快速建立从函数调用到效果验证的完整认知。压缩包内共1个pdf文件约5.94MB内容以实例代码、注释与结果展示为主便于对照练习和查阅。目前已有2004人学习下载说明其在入门与课堂实验场景中具有一定参考价值。读者可从中获得图像灰度转换、裁剪与子图显示、roipoly与roifilt2区域处理、fspecial滤波、fft2与dct2变换、imfinfo信息读取等具体操作思路适合作为课程实验、自学练手和函数速查的辅助材料。1. 从一份 PDF 说起为什么我建议你先跑通这 30 个 MATLAB 图像处理实例去年带一个做视觉检测的学弟调代码他卡在“彩色图像边缘检测”上整整两天最后发现不是算法写错而是把rgb2gray用在了已经归一化的 double 矩阵上imshow出来的图一片灰白。这种坑翻手册要半天但一份能直接跑的实例集十分钟就能对照出来。这份《matlab图像处理基础实例.pdf》就是干这个的它把 MATLAB 图像处理里最常被反复查的三十来段代码——从imread/imshow的读写显示到edge边缘检测、roipoly区域选择、fft2频域变换、watershed分水岭分割、HIS 空间彩色处理——按“能复制、能出图、能改参数”的方式串了一遍。适合两类人刚上手 Image Processing Toolbox 的新手拿来照着敲以及需要快速回忆某个函数签名和参数含义的老手拿来当速查卡。下面我按“这项目是什么 → 怎么跑 → 怎么改”的顺序把它拆开讲。2. 实例集的技术骨架函数分组与运行环境2.1 这份实例到底覆盖了哪几层能力把正文里的代码按调用链捋一遍能清楚看到它其实是一条完整的图像处理流水线而不是零散函数堆砌。最底层是图像 I/O 与信息查询imread读图、imshow显示、imfinfo拿元数据、subplot做多图对比。往上一层是几何与区域操作imcrop裁剪、imresize缩放、imrotate旋转、roipoly/roicolor/poly2mask做区域选择和掩膜、roifilt2/roifill做区域滤波与填充。再往上是点运算与代数运算imadjust灰度拉伸、对数扩展、灰度倒置、im2bw二值化、imadd/imsubtract/immultiply/imdivide四则运算。核心层是滤波与变换fspecial造算子、filter2/wiener2/medfilt2空域滤波、fft2/fftshift/dct2频域变换、radon投影。最上层是分割与彩色处理edge边缘检测、imerode/imdilate形态学、watershed分水岭、RGB↔HIS 空间转换、彩色向量梯度。这个分层不是学术分类而是调试顺序出问题先确认图读进来没有I/O 层再确认坐标和尺寸对不对几何层最后才怀疑算法滤波/分割层。我一般排查图像处理 bug 就按这个顺序倒着走能省掉大量“算法明明没错”的自我怀疑。2.2 运行环境与依赖清单这份实例全部基于 MATLAB 基础环境加Image Processing Toolbox没有额外第三方包。正文里出现的函数按工具箱归属大致是函数所属工具箱用途imread/imshow/imfinfoMATLAB 基础读写与信息查询rgb2gray/imadjust/im2bwImage Processing Toolbox色彩转换与点运算edge/fspecial/filter2Image Processing Toolbox边缘检测与滤波fft2/fftshift/dct2MATLAB 基础频域变换watershed/imerode/imdilateImage Processing Toolbox形态学与分割roipoly/poly2mask/roifilt2Image Processing Toolbox区域选择与掩膜版本上不用太纠结正文用到的都是长期稳定的老接口R2015a 之后的版本基本都能跑。唯一要注意的是roipoly在新版本里交互式调用和传坐标调用行为略有差异正文用的是传 c/r 坐标向量的非交互写法这个写法跨版本最稳。提示如果你的 MATLAB 没装 Image Processing Toolboxver命令里看不到它edge、fspecial、watershed会直接报 undefined function。装工具箱这一步绕不过去。2.3 目录与文件组织建议PDF 本身是线性文档但你要真跑起来建议按功能拆成脚本文件别在一个.m里从头敲到尾。我一般这样组织matlab-ip-demo/ ├── data/ % 放测试图如 onion.png、football.jpg、lbxx.bmp ├── 01_io_display.m % 读写、imfinfo、subplot ├── 02_geometry.m % imcrop、imresize、imrotate ├── 03_roi_mask.m % roipoly、roicolor、poly2mask、roifilt2、roifill ├── 04_point_ops.m % imadjust、对数扩展、灰度倒置、im2bw ├── 05_filter.m % filter2、wiener2、medfilt2 ├── 06_frequency.m % fft2、fftshift、dct2、radon ├── 07_segmentation.m % edge、imerode/imdilate、watershed └── 08_color.m % RGB↔HIS、彩色向量梯度这样拆的好处是每个脚本独立可跑改一个不影响别的坏处是要手动管理data/路径。常见做法是在每个脚本开头加一句cd(fileparts(mfilename(fullpath)))保证不管从哪运行都能找到图。3. 核心实例逐段拆从读图到频域变换3.1 图像读取、显示与信息查询一切从读图开始。正文第一段就是最朴素的读写f imread(lbxx.bmp); % 读入 BMP返回 uint8 矩阵灰度图是二维彩色是三维 a rgb2gray(f); % 若是彩色图转灰度已是灰度图则原样返回 [g, t] edge(a, canny);% canny 边缘检测g 是二值边缘图t 是自动阈值 imshow(g); % 显示二值图白边黑底这里有个容易被忽略的点edge的第二个返回值t是算法自动算出的阈值很多人只接第一个返回值调参时就没法知道当前阈值是多少。我一般会fprintf(canny threshold %.4f\n, t)打出来改edge(a,canny,0.3)手动指定阈值时心里有数。imfinfo是另一个高频函数正文里info imfinfo(trees.tif)一行带过但它返回的结构体里有Width、Height、BitDepth、ColorType等字段读图前先查一下能避免“以为读进来是彩色其实是索引图”的翻车。subplot(121)和subplot(122)的用法在正文里反复出现本质是把 figure 切成 1 行 2 列第三个数字是当前激活的子图序号subplot(211)/subplot(212)则是 2 行 1 列别把行列顺序记反。3.2 几何操作与 ROI 区域选择裁剪和缩放是几何层最常用的两个。imcrop的矩形参数格式正文注释写得很清楚a imread(onion.png); b imcrop(a, [75 68 130 112]); % RECT [XMIN YMIN WIDTH HEIGHT]注意是宽高不是右下角坐标 subplot(121); imshow(a); subplot(122); imshow(b);[75 68 130 112]里前两个是左上角 x/y后两个是宽和高不是右下角坐标——这是新手最常写错的地方写成右下角坐标会裁出一块偏移的区域。imresize(I,2)是按比例放大两倍imresize(I,[33 24])是强制到指定行列尺寸后者会改变宽高比做模板匹配前要留意。ROI 部分是这份实例比较有含量的地方。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); % 返回二值掩膜多边形内为 1 subplot(121); imshow(a); subplot(122); imshow(b);c和r必须等长且顺序要对应同一个顶点否则多边形会自交。poly2mask(x,y,256,256)是同一类操作的底层函数直接给顶点坐标和输出尺寸生成掩膜正文里还配了hold on; plot(x,y,b,LineWidth,2)把多边形轮廓画在掩膜上这个组合在写论文插图时很好用。roifilt2(h, i, b)把滤波器h只作用在掩膜b为 1 的区域roifill(i, c, r)则是用周围像素插值填充多边形区域做去水印或修补小瑕疵时能应急。3.3 点运算、代数运算与灰度变换点运算这一段正文给了很完整的对比实验一张图六个子图看不同灰度变换效果i imread(football.jpg); subplot(231); imshow(i); title(原图); j imadjust(i, [.3; .6], [.1 .9]); % 把 [0.3,0.6] 的灰度拉伸到 [0.1,0.9] subplot(232); imshow(j); title(线性扩展); i1 double(i); i2 i1/255; % 归一化到 [0,1] c 2; k c*log(1i2); % 对数扩展压缩高灰度、拉伸低灰度 subplot(233); imshow(k); title(非线性扩展); m 255 - i; % 灰度倒置uint8 下 255 减不会溢出 subplot(234); imshow(m); title(灰度倒置); n1 im2bw(i, .4); n2 im2bw(i, .7); % 两个阈值对比 subplot(235); imshow(n1); title(二值化阈值 0.4); subplot(236); imshow(n2); title(二值化阈值 0.7);imadjust的两个参数向量[LOW_IN; HIGH_IN]和[LOW_OUT; HIGH_OUT]是列向量用分号不是逗号写成行向量会报维度错。对数扩展前必须double再/255直接在uint8上做log会得到全 0 或全 255这是血泪经验。im2bw的阈值是 0 到 1 的归一化值不是 0 到 255传 128 进去等于全白。代数运算里imadd/imsubtract/immultiply/imdivide和直接 - * /的区别在于前者会做饱和截断uint8相加超过 255 截到 255 而不是回绕。做图像叠加、背景差分时用imsubtract更安全。3.4 空域滤波均值、中值、维纳滤波这段正文用filter2配fspecial(average,n)做了 3×3、5×5、7×7 三档对比i rgb2gray(imread(onion.png)); k1 filter2(fspecial(average,3), i) / 255; % 3×3 均值核除以 255 归一化 k2 filter2(fspecial(average,5), i) / 255; % 5×5更模糊 k3 filter2(fspecial(average,7), i) / 255; % 7×7最模糊 figure, imshow(k1); figure, imshow(k2); figure, imshow(k3);filter2返回的是 doublefspecial(average,n)生成的核元素和是 1但和uint8卷积后数值范围会超出 0-255所以要么/255归一化要么imshow(k1,[])自动缩放显示。wiener2(I,[3,3])是自适应维纳滤波对高斯噪声比均值滤波保边更好medfilt2是中值滤波对椒盐噪声几乎是标配。正文还提到“马赫带效应”说的是灰度条带相邻处人眼会看出虚假边缘做灰度量化展示时要注意不是算法 bug。3.5 频域变换FFT、DCT 与 Radon频域这段是整份实例里信息密度最高的。先看 FFT 的基本流程f zeros(100,100); f(20:70,40:60) 1; % 构造一个矩形亮块 imshow(f); F fft2(f); % 二维傅里叶变换结果是复数矩阵 F2 log(abs(F)); % 取模后取对数压缩动态范围才能显示 imshow(F2), colorbar; % 低频在四角高频在中心fft2结果直接imshow是一片黑因为直流分量幅值远大于其他频率必须log(abs(F))。补零和象限搬移是配套操作F fft2(f, 256, 256); % 补零到 256×256频域采样更密 F2 fftshift(F); % 把零频搬到中心 imshow(log(abs(F2))); % 现在中心是低频四周是高频fftshift只是把象限对角互换不改变频谱内容但显示和后续频域滤波都依赖零频在中心这个约定。DCT 那段j dct2(i); j(abs(j)10)0; k idct2(j);是典型的频域截断压缩演示把绝对值小于 10 的系数置零再逆变换能看到图像变模糊但主体还在这就是 JPEG 压缩的简化版思路。radon(b, theta)对二值边缘图做 0 到 179 度投影imagesc(theta,xp,r)画出正弦图是 CT 重建的数学基础正文里这段代码能直接出图。3.6 分割与彩色处理边缘、形态学、分水岭、HIS边缘检测除了edge(a,canny)正文还对比了prewitt、sobel以及彩色图像的分量梯度合成。形态学那段用strel(square,3)和strel(square,5)两种结构元素做腐蚀膨胀对比a imread(football.jpg); t graythresh(a); % Otsu 自动阈值返回 0-1 bw1 im2bw(a, t); se1 strel(square,3); se2 strel(square,5); bw2 imerode(bw1, se1); % 3×3 腐蚀前景缩小 bw3 imdilate(bw1, se1); % 3×3 膨胀前景扩大 bw4 imerode(bw1, se2); % 5×5 腐蚀缩得更狠 bw5 imdilate(bw1, se2); % 5×5 膨胀扩得更狠结构元素尺寸直接决定腐蚀/膨胀强度strel(square,n)的 n 越大效果越明显但超过目标尺寸会把小目标整个吃掉。分水岭那段先算梯度幅值g sqrt(gv.^2gh.^2)再watershed(g)l0是分水岭脊线imregionalmin(g)找局部极小值作为种子点这套流程是粘连目标分割的标准套路。彩色部分最值得看的是 RGB→HIS 的手工转换和 H 分量模糊rgb1 im2double(imread(football.jpg)); r rgb1(:,:,1); g rgb1(:,:,2); b rgb1(:,:,3); i (rgb)/3; tmp1 min(min(r,g),b); tmp2 rgb; tmp2(tmp20) eps; % 防除零 s 1 - 3.*tmp1./tmp2; tmp1 .5*((r-g)(r-b)); tmp2 sqrt((r-g).^2(r-b).*(g-b)); theta acos(tmp1./(tmp2eps)); h theta; h(bg) 2*pi - h(bg); h h/(2*pi); h(s0) 0; h1 filter2(fspecial(average,25), h)/255; % 只模糊 H 分量只模糊 H 分量再转回 RGB图像会变柔和但饱和度不变换成模糊 S 分量饱和度降低。这个对比实验把 HIS 空间“亮度、色调、饱和度可独立操作”的特性讲得很直观。彩色向量梯度那段用 2×2 张量gxx/gyy/gxy求最大特征值方向比逐分量求梯度再合成更符合彩色边缘的物理意义代码里g1.^5和g2.^5是增强对比的经验指数不是理论推导结果。4. 跑起来环境准备、脚本执行与结果验证4.1 环境准备与测试图先把 MATLAB 装好命令行敲ver确认列表里有 Image Processing Toolbox。测试图不用自己找MATLAB 安装目录下toolbox/images/imdata/里有onion.png、football.jpg、trees.tif、kids.tif等正文用到的图直接which onion.png能定位路径。我一般把这几张图复制到项目data/下避免依赖安装路径。4.2 单脚本执行与常见报错每个脚本独立跑命令窗口run(03_roi_mask.m)或在编辑器里 F5。最常见的三类报错Undefined function edge工具箱没装或没授权ver确认。Index exceeds matrix dimensionsimcrop矩形超出图像边界或roipoly的 c/r 长度不一致。Subscripted assignment dimension mismatchsubplot序号超过行列乘积比如subplot(236)在 2×3 布局里是最后一个写成subplot(237)就崩。4.3 结果验证怎么判断跑对了图像处理没有单元测试验证靠对照。我的习惯是每个脚本至少保留一组subplot(121)原图 subplot(122)结果图的对比跑完肉眼确认边缘图应该是黑底白边、二值图只有 0/1、频域图中心亮四周暗fftshift后。数值上可以max(g(:))、min(g(:))确认二值图范围size(b)确认裁剪尺寸和[WIDTH HEIGHT]对得上。跑完一个脚本存一张print(-dpng,03_result.png)后面改参数时能直接对比前后差异。5. 避坑与排查五个真实会翻车的点5.1 现象imshow出来一片白或一片黑原因矩阵是double类型但数值范围是 0-255imshow对 double 默认按 0-1 显示超过 1 全白或者uint8矩阵被log后变成极小值全黑。解决double 图用imshow(img,[])自动缩放或先/255归一化log前确保输入是归一化 double。5.2 现象imcrop裁出来的区域位置偏了原因把[XMIN YMIN WIDTH HEIGHT]当成[x1 y1 x2 y2]写了。解决记住后两位是宽高x2 XMINWIDTH-1差一位在边界处会少一行一列。5.3 现象roipoly报错“C and R must be the same length”原因多边形顶点列坐标c和行坐标r元素个数不一致或其中一个用了行向量另一个用了列向量。解决numel(c)numel(r)先断言且都保证是行向量顶点按顺时针或逆时针顺序排列别交叉。5.4 现象fft2后imshow全黑colorbar也看不出结构原因没取模没取对数复数矩阵直接显示或直流分量把动态范围拉爆。解决imshow(log(abs(F)),[])需要看中心对称就再套fftshift。5.5 现象watershed分割结果过分割碎成几百块原因梯度图噪声太多局部极小值遍地都是分水岭从每个极小值开始泛洪。解决先medfilt2或imhmin压制浅极小值或用imregionalmin限定种子点正文里imregionalmin(g)那一步就是给种子点做约束的。6. 二次开发把实例改造成可复用函数与批处理管线这份 PDF 的价值不在“读完”而在“改起来”。我拿到手第一件事是把散落的代码段抽成带默认参数的函数比如把 ROI 滤波封装成function J roi_filter_demo(I, poly_c, poly_r, filt_type, filt_size) % ROI_FILTER_DEMO 对多边形区域做指定滤波其余区域保持原样 % I: 输入灰度图; poly_c/poly_r: 多边形顶点列/行坐标 % filt_type: average|unsharp|sobel; filt_size: 核尺寸 mask roipoly(I, poly_c, poly_r); % 生成二值掩膜 h fspecial(filt_type, filt_size); % 造滤波器 J roifilt2(h, I, mask); % 只对掩膜内滤波 end这样改的好处是参数全暴露在函数签名里批量跑不同核尺寸时写个for循环就行不用每次改脚本。再进一步把第 3 章的八个脚本串成一条管线读图 → 灰度化 → 去噪 → 边缘 → 形态学 → 分水岭 → 区域统计每步输出中间结果存struct最后统一montage展示。验证方法很简单固定随机种子如果用了随机、固定测试图、固定参数跑两遍结果矩阵isequal必须为真否则说明有未初始化变量或依赖了rand。改造时有两个技巧值得记一是所有涉及double和uint8转换的地方统一用im2double/im2uint8别手写/255和*255后者在imshow和imwrite之间来回切时容易漏二是频域滤波的掩膜尺寸必须和补零后的fft2尺寸一致我一般先sz size(F)再mask fspecial(...)后padarray到sz这个顺序反了会报维度不匹配。从那以后我每次写频域相关代码都强制先打印size(F)和size(mask)对一遍再往下走省下的调试时间比打印那两行多得多。希望帮到你。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站