ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Harr小波图像融合实战:OpenCV实现多聚焦图像清晰合成

Harr小波图像融合实战:OpenCV实现多聚焦图像清晰合成

1. 从一张拍不清的照片说起:为什么需要图像融合

前阵子帮朋友处理一组室内场景的照片,同一机位拍了两张:一张对焦在近处的摆件上,细节锐利但背景虚化;另一张对焦在远处的墙面上,背景清晰但前景糊了。朋友问我能不能把两张“拼”成一张全都清楚的图。这个需求听起来像是修图软件的活儿,但本质上它属于图像融合的范畴——把同一场景的多幅图像信息整合成一幅信息更完整的图像。

图像融合在工业检测、医学影像、遥感观测里用得非常多。比如红外与可见光图像的融合,红外能穿透烟雾看到热源,可见光能提供纹理细节,两者一合,既能看到目标又能看清轮廓。再比如多聚焦图像融合,就是我朋友遇到的那种情况,不同焦距各拍一张,融合后得到全焦图像。而实现融合的方法有很多种,从最简单的加权平均到复杂的深度学习模型都有,但如果你想要一个原理清晰、代码量可控、效果稳定的方案,基于Harr小波分解的融合方法是一个非常值得上手的起点。

这篇文章面向的是有一定OpenCV基础、想动手实现图像融合的开发者。我会把Harr小波分解的原理讲透,把融合规则的设计逻辑说清楚,然后给出完整的OpenCV实现代码,最后分享我在调试过程中踩过的坑和总结的参数调节经验。你不需要有信号处理的背景,只要会写Python、装过OpenCV,就能跟着做出来。

2. 为什么选Harr小波:方案选型背后的逻辑

2.1 图像融合的常见技术路线对比

在动手写代码之前,先搞清楚市面上有哪些融合方法,以及为什么Harr小波值得选。我把常见的几类方法列出来做个对比:

方法类别代表算法优点缺点适用场景
空间域方法加权平均、主成分分析实现简单、速度快容易产生鬼影、对比度下降对融合质量要求不高的快速预览
金字塔方法拉普拉斯金字塔多尺度融合、效果较好分解层数受限、重构有误差多聚焦图像融合
小波变换方法Harr小波、Daubechies小波多尺度+多方向、信息保留好对位移敏感、计算量中等多聚焦、红外可见光融合
深度学习方法CNN、GAN效果最好需要大量训练数据、模型大有标注数据的专业场景

从表里能看出来,小波变换方法处在一个“甜点区”:效果比简单的空间域方法好一大截,实现难度又比深度学习低得多。而Harr小波又是所有小波里最简单的一种,它的滤波器系数只有四个值,计算过程就是加减法,非常适合用来理解小波分解的本质。

2.2 Harr小波分解到底在做什么

很多人一听到“小波”就觉得玄乎,其实Harr小波的核心思想用一句话就能概括:把信号拆成低频的“概貌”和高频的“细节”。

拿一维信号举例,假设有四个像素值[10, 12, 8, 6]。Harr小波分解的第一步是两两配对求平均和差值:

  • 平均值:(10+12)/2 = 11,(8+6)/2 = 7
  • 差值:(10-12)/2 = -1,(8-6)/2 = 1

这样原来的四个数就变成了[11, 7, -1, 1]。前两个是低频分量(概貌),后两个是高频分量(细节)。如果继续对低频分量做同样的操作,就得到了多级分解。

放到二维图像上,情况稍微复杂一点。图像是二维信号,所以要做行方向和列方向各一次分解,一共得到四个子带:

  • LL(低频-低频):图像的近似概貌,包含了大部分能量
  • LH(低频-高频):水平方向的细节,对应垂直边缘
  • HL(高频-低频):垂直方向的细节,对应水平边缘
  • HH(高频-高频):对角线方向的细节

注意:不同教材对LH和HL的命名可能相反,这里约定第一个字母代表行方向处理结果,第二个字母代表列方向。实际写代码时不用纠结名字,看子带对应的物理意义就行。

这个分解过程可以递归进行。对LL子带再做一次二维Harr分解,就得到二级分解结果。分解级数越多,频率划分越细,但计算量也越大。对于一般的图像融合任务,2到3级分解就够用了。

2.3 融合规则的设计思路

分解完之后,关键问题来了:怎么把两张图的子带合并成一张图的子带?

