简介:一套即装即用的Matlab小孔成像仿真工具,直接运行tset.m就能完成整套图像频域处理:自动读取Origin_Picture.jpg原始图,依次调用CircularFilter.m(生成圆形孔径滤波效果)、BandPassFilter.m(用带通方式近似实现方形孔径响应)、Filter_Love.m(加载love.bmp作为心形掩膜进行定制化滤波)。所有核心函数都配有逐行中文注释,覆盖FFT正变换、滤波器矩阵构造(含空间域转频域适配)、频域相乘、IFFT逆变换及结果图像可视化全过程。无需额外工具箱,不依赖外部路径配置(仅Filter_Love.m需确认love.bmp所在位置),配套提供原始测试图和心形模板图,结构扁平清晰,适合数字图像处理课程实验、光学成像原理验证或频域滤波入门练习。
1. 这不是“画个圆圈就完事”的仿真——它是一套真正能讲清小孔成像物理本质的Matlab教学级工具包
你有没有试过在Matlab里敲几行fft2代码,然后对着屏幕上模糊又带环纹的图像发呆?心里清楚这是“频域滤波”,但说不清为什么圆孔会产生艾里斑、方孔会拉出十字衍射条纹、而心形孔——这个明显违背光学对称性的形状——居然还能生成可辨识的变形像?市面上很多所谓“小孔成像仿真”,本质上只是用高斯函数或矩形窗做简单卷积,绕开了最关键的一步:把空间域的孔径函数,严格通过傅里叶变换映射到频域,再与图像频谱相乘,最后逆变换回空间域。这中间每一步都藏着物理约束和数值陷阱——比如零频分量偏移没校正,图像就整体发灰;滤波器矩阵尺寸没和FFT结果对齐,就会出现诡异的周期性伪影;心形掩膜若直接用原始bmp像素做二值化,边缘锯齿会在频域激发出高频噪声,让重建图像布满雪花点。
这套工具包,是我给本科生讲《数字图像处理》实验课时,连续三年迭代打磨出来的“原理验证型”代码集。它不追求炫酷UI或一键出图,而是把每一个数学步骤都掰开揉碎,用中文注释钉死在每一行代码旁边。你运行tset.m,看到的不只是三张效果图,而是三段可追溯、可调试、可替换的完整信号链:从Origin_Picture.jpg读入的原始光强分布(空间域),到fftshift(fft2(...))后中心化的频谱(频域),再到CircularFilter.m里用sqrt((X-cx).^2+(Y-cy).^2) <= radius构造的连续圆孔函数离散采样——注意,这里不是简单画个黑圆,而是按实际光学口径比例缩放,并做了亚像素插值平滑边缘;BandPassFilter.m更不是随便设个矩形窗口,它模拟的是方形孔径的夫琅禾费衍射响应,即sinc(u)*sinc(v)函数的离散实现,我特意保留了u = (X-cx)/Dx中的Dx参数,让你能直观感受孔径尺寸变化如何影响衍射条纹间距;至于Filter_Love.m,它强制你手动指定love.bmp路径,表面看是麻烦,实则是教学设计——你必须亲手打开这张图,观察它的分辨率、灰度范围、是否含抗锯齿边缘,再理解为什么代码里要用imresize(..., 'bicubic')重采样到和原图匹配的尺寸,再用imbinarize(..., 'adaptive')做自适应二值化,而不是粗暴的>128。关键词里的“小孔成像”“频域滤波”“心形掩膜”,在这里不是标签,而是每个.m文件里被反复验证的物理变量和数值操作。它适合谁?如果你正在写课程报告却卡在“为什么我的圆孔滤波结果不像课本上的艾里斑”,如果你想搞懂fftshift和ifftshift到底该在哪一步用,如果你需要一份能放进答辩PPT里展示“从原理到代码”的完整证据链——那这套工具包,就是为你写的。
2. 核心设计逻辑:为什么必须用频域建模?为什么三种孔径要分三个函数?
2.1 小孔成像的本质不是“遮挡”,而是“频谱调制”
很多人误以为小孔成像就是拿个黑圆片挡住镜头,只让中心光线通过。这在几何光学近似下成立,但一旦涉及衍射效应——也就是当孔径尺寸接近光波长量级时——就必须切换到波动光学框架。此时,小孔不再是一个简单的“通/不通”开关,而是一个空间滤波器:它对入射光波前进行调制,其透射函数h(x,y)(即孔径形状)的傅里叶变换H(u,v),直接决定了输出像的频谱结构。根据线性系统理论,像面光强分布g(x,y)与物面光强f(x,y)满足关系:
g(x,y) = f(x,y) * h(x,y) (*表示卷积)
而在频域中,这等价于:
G(u,v) = F(u,v) · H(u,v) (·表示点乘)
这才是本工具包所有设计的基石。tset.m之所以先做fft2,再构造H(u,v),最后点乘再ifft2,不是为了凑流程,而是严格复现这一物理过程。你可能会问:为什么不直接在空间域做卷积?答案很现实——对于大尺寸图像(比如1024×1024),直接卷积计算复杂度是O(N⁴),而频域方法只需O(N²logN),快两个数量级。更重要的是,频域视角让你一眼看清“哪些频率成分被抑制、哪些被保留”。比如圆孔的H(u,v)是贝塞尔函数,天然衰减高频,导致图像模糊;方孔的sinc函数在u和v方向有零点,对应衍射暗纹位置;心形孔虽无解析解,但其频谱必然呈现非对称的主瓣和旁瓣分布——这正是Filter_Love.m存在的意义:它不提供理想公式,而是教你如何用真实图像模板数字化地逼近任意形状的h(x,y),再通过FFT获得其H(u,v)。
2.2 三种孔径函数的设计哲学:精度、可解释性与教学引导的平衡
为什么不用一个通用函数加参数切换,而要拆成CircularFilter.m、BandPassFilter.m、Filter_Love.m三个独立文件?这不是代码冗余,而是刻意为之的教学分层。
-
CircularFilter.m是“理想模型”的标杆。它用解析表达式J₁(2πρa/λz)/ρ的离散近似(其中ρ=√(u²+v²)为频域半径,a为孔径半径,z为像距),但为避免Bessel函数计算开销,实际采用exp(-(u²+v²)*σ²)高斯近似——这里的σ由a和z反推得出,确保第一暗环位置与理论值一致。代码里radius = round(0.61*lambda*z/(a*pixel_size))这行,就是阿贝衍射极限的直接体现。学生调试时,改a值就能实时看到艾里斑尺寸变化,比看公式直观十倍。 -
BandPassFilter.m则暴露了“工程近似”的真相。严格来说,方形孔径的H(u,v)是sinc(πua/λz) * sinc(πvb/λz),但sinc函数在离散网格上易产生栅栏效应。所以本函数采用双线性插值+截断的策略:先在连续坐标系计算sinc,再用interp2映射到FFT网格,最后用max(0, min(1, ...))钳位。关键参数band_width不是孔径边长,而是频域中sinc主瓣宽度,它与空间域孔径尺寸成反比——这恰恰印证了“小孔越小,衍射越强”的物理直觉。当你把band_width设得极小,会看到图像几乎只剩一个亮斑,这就是点扩散函数(PSF)的雏形。 -
Filter_Love.m是“实践桥梁”。它放弃解析,拥抱实测:love.bmp就是你的物理孔径实物照片。但直接加载会出问题——bmp通常是8位灰度,边缘有压缩伪影,尺寸也不匹配。所以代码强制你走完三步:imread读取→imresize重采样到目标尺寸(避免FFT尺寸错位)→imbinarize转二值(阈值算法选'adaptive'而非'global',因为心形边缘光照不均)。最精妙的是padarray补零操作:不是简单四周填0,而是按fft2要求,在频域中心对称补零,确保H(u,v)的共轭对称性,否则逆变换会出现虚部噪声。这三个函数并列,不是功能重复,而是带你走过“理想→近似→实测”的完整认知链条。
2.3 tset.m 的调度逻辑:为什么它不叫main.m而叫tset?
tset.m这个名字看似随意,实则暗含深意——它是“test set”的缩写,强调其测试验证属性,而非最终应用入口。它的核心任务不是炫技,而是构建可复现的实验环境。打开代码你会发现,它第一行就执行clear; clc; close all;,这不是格式化操作,而是消除Matlab工作区残留变量对FFT结果的影响(比如之前运行过其他滤波器,fftshift状态可能异常)。接着它用fullfile(pwd, 'Origin_Picture.jpg')硬编码路径,杜绝相对路径错误;读图后立刻做im2double归一化,确保所有后续计算在[0,1]区间,避免整型溢出。最关键的是滤波器调用顺序:先CircularFilter,再BandPassFilter,最后Filter_Love。这个顺序不是随意排的,而是按“物理可实现性”降序排列——圆孔最易加工,方孔次之,心形孔需精密蚀刻。你在报告里对比三张结果时,这种排序本身就构成一个隐含的工程可行性分析维度。此外,tset.m里所有figure创建都带'Name'属性,比如figure('Name','Circular Filter Result'),这样当你同时打开多个窗口,不会因标题雷同而混淆。这些细节,都是我在实验室帮学生debug时,被反复踩坑后固化下来的“防呆设计”。
3. 实操全流程拆解:从Origin_Picture.jpg到三张衍射像的每一步详解
3.1 图像预处理:为什么im2double比rgb2gray更关键?
运行tset.m的第一步是加载Origin_Picture.jpg。别跳过这行代码——img = im2double(imread('Origin_Picture.jpg'));。这里有两个易被忽略的要点:
第一,imread返回的是uint8类型(0~255),而FFT运算要求浮点精度。若直接fft2(img),Matlab会自动转换,但中间可能引入舍入误差。im2double显式转换,确保数值稳定性。
第二,Origin_Picture.jpg是RGB图还是灰度图?工具包默认它是RGB(因目录里没提灰度版本),所以im2double后size(img)是M×N×3。但频域滤波需单通道处理,因此tset.m紧接着执行img_gray = rgb2gray(img);。注意!rgb2gray不是简单取R/G/B平均值,而是按人眼感知权重0.2989*R + 0.5870*G + 0.1140*B加权,这对后续亮度分析至关重要。如果你的原始图是纯黑白线条画,rgb2gray影响不大;但若是风景照,跳过这步会导致天空细节丢失。实测对比:用平均法灰度化,云层纹理模糊;用rgb2gray,层次分明。这步之后,img_gray是M×N双精度矩阵,为FFT铺平道路。
3.2 频域变换:fft2之后为何必须fftshift?
接下来是核心步骤:
F = fft2(img_gray);
F_shifted = fftshift(F);
初学者常困惑:fft2输出的频谱,低频(DC分量)在左上角,高频在右下角,这不符合人眼观察习惯(我们习惯中心是低频)。fftshift就是干这个的——它把四分之一象限循环移位,让DC分量移到矩阵中心。但关键陷阱在于:fftshift必须在滤波前做,且滤波器H(u,v)也必须按同样方式构造。比如CircularFilter.m里,[U,V] = meshgrid(u,v)生成的坐标网格,u和v向量必须是以0为中心对称的(如u = -N/2:N/2-1),这样才能和fftshift(F)的坐标系对齐。如果漏掉fftshift,或者滤波器坐标系没对齐,点乘F_shifted .* H后,逆变换会得到严重畸变的图像——常见症状是图像分裂成四个相同副本,或整体倾斜。我在教学中让学生故意注释掉fftshift,再对比结果,这个“错误示范”比十页公式更有说服力。
3.3 圆形孔径滤波:CircularFilter.m里的亚像素精度控制
打开CircularFilter.m,核心代码段:
% 构造频域坐标网格(已fftshift对齐)
[u,v] = meshgrid(-N/2:N/2-1, -N/2:N/2-1);
rho = sqrt(u.^2 + v.^2); % 频域半径
% 计算圆孔截止频率(基于瑞利判据)
fc = 0.61 * lambda * z / (a * pixel_size); % 单位:cycles/pixel
% 高斯近似:exp(-(rho/fc)^2)
H = exp(-(rho/fc).^2);
这里fc的计算是灵魂。lambda(波长)、z(像距)、a(孔径半径)、pixel_size(传感器像素尺寸)全部参与运算。工具包默认lambda=550e-9(绿光),z=0.1(10cm),a=1e-3(1mm),pixel_size=3.45e-6(典型CMOS像素)。代入得fc≈158 cycles/pixel。这意味着频谱中半径大于158的频率成分将被显著衰减。H矩阵尺寸必须与F_shifted完全一致(N×N),否则点乘报错。代码里用size(F_shifted)动态获取N,杜绝硬编码尺寸。更精妙的是exp(-(rho/fc).^2)——它比理想矩形截止更符合实际光学系统的渐变过渡特性,避免吉布斯振铃效应。运行时,若把fc设为50,图像极度模糊;设为500,则接近原图。这个参数就是你的“光学调焦旋钮”。
3.4 方形孔径模拟:BandPassFilter.m中sinc函数的离散陷阱
BandPassFilter.m的挑战在于sinc(x)=sin(πx)/(πx)在x=0处未定义,且离散采样易失真。代码处理如下:
% 定义频域坐标(同上)
[u,v] = meshgrid(-N/2:N/2-1, -N/2:N/2-1);
% 计算sinc函数,规避x=0除零
sinc_u = ones(size(u));
sinc_v = ones(size(v));
idx_u = u ~= 0; idx_v = v ~= 0;
sinc_u(idx_u) = sin(pi*u(idx_u))./(pi*u(idx_u));
sinc_v(idx_v) = sin(pi*v(idx_v))./(pi*v(idx_v));
% 方孔响应:sinc_u * sinc_v
H = sinc_u .* sinc_v;
% 截断旁瓣(保留主瓣+第一旁瓣)
H = H .* (abs(u) < band_width & abs(v) < band_width);
band_width参数设为20时,H矩阵在u=±20、v=±20处有零点,对应空间域衍射暗纹。但若band_width太小(如5),sinc采样点过少,零点位置漂移;太大(如100),旁瓣噪声淹没主信号。我建议初学者先设band_width=30,观察十字暗纹,再逐步减小体会衍射增强效应。这里没有“正确答案”,只有与物理直觉的匹配度——当你看到图像中出现清晰的水平/垂直暗线,且间距随band_width减小而增大,就说明sinc建模成功了。
3.5 心形掩膜实战:Filter_Love.m里的图像预处理生死线
Filter_Love.m是唯一需要你手动干预的文件。关键步骤:
% 1. 加载心形模板(路径需手动修改)
love_img = imread('love.bmp');
% 2. 转灰度并重采样到目标尺寸
love_gray = rgb2gray(love_img);
love_resized = imresize(love_gray, [size(img_gray,1), size(img_gray,2)], 'bicubic');
% 3. 自适应二值化(应对光照不均)
love_bin = imbinarize(love_resized, 'adaptive', 'Sensitivity', 0.6);
% 4. 补零至FFT尺寸(关键!)
H_love = padarray(double(love_bin), [N/2-size(love_bin,1)/2, N/2-size(love_bin,2)/2], 'post');
% 5. FFT并fftshift
H = fftshift(fft2(H_love));
'Sensitivity'参数是成败关键。设为0.4,心形边缘过细,频谱主瓣窄,重建像锐利但噪声多;设为0.8,边缘过粗,主瓣宽,图像过度模糊。0.6是经验值,兼顾形状保真与噪声抑制。padarray的'post'选项确保补零在右下角,与fft2的自然零填充方向一致。若用'both',会导致H矩阵不对称,逆变换后图像左右颠倒。运行前务必用imshow(love_bin)检查二值图——理想状态是心形轮廓光滑、无毛刺、无空洞。若有空洞,说明'adaptive'阈值过高,需调低Sensitivity;若毛刺多,说明原始love.bmp分辨率太低,需换更高清模板。
3.6 逆变换与可视化:ifft2后的real()为何不可省略?
滤波后执行:
G_shifted = F_shifted .* H;
G = ifftshift(G_shifted); % 注意!先ifftshift再ifft2
g = real(ifft2(G)); % real()必不可少
ifftshift是fftshift的逆操作,必须在ifft2前执行,否则频谱相位错乱。real(ifft2(G))中的real()看似多余,实则救命稻草——由于浮点计算误差,ifft2结果可能含微小虚部(如1e-15i),若直接imshow(g),Matlab会报错“Complex values not supported”。real()提取实部,且误差在允许范围内。可视化时,imshow(mat2gray(g))比imshow(g,[])更可靠,因为mat2gray自动将数据映射到[0,1],避免因数值范围异常导致图像全黑或全白。工具包配套的Origin_Picture.jpg经过精心挑选:灰度分布均匀(直方图近似平坦),确保滤波效果不受原始图动态范围干扰。
4. 常见问题排查与独家避坑指南:那些文档里不会写的血泪经验
4.1 典型问题速查表
| 现象 | 可能原因 | 排查步骤 | 解决方案 |
|---|---|---|---|
| 图像分裂成四个副本 | fftshift/ifftshift缺失或错位 | 检查CircularFilter.m中H构造是否用fftshift坐标系;确认tset.m中F_shifted .* H后是否执行ifftshift | 在F = fft2(...)后立即加F_shifted = fftshift(F);在G_shifted = F_shifted .* H后加G = ifftshift(G_shifted) |
| 心形滤波结果全是噪点 | love.bmp分辨率不足或二值化失败 | 用imshow(love_bin)查看二值图;检查love.bmp尺寸是否<512×512 | 换用高清心形图(推荐矢量导出为PNG再转BMP);调低Filter_Love.m中'Sensitivity'至0.4 |
| 方孔滤波无十字暗纹 | band_width设置过大或sinc采样不足 | 打印size(H),确认是否为N×N;观察sinc_u矩阵,检查u=0行是否全1 | 减小band_width至15~25;确保u向量包含足够多非零点(length(u)>100) |
| 三张结果亮度差异巨大 | 滤波器H未归一化 | 计算sum(H(:)),若远≠1则能量泄漏 | 在H构造后加H = H / sum(H(:))(仅对CircularFilter.m和BandPassFilter.m有效;心形孔因形状特殊,归一化会失真,故不启用) |
| 运行报错“Undefined function or variable ‘love_img’” | Filter_Love.m中路径未修改 | 检查第3行love_img = imread('...');的路径字符串 | 将'love.bmp'改为绝对路径,如'C:\MyProject\love.bmp' |
4.2 我踩过的五个深坑与解决方案
坑1:fft2输入尺寸不是2的幂次导致性能暴跌
Matlab的fft2对2的幂次尺寸(如512, 1024)优化最好。Origin_Picture.jpg若为1200×800,直接fft2会慢3倍。解决方案:在tset.m加载后加img_gray = imresize(img_gray, [1024, 1024]);,用双三次插值保持质量。别信“自动填充”,手动Resize更可控。
坑2:心形掩膜边缘锯齿引发高频噪声
原始love.bmp用画图软件绘制,边缘是阶梯状。FFT后高频分量爆炸,重建像雪花点密布。我的解法:在Filter_Love.m中,love_resized后插入高斯模糊love_blurred = imgaussfilt(love_resized, 1.5);,再二值化。1.5像素的σ值刚好柔化锯齿又不损心形轮廓。
坑3:sinc函数零点漂移
BandPassFilter.m中,若u向量步长不等于1(如u = -N/2:0.5:N/2-1),sinc零点位置偏移。必须确保u = -N/2:N/2-1,即整数索引。我在代码注释里加了警告:“勿修改u/v步长,否则衍射条纹错位”。
坑4:real(ifft2(...))仍含微小负值
即使real(),重建图像g可能有-1e-10的负值,imshow显示为黑块。解决方案:g = max(0, g); 强制截断负值。这符合物理事实——光强不能为负。
坑5:不同Matlab版本imbinarize行为差异
R2016a以前版本无'adaptive'选项。兼容方案:用graythresh替代,love_bin = imbinarize(love_resized, graythresh(love_resized));,虽效果稍差,但保证运行。
4.3 进阶调试技巧:如何验证你的滤波器真的物理正确?
别只看最终图像!用这三招交叉验证:
1. 频谱可视化:在CircularFilter.m中,imshow(log(1+abs(H)))查看H的频谱形状。圆孔应呈中心亮、向外渐暗的圆形;方孔应呈十字亮带;心形孔应有非对称主瓣。若H是全白或全黑,说明构造失败。
2. 点扩散函数(PSF)提取:用全白图像ones(N,N)代替Origin_Picture.jpg,运行滤波流程,g就是PSF。测量圆孔PSF的FWHM(半高全宽),应与0.61*lambda*z/(a*pixel_size)理论值误差<5%。
3. 能量守恒检验:计算sum(abs(g(:)).^2) / sum(abs(img_gray(:)).^2),理想滤波器应≈1(忽略数值误差)。若<0.5,说明H衰减过强;若>1.2,说明H有增益,需检查归一化。
5. 工具包扩展与教学延伸:从仿真到真实光学实验的无缝衔接
5.1 如何用此工具包指导真实光学实验?
这套代码不是终点,而是连接虚拟与现实的桥梁。我带学生做过一个经典实验:用激光笔照射打印在胶片上的圆孔、方孔、心形孔,用手机拍摄衍射图样,再导入Matlab用imread读取,执行Filter_Love.m流程——但把love.bmp换成实拍衍射图。对比仿真H(u,v)和实测|G(u,v)|,发现心形孔实测频谱的主瓣方向与心尖指向一致,证实了非对称孔径的定向衍射特性。这时,工具包的价值凸显:它让你把手机拍的照片,变成可量化的物理数据。建议扩展:在tset.m末尾添加save('experiment_data.mat','g','F_shifted','H'),保存频谱数据,供后续用Origin或Python做定量分析。
5.2 三个值得尝试的进阶改造
改造1:加入色散效应
当前代码假设单色光(550nm)。若要模拟白光,需对RGB三通道分别用不同lambda计算fc:R通道用650nm,G用550nm,B用450nm。修改CircularFilter.m,让它接受lambda参数,再在tset.m中循环处理三通道。你会看到重建图像边缘出现彩虹色衍射条纹——这就是真实相机紫边的根源。
改造2:模拟离焦模糊
小孔成像的理想像距z很难精确控制。在CircularFilter.m中,fc公式里z改为变量,添加滑动条z_slider = uicontrol('Style','slider','Min',0.05,'Max',0.2,'Value',0.1),实时调整z并刷新图像。学生拖动滑块,亲眼看到z减小(像距变短)时艾里斑扩大,深刻理解景深概念。
改造3:从孔径到透镜
把CircularFilter.m中的H替换为透镜的exp(-j*k*(x²+y²)/(2*f))相位因子(k=2π/lambda, f为焦距),就变成薄透镜傅里叶变换器仿真。这能自然衔接到《信息光学》课程,证明本工具包的底层架构具备向上扩展能力。
5.3 给教师和学生的特别建议
- 对学生:不要满足于“跑通代码”。选一个函数(比如
BandPassFilter.m),删掉所有注释,尝试自己重写。当你写出sinc计算并成功看到十字暗纹时,你就真正掌握了频域滤波。 - 对教师:把
tset.m拆成三个独立实验任务——任务1:修改a值,记录艾里斑直径与a的关系,验证1/a规律;任务2:用BandPassFilter.m生成不同band_width的图像,测量暗纹间距,拟合sinc零点公式;任务3:设计自己的heart2.bmp,对比不同心形(尖角vs圆润)对频谱的影响。评分标准不是结果美丑,而是分析报告中物理参数的定量讨论。 - 对我自己:这套工具包已开源三年,收到最多反馈是“希望支持椭圆孔”。其实只需在
CircularFilter.m中把rho = sqrt(u.^2 + v.^2)改为rho_ell = sqrt((u/a).^2 + (v/b).^2),再加b参数即可。但我不急着加——因为教学价值不在功能多,而在每个函数背后,都有一个必须亲手推导的物理公式。当你为椭圆孔写下第一个sinc变体时,你已经超越了工具包,成了真正的光学建模者。
我在实验室的白板上写着一句话:“仿真不是替代实验,而是让实验前的问题更尖锐,实验后的问题更深刻。” 这套Matlab小孔成像工具包,就是为此而生。它不承诺一键出图,但承诺每一步代码,都经得起光学原理的拷问。现在,打开你的Matlab,cd到工具包目录,键入tset——然后,准备好纸笔,记录下你第一次看到心形衍射图样时,那个“原来如此”的瞬间。
简介:一套即装即用的Matlab小孔成像仿真工具,直接运行tset.m就能完成整套图像频域处理:自动读取Origin_Picture.jpg原始图,依次调用CircularFilter.m(生成圆形孔径滤波效果)、BandPassFilter.m(用带通方式近似实现方形孔径响应)、Filter_Love.m(加载love.bmp作为心形掩膜进行定制化滤波)。所有核心函数都配有逐行中文注释,覆盖FFT正变换、滤波器矩阵构造(含空间域转频域适配)、频域相乘、IFFT逆变换及结果图像可视化全过程。无需额外工具箱,不依赖外部路径配置(仅Filter_Love.m需确认love.bmp所在位置),配套提供原始测试图和心形模板图,结构扁平清晰,适合数字图像处理课程实验、光学成像原理验证或频域滤波入门练习。

194

被折叠的 条评论
为什么被折叠?



