一,简介:
图像融合是一种将两个或多个图像合成为一幅新图像的技术,目的是结合源图像中的有用信息,生成一幅更具信息量和视觉效果的新图像。拉普拉斯金字塔是一种常用于图像融合的方法,它通过多尺度分解图像,并在不同尺度上进行融合,最终重建出融合后的图像。
二,拉普拉斯金字塔介绍:
在拉普拉斯金字塔的构建过程中如下所示:首先通过高斯模糊和逐层减半尺寸的下采样,形成高斯金字塔。然后,通过从当前层高斯图像中减去经过上采样和下采样处理的上一层高斯图像,计算出拉普拉斯金字塔的每一层。在这个过程中,下采样用于降低图像分辨率,上采样用于恢复分辨率。最后,使用掩模对两张图像的拉普拉斯金字塔进行加权平均,生成混合的拉普拉斯金字塔。通过迭代处理高斯金字塔的每一层,直至达到预设的最大迭代次数,完成图像的融合和细节保留。这种多尺度分解技术可以在不同的尺度上处理图像,保留更多的细节信息,并且在图像融合、图像放大等任务中发挥着重要作用。
三,算法实现步骤
3.1 构建融合拉普拉斯金字塔
为了实现图像融合,我们构建了一个六层的拉普拉斯金字塔。每一层都通过从原始图像中减去经过高斯滤波和上下采样处理后的图像来构造。构建完当前层后,我们对其进行下采样,并按照相同的步骤继续构建下一层。通过这种方式,我们能够有效地融合两张图片的特征,从而实现图像融合的目标。制作拉普拉斯金字塔使用opencv内置函数cv2.pyrUp,以及cv2.pyrDown实现
cv2.pyrUp:
● 功能:上采样图像。
● 参数:输入图像。
● 返回值:上采样后的图像。
● 说明:cv2.pyrUp函数通过对输入图像进行双线性插值来扩大图像的尺寸。双线性插值是一种常用的图像插值方法,它通过计算像素周围点的加权平均值来估算新的像素值。这个函数通常与cv2.pyrDown一起使用,以构建高斯金字塔和拉普拉斯金字塔。
cv2.pyrDown:
● 功能:下采样图像。
● 参数:输入图像。
● 返回值:下采样后的图像。
● 说明:cv2.pyrDown函数通过对输入图像进行高斯滤波和下采样来减小图像的尺寸。高斯滤波器用于平滑图像,去除噪声,而下采样则是通过去除图像的偶数行和列来实现的。这个函数也是构建高斯金字塔和拉普拉斯金字塔的关键步骤之一。
实现代码:
for i in range(maxIterations):
# 计算拉普拉斯金字塔
laplacianA = cv2.subtract(guassianA, cv2.pyrUp(cv2.pyrDown(guassianA)))
laplacianB = cv2.subtract(guassianB, cv2.pyrUp(cv2.pyrDown(guassianB)))
# 结合两张图片的拉普拉斯金字塔,通过掩模的高斯金字塔取加权平均值
combinedLaplacian = guassianMask * laplacianA + (1.0 - guassianMask) * laplacianB
# 将组合的拉普拉斯金字塔添加到列表的开始位置
combinedLaplacianPyramids.insert(0, combinedLaplacian)
# 更新高斯金字塔,进行下一次迭代
guassianA = cv2.pyrDown(guassianA)
guassianB = cv2.pyrDown(guassianB)
guassianMask = cv2.pyrDown(guassianMask)
# 添加最后一级的拉普拉斯金字塔(金字塔的顶部)
lastCombined = guassianMask * guassianA + (1.0 - guassianMask) * guassianB
combinedLaplacianPyramids.insert(0, lastCombined)
3.2 融合后的拉普拉斯金字塔复原:
为了将两张图片融合成一张新的图片,我们首先获取了融合后的拉普拉斯金字塔的顶层图像,并将其存储在变量blendedImage中。接着,我们进入一个循环,从第二层开始,遍历融合后的拉普拉斯金字塔中的每一层。在循环中,我们首先将blendedImage上采样到下一层金字塔的尺寸,然后将上采样后的blendedImage与金字塔中的当前层图像相加,以重建金字塔。通过这种方式,我们逐渐重建出融合后的图片,保留了两张图片的细节信息,并最终得到了一张融合后的图像。
代码如下(示例):
blendedImage = combinedLaplacianPyramids[0]
for i in range(1, len(combinedLaplacianPyramids)):
blendedImage = cv2.pyrUp(blendedImage)
blendedImage = cv2.add(blendedImage, combinedLaplacianPyramids[i])
四,整体代码实现:
# 导入必要的库
import cv2
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
# 读取两张图片
A = cv2.imread(r"F:\learnopencv-master\SeamlessCloning\images\man.jpg") # 读取男性图片
B = cv2.imread(r"F:\learnopencv-master\SeamlessCloning\images\woman.jpg") # 读取女性图片
# 将图片转换为浮点数并归一化
A = np.float32(A) / 255.0
B = np.float32(B) / 255.0
# 在图片A中创建一个男性脸部的大致掩模
mask = np.zeros(A.shape, A.dtype) # 初始化掩模为零矩阵
# 取出男性脸部区域制作蒙版
polygon = np.array([[164,226], [209,225], [238,188], [252,133], [248,75], [240,29], [192,15], [150,15], [100,70], [106,133], [123,194]], np.int32)
cv2.fillPoly(mask, [polygon], (255, 255, 255)) # 填充多边形
mask = np.float32(mask) / 255.0 # 将掩模转换为浮点数并归一化
# 通过与小于1.0的浮点数相乘来取得男性和女性脸部的加权平均值
mask = mask * 0.7 # 男性脸部占比0.7,女性脸部占比0.3
# 将图片调整为2的幂次方大小,此处为32,调整为384x352
A = cv2.resize(A, (384, 352))
# B和掩模需要与A尺寸相同,以便后续的乘法和加法操作
B = cv2.resize(B, (A.shape[1], A.shape[0]))
mask = cv2.resize(mask, (A.shape[1], A.shape[0]))
# 从原始图片(金字塔的底部)开始
guassianA = A.copy()
guassianB = B.copy()
guassianMask = mask.copy()
# 存储合并的拉普拉斯金字塔
combinedLaplacianPyramids = []
# 金字塔的层数,可以尝试不同的值,注意图片尺寸
maxIterations = 5
for i in range(maxIterations):
# 计算拉普拉斯金字塔
laplacianA = cv2.subtract(guassianA, cv2.pyrUp(cv2.pyrDown(guassianA)))
laplacianB = cv2.subtract(guassianB, cv2.pyrUp(cv2.pyrDown(guassianB)))
# 结合两张图片的拉普拉斯金字塔,通过掩模的高斯金字塔取加权平均值
combinedLaplacian = guassianMask * laplacianA + (1.0 - guassianMask) * laplacianB
# 将组合的拉普拉斯金字塔添加到列表的开始位置
combinedLaplacianPyramids.insert(0, combinedLaplacian)
# 更新高斯金字塔,进行下一次迭代
guassianA = cv2.pyrDown(guassianA)
guassianB = cv2.pyrDown(guassianB)
guassianMask = cv2.pyrDown(guassianMask)
# 添加最后一级的拉普拉斯金字塔(金字塔的顶部)
lastCombined = guassianMask * guassianA + (1.0 - guassianMask) * guassianB
combinedLaplacianPyramids.insert(0, lastCombined)
# 重建图片
blendedImage = combinedLaplacianPyramids[0]
for i in range(1, len(combinedLaplacianPyramids)):
blendedImage = cv2.pyrUp(blendedImage)
blendedImage = cv2.add(blendedImage, combinedLaplacianPyramids[i])
cv2.imshow('Blended', blendedImage) # 显示混合后的图片
# 直接混合两张图片以进行比较
directCombination = mask * A + (1.0 - mask) * B
cv2.imshow('Direct combination', directCombination) # 显示直接混合后的图片
cv2.waitKey(0) # 等待按键后关闭窗口
五,效果:
原图:
融合后效果(左图为直接融合,右图为拉普拉斯融合):