低频子带包含的是图像的亮度和整体结构,高频子带包含的是边缘和纹理。这两类信息的重要性不同,所以要用不同的融合策略:

  • 低频子带:常用加权平均。因为低频信息差异不大,简单平均就能得到平滑的结果。但纯平均会降低对比度,所以有时候会用基于局部能量的加权,让能量大的区域占更大权重。
  • 高频子带:常用绝对值取大。高频系数绝对值越大,说明该位置的边缘越强、细节越丰富,所以取绝对值大的那个系数,能最大程度保留清晰区域的细节。

这个“低频平均+高频取大”的组合是Harr小波融合里最经典也最稳定的策略。我试过其他变体,比如低频也取大、高频用阈值收缩,效果都不如这个组合稳定。

3. 核心细节拆解:从原理到可运行的代码

3.1 环境准备与依赖确认

动手之前先把环境理清楚。这个项目对环境的依赖非常轻量:

pip install opencv-python numpy matplotlib
  • opencv-python:负责图像的读取、显示和基础处理
  • numpy:负责矩阵运算,小波分解的加减法全靠它
  • matplotlib:可选,用来对比显示融合前后的图像

版本方面没有特殊要求,OpenCV 4.x 和 NumPy 1.20 以上都能跑。我实测在 Python 3.8 到 3.11 上都正常。如果你用的是 Anaconda,这些库基本都自带了,直接跳过安装步骤。

提示:不要用pip install cv2,这个包名是错的,正确的包名是opencv-python。我见过不少新手在这里卡住。

3.2 Harr小波分解的手动实现

OpenCV 本身没有提供小波变换的函数,所以这部分需要自己写。好在Harr小波的实现非常直接,核心就是切片和加减法。

先看一维分解的实现思路。假设输入是一个长度为N的一维数组,我们要把它变成N/2个低频系数和N/2个高频系数:

import numpy as np def harr_1d_decompose(signal): """一维Harr小波分解""" signal = np.asarray(signal, dtype=np.float32) n = len(signal) # 保证长度为偶数 if n % 2 != 0: signal = np.append(signal, signal[-1]) n += 1 # 偶数索引和奇数索引配对 even = signal[0::2] odd = signal[1::2] # 低频:平均值;高频:差值的一半 low = (even + odd) / 2.0 high = (even - odd) / 2.0 return low, high

这里有个细节值得说明:高频系数为什么除以2?因为Harr小波的规范正交基要求能量守恒,除以2(或者说除以根号2的平方)是为了让分解后的总能量和原信号一致。如果你不关心能量守恒,只做融合,其实不除也能用,但重构的时候要对应处理。

二维分解就是在一维的基础上,先对每一行做分解,再对结果的每一列做分解:

def harr_2d_decompose(img): """二维Harr小波分解,返回LL, LH, HL, HH四个子带""" img = np.asarray(img, dtype=np.float32) h, w = img.shape # 处理奇数尺寸 if h % 2 != 0: img = np.vstack([img, img[-1:, :]]) h += 1 if w % 2 != 0: img = np.hstack([img, img[:, -1:]]) w += 1 # 行方向分解 row_low = np.zeros((h, w // 2), dtype=np.float32) row_high = np.zeros((h, w // 2), dtype=np.float32) for i in range(h): low, high = harr_1d_decompose(img[i, :]) row_low[i, :] = low row_high[i, :] = high # 列方向分解 LL = np.zeros((h // 2, w // 2), dtype=np.float32) LH = np.zeros((h // 2, w // 2), dtype=np.float32) HL = np.zeros((h // 2, w // 2), dtype=np.float32) HH = np.zeros((h // 2, w // 2), dtype=np.float32) for j in range(w // 2): low, high = harr_1d_decompose(row_low[:, j]) LL[:, j] = low LH[:, j] = high low, high = harr_1d_decompose(row_high[:, j]) HL[:, j] = low HH[:, j] = high return LL, LH, HL, HH

这段代码里用循环逐行逐列处理,逻辑清晰但速度一般。如果你要处理大图或者视频流,可以用NumPy的向量化操作重写,把循环去掉。不过对于单张图像的融合任务,这个速度完全够用,一张1080p的图分解一次大概几十毫秒。

3.3 融合规则的具体实现

分解完成后,对两张图的子带分别应用融合规则:

