7.2. 图像补全与融合#
在图像补全(image completion) 任务中,我们需要对图像缺失的部分进行填充,并确保填充后的结果尽可能合理,如图 7.11 和图 7.12 所示。“合理”是指尽可能平滑,具体可描述为以下两点:
空间局部性(spatial locality):图像中同一个物体上相邻的部分应该相似。
奥卡姆剃须刀原则(Occam’s razor):被填补的区域不应该存在任何多余的东西,即无法从非填充区域推理得出的东西。
图像融合(image cloning) 是另一个问题,指的是我们将一张图片的一个物体扣下来,粘贴到另一张图片上,还要保证粘贴的结果尽可能自然,仿佛另一张图片中真的有这么一个物体,如图 7.13 和图 7.14 所示。
这两个问题都可以使用泊松编辑(Poisson editing) 来解决。接下来,我们会形式化地描述要解决的问题,然后介绍泊松图像编辑技术具体是如何解决的,最后再介绍一些泊松图像编辑的拓展应用。
7.2.1. 问题描述#
在数学上,我们可以用梯度的大小来衡量图片的变化程度,所以平滑的意思就是让图片亮度的梯度尽可能小。如图 7.11 所示,我们设 \(\Omega\) 表示待填补区域所有像素点的集合,\(\partial\Omega\) 为与待填补区域相邻的所有已知像素点的集合,\(f(x,y)\) 为定义在 \(\Omega\cup\partial\Omega\) 上的颜色场,表示要填补的内容,\(f^*(x,y)\) 为定义在 \(\Omega\) 的补集上的颜色场,表示图片的已知部分。那么我们可以将图像补全任务表达为如下最优化问题:
含义就是找到一个颜色场 \(f\) 使得内部的梯度尽可能小,同时边界上能够无缝衔接。
图像补全的任务只能为图像填上一部分“空白”,就像图 7.11 中被填补的湖水一样。如果我们希望填补上用户指定的内容,这个问题就变成了无缝图像融合任务。在图像融合任务中,我们还额外需要一个源图像 (比如图 7.13 中截取出来的木头),源图像的形状、大小与待填补区域完全一致。
与图像补全任务不同的是,我们需要在图像融合的过程中保留源图像的纹理信息,也就是要尽可能地保留源图像的梯度。记源图像为定义在 \(\Omega\) 上的颜色场 \(g(x,y)\),那么图像融合任务可以表达为如下最优化问题:
含义就是我们需要让填补部分 \(f\) 的梯度与 \(g\) 的梯度尽可能接近,同时保证边界上无缝衔接。
7.2.2. 求解#
由于公式 (7.11) 是公式 (7.12) 的特殊情况 (\(g\) 取常值函数),我们只需要考虑如何求解公式 (7.12)。这是对一个连续函数的最小化问题,也就是泛函优化问题,需要借助欧拉-拉格朗日方程[1]。这里我们直接给出结论,公式 (7.12) 中优化目标取极值当且仅当 \(f\) 满足如下狄利克雷边界条件的泊松方程:
其中 \(\nabla^2=\frac{\partial^2}{\partial x^2}+\frac{\partial^2}{\partial y^2}\) 为拉普拉斯算子。这也是泊松图像编辑名字的由来。我们需要求解的是颜色场 \(f\),在离散场景下,我们需要求的是 \(\Omega\) 中每个像素点上 \(f(x,y)\) 的值。我们可以使用上一节公式 (7.10) 中介绍的离散 Laplacian 算子代入公式 (7.13) 中,右手项可以直接计算出结果,左手项展开为:
对于大多数 \(\Omega\) 内的像素点,公式 (7.14) 中的五个 \(f\) 值都是待求的未知数。但是对于在边界上的像素点 (和 \(\partial\Omega\) 相邻的像素点),其四个相邻的像素点不全在 \(\Omega\) 中,此时我们就需要借助公式 (7.13) 中的边界条件,把公式 (7.14) 中相应的邻居项换成 \(f^*\) 的取值。举个例子,如图 7.15 所示,计算 \((2,2)\) 处的拉普拉斯时,其左、上邻居为 \(\partial\Omega\) 内的像素点,所以这两项需要替换成 \(f^*\) 的值,即:
于是这个像素的 \(\nabla^2f\) 中只包含了三个未知数。对于每个 \(\Omega\) 中的像素 \((x,y)\),我们都可以写出一个方程 \(\nabla^2f(x,y)=\nabla^2g(x,y)\);对于这个方程,要将修改为 \(f^*\) 的项移到等号右边,保证等号左边只包含未知量的一次项,常数项均移到等号右边。例如,图 7.15 中像素 \((2,2)\) 处的方程应当写为:
这样,我们就得到了一个含有 \(|\Omega|\) 个方程、关于 \(f(x,y),\forall(x,y)\in\Omega\) 的线性方程组。方程与未知数个数相等,求解线性方程组可以得到唯一解。
我们可以进一步将所有的 \(f(x,y)\) 排成一个向量 \(\mathbf f\),并将这个线性方程组写成 \(\mathbf L\mathbf f=\mathbf b\) 的形式。对于图 7.15 所示的例子,矩阵 \(\mathbf L\) 为:
向量 \(\mathbf b\) 为:
未知量按如下顺序排成向量 \(\mathbf f\):
在这个问题中,我们可以分析 \(\mathbf{L}\) 所具有的一些性质:
稀疏性:由于每行只与至多 5 个未知数相关,\(\mathbf L\) 是一个稀疏矩阵。
对称性:在 \(\Omega\) 内,如果 \((x_1,y_1)\) 与 \((x_2,y_2)\) 相邻,则 \(\nabla^2f(x_1,y_1)\) 中 \(f(x_2,y_2)\) 一项的系数为 \(1\),且 \(\nabla^2f(x_2,y_2)\) 中 \(f(x_1,y_1)\) 一项的系数也为 \(1\),否则都为 \(0\),所以这两个系数永远相等。
主对角占优:\(\mathbf L\) 的对角项为 \(-4\),每一行除对角项外至多还有 4 个 1 (因为至多 4 个未知的邻居),非对角项绝对值加起来不超过对角项绝对值。
对于这样的线性系统,有许多高效的求解器,这里列举三类,读者可以自行了解更多细节:
直接求解法。如 LU 分解。
迭代法。如雅克比 (Jacobi) 迭代、高斯-赛德尔 (Gauss-Seidel) 迭代、逐次超松弛 (SOR) 迭代。
多重网格法。
7.2.3. 拓展应用#
接下来我们介绍一些无缝图像融合算法的拓展应用。
在上述算法的基础上,还可以根据任务的需要加一些简单的处理,达到更加自然的效果。这些处理都是简单地将公式 (7.12) 中的 \(\nabla g\) 改成另外一个向量场 \(\mathbf v\),从而求解的问题将变成下式:
对应的泊松方程变为:
所以再计算右手项的时候还需要一个离散的散度算子 \(\nabla \cdot \)。我们已经在上一节中介绍过 Sobel 算子,根据散度的定义,我们可以对向量场的每个分量使用相应的 Sobel 算子然后再相加。具体的公式留给读者推导。
7.2.3.1. 梯度混合#
对于图 7.14 所示的例子,如果简单地套用无缝图像融合算法,得到的效果会像图 7.16 一样过于平滑,没办法保留墙壁上凹凸不平的纹理。为解决这个问题,我们可以令
其中 \(f^*(x,y)\) 指的是背景图的颜色场。也就是说,我们要求 \(f\) 的梯度尽可能接近源图像和背景图梯度的较大值,这样就可以避免过度平滑的问题了。
7.2.3.2. 纹理抹平与去除#
有时我们希望将图像的一些纹理抹平,如图 7.17 所示,将孩子的脸变得更加光滑。将 \(\mathbf v\) 设为 \(\nabla g\),并把其中梯度模长在一个阈值以下的部分修改为 \(\mathbf 0\),即可得到这个效果。
我们还可以将图片的一些内容去除掉,如图 7.18 所示,我们可以在图片中选取一小片席子,用它的纹理替换掉梨的枝干。