ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于深度学习框架的红外与可见光图像融合MATLAB实现与避坑指南

基于深度学习框架的红外与可见光图像融合MATLAB实现与避坑指南 简介一份面向图像处理与深度学习初学者及研究者的MATLAB项目以红外和可见光图像融合为切入点解决如何在单一开发环境中结合深度神经网络完成多波段图像信息互补与增强的问题。项目流程涵盖数据预处理、多层特征提取、融合策略设计、模型训练及效果评估帮助读者将深度学习理论落地到图像融合实践相关思路可迁移至目标检测、人脸识别、夜视增强、医疗成像等场景。压缩包为zip格式共75个文件以MATLAB源码如fusion_method_multi_layers.m、extract_l1_feature.m、lowpass.m、PNG红外/可见光配对图像、ZIP格式的CBF、WLS、ConvSR等对比算法代码包及README说明为主整体约12.17MB另有zbak备份文件便于对照历史版本。目前已有55人学习下载包内提供融合策略分析图、框架说明与完整目录结构可直接运行现有脚本、替换测试图片或在此基础上改进融合算法既适合课程设计也适合论文复现与算法对比实验。1. 红外和可见光图像融合为什么偏要用深度学习框架在 MATLAB 里做拿到「使用深度学习框架的红外和可见光图像融合 MATLAB」这个标题的读者多半已经受够了传统融合方法的折腾——小波变换、稀疏表示、 Guided Filter调了一下午参数融合结果不是目标泛白就是背景细节丢光。红外图能清楚看到发热的车辆和行人可见光图有墙上的纹理和路牌文字可一旦把两者硬叠在一起要么热目标被背景淹没要么细节被红外的低纹理拖垮。深度学习框架的思路是让网络自己去学「该保留红外的什么、该从可见光取什么」而不是人为设计规则。这个方向适合两类人一类是做安防监控、夜间辅助驾驶、遥感侦察的算法工程师手里的红外相机和可见光相机已经架好就差一套能落地的融合算法另一类是研究生需要跑通一个完整的深度图像融合基线拿客观指标写论文。MATLAB 在这里不是替代 Python而是把数据标注、预处理、指标评估和结果可视化串成一条流水线模型训练可以交给 PyTorch 或 TensorFlow推理部署再回到 MATLAB——这是目前投入产出比最高的一条路径。2. 方法选型先想清楚深度学习在红外与可见光融合里到底学什么2.1 三种主流网络结构从 CNN 自动编码器到生成对抗网络红外和可见光的融合任务和普通图像增强不同输入是两幅已配准的图像输出是一幅包含两者关键信息的单通道或三通道图。深度学习模型在这里的角色是学习一个映射函数从两幅输入图到一幅融合图的映射。常见的做法有三种按实现难度从低到高排。第一种是 CNN 自动编码器思路。编码器把红外图和可见光图分别提特征融合层把特征图按通道拼接或加权求和解码器还原成融合图。代表工作如 DenseFuse、FusionGAN 的生成器部分这类网络结构简单训练稳定MATLAB 的 Deep Learning Toolbox 就能直接搭出来。第二种是生成对抗网络思路生成器负责生成融合图判别器负责判断输入的是「真实融合图」还是「网络生成的图」通过对抗损失让融合图在统计分布上更接近理想结果。第三种是 Transformer 思路用自注意力机制捕获全局依赖但对训练数据量要求高MATLAB 实现相对冷门。我在实际项目中通常先跑 CNN 自动编码器作为基线因为它的损失函数容易调训练收敛快而且 MATLAB 的 trainNetwork 接口直接支持这类网络。如果基线指标已经满足需求就不必上 GAN——GAN 的训练崩溃问题在融合任务里尤其烦人判别器一强生成器就开始输出色彩异常的伪影。2.2 MATLAB 里的两条技术路线纯 MATLAB 和 MATLAB Python 混合标题里同时出现深度学习框架和 MATLAB这就有个绕不开的选型问题训练用哪个环境。纯 MATLAB 路线是依赖 Deep Learning Toolbox自己写 dlnetwork 定义网络结构用 adam 优化器训练。优点是整个流程在一个环境里跑完数据接口不用转换缺点是社区生态弱想加载别人预训练好的 PyTorch 模型很麻烦调试网络结构也不如 Python 灵活。我一般推荐 MATLAB Python 混合路线用 PythonPyTorch 或 TensorFlow负责训练模型把训练好的权重导出为 ONNX 格式再用 MATLAB 的 importNetworkFromONNX 加载权重在 MATLAB 里做推理、后处理和指标评估。这样做的核心理由是融合模型的训练需要大量迭代实验Python 生态的 TensorBoard 可视化、torchvision 预训练权重和数据增强库都更成熟而 MATLAB 的优势在于图像处理工具箱的函数丰富像 imfuse、imshowpair 这类可视化工具做对比展示非常直观写论文出图也方便。这个混合路线的代价是要多维护一套环境但实际用下来训练和推理分离反而让工程结构更清晰。导出 ONNX 的过程注意点是在 Python 端固定输入尺寸不要用动态尺寸否则 MATLAB 导入时容易报维度错误。2.3 损失函数设计的取舍像素损失、结构损失与感知损失的组合深度图像融合的损失函数直接决定融合结果的质量。最常见的组合是像素损失加结构相似度损失。像素损失通常用 L2 或 L1 范数让融合图在像素值上接近两张输入图的加权结果结构损失用 SSIM让融合图在亮度、对比度、结构三方面都保持输入图的特征。我常用的损失函数形式是L_total α * L_pixel β * L_ssim γ * L_grad。其中 L_pixel 是融合图与红外图、可见光图的均方误差L_ssim 是融合图分别与两张输入图的 SSIM 之和L_grad 是梯度域的损失用来增强边缘保持能力。α、β、γ 的经验值分别是 1、10、5但这不是固定不变的需要根据数据特性调整。这里有一个容易翻车的点如果 L_pixel 的权重设得太大融合图会偏向两张输入图的平均红外目标突出得不明显如果 L_ssim 权重太大又会过度保留纹理导致热目标周围出现「光晕」。调试损失函数时不要只看训练 loss 曲线每隔几个 epoch 就要 visualize 一次融合结果用肉眼检查——这是做图像融合和做分类任务最大的不同分类只看 accuracy 就行融合必须看效果图。3. 数据准备与预处理配准、归一化和数据增强的完整 MATLAB 流程3.1 红外与可见光图像的配准为什么融合前必须解决视差问题图像配准和图像融合是两个工作吗答案是是而且必须分开做。融合算法假设输入的两幅图已经像素级对齐如果红外相机和可见光相机的位置、视场角有差异直接拿去融合结果就是重影、边缘错位深度学习网络根本学不到正确的对应关系。配准的常见做法是先用 MATLAB 的 Registration Estimator 或计算机视觉工具箱里的 estimateGeometricTransform2D 做一次全局配准。操作流程是先分别读入红外图和可见光图用 detectSURFFeatures 提取特征点再用 matchFeatures 匹配然后 estimateGeometricTransform2D 估计单应性矩阵最后用 imwarp 把可见光图变换到红外图的坐标系。配准的参数设置上SURF 特征的 MetricThreshold 默认值是 1000如果匹配点太少就降到 100MaxRatio 控制匹配筛选的严格程度0.6 到 0.8 之间比较合适。注意配准做完之后一定要验证用 imshowpair 把两张图叠在一起看边缘是否重合——这一步偷懒的话后面融合效果再好的网络也救不回来。3.2 读入数据、归一化与数据类型转换的标准代码块MATLAB 处理红外和可见光图像时遇到的第一个实际问题就是数据类型的差异。红外相机输出的通常是 16 位单通道灰度图可见光相机输出的是 8 位三通道 RGB 图两者的亮度范围和数据格式完全不一样。下面是处理这两类图像的标准化代码% 读取红外和可见光图像 ir_raw imread(ir_image.png); % 红外图可能是16位或8位 vi_raw imread(vi_image.jpg); % 可见光图8位RGB % 红外图如果是16位先转成double并归一化 if isa(ir_raw, uint16) ir_gray double(ir_raw) / 65535.0; % 归一化到[0,1] else ir_gray double(ir_raw) / 255.0; end % 可见光图转灰度提取亮度分量用于融合 vi_gray rgb2gray(vi_raw); % RGB转灰度 vi_gray double(vi_gray) / 255.0; % 同样归一化到[0,1] % 统一尺寸以红外图尺寸为基准对可见光图做缩放 vi_resized imresize(vi_gray, size(ir_gray));这段代码的逻辑是先把两种不同位深的图像统一到 [0,1] 范围的 double 类型再统一尺寸。注意红外图如果是 16 位直接转 uint8 会把暗部细节全部压掉一定要先转 double 再归一化。可见光图转灰度而不是直接用 RGB 三通道是因为融合模型通常设计成输入单通道灰度图可以大幅减少参数量和计算量。这里有个参数细节imresize 默认用双三次插值对可见光图缩放没问题但如果是把红外图缩放建议用 bilinear 或 nearest避免红外图的锐利边缘被插值模糊。尺寸不一致时最好以低分辨率图通常是红外图为基准因为放大会损失信息缩小不会。3.3 数据增强策略与训练/测试数据集的划分方法深度学习融合模型最怕的就是数据量不足。红外和可见光的成对数据集公开的并不多常见的 TNO 数据集大概就几十对这点数据训练一个深网络远远不够。数据增强是必须做的而且和分类任务不同融合任务的数据增强必须保持红外图和可见光图同步变换。我常用的增强操作包括随机水平翻转、随机垂直翻转、随机旋转90、180、270 度、随机裁剪。裁剪时注意要保证裁剪区域包含主要的红外目标否则网络学到的是大量无目标的背景冗余。增强代码在 MATLAB 里可以这样写% 随机水平翻转成对进行 if rand 0.5 ir_aug fliplr(ir_gray); vi_aug fliplr(vi_resized); end % 随机旋转90度的整数倍 k randi([0, 3]); ir_aug rot90(ir_aug, k); vi_aug rot90(vi_aug, k); % 随机裁剪到固定尺寸 crop_size [256, 256]; h size(ir_aug, 1); w size(ir_aug, 2); x_start randi([1, h - crop_size(1) 1]); y_start randi([1, w - crop_size(2) 1]); ir_crop imcrop(ir_aug, [y_start, x_start, crop_size(2)-1, crop_size(1)-1]); vi_crop imcrop(vi_aug, [y_start, x_start, crop_size(2)-1, crop_size(1)-1]);裁剪尺寸一般是 256 或 224这与后续网络的输入大小保持一致。需要注意的是imcrop 的坐标参数是先 x 后 y 的格式这和矩阵索引先 y 后 x 容易搞混我在这个坑里翻过车——裁剪出来图像错位严重排查了半天才发现是坐标顺序反了。训练集和测试集的划分上我习惯按场景划分而不是按图像划分。比如 TNO 数据集里有城市、乡村、树林不同场景如果随机划分同一场景的图像会同时出现在训练集和测试集指标虚高但没有说服力。按场景把所有图像分到训练集或测试集再在训练集内部做 augmented 数据增强这才是公平的评估方式。4. 模型搭建与训练从零到一跑通一个 CNN 融合基线4.1 用 dlnetwork 定义双分支 CNN 融合网络理解了数据准备之后就可以开始搭建网络了。这里选择双分支 CNN 结构两个分支分别提取红外和可见光的特征中间通过融合层合并特征最后由解码器重建融合图像。MATLAB 的 Deep Learning Toolbox 从 R2019b 开始支持 dlnetwork可以用自定义层和 forward 函数灵活定义网络。下面是使用 MATLAB 的 dlnetwork 定义简化的双分支融合网络% 定义双分支编码器网络用于提取特征 encoder_layers [ imageInputLayer([256 256 1], Name, input) convolution2dLayer(3, 32, Padding, same, Name, conv1) reluLayer(Name, relu1) convolution2dLayer(3, 64, Padding, same, Name, conv2) reluLayer(Name, relu2) convolution2dLayer(3, 128, Padding, same, Name, conv3) reluLayer(Name, relu3) ]; encoder_net dlnetwork(encoder_layers); % 定义解码器网络用于重建融合图 decoder_layers [ imageInputLayer([256 256 128], Name, decoder_input) convolution2dLayer(3, 64, Padding, same, Name, deconv1) reluLayer(Name, decoder_relu1) convolution2dLayer(3, 32, Padding, same, Name, deconv2) reluLayer(Name, decoder_relu2) convolution2dLayer(3, 1, Padding, same, Name, deconv3) tanhLayer(Name, tanh_output) ]; decoder_net dlnetwork(decoder_layers);这段代码定义了两个 dlnetwork 对象但实际训练时我会把它们封装成一个自定义的 forward 函数来处理双输入。imageInputLayer 的数字 1 表示单通道灰度图。卷积核大小 3、通道数 32-64-128 是参考 DenseFuse 设计的适合小规模数据集如果数据量大可以加深到 128-256。一个重要的设计决策是融合层不用图像空间域的加权平均而是用特征图拼接后加卷积。具体做法是在 forward 函数里把红外和可见光的 encoder 输出在通道维度上 concatenate然后由一个 1x1 卷积把通道数压缩回 128再送进 decoder。这样网络自己学习每个位置应该信红外还是信可见光比手动设权重要灵活得多。4.2 自定义训练循环前向传播、损失计算与参数更新训练循环是整个流程中最不能照搬网上的部分。MATLAB 的 trainNetwork 要求 loss 函数是内置的或者封装成自定义层而融合任务的自定义损失函数往往要在执行环境下做大量调试这时候用自定义训练循环更可控。% 初始化优化器参数 learnRate 1e-4; trailingAvg []; trailingAvgSq []; gradDecay 0.9; gradDecaySq 0.999; % 自定义训练循环 numEpochs 50; for epoch 1:numEpochs % 打乱训练数据顺序 idx randperm(numTrainPairs); for i 1:numTrainPairs % 取一对红外和可见光图像 ir_in dlarray(train_ir(:,:,:,idx(i)), SSCB); vi_in dlarray(train_vi(:,:,:,idx(i)), SSCB); % 前向传播并计算损失 [loss, grad_ir, grad_vi] dlfeval(modelLoss, encoder_net, decoder_net, ... ir_in, vi_in); % 使用adam优化器更新参数 [encoder_net.Learnables, trailingAvg, trailingAvgSq] ... adamupdate(encoder_net.Learnables, grad_ir, trailingAvg, trailingAvgSq, ... epoch, learnRate, gradDecay, gradDecaySq); [decoder_net.Learnables, trailingAvg, trailingAvgSq] ... adamupdate(decoder_net.Learnables, grad_vi, trailingAvg, trailingAvgSq, ... epoch, learnRate, gradDecay, gradDecaySq); end % 每个epoch结束后在验证集上计算指标 fprintf(Epoch %d, Loss: %.4f\n, epoch, extractdata(loss)); end这段代码的关键在于 dlfeval 配合自定义函数 modelLoss 实现自动微分。modelLoss 内部要做的事是三个前向传播得到融合图、计算像素损失加 SSIM 损失、调用 dlgradient 返回损失对两个网络所有可学习参数的梯度。adamupdate 函数的参数含义依次是待更新参数、梯度、动量项、平方梯度项、迭代次数、学习率、梯度衰减系数和平方梯度衰减系数。训练时注意学习率的设置1e-4 是个安全起点如果 loss 曲线不下降降到 5e-5 再试。batch size 在自定义循环里可以设为 1因为融合任务的输入尺寸较大显存消耗大但 batch size 为 1 会导致梯度震荡厉害我的做法是累积梯度先算 8 对图像的梯度求平均再更新一次参数。4.3 MNTAAB 中加载 PyTorch 预训练模型ONNX 转换与网络导入的实操训练好模型之后另一个常见的需求是在 MATLAB 里加载别人用 PyTorch 训练好的融合模型。流程是 Python 端导出 ONNXMATLAB 端 importNetworkFromONNX。下面以导出 DenseFuse 风格的模型为例Python 端导出 ONNX 的代码import torch import torch.onnx # 加载训练好的模型并设为评估模式 model DenseFuseEncoderDecoder() model.load_state_dict(torch.load(fusion_model.pth)) model.eval() # 构造一个随机输入红外图和可见光图 dummy_ir torch.randn(1, 1, 256, 256) dummy_vi torch.randn(1, 1, 256, 256) # 导出ONNX注意固定输入尺寸 torch.onnx.export( model, (dummy_ir, dummy_vi), fusion_model.onnx, input_names[ir_input, vi_input], output_names[fusion_output], opset_version11, dynamic_axesNone # 不用动态轴固定尺寸 )MATLAB 端导入并推理的代码% 导入ONNX网络 net importNetworkFromONNX(fusion_model.onnx); % 准备输入数据需要单通道gray格式 ir_input dlarray(ir_gray, SSCB); vi_input dlarray(vi_resized, SSCB); % 前向推理 fusion_result predict(net, ir_input, vi_input); fusion_img extractdata(fusion_result); fusion_img reshape(fusion_img, [256, 256]); imshow(fusion_img, []);这个流程里的坑主要集中在 ONNX 版本兼容性上。PyTorch 导出的 ONNX 如果用了高版本的算子MATLAB 的 importNetworkFromONNX 可能不支持报错信息往往含糊不清。我的解决经验是在 Python 端把 opset_version 调到 11 或 12这两个版本 MATLAB 兼容性最好如果还报错用 ONNX Simplifier 简化模型结构减少特殊算子的使用。5. 避坑笔记红外与可见光融合中最常见的 5 个翻车现场5.1 现象融合图像出现「鬼影」和重影——原因是对齐精度不足这是初学者最容易遇到的问题。融合结果里路灯的边缘有两层轮廓房屋的墙角有虚影看起来像没戴 3D 眼镜看 3D 电影。原因不是融合网络的问题而是输入图像本身没有配准好。回流图对不上网络拼了命也学不到正确的融合映射。解决方法是回到配准环节不要用 SURF 特征点匹配了就完事。我一般会做两遍配准先用 SURF 算全局单应性矩阵然后用 imregister 基于灰度信息做一次局部精细配准最后用 imshowpair 检查融合边缘是否对齐。如果只是平移和轻微旋转估计一个仿射变换就够了计算量小且更稳定。5.2 现象训练 loss 不下降且最终指标负优化——数据归一化出了问题损失函数一直震荡在某个值附近不下降训练了 20 个 epoch 后融合结果反而比输入图像还暗。检查数据的归一化范围如果红外图的像素值在 [0.2, 0.8] 之间而可见光图在 [0, 1] 之间网络会一直试图抹平这种分布差异导致无法收敛。解决方法是先把所有输入图像做直方图均衡化或标准化确保两幅输入图的亮度分布在相近的范围。注意不要在训练集上做全局归一化后测试时拿新的图像用不同的归一化参数——阈值和均值要统一否则训练测试不在同一个分布里。5.3 现象融合结果中红外目标被可见光纹理淹没——损失函数权重失衡这是高对比度场景下的常见问题。夜间图像中红外能清楚看到一个发热的人形但融合结果里人的轮廓和背景墙的纹理混在一起看不出哪里有异常。原因就是 L_pixel 和 L_ssim 的组合不够好网络选择了「平滑平均」这种最保守的路线。解决方法是调高红外分支的权重或者改用注意力机制——在融合层前加一个空间注意力模块让网络自动增强红外显著区域的特征响应。实操中最简单有效的办法是修改损失函数为加权形式 L L_ssim_ir * 1.5 L_ssim_vi * 1.0把红外通道的结构损失权重调高效果立竿见影。5.4 现象MATLAB 导入 ONNX 时报错「Unsupported operator」——版本不匹配用 importNetworkFromONNX 导入 PyTorch 导出的模型时报错提示某个算子不支持比如 aten::max_pool2d_with_indices 或 aten:: reflection_pad2d。原因是 PyTorch 的某些层导出 ONNX 时映射到的算子比较特殊MATLAB 版本没跟上。解决方法是优先升级 MATLAB 到 R2023a 及以上版本支持更多 ONNX 算子其次是修改 Python 端模型把不支持的层替换成等价层比如把 MaxPool2d 替换为 AvgPool2d对融合任务影响不大最后可以用 onnxsurgeon 工具修改计算图手动替换不支持算子。5.5 现象训练时显存溢出但 batch size 已降到 1——输入分辨率过大融合模型如果输入分辨率是 512x512 甚至更高加上双分支结构显存消耗很容易突破 8GB。gradient accumulation 已经做了batch size 已是 1还是 OOM。解决方法是做分块训练而不是直接输入全分辨率图像。把 512x512 的图像切成 4 块 256x256 的 patch每块独立过网络融合输出再拼回原图。注意切块时要有 overlap比如 16 像素的 overlap拼回时在重叠区域做线性插值融合避免拼缝。这个方法几乎不会损失融合质量因为融合网络对局部区域的推理是独立进行的。6. 效果验证与模型落地客观指标计算和 MATLAB 部署的一个完整方案融合效果好不好看是一回事但论文和项目验收都要用客观指标说话。我在 MATLAB 里用的指标组合是信息熵Entropy、互信息Mutual Information、边缘保持度Qabf和结构相似度SSIM。信息熵衡量融合图的信息量互信息衡量融合图与两张输入图的信息相关性Qabf 衡量边缘梯度信息的保持程度SSIM 衡量结构相似性。在 MATLAB 里写一个评估脚本最方便的方式是调用 Image Processing Toolbox 里的 entropy 函数以及自己实现 Qabf。核心代码如下% 计算信息熵 E entropy(uint8(fusion_img * 255)); % 计算融合图与红外图的SSIM ssim_ir ssim(fusion_img, ir_gray); % 计算融合图与可见光图的SSIM ssim_vi ssim(fusion_img, vi_resized); % 计算与红外图的互信息 mi_ir mutual_information(fusion_img, ir_gray); mi_vi mutual_information(fusion_img, vi_resized);评估结果只有在同一测试集和同一配准结果下比较才有意义。我习惯把每张测试图的融合结果存成单独文件夹然后跑一个统一脚本批量计算所有指标输出成表格这样写论文时可以直接引用。指标和数据可视化要同时放——审稿人不会只看数字他们更倾向于看融合图的细节对比图。关于模型落地如果目标平台是嵌入式设备或无人机机载平台MATLAB 的 GPU Coder 可以把训练好的网络转成 CUDA 代码部署到 NVIDIA Jetson 平台。如果只是做软件方案可以在 MATLAB Compiler 里打包成独立的 exe 或 .NET 程序集给上位机调用。部署时注意输入图像的预处理必须和训练时完全一致包括归一化系数、裁剪方式和通道顺序。最后分享一个我自己的习惯每完成一个融合模型的训练第一件事不是看指标而是把融合结果和红外图、可见光图放在同一张画布里用 imshowpair 逐个像素对比。指标好但视觉效果差说明模型学会了「刷指标」——比如生成一个过度平滑的图像SSIM 很高但毫无实用价值。图像融合是一个面向视觉效果的任务最终话语权在人的眼睛。这个观念帮我避开了很多论文里指标漂亮但落地无用的坑希望帮到你。本文还有配套的精品资源点击获取
返回列表