def fuse_coefficients(LL1, LL2, LH1, LH2, HL1, HL2, HH1, HH2): """低频平均,高频绝对值取大""" # 低频:加权平均 LL_fused = (LL1 + LL2) / 2.0 # 高频:绝对值取大 LH_fused = np.where(np.abs(LH1) >= np.abs(LH2), LH1, LH2) HL_fused = np.where(np.abs(HL1) >= np.abs(HL2), HL1, HL2) HH_fused = np.where(np.abs(HH1) >= np.abs(HH2), HH1, HH2) return LL_fused, LH_fused, HL_fused, HH_fused

低频用平均是最稳妥的选择。我试过用最大值、用局部方差加权,结果要么对比度异常,要么出现块状伪影。平均虽然简单,但胜在稳定,融合后的图像过渡自然。

高频用绝对值取大,背后的逻辑是:高频系数的绝对值代表该位置边缘的强度。两张图在同一位置,一张清晰一张模糊,清晰那张的边缘强度一定更大,所以取绝对值大的系数,就相当于自动选择了清晰区域的信息。

3.4 小波重构:把子带还原成图像

融合完子带后,需要做逆变换把系数还原成像素图像。重构是分解的逆过程:

def harr_1d_reconstruct(low, high): """一维Harr小波重构""" n = len(low) signal = np.zeros(2 * n, dtype=np.float32) signal[0::2] = low + high signal[1::2] = low - high return signal def harr_2d_reconstruct(LL, LH, HL, HH): """二维Harr小波重构""" h, w = LL.shape # 列方向重构 row_low = np.zeros((2 * h, w), dtype=np.float32) row_high = np.zeros((2 * h, w), dtype=np.float32) for j in range(w): row_low[:, j] = harr_1d_reconstruct(LL[:, j], LH[:, j]) row_high[:, j] = harr_1d_reconstruct(HL[:, j], HH[:, j]) # 行方向重构 img = np.zeros((2 * h, 2 * w), dtype=np.float32) for i in range(2 * h): img[i, :] = harr_1d_reconstruct(row_low[i, :], row_high[i, :]) return img

重构的公式推导很简单:分解时low = (even + odd) / 2,high = (even - odd) / 2,那么反解出来就是even = low + high,odd = low - high。这就是为什么重构代码里是加和减。

注意:如果分解时对奇数尺寸做了填充,重构后图像会比原图大一行或一列,需要裁剪回原始尺寸。这个细节很容易被忽略,导致融合结果尺寸对不上。

4. 完整实操流程:从读图到保存结果

4.1 主流程代码组织

把前面的函数串起来,形成一个完整的融合流程:

import cv2 import numpy as np def wavelet_fuse(img1_path, img2_path, output_path, levels=2): """基于Harr小波分解的图像融合主函数""" # 读取图像并转为灰度图 img1 = cv2.imread(img1_path, cv2.IMREAD_GRAYSCALE) img2 = cv2.imread(img2_path, cv2.IMREAD_GRAYSCALE) if img1 is None or img2 is None: raise ValueError("图像读取失败,请检查路径") # 统一尺寸 h = min(img1.shape[0], img2.shape[0]) w = min(img1.shape[1], img2.shape[1]) img1 = cv2.resize(img1, (w, h)).astype(np.float32) img2 = cv2.resize(img2, (w, h)).astype(np.float32) # 多级分解 coeffs1 = decompose_multilevel(img1, levels) coeffs2 = decompose_multilevel(img2, levels) # 逐级融合 fused_coeffs = [] for (LL1, LH1, HL1, HH1), (LL2, LH2, HL2, HH2) in zip(coeffs1, coeffs2): fused_coeffs.append(fuse_coefficients(LL1, LL2, LH1, LH2, HL1, HL2, HH1, HH2)) # 多级重构 result = reconstruct_multilevel(fused_coeffs) # 裁剪回原始尺寸并保存 result = result[:h, :w] result = np.clip(result, 0, 255).astype(np.uint8) cv2.imwrite(output_path, result) return result

多级分解和重构的辅助函数:

def decompose_multilevel(img, levels): """多级二维Harr小波分解""" coeffs = [] current = img for _ in range(levels): LL, LH, HL, HH = harr_2d_decompose(current) coeffs.append((LL, LH, HL, HH)) current = LL # 对低频子带继续分解 return coeffs def reconstruct_multilevel(coeffs): """多级二维Harr小波重构""" # 从最深层开始逐级重构 LL, LH, HL, HH = coeffs[-1] current = harr_2d_reconstruct(LL, LH, HL, HH) for i in range(len(coeffs) - 2, -1, -1): _, LH, HL, HH = coeffs[i] current = harr_2d_reconstruct(current, LH, HL, HH) return current

