简介:这是一份基于MATLAB与深度学习框架的红外和可见光图像融合项目资料,面向具备一定图像处理基础、希望掌握融合算法落地实践的开发者和研究人员。内容覆盖数据预处理、特征提取、融合策略、模型训练与结果评估等完整流程,并配有M脚本源码、示例图像、ZBAK备份文件及说明文档。压缩包共75个文件,包含46个PNG示例图、5个M脚本、多个ZIP算法包和备份文件,大小约12.17MB,目录组织清晰,便于按模块检索学习。目前已有54人学习下载。借助这些素材,读者可了解多层级融合策略、低通滤波等方法的实现细节,同时可结合附赠的多种对比算法包进行效果验证,对开展相关课题实验或工程应用具有较高参考价值。
1. 深度学习框架做红外与可见光融合:MATLAB 是更适合新手起步的地方
拿到红外和可见光两路图像,最直接的诉求是:红外把热目标点亮,可见光把背景纹理讲清楚,融合结果要两者兼顾。用深度学习框架做这件事,大家第一反应是去开 Python 环境,但实际上 MATLAB 的 Deep Learning Toolbox 就能把“加载预训练网络、定义融合网络、做数据增强、训练和评估”整条链路走完,对没有独立 GPU 服务器、不想折腾环境的工科生来说反而更省事。本文围绕“深度学习框架 + 红外和可见光图像融合 + MATLAB”这个组合,讲清选型理由、一套能跑通的最小方案,以及我从数据准备到出图验证踩过的真实坑位。适合课程项目、课题预研和想快速出效果图的算法工程师。
2. 框架选型与数据准备:把红外可见光数据集变成可训练的 datastore
2.1 框架选型:全 MATLAB 训练还是 Python 训练后导入
红外和可见光融合任务里,深度学习框架的价值不在于“模型有多深”,而在于它替你解决了三件事:自动求导、批量训练、层与参的管理。MATLAB 的 Deep Learning Toolbox 对这三件事的支持已经非常成熟,VGG16、ResNet 这类预训练模型也能直接加载。常见的实现路线有两条。
| 路线 | 训练环境 | 推理环境 | 适合场景 |
|---|---|---|---|
| A:全 MATLAB | Deep Learning Toolbox + trainnet/trainNetwork | MATLAB 内直接调用 | 中小规模数据、快速出融合图、与图像处理工具箱无缝配合 |
| B:Python 训练后导入 | PyTorch/TensorFlow | 导出 ONNX 到 MATLAB 推理 | 已有现成 Python 模型、要在 MATLAB 里做后处理和指标对比 |
我一般会建议第一次做的人选路线 A。理由很实际:融合任务没有标准答案(ground truth),网络设计、数据增强、损失函数都要反复调,路线 A 改一行代码就能重跑,路线 B 每次都要在 Python 和 MATLAB 之间来回导文件,时间全耗在格式转换上了。而且 MATLAB 自带的 imageDatastore、augmentedImageDatastore 处理配对图像非常顺手,图像处理工具箱里的 imhistmatch、imfuse 还能直接辅助做亮度平衡和可视化。
2.2 数据准备:配对检查、裁剪、归一化与亮度平衡
做红外和可见光融合,数据来源通常有这几类:TNO 军用场景配对图像、RoadScene 道路场景、以及 LLVIP 这种红外可见光目标检测数据集。这些数据集都能在学术搜索里直接找到公开版本。值得注意的是,检测数据集也能拿来当融合训练数据,因为配对本身就是对齐好的,但用的时候要小心它目标密集、背景单一,后面我再细说。
拿到数据后的第一步不是写网络,而是检查配准质量。公共数据集的图像大多已经对齐,但分辨率、视场角偶尔有差异。我习惯先把每对图并排叠起来看:
% 检查红外与可见光配准情况 im1 = imread('ir_001.png'); % 红外图,单通道 im2 = imread('vi_001.png'); % 可见光图,通常三通道 im2gray = rgb2gray(im2); % 并排显示错位情况,用 'falsecolor' 可以直观看出边缘是否对齐 figure; imshowpair(im1, im2gray, 'falsecolor'); title('红外(红) vs 可见光(青) 配准检查');imshowpair 的 falsecolor 模式会把两幅图的差异用颜色叠加显示,配准良好的区域呈灰色,边缘错位的地方会有明显的红青色边。如果有全局偏移,用 imregister 做一次刚性配准即可;如果只有个别图对错位,直接把这组样本从训练集里筛掉更省事。
im1和im2gray必须是相同尺寸,不然 imshowpair 会报错;数据集中常见的问题是尺寸差一两个像素,先用 imresize 统一。
接下来做裁剪和归一化。网络输入不一定要用原图全尺寸,裁剪成 128×128 的 patch 既能扩大样本量,又不会把显存吃爆。亮度方面,红外图的灰度分布通常集中在高温目标上,可见光整体偏暗,两者直接喂给网络会让融合结果总是偏向高亮度模态。常见做法是先把两种模态的均值方差对齐,这就是常说的“亮度平衡”:
% 数据预览和亮度平衡 ds = imageDatastore({'ir_001.png', 'vi_001.png'}); % 只是演示读取方式 ir = imread('ir_001.png'); vi = rgb2gray(imread('vi_001.png')); % 直方图匹配:把红外图的灰度分布映射到可见光分布上去 ir_match = imhistmatch(ir, vi); % 也可以统一归一化到 [0,1] 并调整均值方差 ir_norm = double(ir_match) / 255; vi_norm = double(vi) / 255; ir_bal = (ir_norm - mean(ir_norm(:))) * (std(vi_norm(:))/std(ir_norm(:))) + mean(vi_norm(:));imhistmatch是图像处理工具箱里的函数,直接把红外图的直方图形状拉成和可见光一致。只做归一化不够,因为红外图的对比度通常远高于可见光,归一化后两者方差差异依然很大。
上面这段是预处理逻辑,实际训练不会一张张处理,而是用 imageDatastore 加 transform 把预处理写进数据流里,这样训练时每个 batch 自动完成读取、裁剪、亮度平衡。关于 transform 的写法,第四章训练流程里会给完整代码。
2.3 红外可见光目标检测数据集迁移到融合任务:偏差要心里有数
LLVIP 这类红外可见光目标检测数据集经常被当成融合训练数据,因为它配对质量高、数量大。但有两个坑:第一,检测数据集的场景多为夜间监控,目标密集且以行人车辆为主,纹理信息比 TNO 那种军事场景少,训练出来的模型在白天户外图上效果会打折扣;第二,检测标注里的边界框是目标定位信息,不是融合期望输出,不能拿它当融合的监督信号。融合训练的本质是“从两幅源图重建出信息更全的一幅图”,监督信号只能来自源图本身的重建一致性,而不是任何语义标注。这一点新手很容易想歪,以为检测框能帮网络聚焦目标区域,实际加上去反而让非目标区域的纹理被丢掉。
3. 网络设计与融合策略:VGG16 提取特征,轻量解码器完成重建
3.1 为什么选“预训练特征提取 + 可训练解码器”而不是端到端黑匣子
红外和可见光融合的网络结构有很多种:端到端的生成对抗网络、基于 Transformer 的融合模型、自编码器。但对 MATLAB 用户来说,最可靠、最容易复现的是“共享权重的双分支自编码器 + 测试时特征融合”结构,代表思路与 DenseFuse 这类论文一脉相承。
设计逻辑分两步。训练阶段:把红外图和可见光图分别输入同一个编码器,得到深度特征,再用解码器把特征重建回原始图像,训练目标是“重建得越像越好”。测试阶段:红外和可见光各过一遍编码器,得到两组特征图,在特征层面做融合(加权、取最大、L1 范数引导),然后把融合特征交给解码器生成最终融合图像。
这样设计的好处是,训练阶段只需要单张图像就能做自重建,不需要配对的融合标签;测试阶段插在中间的那个“融合层”可以自由替换成各种策略,不用重新训练网络。预训练 VGG16 在这里充当特征提取器,它 ImageNet 上学会的通用纹理和边缘表征对红外和可见光都有一定迁移性,尤其是可见光分支受益明显。VGG16 也可以换成 ResNet18,但 VGG 结构规整、层名好记,调试时少踩坑。
网络整体结构:
| 模块 | 构成 | 输出尺寸(128×128 输入) |
|---|---|---|
| 编码器 | 卷积 3×3×16 + ReLU + 卷积 3×3×16 + ReLU + 池化 | 64×64×16 |
| 融合层(测试时插入) | L1 范数加权 / 取最大 / 加法 | 64×64×16 |
| 解码器 | 反卷积 2×2×16 + ReLU + 卷积 3×3×32 + ReLU + 卷积 3×3×1 | 128×128×1 |
3.2 MATLAB 搭建编码器与解码器:层定义和参数说明
用 Deep Learning Toolbox 的 layer 定义网络,代码很直白。下面是训练阶段用的自编码器结构:
% 定义自编码器:输入单通道灰度图,输出重建单通道灰度图 layers = [ imageInputLayer([128 128 1], 'Name', 'input', 'Normalization', 'none') % 编码器:两轮 3x3 卷积,通道数从 1 扩到 16 convolution2dLayer(3, 16, 'Padding', 'same', 'Name', 'enc_conv1') reluLayer('Name', 'enc_relu1') convolution2dLayer(3, 16, 'Padding', 'same', 'Name', 'enc_conv2') reluLayer('Name', 'enc_relu2') maxPooling2dLayer(2, 'Stride', 2, 'Name', 'enc_pool') % 解码器:反卷积升采样,再卷积重建 transposedConv2dLayer(2, 16, 'Stride', 2, 'Name', 'dec_deconv1') reluLayer('Name', 'dec_relu1') convolution2dLayer(3, 32, 'Padding', 'same', 'Name', 'dec_conv1') reluLayer('Name', 'dec_relu2') convolution2dLayer(3, 1, 'Padding', 'same', 'Name', 'dec_conv2') ]; % 把 layer 数组转成网络,并检查是否有维度错误 lgraph = layerGraph(layers); analyzeNetwork(lgraph);- 卷积核大小选 3×3,这是特征提取的经典配置,感受野够用且参数量小。第一层卷积把通道从 1 扩到 16,不需要一开始就扩到 64,因为输入本身只有单通道灰度图,信息量有限。
maxPooling2dLayer(2, 'Stride', 2)把 128×128 降采样到 64×64,解码器里用transposedConv2dLayer(2, 'Stride', 2)升采样回 128×128。这里的反卷积核大小固定为 2,与池化窗口一致,避免棋盘效应。analyzeNetwork一定要跑一遍,维度不匹配会直接报错,比训练到一半再崩省时间。
3.3 测试阶段的融合策略:L1 范数加权与更激进的变体
训练好的自编码器里,编码器输出的特征图承载了源图的显著信息。测试阶段把红外和可见光特征送进融合层,最常用的是 L1 范数引导的加权平均。原理是:某个空间位置的红外特征 L1 范数大,说明该位置的信息强度高,融合时应该给红外更高权重;反之则给可见光更高权重。
% 假设 enc_ir 和 enc_vi 分别是红外和可见光过编码器后的特征图(H×W×C) % 计算每个通道组的 L1 范数作为显著度 ir_l1 = sum(abs(enc_ir), 3); % 在通道维度上求和,得到 H×W 的显著图 vi_l1 = sum(abs(enc_vi), 3); % 权重归一化 ir_w = ir_l1 ./ (ir_l1 + vi_l1 + eps); vi_w = vi_l1 ./ (ir_l1 + vi_l1 + eps); % 融合特征:按权重叠加 enc_fused = enc_ir .* ir_w + enc_vi .* vi_w;sum(abs(x), 3)是在通道维度上做绝对值和,输出的是每个空间位置的总体激活强度。- 加上
eps防止某位置两幅图特征都为零时除以零。 - 这个融合层接管了原来编码器到解码器的通路:测试时将
enc_fused喂给解码器,得到的就是融合图像。
比 L1 加权更简单的方案是逐元素取最大(max(enc_ir, enc_vi)),它保留最强烈的响应,适合红外目标突出、可见光纹理平淡的场景。L1 加权整体过渡更自然,缺点是红外小目标的权重可能被周围大范围背景稀释。实际哪个好,用第 6 章的指标对比一下就知道,不要凭感觉定。
4. 端到端训练与参数调优:用重建任务训练,测试时插入融合层
4.1 训练数据流:imageDatastore 与 transform 预处理
训练自编码器不需要配对数据,只需要大量“单张灰度图”。我把红外和可见光的全部训练图像混合在同一个 datastore 里,让网络同时见过两种模态的分布。这样解码器不会偏向某一种模态的灰度习惯。
% 数据准备:红外图和可见光图分别放在两个文件夹 ds_ir = imageDatastore('data/ir/*.png'); ds_vi = imageDatastore('data/vi/*.png'); % 合并两个 datastore 的底层文件列表 allFiles = vertcat(ds_ir.Files, ds_vi.Files); ds_all = imageDatastore(allFiles); % 预处理:统一尺寸 + 单通道 + 归一化到 [0,1] ds_aug = transform(ds_all, @(x) preprocessPatch(x)); % 划分训练集和验证集 numFiles = numel(ds_aug.Files); idx = randperm(numFiles, round(numFiles * 0.1)); ds_val = subset(ds_aug, idx); ds_train = subset(ds_aug, setdiff(1:numFiles, idx));预处理函数preprocessPatch定义如下:
function patch = preprocessPatch(img) % 统一缩放到 128x128,转灰度,转 double 并归一化 if size(img, 3) == 3 img = rgb2gray(img); end img = imresize(img, [128 128]); patch = double(img) / 255; endtransform的返回值在 datastore 层面惰性执行,不占用额外内存,训练时才逐个处理。- 验证集数量取 10% 是经验值;如果整体样本量只有几百张,验证集 10% 可能只有几十张,这时把验证集改成五折交叉里的一折意义不大,更多是看训练曲线是否过拟合。
- 如果原图很大(比如 640×512),直接 resize 到 128×128 确实会丢失红外小目标细节。保留原尺寸训练太耗显存,折中方案是随机裁剪 128×128 patch 而不是整体缩放。但随机裁剪要求输入输出对齐,写预处理时要保证每次裁剪的坐标一致,这里为了简洁没有展开。
4.2 损失函数配置:MSE 重建损失为什么不够,怎么加结构约束
自编码器训练目标是重建源图,最基础的损失是 MSE。但只用 MSE 容易让融合结果发糊,因为 MSE 对高频边缘不敏感,网络倾向于输出“平均化”的图像。一个有效的改进是在重建损失基础上叠加结构相似度损失(SSIM)。MATLAB 的trainnet支持自定义损失函数,写法很简洁:
% 定义训练损失:MSE + (1 - SSIM),两者都在 [0,1] 量级 lossFcn = @(Y, T) mse(Y, T) + (1 - ssim(Y, T)); % 训练选项:Adam 优化器,初始学习率 1e-3 options = trainingOptions('adam', ... 'InitialLearnRate', 1e-3, ... 'MaxEpochs', 50, ... 'MiniBatchSize', 16, ... 'ValidationData', ds_val, ... 'ValidationFrequency', 100, ... 'Plots', 'training-progress', ... 'OutputNetwork', 'best-validation', ... 'Shuffle', 'every-epoch', ... 'Verbose', false); % 执行训练 net = trainnet(ds_train, lgraph, lossFcn, options);trainnet是 R2023a 之后推荐的训练接口,损失函数可以是任意接受(Y, T)两个参数的函数句柄。如果你的 MATLAB 版本还在用trainNetwork,自定义损失就得写成自定义输出层,代码量翻倍,建议升级。mse惩罚像素误差,ssim保住结构相似性,两者相加时要确认量级匹配。SSIM 的值域是 [-1,1] 或 [0,1](按默认参数),MSE 归一化后在 [0,1] 附近,直接相加不会出现一项压过另一项。- 验证集在这里承担两个职责:一是每 100 次迭代看一次验证损失有没有跟着训练损失下降;二是
'OutputNetwork', 'best-validation'让训练结束后自动保留验证损失最小的那版权重,而不是最后一个 epoch 的权重。 - 如果训练到一半验证损失上升、训练损失还在降,就是过拟合了,优先加数据增强(随机翻转、旋转 90°),而不是减少网络深度——编码器只有两层卷积,本身容量不大。
4.3 训练参数怎么调:学习率、批大小、epoch 与显存边界
参数选择直接决定这个网络是能收敛还是疯狂震荡。以下是我常用的初始值及调整依据:
| 参数 | 初始值 | 调整方向 | 失败时看什么 |
|---|---|---|---|
| InitialLearnRate | 1e-3 | 损失震荡时降为 1e-4 | 训练曲线是否呈锯齿状 |
| MiniBatchSize | 16 | 显存不足时降为 8 或 4 | GPU 利用率是否接近 100% |
| MaxEpochs | 50 | 损失收敛慢时加 50 | 验证损失是否还在平台期 |
| Shuffle | every-epoch | 固定为 every-epoch | 不洗牌会让模型记住顺序 |
| ValidationFrequency | 100 | 数据少时增大 | 太频繁会拉慢训练 |
用gpuDevice查看 GPU 显存占用,输入 128×128、批大小 16 的显存开销大约在 2~4 GB,这基本覆盖了大多数笔记本独显。如果报“out of memory on GPU”,先降 MiniBatchSize,再考虑裁剪尺寸降到 96×96。batch size 降到 4 还爆显存,那大概率是 GPU 太老,直接options.ExecutionEnvironment = 'cpu'吧,128×128 的小网络跑 CPU 也就慢两三倍,不会等死人。
调参有个易被忽略的点:MaxEpochs不等于训练次数。如果数据集只有 400 张图,批大小 16,一个 epoch 只有 25 次迭代,50 个 epoch 总共 1250 次迭代,这个量级对自编码器来说偏少。我一般会同时观察训练曲线横轴的迭代次数而不是 epoch 数,保证有效迭代在 3000 次以上再谈效果。
5. 避坑清单:红外-可见光融合在 MATLAB 里最容易翻车的 5 个位置
5.1 单通道图复制成三通道后特征漂移,融合图偏色
现象:融合结果出现不自然的红绿边或者整体偏色,红外目标边缘尤其明显。
原因:VGG16 的输入设计为 RGB 三通道,很多教程直接把红外单通道图用repmat复制成三通道再送进去。问题在于,VGG16 的 ImageNet 预训练权重对 RGB 三个通道有不同的通道级统计特性,复制后的红外图相当于人为构造了一个“伪 RGB 图”,卷积特征会发生偏移,解码器拿到这种特征重建,融合图就带上了颜色伪影。
解决:融合框架里的编码器用自己训练的自编码器,而不是直接套 VGG16 做编码。如果一定要用 VGG16 提特征,就把红外和可见光分别送入网络后取activations的中间层特征,且不要对融合特征做跨通道的加权操作,只在同语义通道上做融合,最后重建时固定映射到灰度输出。我的经验是,自编码器的编码器虽然不如 VGG16 表征能力强,但它是针对单通道灰度图训练的,特征分布干净,后期处理省心得多。
5.2 imresize 之后忘记归一化,融合图整体发黑
现象:网络输出的融合图显示出来是黑的,用imhist查看直方图发现像素值集中在 0 附近。
原因:训练时输入归一化到 [0,1],但测试阶段如果先imresize得到 [0,255] 范围的数据,直接喂给网络会出现分布偏移。更隐蔽的一个场景是,imresize默认插值会把原有的 uint8 数据转成 double,但数值范围仍是 0~255,网络输出的 Sigmoid 激活范围是 0~1,输出自然全黑。
解决:测试阶段统一走训练时同一个预处理函数,出门前先double(img) / 255。我自己的习惯是写一个preprocessPatch和postprocessPatch配套函数,前者负责训练和测试输入的归一化,后者负责把网络输出乘 255 并转 uint8,两头都卡标准。
function out = postprocessPatch(x) out = uint8(round(x * 255)); out = imresize(out, [origH origW]); % 测试前先保存原图尺寸 end5.3 GPU 显存不足,先别急着换显卡
现象:训练刚开始就报out of memory on GPU,或者跑几个 batch 之后报错。
原因:最常见的是批大小太大,其次是输入 patch 尺寸偏大。另一个经常被忽略的原因是没有限制 GPU 显存增长,MATLAB 默认会一次性把整个网络结构搬到 GPU,如果网络里有多条并行分支,显存开销会高于直觉预期。
解决:按顺序排查。第一步把 MiniBatchSize 从 16 降到 8,第二步把输入尺寸从 128 降到 96,第三步在训练选项里加'DispatchInBackground', true让数据加载和计算并行。如果都没解决,用gpuDevice查看“AvailableMemory”是不是已经被其他进程占满,关掉其他占用显存的应用再试。实在不行换 CPU 训练,128×128 的小网络 CPU 也熬得住。
5.4 vgg16 加载报错与版本行为差异:训练好网络后推理结果却不对
现象:第一次调用vgg16提示需要下载支持包;下载后网络能加载,但activations提取的特征和论文里描述的对不上,或者融合效果明显退化。
原因:MATLAB 的预训练模型以支持包的形式提供,R2023a 前后下载方式和模型版本有差异。另一个更隐蔽的问题是,VGG16 的activations默认对输入做 zerocenter 归一化(减 ImageNet 均值),如果你在调用前手动减了一次均值,特征就错位了。
解决:第一次使用vgg16时按提示安装支持包,装完用analyzeNetwork(net)确认输入层大小。提取特征时不要手动减均值,直接传原始 uint8 图给activations。如果发现融合效果不对,最直接的排查方法是先跑一张可见光图的重建,看解码器能否还原原图;重建没问题,问题就在融合策略上,和网络版本无关。
5.5 MATLAB 中文注释乱码:一个浪费一小时的环境问题
现象:打开项目.m文件,中文注释全部变成乱码;运行脚本时警告信息也是乱码。
原因:MATLAB R2021b 之前默认使用系统本地编码打开.m文件,如果你的脚本保存在 UTF-8 编码下,在中文版 Windows 上打开就是 GBK 解码,乱码几乎是必然。R2021b 之后默认切换为 UTF-8,但老版本升级后旧文件编码不会自动转换。
解决:在 MATLAB 预设里找到“MATLAB > 常规 > 文件格式编码”,把编码改为 UTF-8,然后重新打开文件。如果乱码已经出现,用记事本把.m文件另存为 UTF-8 编码覆盖原文件。后续所有脚本统一用 UTF-8 保存,团队协作时能够避免同一份代码在不同机器上出现编码行为不一致。这个问题跟算法无关,但处理不好能卡你一下午。
6. 验证与进阶:用指标和三图对比把融合效果讲清楚
6.1 量化指标:PSNR、SSIM、互信息一个都别少
融合效果不能只靠肉眼,评审和论文里都需要量化指标。最常用的三个指标是:PSNR(峰值信噪比,看融合结果与源图间的像素保真度)、SSIM(结构相似度,看纹理结构保留程度)、互信息(看融合结果包含了多少源图的信息量)。MATLAB 图像处理工具箱里直接有psnr和ssim,互信息需要自己算,下面给一个可用的实现。
% 计算融合结果与红外源图的 PSNR 和 SSIM psnr_ir = psnr(fused, ir); ssim_ir = ssim(fused, ir); % 互信息:用联合直方图估计 function mi = mutualInfo(a, b) % 将灰度量化到 64 级,减少计算量 a = round(double(a) / 255 * 63) + 1; b = round(double(b) / 255 * 63) + 1; % 二维联合直方图,归一化为联合概率 jhist = histcounts2(a, b, 64, 64, 'Normalization', 'probability'); % 分别计算边缘概率 pa = sum(jhist, 2); pb = sum(jhist, 1); % 计算互信息:sum(p * log(p / (pa*pb))) [Pa, Pb] = meshgrid(pa, pb); valid = jhist > 0; mi = sum(jhist(valid) .* log(jhist(valid) ./ (Pa(valid) .* Pb(valid)))); end指标对比时要注意两点:PSNR 和 SSIM 都要分别与红外和可见光各算一次,因为融合结果不可能同时超过两幅源图的所有指标,合理的融合结果是“红外指标略降、可见光指标明显提升”或反过来,两者都大幅低于源图说明融合策略有问题;互信息则是在像素级信息维度上衡量融合是否把两边的信息都吸纳进来,通常融合后的互信息应该高于任意一幅源图与自身的互信息(也就是等于该图的熵)。
6.2 一张图画完红外、可见光、融合结果,不用再导到 Origin 拼图
很多项目的汇报要求把红外图和融合图并排展示,不少人习惯把图导出到 Origin 再排版,多此一举。MATLAB 里montage一行就能把多张图拼在一张图上,还能保持坐标对齐。
% 三图并排:红外、可见光、融合 figure('Color', 'w'); montage({ir, vi, fused}, 'Size', [1 3]); % 给每张图加标题 title('红外 / 可见光 / 融合结果'); % 保存高清图 exportgraphics(gcf, 'fusion_result.png', 'Resolution', 300);如果要在融合图上标注局部区域(比如某个红外目标是否保留清晰),用imshow加rectangle手动画框比 montage 更灵活。对比时有个习惯值得养成:把源图、中间特征显著图、最终融合结果三行放一起,这样调参时能一眼看出问题是出在特征提取还是融合权重上,不用每次都靠猜。
我的习惯是每次只改融合策略里的一个参数,比如把ir_w的权重从 0.5 调到 0.7,跑一遍生成融合图,同时记录三个指标,这样积累几次之后就能摸清自己的数据分布适合加性融合还是取最大融合。千万不要同时改融合策略和网络结构,不然效果变好都不知道是哪一步起作用。融合这个领域没有银弹,红外目标检测数据集上表现好的策略,到白天可见光场景可能直接翻车,唯一可靠的做法是保留一套自动化指标脚本,每次实验跑完立刻出数,让数字说话,而不是靠记忆里的视觉印象。希望帮到你。
本文还有配套的精品资源,点击获取