简介这是一份面向信号处理与图像分析学习者的 Morlet 小波实验资料包聚焦小波去噪、一维与二维多尺度分解、图像特征可视化等主题。压缩包共9个文件、整体仅2.81MB其中4个 MATLAB 脚本.m承担核心实现1个 .mat 数据文件存放实验数据2张 .jpg 和1张 .png 为去噪前后对比或二维 Morlet 变换结果图1个 .fig 保留了可继续编辑的图窗便于动手复现和调整参数。目前已有557人学习下载。资料覆盖一维信号与二维图像的三级分解、小波系数提取、阈值去噪等关键环节借助源码和数据可直观理解 Morlet 小波由高斯函数与正弦函数复合而成、具备时频局部化优势的原理观察不同尺度下信号与图像的细节变化对医学影像、遥感数据等非平稳数据的多尺度分析和降噪实践也有直接参考价值。1. 用 Morlet 小波同时拆解信号和图像这个实验包里能学到什么如果有人给你一个压缩包里面是b.m、e.m、f.m、imageScaleT.m和一个名为7.31.mat的 mat 文件第一反应大概是去查这些小脚本还跑不跑得动。拆完这套小波实验源码你会发现它其实覆盖了两条最常用的技术路线一维信号的小波去噪以及用二维 Morlet 小波对图像做多尺度分析和去噪。Morlet 小波由高斯窗和复指数波相乘构成在时频域具有很好的局部化能力对信号里的谐波成分和图像里的纹理方向都敏感因此频繁出现在生物医学信号处理、探地雷达数据分析以及工业视觉检测场景里。下面以这个包为骨架逐段说明 Morlet 小波的理论、三级分解的实现、阈值去噪的调参方法以及把示例代码改造成可复用工具时容易踩的几个边界问题。后面给出的代码和参数对照表可以直接抄到工作区里跑。2. Morlet 小波的时频定位和二维小波分解的数学基础小波去噪能在时域和频域同时定位噪声核心原因在于小波基函数不像傅里叶基那样用无限长正弦铺满整个时间轴而是在某个局部区间内振荡、在区间外快速衰减。Morlet 是其中最典型的复小波它的实部和虚部相差 90°相位因此对相位信息敏感。这个特性落到二维图像里就变成方向选择性实部响应图像中的边缘虚部响应纹理的相位变化。理解这一点再去读b.m、f.m里的系数处理逻辑就不会觉得那些复数运算多余。2.1 Morlet 小波的构造高斯窗与复正弦相乘Morlet 小波的标准定义是一个高斯包络乘上复正弦。一维公式是ψ(t) π^(-1/4) * exp(-t²/2) * exp(i·ω₀·t)在 MATLAB 里不需要额外工具箱直接用exp、cos、sin组合即可。下面这段代码生成一维 Morlet 小波之后可以直接用在b.m对应的信号去噪流程里。function psi morlet_1d(t, w0) % t : 时间轴建议用 linspace(-4,4,N) % w0 : 中心角频率常用范围 [4, 8] % 越大频率分辨率越高但对瞬态信号越不敏感 psi exp(-t.^2 / 2) .* exp(1i * w0 * t); end这段代码的逻辑是高斯包络exp(-t.^2/2)决定时域窗的宽度w0决定小波的振荡快慢。w0取 4 时频带较宽适合检测瞬态冲击取 8 时频带变窄适合分离两个频率接近的谐波分量。我一般取w0 6因为此时小波接近容许条件重构时的边界误差最小。实际实验里b.m如果做的是声波信号分析w0从 4 到 6 之间调得到的小波系数差别不大但对阈值去噪的最终信噪比影响很明显。2.2 从一维到二维的 Morlet 图像分解二维 Morlet 滤波器的构造需要把一维定义提高到二维坐标(x,y)并引入两个额外参数尺度scale和方向角theta。尺度控制高斯包络的半径和振荡频率方向角使小波核在特定方向上有最大响应。生成二维核时先对坐标做旋转变换再按旋转后的坐标计算高斯窗和复指数。function psi2 morlet_2d(x, y, scale, theta, w0) % x,y : 由 meshgrid 生成的二维网格坐标 % scale : 小波尺度直接影响中心频率 % theta : 方向角0 表示水平方向 xr x * cos(theta) y * sin(theta); yr -x * sin(theta) y * cos(theta); g exp(-(xr.^2 yr.^2) / (2 * scale^2)); psi2 g .* exp(1i * (w0 / scale) * xr); end这里把坐标旋转到(xr,yr)等价于先在方向theta上做一维 Morlet再沿垂直方向用高斯窗平滑。尺度scale缩小一倍中心频率就提高一倍对应的图像细节更细。二维图像在内存里就是按行列索引的二维数组所以这个函数返回的psi2可以直接与conv2或imfilter配合。处理各向异性纹理时通常需要同时生成多个方向的小波核方向间隔取 60° 就能覆盖六个主方向如果只做去噪方向数可以减少到三个。参数名取值范围对输出图像的影响适用场景scale2~32越小越能提取细纹理越大越关注粗结构去噪时适度选大保留整体形貌theta0、pi/3、2pi/3...控制响应最强的方向各向异性纹理分析w04~8控制频率选择的锐度通用去噪取 4~6在二维情形中不能直接把一维阈值搬过来因为二维小波系数的实部和虚部能量分布并不均匀。更稳妥的做法是计算abs(psi2)得到幅度系数矩阵再对这个二维数组做阈值处理。这也是 Morlet 图像实验里常见可视化方式展示的是幅度谱而不是让用户直接看复数系数。2.3 三级分解的系数结构摘要里提到的“三级分解”并不是 MATLAB 内置wavedec的离散小波三级分解而是连续小波场景下按三个尺度分别做卷积得到三组系数。每组系数与原始图像尺寸一致所以你会得到三个二维数组一维信号则对应三条与输入等长的系数曲线。三级分解的结构意义在于噪声在小尺度系数中能量占比高在大尺度系数中占比低。三级分解提供了从细到粗的三个观察视角阈值处理可以分别设置不同强度而不是一把尺子量到底。实现三级分解时最省事的写法是循环遍历尺度数组例如scales [4, 8, 16]每一轮用morlet_2d生成核并做卷积。这里还要注意连续小波变换的系数存在大量冗余三级分解的内存开销大约是输入图像的 3 到 4 倍。处理大图时建议先把图像转成单精度single避免双精度浮点矩阵把内存撑爆。提示连续小波的系数冗余不完全是坏事。冗余意味着对噪声的鲁棒性更好但代价是计算量上升。实验阶段用 3 个尺度足够不要为了追求“更精细”而堆到 10 个尺度。3. 从 b.m 到 imageScaleT.m复现包里的三级小波去噪流程实验包里每个文件的分工其实是跟着小波实验的步骤走的先运行b.m处理一维信号再运行f.m或imageScaleT.m处理图像最后用untitled.fig查看图形界面里的结果。理解了这个顺序你就知道哪些是核心脚本、哪些只是验证用的辅助文件。3.1 包内文件与数据流文件我判断的作用在流程中的位置b.m一维信号去噪主脚本读7.31.mat对信号做 Morlet 小波分解和阈值处理e.m误差分析或重构验证比较去噪前后信号的差异f.m二维图像去噪主脚本读图象.jpg或66.jpg生成滤波结果imageScaleT.m图像多尺度缩放与分解函数被f.m调用负责生成不同尺度的滤波器核7.31.mat实验采集信号数据一维信号来源new.png去噪后的输出图像验证效果文件untitled.figGUI 界面文件用于交互式查看小波系数这种文件组织方式非常像一个课堂实验的产物主脚本把参数写死在文件头部函数文件只负责核心计算。拿到源码后不需要改动整个函数文件只需要在f.m里调整尺度参数与阈值就能看到去噪结果的变化。3.2 一维信号的三级小波去噪实现一维信号去噪最直接的做法是把原始信号分别与三个尺度的 Morlet 小波做卷积得到三组复小波系数然后对幅度系数做软阈值处理最后用保留的系数重建。下面这段代码可以在 R2016b 之后的 MATLAB 中运行。% 读入信号假设 7.31.mat 里存的变量名是 sig load(7.31.mat); if ~exist(sig,var) sig x; % 实际使用时按 mat 文件里的变量名修改 end fs 1000; t (0:length(sig)-1) / fs; w0 6; scales [4 8 16]; coeffs zeros(length(scales), length(sig)); for i 1:length(scales) tau -4:0.02:4; psi morlet_1d(tau, w0) / scales(i); coeffs(i,:) conv(sig, psi, same); end % 计算全局噪声水平生成阈值 sigma median(abs(coeffs(:))) / 0.6745; thr sigma * sqrt(2 * log(length(sig))); coeffs_den zeros(size(coeffs)); for i 1:length(scales) mag abs(coeffs(i,:)); % 软阈值低于阈值的系数置零高于阈值的幅度收缩 coeffs_den(i,:) sign(coeffs(i,:)) .* max(mag - thr, 0); end % 用三个尺度的去噪系数做平均得到重建信号 sig_den mean(coeffs_den, 1);卷积核归一化是这段代码里容易忽略的点psi / scales(i)是为了让不同尺度的系数量纲一致。如果不除以scales(i)小尺度系数幅度天然偏大阈值处理会偏向滤掉大尺度信息。软阈值的操作max(mag - thr, 0)会把系数向零收缩有利于保留信号轮廓硬阈值则直接切断适合脉冲噪声。实际试验里信噪比较低的信号建议先用软阈值并观察三级系数中哪个尺度还保留着可辨识的周期性峰值。mean(coeffs_den, 1)是一种快速重建方式虽然不是严格的小波逆变换但在演示去噪流程时足够稳定如果要做定量分析建议换成icwt或基于典则对偶框架的重构函数。3.3 imageScaleT.m 与二维 Morlet 图像去噪二维图像去噪的关键在于把morlet_2d生成的滤波器与图像进行卷积同时保持输出尺寸不变。imageScaleT.m里的ScaleT我理解为 “scale by T”也就是在某个给定尺度下对图像做小波变换。它的流程是读取彩色图像转灰度调用morlet_2d生成实部与虚部核分别做卷积再把两个结果合成幅度系数最后用软阈值压缩噪声。下面这一小段演示单个尺度、单个方向的处理方式img imread(66.jpg); if size(img,3) 1 img rgb2gray(img); end img double(img); % 尺度取 8方向取 0 度w0 取 6 N 31; [x, y] meshgrid(linspace(-4, 4, N)); psiR real(morlet_2d(x, y, 8, 0, 6)); psiI imag(morlet_2d(x, y, 8, 0, 6)); cR conv2(img, psiR, same); cI conv2(img, psiI, same); coef sqrt(cR.^2 cI.^2); % 二维小波系数的阈值 sigma median(abs(coef(:))) / 0.6745; thr sigma * sqrt(2 * log(numel(img))); coef_d max(coef - thr, 0); % 用收缩后的幅度乘上原系数方向保留相位信息 phase atan2(cI, cR); img_den coef_d .* cos(phase);这个方案只用一个尺度效果可能不够平滑。要形成三级分解就把它放进循环对scales [4 8 16]分别生成卷积结果再把三级去噪后的图像取平均。取平均的作用是抵消单尺度重建时出现的振铃波纹。调用conv2时要注意same输出会把边界附近的计算结果丢掉一部分因此用same之后最好改用imfilter配合symmetric选项做边缘延拓。注意如果原包代码里直接用conv2而没有处理边界去噪结果会在图像四周出现约 15 像素宽的黑边。这种边界误差在小波实验中经常被误认为是去噪伪影实际上只是卷积边界策略的问题。4. 阈值与尺度怎么配合小波阈值去噪的工程调参跑通一个实验只需要脚本能运行但要用到真实信号上阈值策略和尺度选择会被反复修改。小波去噪的误差主要来自两个方向阈值过高会把真实突变当成噪声削平阈值过低又会让噪声透过三层分解泄漏到重建图像里。这一章把调参拆成三个可控维度软硬阈值选择、分尺度阈值计算、常见的参数陷阱。4.1 软阈值与硬阈值的实际差别软阈值和硬阈值在 MATLAB 代码里只差一个max比较但结果差异很大。硬阈值把小于阈值的系数直接置零大于阈值的系数保持不变软阈值把所有系数都收缩一个thr的量。硬阈值保留信号峰值但重建信号会在突变点附近出现小幅振荡软阈值更平滑却可能让尖峰变钝。function y soft_threshold(x, thr) y sign(x) .* max(abs(x) - thr, 0); end function y hard_threshold(x, thr) y x; y(abs(x) thr) 0; end实践中我一般这样取舍处理心电图、地震波这类有陡峭上升沿的信号时用软阈值会拉平 R 波峰这时候硬阈值更合适处理连续渐变信号或自然图像时软阈值能显著减少视觉上的方块感。更精细的做法是加一个介于两者之间的折中阈值例如max(abs(x) - alpha*thr, 0)其中alpha取 0.5~0.8。你可以把它理解成软硬阈值的连续插值去噪强度不再是非 0 即 1而是可以在“保留陡峭度”和“平滑噪声”之间滑动。4.2 三级分解里每个尺度的阈值怎么分开定全局阈值thr sigma * sqrt(2*log(N))是基于高斯白噪声假设的经典公式。它在均匀噪声场里效果不错但真实信号往往是非平稳的小尺度上的干扰可能比大尺度强得多。更合适的做法是分别统计每个尺度系数的中位绝对偏差而不是共用一个全局噪声水平。for i 1:length(scales) mag_i abs(coeffs(i,:)); sigma_i median(abs(mag_i - median(mag_i))) / 0.6745; thr_i(i) sigma_i * sqrt(2 * log(length(sig))); end用每个尺度自己的中位绝对偏差替代全局 σ会让小尺度阈值变大、大尺度阈值变小。对应到图像上就是高频细节保留能力提升大面积平坦区域也不会被滤成水彩画。如果你发现去噪后图像仍然偏毛糙说明小尺度的阈值不够高可以乘一个系数beta典型值 1.1~1.5反过来如果图像丢失了细线或窄条结构就说明大尺度阈值太高应调低 20%。4.3 三个容易反复踩的参数陷阱第一个陷阱是尺度数组的间距。scales [4 8 16]是按倍数递增对应频带刚好覆盖一倍频程如果改成等间距[4 6 8]相邻尺度的频带会大量重叠三层分解实际上等效于一层去噪质量提升有限。第二个陷阱是小波核尺寸N的设置。N31时核覆盖约 8 个时间单位w06能容纳约 3 个完整振荡如果 N 太小小波核被截断重构时会产生能量泄漏。第三个陷阱是图像矩阵的数据范围。很多示例代码直接对uint8做卷积超过 255 的系数被截断导致阈值永远失效。读取图像后第一件事就是转成double并归一化到 0~1。陷阱表现改法三个尺度频带重叠去噪前后几乎无变化尺度改用 2 倍递增关系小波核截断边缘出现异常高亮核尺寸与w0联动N 4*w06未转 double阈值无效灰度被截断读图后立即double(img)/255如果实验结果出现上述三种现象中的任意一项优先检查参数定义而不要怀疑去噪算法本身。这也是把这个 MATLAB 实验包迁移到其他数据上时最值得保留的经验。5. 把实验包改造成可复用的去噪工具边界延拓与质量验证跑通b.m和f.m之后下一步不是直接拿结果交差而是把实验里的固定阈值变成自适应参数并用客观指标验证去噪效果。一个完整方案是先用镜像延拓处理边界再计算峰值信噪比和结构相似度用这些指标决定三级分解里每一层阈值的最优区间。这样你得到的就不再是只适用于7.31.mat的一次性脚本。5.1 用镜像延拓替代零填充conv2默认把边界外补零这会给图像引入不存在的跳跃边缘。改用imfilter的symmetric选项可以避免边界伪影。对连续小波卷积我一般选择镜像对称延拓因为这种延拓方式能保证边界处导数连续对 Morlet 小波这类带方向的核尤为重要。cR imfilter(img, psiR, symmetric, same); cI imfilter(img, psiI, symmetric, same);把之前conv2的两行替换成imfilter去噪图像四周的黑边会立刻消失。代价是计算量大约增加 15%因为镜像延拓需要额外拷贝边缘数据。对于 1024×1024 的图像这仍然在可接受范围内。5.2 用 PSNR 和 SSIM 确定阈值参数当有干净图像作为参照时可以把三级去噪的尺度与阈值选择变成一次二维搜索scales保持[4 8 16]不变对每个尺度的阈值乘数beta从 0.8 到 1.5 遍历记录每一组参数下的峰值信噪比和结构相似度。psnr_val 10 * log10(1 / mean((img(:) - img_den(:)).^2)); ssim_val ssim(img_den, img); % 需要 Image Processing Toolboxpsnr_val越高去噪后和原始图像的像素级差异越小ssim_val越高结构纹理保留得越好。一个可用的判定条件是ssim 0.9且psnr比噪声图像高 3dB 以上。达不到这个目标时优先调小大尺度阈值而不是继续提高小尺度阈值。这也是二维小波去噪和普通低通滤波最大的区别小波去噪允许在保留结构的同时削弱噪声而低通滤波一定会牺牲边缘锐度。把这两个验证函数加进去以后这套实验就可以脱离原始 mat 文件直接用于新采集的视频帧或传感器信号。遇到去噪效果不理想时先看是边界伪影还是尺度参数不合理再用 PSNR 和 SSIM 做回归比较比肉眼调图高效得多。本文还有配套的精品资源点击获取