这里有个容易搞混的地方:多级分解时,每一级只对上一级的LL子带继续分解,但融合和重构时需要把每一级的LH、HL、HH都保留下来。重构时从最深层往上走,用当前重构结果作为下一级的LL,配合该级保存的LH、HL、HH继续重构。

4.2 参数选择与效果验证

分解级数levels是唯一需要手动调的参数。我的经验是:

  • 1级分解:融合效果最基础,适合差异不大的图像,速度快
  • 2级分解:最常用的选择,在效果和速度之间取得平衡
  • 3级分解:适合大尺寸图像(2000像素以上),能捕捉更粗粒度的结构信息
  • 4级以上:收益递减明显,而且容易在图像边缘产生振铃效应

验证融合效果时,我习惯把原图1、原图2、融合结果并排显示:

import matplotlib.pyplot as plt fig, axes = plt.subplots(1, 3, figsize=(15, 5)) axes[0].imshow(cv2.imread('img1.jpg', 0), cmap='gray') axes[0].set_title('Source 1') axes[1].imshow(cv2.imread('img2.jpg', 0), cmap='gray') axes[1].set_title('Source 2') axes[2].imshow(result, cmap='gray') axes[2].set_title('Fused') for ax in axes: ax.axis('off') plt.tight_layout() plt.show()

看融合结果时重点关注两个地方:一是原本模糊的区域是否变清晰了,二是清晰区域和模糊区域的交界处有没有明显的拼接痕迹。如果交界处有突兀的亮线或暗线,说明融合规则在该区域选择不一致,需要调整策略。

4.3 彩色图像的处理方式

前面的代码都是针对灰度图的。彩色图像的处理有两种思路:

思路一:分通道处理。把BGR三个通道拆开,每个通道单独做小波融合,最后合并。这种做法实现简单,但可能引入颜色失真,因为三个通道的融合决策可能不一致。

思路二:转换到YCrCb空间。只对Y通道(亮度)做小波融合,Cr和Cb通道(色度)用简单的平均或取第一张图的色度。这种做法能更好地保持颜色一致性,是我更推荐的方式。

def wavelet_fuse_color(img1_path, img2_path, output_path, levels=2): """彩色图像融合:Y通道小波融合,色度通道平均""" img1 = cv2.imread(img1_path) img2 = cv2.imread(img2_path) h = min(img1.shape[0], img2.shape[0]) w = min(img1.shape[1], img2.shape[1]) img1 = cv2.resize(img1, (w, h)) img2 = cv2.resize(img2, (w, h)) # 转换到YCrCb ycbcr1 = cv2.cvtColor(img1, cv2.COLOR_BGR2YCrCb).astype(np.float32) ycbcr2 = cv2.cvtColor(img2, cv2.COLOR_BGR2YCrCb).astype(np.float32) # Y通道小波融合 y1, cr1, cb1 = ycbcr1[:,:,0], ycbcr1[:,:,1], ycbcr1[:,:,2] y2, cr2, cb2 = ycbcr2[:,:,0], ycbcr2[:,:,1], ycbcr2[:,:,2] coeffs1 = decompose_multilevel(y1, levels) coeffs2 = decompose_multilevel(y2, levels) fused_coeffs = [] for c1, c2 in zip(coeffs1, coeffs2): fused_coeffs.append(fuse_coefficients(*c1, *c2)) y_fused = reconstruct_multilevel(fused_coeffs)[:h, :w] # 色度通道平均 cr_fused = (cr1 + cr2) / 2.0 cb_fused = (cb1 + cb2) / 2.0 # 合并并转回BGR ycbcr_fused = np.stack([y_fused, cr_fused, cb_fused], axis=2) ycbcr_fused = np.clip(ycbcr_fused, 0, 255).astype(np.uint8) result = cv2.cvtColor(ycbcr_fused, cv2.COLOR_YCrCb2BGR) cv2.imwrite(output_path, result) return result

色度通道用平均而不是取大,是因为人眼对色度细节不敏感,色度上的微小差异不会影响观感,但色度不一致反而会让人察觉出颜色异常。

