上个月有个做遥感课题的学弟跑来找我,说导师丢给他一对红外和可见光图像,让他“做个融合”,代码要能跑、效果要能看、报告要能写。他翻了半天网上的资料,要么是讲概念的PPT截图,要么是只有半截代码的博客,跑起来全是报错。我给他捋了一遍思路,顺手整理了这几种方法在MATLAB里的实现路径。后来想了一下,这类需求确实很常见——做图像处理课设、研究生入门实验、遥感数据预处理的同学,几乎都会撞上同一个问题:红外与可见光图像融合代码到底怎么落地。
先说我个人的结论:融合算法的本质其实就一句话——你更相信哪幅图像的哪个部分。红外图对热目标敏感、不受光照和遮挡影响,但纹理细节稀碎;可见光图色彩自然、边缘丰富,但晚上或阴影里很容易“瞎”。所谓的融合,就是按某种规则把两边的优点叠加到同一张图里。MATLAB做这件事非常顺手,因为图像处理工具箱把底层操作都封装好了,我们真正要花心思的是融合规则的设计,而不是从零去写变换算法。
这篇内容我尽量讲透:先聊为什么这两类图像能互补,再把配准、归一化这些前置工作交代清楚,然后给出加权平均、拉普拉斯金字塔、小波变换、引导滤波这几种经典方法的完整代码和参数经验,最后补充客观评价指标和一堆我实际踩过的坑。适合正在做课设、比赛或论文实验的同学直接“抄作业”,也适合想搞清楚“为什么不同方法效果差这么多”的朋友慢慢看。
1. 红外与可见光融合到底解决什么问题:从像素差异说起
1.1 两类图像的本质差异:一个“看得见”,一个“看得清”
红外图像记录的是场景的热辐射分布,像素值大致对应温度高低。它的优点是几乎不受可见光光照条件限制——晚上、雾天、强逆光环境里,可见光相机拍出来一团黑,红外依然能勾勒出人物、车辆、设备发热区域。但红外的空间分辨率普遍偏低,图像看起来“糊”,几乎没有什么边缘纹理,灰度层次也比较弱,甚至会出现“热晕”效应,让目标边缘圈一圈伪影。
可见光图像正好相反。它靠反射光成像,细节丰富、边缘锐利、色彩自然,人眼看着非常舒服。可它受光照变化影响极大,夜间基本报废,树叶遮挡、浓雾、阴影这些场景下,目标区域的信息直接缺失。
所以这两类图像是天然互补的。融合的目标就是在结果图里同时保住两样东西:红外图里的热目标显著性,以及可见光图里的背景纹理和色彩。
1.2 像素级融合的基本流程:不只是“两张图叠加”
图像融合分三个层次:像素级、特征级、决策级。像素级融合最直观、实现最简单、信息保留也最完整,是绝大多数MATLAB项目的首选。它的基本流程固定在以下五步:
- 输入两幅已配准的图像;
- 预处理(归一化、去噪、灰度转换);
- 按某种变换把图像分解(金字塔、小波等)或直接进入融合规则;
- 设计融合规则,对分解后的系数进行合并;
- 逆变换/重构,得到融合结果。
这五步里最容易出错的是第1和第2步,很多人拿到两张图就直接往融合函数里塞,结果出来重影、伪影、颜色怪异,还以为算法有问题。实际上配准和归一化的优先级永远高于融合算法本身,我会在下一节详细说。
1.3 融合效果的评价思路:眼睛说了算一半,指标说了算一半
很多初学者只用肉眼看融合效果,这是不够的。人眼对灰度图差异的感知很迟钝,尤其是两张结果图都很亮堂的时候,你根本分不清哪个信息保留得更多。后面我会专门写一节客观评价指标,这里先强调一个核心认知:融合结果的评价必须同时考虑“热目标是否突出”和“背景细节是否保留”这两个维度,单一指标会骗人。
2. 动手前先把数据和环境备齐:配准、归一化与MATLAB工具箱检查
2.1 测试图像从哪里来:公开数据集优先
做融合实验最怕折腾完代码,发现没有像样的测试图。我常用的几个方案:
- TNO数据集:夜间红外与可见光融合的经典基准集,包含人物、车辆、建筑各种场景,尺寸适中,非常适合算法对比实验。
- KAIST多光谱数据集:包含红外和可见光的成对序列,共配准,适合做视频或序列融合。
- FLIR热成像公开集:车载场景,红外图质量不错。
- 自己合成:实在找不到素材时,可以对同一张灰度图分别做“提亮目标+模糊”和“保留边缘+挖掉目标”的变形,生成一对模拟图,用来调试代码流程完全够用。
2.2 配准不是融合,但不配准的融合等于白做
融合要求两幅图逐像素对应,也就是说同一个物体在两幅图里必须落在同一个坐标上。如果相机位置、焦距、角度有差异,直接融合就会重影。MATLAB处理配准有两个常用路子:
一是自动配准,用imregconfig和imregister组合。适合两幅图变形不太大的情况:
moving = im2gray(imread('visible.png')); fixed = imread('infrared.png'); [optimizer, metric] = imregconfig('multimodal'); movingRegistered = imregister(moving, fixed, 'affine', optimizer, metric);二是手动选控制点,用cpselect。适合自动配准失败或者两幅图像坐标系差异很大的情况。操作方式也直接:把两幅图并排打开,在图上点选对应的特征点(角落、灯杆、建筑边缘),选够4到8组点后,MATLAB会生成一个变换矩阵,再用imwarp把可见图映射到红外图的坐标系下。
我自己的习惯是把配准结果单独存成一组图,再做融合实验,避免每次重复计算。如果你只是验证融合算法,强烈建议直接用已经配准好的数据集,省去这一步,否则很难分清融合效果的优劣是算法造成的还是配准误差造成的。
2.3 数据归一化:uint8和double是新手第一道坎
读进来的图像默认是uint8,范围0到255。融合时一旦做加权、差值、滤波这些运算,很容易溢出或者丢精度。我一般上来就统一转double并归一化到[0,1]区间:
I1 = im2double(imread('infrared.png')); I2 = im2double(imread('visible.png'));这里有个细节:红外图通常本身就是单通道灰度,直接im2double没问题。但可见光图如果是彩色RGB,你需要决定是转灰度再融合,还是保留色彩、只对亮度分量做融合。后者效果要好得多。规范的流程是先把可见光RGB转成YCbCr,只对Y(亮度)分量和红外图做融合,再把融合后的亮度和原来的Cb、Cr合并转回RGB。
visYcbcr = rgb2ycbcr(I2_rgb); visY = visYcbcr(:,:,1); % 对visY和I1融合得到 F_Y F_ycbcr = cat(3, F_Y, visYcbcr(:,:,2), visYcbcr(:,:,3)); F_rgb = ycbcr2rgb(F_ycbcr);这一步非常重要,能直接避免“融合后颜色发灰、色彩饱和度下降”的怪象,后面踩坑章节我还会再提。
2.4 MATLAB环境检查:工具箱缺了会当场报错
以下工具箱按需准备:
| 功能 | 需要的工具箱 | 对应函数 |
|---|---|---|
| 图像读写、滤波 | Image Processing Toolbox | imread, imfilter, imguidedfilter |
| 金字塔分解 | Image Processing Toolbox | impyramid |
| 小波分解 | Wavelet Toolbox | dwt2, idwt2 |
| 自动配准 | Image Processing Toolbox | imregister, imregconfig |
| 深度学习融合 | Deep Learning Toolbox | layerGraph, trainNetwork |
装完可以用ver命令查看工具箱列表。注意:2022a之后的版本对impyramid等老函数的调用方式基本没变,兼容性不用担心,反而是老版本(如2016以前的)可能缺函数,遇到报错优先查工具箱是否完整。
3. 三种经典融合方法的MATLAB实现与代码拆解
3.1 加权平均法:一分钟跑通的最朴素基线
先说最简单的方法。公式就一行:F = w * I1 + (1-w) * I2,w是权重。MATLAB实现:
w = 0.6; F = w * I1 + (1-w) * I2; imshow(F);权重取值对结果影响极大,w偏大则红外特征明显,但背景偏暗模糊;w偏小则背景自然,但热目标不够突出。实战中很少全局固定权重,因为融合需求本身就是局部的——目标区域希望权重给红外,背景区域希望权重给可见光。全局加权在“目标”和“背景”两类区域里只能顾一头。
改进版本是分块或像素级权重图:
saliency = abs(I1 - 0.5); % 红外显著性估计,偏离均值越多越像是目标 wMap = imfilter(saliency, fspecial('gaussian', 15, 5), 'replicate'); wMap = wMap / max(wMap(:)); % 归一化到0~1 F = wMap .* I1 + (1-wMap) .* I2;这个思路虽然简单,但骨架已经有了:权重图决定了融合质量的上下限。后面讲引导滤波时,本质上也是在构造更好的权重图。
加权平均法适合做基线参考。答辩或报告里写好“方法一:基线加权融合”,用于和更复杂的方法做对比,就能衬托出后续方法的价值。
3.2 拉普拉斯金字塔:把图像拆成“细节层”和“底座层”
金字塔融合的核心思想是多尺度分解。图像可以分解成不同尺度的组成部分:底座层(整体亮度/能量)、中等细节层(纹理)、细小细节层(边缘)。红外和可见光的优势往往分布在不同尺度上——红外图的显著目标体现在大尺度亮度结构上,可见光的纹理则体现在小尺度细节上。金字塔融合让每层各取所长。
MATLAB里构建拉普拉斯金字塔用impyramid非常方便:
function pyr = laplacian_pyramid(img, levels) pyr = cell(levels, 1); current = img; for k = 1:levels-1 down = impyramid(current, 'reduce'); up = impyramid(down, 'expand'); pyr{k} = current - up; % 本层高频残差 current = down; end pyr{levels} = current; % 最底层为低频残差 end重建也是固定套路:
function rec = pyramid_reconstruct(pyr) levels = length(pyr); rec = pyr{levels}; for k = levels-1:-1:1 rec = impyramid(rec, 'expand') + pyr{k}; end end融合规则:高频层取绝对值大者,低频层取平均。这样设计是有道理的——高频系数绝对值大意味着局部边缘强度高,保留它等于保留更锐利的细节;低频层是能量底座,简单平均防止单边亮度偏移。
pyrA = laplacian_pyramid(I1, 4); pyrB = laplacian_pyramid(I2, 4); pyrF = cell(4, 1); for k = 1:3 pyrF{k} = max(abs(pyrA{k}), abs(pyrB{k})); end pyrF{4} = 0.5 * (pyrA{4} + pyrB{4}); F = pyramid_reconstruct(pyrF);我实测过大量TNO图像,4层金字塔是效果和计算量的最优折中。层数太少(1到2层)细节保留不够,层数太多(6层以上)会引入明显的块状伪影,而且几乎不带来指标收益。
3.3 小波变换(DWT):给裂缝中注入方向性细节
小波分解比拉普拉斯金字塔更进一步:它不仅分尺度,还分方向。单层二维小波把图像拆成四块——LL(低频近似)、LH(水平高频)、HL(垂直高频)、HH(对角高频)。物理含义是:LL代表整体亮度结构,LH、HL、HH分别代表水平、垂直和对角方向上的边缘细节。
MATLAB用dwt2一行就能完成分解:
[LLA, LHA, HLA, HHA] = dwt2(I1, 'db4'); [LLB, LHB, HLB, HHB] = dwt2(I2, 'db4');融合规则依然遵循“低频平均,高频取大”的思路,但多了方向维度:
LLF = 0.5 * LLA + 0.5 * LLB; LHF = max(abs(LHA), abs(LHB)); HLF = max(abs(HLA), abs(HLB)); HHF = max(abs(HHA), abs(HHB)); F = idwt2(LLF, LHF, HLF, HHF, 'db4');千万别小看这个简简单单的dwt2组合——它已经足够赢过大多数加权平均和全屏滤波方法,而且代码量极小。
实际项目中往往需要多层分解。封装一个多级小波融合需要递归处理LL子带,完整的代码会是这个样子:
function F = dwt_fuse(I1, I2, wname, level) if level == 0 F = 0.5 * I1 + 0.5 * I2; return; end [A1, H1, V1, D1] = dwt2(I1, wname); [A2, H2, V2, D2] = dwt2(I2, wname); AF = dwt_fuse(A1, A2, wname, level - 1); HF = max(abs(H1), abs(H2)); VF = max(abs(V1), abs(V2)); DF = max(abs(D1), abs(D2)); F = idwt2(AF, HF, VF, DF, wname); end F = dwt_fuse(I1, I2, 'db4', 3);小波基的选择也值得说两句。'db4'是学术论文里的默认选择,因为它紧支撑、正交、计算快;'sym4'近乎对称,相位失真小,视觉效果略细腻;'bior4.4'具有线性相位特性,适合边缘要求高的场景。我个人习惯:快速实验用'db4',正式出图用'sym4',两者在客观指标上差别不大,但'sym4'的结果看起来更自然,不会出现边缘轻微扭曲。
还有个细节容易被忽略:小波分解层数不要贪多。2到3层足够,层数太多会在融合图里出现波纹状伪影,尤其是图像本身有噪点时,高层分解会把噪声当细节放大。
4. 引导滤波与基于深度学习的融合:进阶方向怎么选
4.1 引导滤波融合:把边缘保持从“取大”升级为“保边平滑”
前面两种方法的共同问题在于:高频取大策略本质上是逐像素独立决策,没有考虑邻域结构,容易在目标边缘附近产生亮暗突变——也就是俗称的晕轮和伪边缘。引导滤波的优势在于它有一个“引导图”的概念,可以用一张结构清晰的图去引导另一张图的平滑过程,达到**“保边去噪”**的效果。
MATLAB从2014b开始提供imguidedfilter函数,使用门槛非常低。我的融合思路是:用可见光图像作为引导图,对红外图做平滑得到红外基础层,原图减基础层得到红外细节层;对可见光做同样处理得到可见光基础层和细节层。然后在基础层上按加权融合、细节层上按绝对值取大融合,最后相加。
r = 8; eps = 0.1; base_ir = imguidedfilter(I1, I2, 'NeighborhoodSize', r, 'DegreeOfSmoothing', eps * 100); detail_ir = I1 - base_ir; base_vis = imguidedfilter(I2, I2, 'NeighborhoodSize', r, 'DegreeOfSmoothing', eps * 100); detail_vis = I2 - base_vis; baseF = 0.5 * base_ir + 0.5 * base_vis; detailF = max(abs(detail_ir), abs(detail_vis)); F = baseF + detailF;几个关键参数的实际经验:
NeighborhoodSize(即局部窗口半径)一般取5到10。过小则引导平滑能力弱,起不到保边滤波的作用;过大则红外图被抹得太狠,细节层噪声激增。DegreeOfSmoothing对应原论文里的正则化参数$\epsilon$,我习惯把它设成0.01到0.1之间的100倍,也就是MATLAB里传1到10。这个值越大,平滑越强,但同时细节层的噪声也越大。- 引导图用可见光而不是用红外,是故意的。可见光结构信息丰富,用它引导可以把可见光的边缘结构“转移”到融合结果中去,这正是我们想要的。
引导滤波融合的视觉效果通常比小波更“干净”,边缘锐利区域不会出现黑边或白边,很适合论文里当“最终效果图”。代价是代码逻辑多几步,但MATLAB运行速度依然很快,1024×1024的图像几百毫秒就能跑完。
4.2 深度学习融合:U-Net风格特征重融合的思路与关键代码
如果你的课题需要“紧跟前沿”,或者导师明确要求用深度学习方法,MATLAB也能做,但难度会高一个量级。当前主流的深度学习融合框架基本都是编码器-融合模块-解码器三段式:先用网络提取红外和可见光的特征,再在特征层设计融合策略,最后用解码器重建图像。MATLAB里可以用layerGraph搭建,也可以借助vgg16这种预训练网络提取深层特征后做特征层融合。
下面给出一个基于深度特征融合的极小示例思路(仅跑通框架,具体网络结构可按需加深):
net = vgg16(); % 需要Deep Learning Toolbox % 取第一个卷积块输出作为特征 layers = net.Layers; featureLayerIndex = 3; feat_ir = activations(net, imresize(I1, [224 224]), featureLayerIndex); feat_vis = activations(net, imresize(I2, [224 224]), featureLayerIndex); % 特征层融合:直接取平均或按显著度加权 feat_fused = 0.5 * feat_ir + 0.5 * feat_vis;这个示例只到特征层,真正的重建需要接解码器网络,实现起来相当复杂。实际做深度学习融合的科研项目,绝大多数人直接用Python的PyTorch框架,MATLAB在这块生态相对薄弱。我的态度是:本科课设和研究生入门,没必要硬上深度学习——经典方法在公开数据集上足够能打,而且答辩时可以说清楚原理,深度学习黑箱反而容易被追问。
如果你确实要尝试,建议走这条路:用公开数据集(TNO或KAIST)裁剪小块训练一个U-Net,输入是“红外+可见光”两通道拼接,输出是融合结果图,损失函数用感知损失或SSIM损失。MATLAB的trainNetwork支持自定义损失,但代码量和调试成本都不小,需要预留至少一周时间。
5. 融合效果怎么量化:客观指标与MATLAB实现
5.1 五个指标分别说明什么
只看主观图容易扯皮,需要几个客观数字来支撑结论。我每次做融合实验都会算下面这五个指标:
| 指标 | 英文/缩写 | 体现什么 |
|---|---|---|
| 信息熵 | Entropy | 灰度层次丰富程度,熵越高信息量越大 |
| 平均梯度 | Average Gradient | 纹理清晰度,梯度大说明边缘细节保留得好 |
| 标准差 | Std | 对比度,值高说明灰度动态范围大 |
| 空间频率 | Spatial Frequency | 图像整体活跃程度,融合常用指标之一 |
| 结构相似性 | SSIM | 融合图与源图的结构保真度,值越接近1越好 |
5.2 指标计算的MATLAB实现
% 信息熵 E = entropy(F); % 标准差 S = std2(F); % 平均梯度 [gx, gy] = gradient(double(F)); AG = mean2(sqrt(gx.^2 + gy.^2)); % 空间频率 rf = sqrt(mean2((diff(F, 1, 2)).^2)); % 行频率 cf = sqrt(mean2((diff(F, 1, 1)).^2)); % 列频率 SF = sqrt(rf^2 + cf^2); % 结构相似性(分别计算与红外图和可见光图的SSIM) ssim_ir = ssim(F, I1); ssim_vis = ssim(F, I2);注意:计算出指标后,多组方法之间比较时,最好统一尺寸、统一预处理流程。否则指标差异可能来自图像尺寸,而不是融合算法。
5.3 四种方法在典型图像上的对比与选型建议
我用TNO数据集里的标准测试图跑过上面几种方法,指标变化通常呈以下规律(不同图像会浮动,但相对关系稳定):
| 方法 | 信息熵 | 平均梯度 | 主观效果 |
|---|---|---|---|
| 加权平均 | 较低 | 低 | 目标或背景牺牲一边,有雾感 |
| 拉普拉斯金字塔 | 中高 | 中 | 细节增强明显,偶有轻微伪影 |
| 小波DWT | 高 | 较高 | 纹理丰富,方向性细节好 |
| 引导滤波 | 高 | 很高 | 边缘干净自然,几乎没有伪影 |
选型建议非常直接:
- 交作业/赶时间:加权平均加一个简单权重图,半小时搞定。
- 课设/中期报告:拉普拉斯金字塔或小波,代码量适中,原理容易讲清楚。
- 论文/比赛出效果:引导滤波,或者引导滤波加小波组合,质量和稳定性都有保证。
- 要水一篇“新颖性”:再套一个自动权重优化(比如用改进灰狼算法搜权重),但本质仍是前三类方法。
6. 我踩过的坑:配准、数据类型与参数调优笔记
6.1 没有配准直接融合:最大的坑,没有之一
我最早做融合实验时图省事,把随手找的两张红外和可见光照片直接扔进融合代码,结果出来一张“重影神图”——同一根路灯杆在结果图里有两条边,人物轮廓像是得了帕金森。我一度以为是小波重构写错了,调试了两天,最后才发现两张图根本没有对齐。这个教训值两整天。
解决办法前面说过:用已配准的公开数据集,或者老老实实跑imregister。如果发现两幅图只是整体平移或轻微旋转,imregister几秒钟就能解决。如果变形严重,就用cpselect手动选点。多花十分钟做配准,能帮你省掉后面几天排查伪影的时间。
6.2uint8与double混用的崩溃现场
图像处理新手最容易碰到的问题:一张图用imread读进来是uint8,你直接和另一个double数组相乘,MATLAB虽然不报错,但结果能被截断得妈都不认。比如uint8图像乘以0.5,像素值大于127的部分直接溢出变白。
我的铁律是:一进融合流程,立刻im2double转成浮点并用im2uint8或imwrite只在最后输出时做。中间所有中间变量都保持double。这样既避免溢出,也方便做各种代数运算。
6.3 彩色可见光直接三通道融合,结果像调色盘打翻
还有个高频雷区:可见光是RGB三通道,直接对整个RGB图像和红外灰度图做融合,Matlab会因为矩阵维度不同报错,即使通过维度转换做了融合,结果也会出现偏色、泛灰、仿佛罩了一层彩色玻璃。
正确做法在第2章已经提到:转YCbCr,只融合Y分量,保留Cb/Cr。这个细节在答辩时很加分——体现你理解了颜色空间选择对融合结果的影响,而不是只会调函数。
6.4 小波层数、正则参数和性能调优的个人经验
最后汇总几条参数经验,都是我拿实际图像跑过几十组实验后的结论:
- 小波分解层数:2到3层足够。再往上,噪声和伪影的增长速度会超过细节收益。
- 小波基:实验用
'db4',出图用'sym4',追求完美边缘可以试试'bior4.4'。 - 引导滤波的
DegreeOfSmoothing:从4到10之间调,越小越保留红外热目标,越大背景纹理越平滑,具体以主观不出现光晕为准。 - 图像尺寸超过2000×2000时,建议先用
imresize缩小到1024以内做参数调试,确定参数后再跑原图。全分辨率跑金字塔分解非常吃内存,尤其多层小波,直接把内存占满导致MATLAB无响应的情况我遇到过好几次。
还有一个小技巧,处理超大图像时可以用blockproc分块融合再拼接,但要注意分块边缘可能出现接缝。我一般不推荐对融合任务分块,因为变换类方法的分块边界很难处理干净,宁可降采样调试、原图最终出结果。
我在实际项目中反复体会最深的一点是:融合方法的选择没有绝对的好坏,只有适不适合当前任务。如果你的应用场景是夜视监控,那红外的热目标保真度是第一优先级,权重图策略就该向红外倾斜;如果你做的是遥感地物融合,背景纹理和色彩保真才是重点,那就该重视可见光的细节层。想清楚需求,再去选方法、调参数,整个实验流程会顺很多。