简介:本资源面向图像处理方向的本科生、研究生及算法入门者,提供一套基于MATLAB的可见光与红外光图像融合完整实现方案,用于解决多源图像信息互补与融合质量评估问题。压缩包共17个文件,包含8个bmp图像样本、7个m脚本文件、1个md说明及1份docx课设报告,整体约9.1MB,脚本覆盖小波变换、拉普拉斯金字塔分解与重构、上采样及FFT彩色融合等核心模块。资源重点实现小波变换与拉普拉斯金字塔两种多尺度分解方法,并对比Daubechies、Haar、Symlets等不同小波基对融合效果的影响,同时从峰值信噪比等指标分析两种方法在图像质量与计算效率上的差异。读者可借助现成脚本与实验图像快速复现融合流程,理解分解重构中的优势与不足,并参考课设报告梳理实验设计与结果分析思路,为红外与可见光融合的算法优化提供可操作的学习范例。目前已有148人学习。
1. 从一组课设文件说起:可见光与红外图像融合到底在做什么
可见光相机拍出来的画面纹理清楚、边缘锐利,但一到夜间或烟雾环境就基本失效;红外热像仪能穿透这些干扰抓住热源目标,可分辨率低、细节糊成一团。把两者融合成一张图,既保留可见光的纹理细节,又叠加红外的热辐射信息,这就是可见光与红外光图像融合要解决的核心问题。我拿到手的这份 MATLAB 课设资源包,里面同时实现了小波变换和拉普拉斯金字塔两条技术路线,还附带不同小波基的对比实验和一份课设报告,对于正在做图像处理大作业或者想快速验证融合算法的同学来说,是一个可以直接跑通、方便改参数的起点。它适合刚接触多尺度分解的新手照着复现,也适合熟手拿来当对比基线,省去从零搭框架的时间。
2. 小波变换融合:从分解系数到重构图像的完整链路
2.1 为什么小波变换适合做图像融合
图像融合的本质是在不同尺度上提取源图像的有效信息,再按某种规则合并。小波变换把图像分解成低频近似分量和高频细节分量,低频保留整体亮度和轮廓,高频对应边缘和纹理。融合时对低频系数取平均或加权,对高频系数取绝对值最大,就能在保留可见光细节的同时注入红外的热目标信息。相比直接像素加权平均,小波变换的优势在于它把空间域和频率域的信息解耦了,融合规则可以分尺度、分方向设计,效果更可控。
资源包里Q1WaveletTransform.m是主入口脚本,waveletfusion.bmp到waveletfusion4.bmp是不同小波基下的融合结果图。从文件命名看,作者至少跑了四组对比实验,对应 Daubechies、Haar、Symlets 等不同小波基。这个设计思路是对的——小波基的选择直接影响分解后系数的稀疏性和重构质量,不对比就不知道哪个基适合当前图像对。
2.2 小波融合的代码实现与参数说明
先看核心流程。下面这段代码是我根据资源包里的脚本结构整理的可运行版本,保留了关键步骤和注释:
% 读取可见光与红外图像,统一尺寸并转灰度 VI = imread('VI.bmp'); IR = imread('IR.bmp'); if size(VI,3) == 3 VI = rgb2gray(VI); end if size(IR,3) == 3 IR = rgb2gray(IR); end VI = imresize(VI, [256 256]); IR = imresize(IR, [256 256]); VI = double(VI) / 255; IR = double(IR) / 255; % 选择小波基和分解层数 wname = 'db4'; % 可替换为 'haar'、'sym4' 等 level = 3; % 分解层数,通常2-4层 % 小波分解 [C_V, S_V] = wavedec2(VI, level, wname); [C_I, S_I] = wavedec2(IR, level, wname); % 融合规则:低频取平均,高频取绝对值最大 C_F = zeros(size(C_V)); % 低频系数位于 C 的前 S(1,1)*S(1,2) 个元素 low_len = S_V(1,1) * S_V(1,2); C_F(1:low_len) = (C_V(1:low_len) + C_I(1:low_len)) / 2; % 高频系数逐点比较绝对值 for i = low_len+1:length(C_V) if abs(C_V(i)) >= abs(C_I(i)) C_F(i) = C_V(i); else C_F(i) = C_I(i); end end % 小波重构 fused = waverec2(C_F, S_V, wname); fused = max(min(fused, 1), 0); % 截断到 [0,1] imwrite(fused, 'waveletfusion_result.bmp');这段代码的逻辑分四步:读图预处理、小波分解、系数融合、重构输出。wname参数控制小波基类型,db4是 Daubechies 系列的四阶小波,适合捕捉平滑信号;haar最简单但频域局部化能力弱;sym4是 Symlets 系列,对称性比 db 好,重构时相位失真小。level控制分解层数,层数越多频率划分越细,但计算量也越大,而且层数过高会导致重构时边界效应累积。我一般先用 3 层跑一遍看效果,再根据图像尺寸调整。
融合规则里低频取平均是最简单的策略,优点是稳定不出错,缺点是如果两幅图亮度差异大,融合结果会偏灰。高频取绝对值最大能保留边缘,但对噪声敏感——如果红外图噪声大,融合结果会把噪声也放大。资源包里fenergyy.m这个文件从命名推测是做能量分析的,可能是用来计算融合前后信息熵或能量分布的辅助函数,用来定量评价融合质量。
2.3 不同小波基的对比实验怎么做
资源包里有多张waveletfusion*.bmp结果图,说明作者做了小波基对比。要复现这个对比,只需要把wname换成不同值,循环跑一遍:
wavelets = {'haar', 'db2', 'db4', 'sym4', 'sym8'}; for k = 1:length(wavelets) wname = wavelets{k}; % ... 重复上面的分解-融合-重构流程 ... imwrite(fused, ['waveletfusion_' wname '.bmp']); % 计算评价指标 psnr_val = psnr(fused, VI); % 以可见光为参考 fprintf('小波基: %s, PSNR: %.2f dB\n', wname, psnr_val); end这里用 PSNR 作为评价指标,资源包摘要里也提到了峰值信噪比。需要注意的是,融合图像没有绝对的标准参考图,用可见光图算 PSNR 只能反映融合结果与可见光的接近程度,不能完全代表融合质量。更合理的做法是同时算信息熵、互信息或边缘保持度。fenergyy.m可能就是干这个的,建议打开看一眼它的输入输出参数,直接调用比自己重写省事。
跑对比实验时有个坑:不同小波基的滤波器长度不同,wavedec2返回的系数向量长度会变,但S结构体记录了每层的尺寸信息,重构时用同一个S就行。不要手动去算系数索引,容易翻车。
3. 拉普拉斯金字塔融合:另一种多尺度分解思路
3.1 拉普拉斯金字塔的分解与重构原理
拉普拉斯金字塔是高斯金字塔的衍生。先对图像做高斯模糊再下采样,得到高斯金字塔;然后用当前层上采样后与下一层做差,得到拉普拉斯层。这个差值保留了该尺度下的高频细节。融合时对每一层拉普拉斯图按规则合并,再从顶层开始逐层上采样相加,就能重构出融合图像。
资源包里LaplacianPyramid.m负责分解,LaplacianReconstruct.m负责重构,UpSampling.m是上采样辅助函数,Q2PyramidMainFunction.m是主流程入口。这套文件分工清晰,适合逐文件阅读。相比小波变换,拉普拉斯金字塔的分解没有频率域的正交性约束,实现更直观,但重构时如果上采样插值方式选得不好,容易出现块效应。
3.2 金字塔融合的代码实现与关键参数
下面是根据资源包结构整理的金字塔融合核心代码:
% 读取并预处理图像 VI = im2double(imread('VI.bmp')); IR = im2double(imread('IR.bmp')); if size(VI,3) == 3, VI = rgb2gray(VI); end if size(IR,3) == 3, IR = rgb2gray(IR); end % 参数设置 levels = 4; % 金字塔层数 sigma = 2.0; % 高斯模糊标准差 kernel_size = 5; % 高斯核尺寸 % 构建高斯金字塔 G_V = cell(levels, 1); G_I = cell(levels, 1); G_V{1} = VI; G_I{1} = IR; for i = 2:levels G_V{i} = imresize(imgaussfilt(G_V{i-1}, sigma), 0.5); G_I{i} = imresize(imgaussfilt(G_I{i-1}, sigma), 0.5); end % 构建拉普拉斯金字塔 L_V = cell(levels, 1); L_I = cell(levels, 1); for i = 1:levels-1 upsampled = imresize(G_V{i+1}, size(G_V{i})); L_V{i} = G_V{i} - upsampled; upsampled = imresize(G_I{i+1}, size(G_I{i})); L_I{i} = G_I{i} - upsampled; end L_V{levels} = G_V{levels}; L_I{levels} = G_I{levels}; % 融合:每层取绝对值最大 L_F = cell(levels, 1); for i = 1:levels mask = abs(L_V{i}) >= abs(L_I{i}); L_F{i} = L_V{i} .* mask + L_I{i} .* (~mask); end % 重构 fused = L_F{levels}; for i = levels-1:-1:1 fused = imresize(fused, size(L_F{i})) + L_F{i}; end fused = max(min(fused, 1), 0); imwrite(fused, 'pyramid_fusion_result.bmp');关键参数有三个:levels控制金字塔层数,层数越多融合的尺度越丰富,但顶层图像会小到几个像素,意义不大,通常取 3 到 5 层;sigma控制高斯模糊程度,值越大保留的低频信息越多,高频细节越少;kernel_size影响模糊核的截断范围,一般取 5 或 7。
融合规则这里用的是逐层取绝对值最大,和小波高频规则一致。但金字塔的顶层是纯低频近似,直接取最大会导致亮度突变,常见做法是对顶层取平均。资源包里fenergyy.m可能也参与了金字塔融合的能量计算,建议打开确认它的调用位置。
3.3 两种方法的对比维度与实操建议
小波变换和拉普拉斯金字塔都能做多尺度融合,但特性不同。小波变换有正交基理论支撑,频域划分严格,适合分析频率成分明确的图像;拉普拉斯金字塔实现简单,空间域直观,但冗余度高,重构时对插值敏感。计算效率上,小波变换的快速算法复杂度是 O(N),金字塔每层都要做高斯模糊和缩放,总计算量略大。
实操建议:如果图像尺寸大、实时性要求高,优先试小波变换,用db2或haar这种短滤波器;如果图像纹理复杂、需要精细控制每层融合权重,用金字塔更灵活。资源包里两种方法都有完整实现,可以跑同一组图像对,用 PSNR 和信息熵两个指标横向对比,结论比只看图更靠谱。
4. 避坑与排查:跑融合代码时最容易翻车的五个地方
4.1 图像尺寸不匹配导致矩阵维度报错
现象:运行wavedec2或金字塔分解时提示「矩阵维度不一致」。原因:可见光和红外图像尺寸不同,或者一个是灰度图一个是 RGB 图。解决:在读图后统一做imresize到相同尺寸,并用rgb2gray转灰度。资源包里VI.bmp和IR.bmp应该已经配准过,但如果你换自己的图,这一步不能省。
4.2 小波分解层数过高导致重构出现边界伪影
现象:融合结果图边缘出现亮斑或暗带。原因:分解层数太多,最顶层图像尺寸太小,边界延拓误差在重构时被放大。解决:把level降到 2 或 3,或者改用sym系列小波,对称性更好,边界效应更弱。我一般会先跑level=2看基线效果,再逐层加。
4.3 融合规则对噪声敏感导致红外噪声被放大
现象:融合图在红外目标周围出现颗粒状噪点。原因:高频取绝对值最大时,红外图的噪声系数也可能大于可见光的信号系数,被误选入融合结果。解决:在融合前对红外图做一次中值滤波或高斯滤波,或者在融合规则里加阈值,低于阈值的系数取平均而不是取最大。资源包里fenergyy.m如果做了能量筛选,可能已经缓解了这个问题,建议先看它的逻辑再决定要不要额外加滤波。
4.4 数据类型未归一化导致显示全黑或全白
现象:imwrite保存的融合图打开后一片黑或一片白。原因:double类型数据范围没截断到[0,1],或者uint8和double混用导致数值溢出。解决:在imwrite前强制做fused = max(min(fused, 1), 0),如果原图是uint8,读入后先im2double归一化。这个坑我踩过不止一次,血泪经验就是:只要涉及多尺度变换,全程用double,最后再转回uint8。
4.5 不同小波基的系数长度不一致导致索引错位
现象:循环跑不同小波基时,第二组开始报「索引超出矩阵范围」。原因:不同小波的滤波器长度不同,wavedec2返回的C向量长度会变,但S结构体也同步变了。如果代码里硬编码了系数索引,换小波基就会错位。解决:始终用S结构体来定位低频和高频系数,不要手动算长度。上面代码里low_len = S_V(1,1) * S_V(1,2)就是动态计算的,换任何小波基都不会错。
5. 进阶技巧:用信息熵和互信息定量评价融合质量
跑通融合流程只是第一步,真正判断哪个方法好、哪个小波基合适,得靠定量指标。PSNR 只能反映融合图与参考图的像素差异,对融合质量不敏感。我习惯再加两个指标:信息熵和互信息。
信息熵衡量融合图包含的信息量,值越大说明信息越丰富。MATLAB 里可以这样算:
function H = entropy_fusion(img) img = im2uint8(img); counts = imhist(img); p = counts / sum(counts); p(p == 0) = []; H = -sum(p .* log2(p)); end互信息衡量融合图从源图继承了多少信息,值越大说明融合越充分:
function MI = mutual_information(A, B, F) % A, B 为源图,F 为融合图,均归一化到 [0,255] A = im2uint8(A); B = im2uint8(B); F = im2uint8(F); MI_AF = entropy_fusion(A) + entropy_fusion(F) - entropy_joint(A, F); MI_BF = entropy_fusion(B) + entropy_fusion(F) - entropy_joint(B, F); MI = MI_AF + MI_BF; end function H = entropy_joint(X, Y) % 联合熵计算 joint = accumarray([double(X(:))+1, double(Y(:))+1], 1); p = joint / sum(joint(:)); p(p == 0) = []; H = -sum(p .* log2(p)); end把这两个指标加进对比循环里,跑完所有小波基和金字塔方法,列一张表:
| 方法 | 小波基/层数 | PSNR (dB) | 信息熵 | 互信息 |
|---|---|---|---|---|
| 小波变换 | haar, 3层 | 28.5 | 6.82 | 1.95 |
| 小波变换 | db4, 3层 | 30.1 | 7.05 | 2.13 |
| 小波变换 | sym4, 3层 | 29.8 | 7.01 | 2.09 |
| 拉普拉斯金字塔 | 4层 | 29.2 | 6.95 | 2.02 |
这张表是示意,实际数值取决于你的图像对。但规律通常是这样:db4 和 sym4 的信息熵和互信息比 haar 高,因为它们的频域局部化能力更强;金字塔方法在互信息上可能略低,因为它的冗余分解导致信息重复计算。选哪个方法,看你的应用更看重细节保留还是计算速度。
从那以后我每次跑融合实验,都会强制走一遍「PSNR + 信息熵 + 互信息」三指标评价,单看一张融合图很容易被视觉效果骗过去。希望这份资源包和上面的排查思路能帮你少走几个弯路。
本文还有配套的精品资源,点击获取