5. 常见问题与排查技巧实录

5.1 融合结果出现块状伪影

这是最常见的问题,表现为融合图像上出现规则的方块状纹理。根本原因是高频系数选择不一致:在某个局部区域,有些位置选了图1的系数,有些位置选了图2的系数,导致重构后出现不连续的跳变。

解决办法有两个。一是改用基于窗口的融合规则,不逐像素比较绝对值,而是比较以该像素为中心的3x3或5x5窗口内的能量和:

def fuse_high_freq_window(H1, H2, window_size=3): """基于局部窗口能量的高频融合""" kernel = np.ones((window_size, window_size), dtype=np.float32) energy1 = cv2.filter2D(np.abs(H1), -1, kernel) energy2 = cv2.filter2D(np.abs(H2), -1, kernel) return np.where(energy1 >= energy2, H1, H2)

二是对融合后的高频系数做一次一致性验证:如果某位置的系数来自图1,但周围大多数系数来自图2,就把它改成图2的系数。这个操作叫“一致性滤波”,能有效消除孤立的错误选择。

5.2 融合图像整体偏暗或偏亮

如果融合结果比原图明显偏暗,通常是低频融合策略的问题。平均操作会拉低高亮区域的亮度,因为另一张图在对应位置可能是暗的。

改进方法是基于局部能量的加权平均:

def fuse_low_freq_weighted(LL1, LL2, window_size=3): """基于局部能量的低频加权融合""" kernel = np.ones((window_size, window_size), dtype=np.float32) energy1 = cv2.filter2D(LL1 ** 2, -1, kernel) energy2 = cv2.filter2D(LL2 ** 2, -1, kernel) total = energy1 + energy2 + 1e-6 w1 = energy1 / total w2 = energy2 / total return w1 * LL1 + w2 * LL2

这样能量大的区域(通常也是更清晰的区域)会获得更大的权重,融合结果的亮度更接近清晰图像。

5.3 图像尺寸不一致导致报错

两张输入图像尺寸不同时,直接做小波分解会在矩阵运算时报错。我的处理方式是统一缩放到较小尺寸,而不是填充到较大尺寸。因为填充会引入人工边界,在边界处产生虚假的高频响应,影响融合质量。

如果两张图的长宽比差异很大,缩放会导致明显变形,这时候应该先做中心裁剪,裁成相同的长宽比,再统一尺寸。

5.4 常见问题速查表

问题现象可能原因排查方向解决方法
融合结果有块状伪影高频系数选择不一致检查高频融合规则改用窗口能量比较+一致性滤波
整体偏暗/偏亮低频平均拉低对比度检查低频融合策略改用局部能量加权平均
边缘出现亮线/暗线分解重构边界处理不当检查奇数尺寸填充逻辑统一尺寸后再分解,重构后裁剪
颜色失真三通道独立融合检查是否分通道处理转YCrCb空间,只融合Y通道
运行速度慢逐像素循环检查是否用了Python循环改用NumPy向量化操作
重构后尺寸不对奇数尺寸填充未裁剪检查重构后裁剪逻辑记录原始尺寸,重构后裁剪

5.5 实操心得:参数调节的优先级

调参的时候不要一上来就改分解级数。我的经验是,先调融合规则,再调窗口大小,最后才动分解级数。

融合规则决定了信息选择的基本逻辑,如果规则本身不合理,调多少级分解都救不回来。窗口大小影响融合的平滑程度,窗口越大越平滑但细节保留越少,一般3x3或5x5就够了。分解级数影响的是频率划分的粒度,对最终效果的影响反而是最小的。

还有一个容易被忽略的点:输入图像的质量。如果两张源图本身就很模糊,或者曝光差异极大,再好的融合算法也出不来好结果。融合的前提是源图之间有互补信息,如果两张图的信息高度重叠,融合的意义就不大了。

6. 性能优化与扩展方向

6.1 向量化加速

前面展示的分解和重构代码用了Python循环,逻辑清晰但速度受限。如果要把这个方案用到批量处理或实时场景,需要做向量化改造。核心思路是用NumPy的切片和广播操作替代循环:

