原理
泊松融合原理
希望将某图像src中roi区域无缝地融合到另一张图像dst中,在保持边缘像素值相等的情况下,dst的roi内部的纹理(梯度场)尽量和某给定梯度场相等(下面示例是src+dst的梯度场,也可以自定义),可列出如下最小化问题:
该问题的解满足带有狄利克雷边界条件的泊松方程,具体推导过程可以看二元欧拉-拉格朗日方程的推导过程,本小白看的这视频和这博客。
DCT解法原理
代码实现
以下实现的是梯度混合,实际上直接梯度相加了
def poisson_merge(src, dst, mask):
""" 泊松融合
src: (h, w) 灰度图
dst: (h, w)
mask: (h, w) {0, 1}
"""
dst_0 = dst.copy()
h, w = src.shape
# 扩充图像
dst1 = np.zeros((h + 2, w + 2), np.uint8)
dst1[1:h + 1, 1:w + 1] = dst
# 边界填充
dst1[0:1] = dst1[1:2]
dst1[-1:] = dst1[-2:-1]
dst1[:, 0:1] = dst1[:, 1:2]
dst1[:, -1:] = dst1[:, -2:-1]
kernal_x = np.array([[0, 0, 0],
[0, -1, 0],
[0, 1, 0]])
kernal_y = kernal_x.T
gradx_src = cv2.filter2D(src, cv2.CV_32F, kernal_x)
grady_src = cv2.filter2D(src, cv2.CV_32F, kernal_y)
gradx_dst1 = cv2.filter2D(dst1, cv2.CV_32F, kernal_x)
grady_dst1 = cv2.filter2D(dst1, cv2.CV_32F, kernal_y)
# 梯度操作 可以有其他操作梯度的方式
gradx_dst1[ 1:h + 1, 1:w + 1][mask!=0] += gradx_src[mask!=0]
grady_dst1[ 1:h + 1, 1:w + 1][mask!=0] += grady_src[mask!=0]
# 和上面的卷积核共同作用于原图 等价于 拉普拉斯算子作用于原图
kernal_x = np.array([[0, -1, 0],
[0, 1, 0],
[0, 0, 0]])
kernal_y = kernal_x.T
lap = (cv2.filter2D(gradx_dst1, cv2.CV_32F, kernal_x) + cv2.filter2D(grady_dst1, cv2.CV_32F, kernal_y))[ 1:h + 1, 1:w + 1]
# dct变换
lap = cv2.dct(lap)
# 计算系数
fx = 2 * np.cos(np.pi * np.arange(h) / (h))
fy = 2 * np.cos(np.pi * np.arange(w) / (w))
f = fx.reshape(-1, 1) + fy - 4
lap /= f
lap[0, 0] = 0
# 反dct变换
dst = cv2.idct(lap)
# 求低频系数
dst -= dst.mean()
dst += dst_0.mean()
dst[dst > 255] = 255
dst[dst < 0] = 0
return dst.astype(np.uint8)
一些问题:
为什么 边界填充0 和 边界填充边缘等值像素 效果完全不一样,只是边缘的梯度改变了,最终结果变化那么大?
实际案例
参考
Poisson Image Editing
Solving a 2D Poisson equation with Neumann boundary conditions through discrete Fourier cosine transform
泊松融合进阶——DFT求解二维泊松方程
离散域下的泊松方程求解(python实现)
[Calculus of Variations] 变分法的基本原理:Euler-Lagrange方程
变分法笔记(2)——Euler-Lagrange方程的基础推广
【图像处理】2D-DCT——二维离散余弦变换
案例图片来源: OpenCV图像处理-泊松融合