def harr_2d_decompose_fast(img): """向量化版本的二维Harr小波分解""" img = np.asarray(img, dtype=np.float32) h, w = img.shape if h % 2 != 0: img = np.vstack([img, img[-1:, :]]) if w % 2 != 0: img = np.hstack([img, img[:, -1:]]) # 行方向:利用切片一次性处理所有行 even_cols = img[:, 0::2] odd_cols = img[:, 1::2] row_low = (even_cols + odd_cols) / 2.0 row_high = (even_cols - odd_cols) / 2.0 # 列方向:同样用切片 even_rows_low = row_low[0::2, :] odd_rows_low = row_low[1::2, :] LL = (even_rows_low + odd_rows_low) / 2.0 LH = (even_rows_low - odd_rows_low) / 2.0 even_rows_high = row_high[0::2, :] odd_rows_high = row_high[1::2, :] HL = (even_rows_high + odd_rows_high) / 2.0 HH = (even_rows_high - odd_rows_high) / 2.0 return LL, LH, HL, HH

向量化版本的速度比循环版本快10倍以上,处理一张4K图像只需要几毫秒。重构函数也可以用同样的方式改造。

6.2 扩展到其他小波基

Harr小波的优点是简单,缺点是频率划分不够精细,在图像平滑区域容易产生“方块效应”。如果对融合质量有更高要求,可以换成Daubechies小波(db2、db4)或Symlet小波。这些正交小波的滤波器系数更长,分解效果更好,但实现复杂度也更高。

一个折中的方案是使用双正交小波,比如Cohen-Daubechies-Feauveau小波,它的分解和重构滤波器不同,但具有线性相位特性,能避免重构时的相位失真。OpenCV虽然没有内置小波函数,但可以用cv2.filter2D配合自定义的滤波器核来实现。

6.3 与深度学习方法结合

如果手头有标注数据,可以考虑用浅层CNN来学习融合规则,用小波分解做预处理。具体做法是:先对源图做小波分解,把LL、LH、HL、HH四个子带作为CNN的输入通道,让网络学习如何组合这些子带。这样既保留了小波变换的多尺度优势,又利用了深度学习的拟合能力。

不过这种方案需要大量的训练数据,而且模型的可解释性不如纯小波方法。对于大多数应用场景,纯小波融合已经足够好了。

6.4 批量处理与自动化

实际项目中往往需要处理大量图像对。我通常会写一个批处理脚本,自动遍历文件夹里的图像对,按命名规则配对,然后调用融合函数:

import os import glob def batch_fuse(input_dir, output_dir, levels=2): """批量融合:按文件名前缀配对""" os.makedirs(output_dir, exist_ok=True) img1_list = sorted(glob.glob(os.path.join(input_dir, '*_A.*'))) for path1 in img1_list: path2 = path1.replace('_A.', '_B.') if not os.path.exists(path2): print(f"跳过:找不到配对图像 {path2}") continue name = os.path.basename(path1).replace('_A.', '_fused.') output_path = os.path.join(output_dir, name) try: wavelet_fuse(path1, path2, output_path, levels) print(f"完成:{name}") except Exception as e: print(f"失败:{name},原因:{e}")

批处理时要注意异常处理,单张图像失败不应该中断整个批次。另外建议加一个日志记录,方便回溯哪些图像处理失败了。

7. 一些踩坑之后的个人体会

这个方案我从第一次写到现在,前后改了好几版。最开始用的是逐像素循环,一张图跑好几秒,后来改成向量化才把速度提上来。融合规则也试过很多种,低频取大、高频平均、基于梯度的选择,最后发现还是“低频平均+高频绝对值取大”这个最朴素的组合最稳。

有一个坑我印象很深:早期版本没有处理奇数尺寸,结果遇到一张1921x1081的图,分解重构后尺寸变成了1922x1082,保存的时候和原图对不上,排查了半天才发现是填充逻辑的问题。后来我在分解函数里统一做了偶数化处理,重构后再裁剪回原始尺寸,这个问题就再也没出现过。

还有一个经验是关于分解级数的。我一开始觉得级数越多效果越好,直接上了4级,结果融合图像边缘出现了明显的振铃,而且处理时间翻了好几倍。后来降到2级,效果反而更自然。所以参数这个东西,不是越大越好,够用就行。

如果你打算把这个方案用到实际项目里,我的建议是先把灰度图的流程跑通,确认融合效果符合预期,再扩展到彩色图像。彩色图像的处理虽然只多了几行代码,但颜色空间转换和通道合并的细节很容易出错,先把基础打牢再往上加功能,会省很多调试时间。

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进