Python图像处理经典实例
上QQ阅读APP看书,第一时间看更新

1.4 应用透视变换和单应性变换

透视(投影)变换的目标是从两个图像之间的点对应估算单应性矩阵(矩阵H)。由于矩阵的景深(DOF)为8,因此至少需要4对匹配点来计算两幅图像的单应性矩阵。计算单应性矩阵所需要的基本概念如图1-6所示。

幸运的是,读者不需要计算奇异值分解(SVD),并且矩阵H也是通过scikit-image库的transform模块中的ProjectiveTransform()函数自动计算的。在本实例中,我们会用该函数来计算单应性矩阵。

图1-6

1.4.1 准备工作

在该实例中,我们会用到一幅“蜂鸟”图像和一幅“月球上的宇航员”图像。我们还是按照常规的做法,先导入所需要的Python库:

from skimage.transform import ProjectiveTransform
from skimage.io import imread
import numpy as np
import matplotlib.pylab as plt

1.4.2 执行步骤

使用scikit-image库的transform 模块,我们执行以下步骤,来对图像应用投影变换。

1.首先读取源图像,并使用np.zeros()函数创建目标图像:

im_src = (imread('images/humming2.png'))
height, width, dim = im_src.shape
im_dst = np.zeros((height, width, dim))

2.创建一个ProjectiveTransform类的实例:

pt = ProjectiveTransform()

3.要自动估算单应性矩阵H,只需在源图像和目标图像之间提供4对匹配点。在这里,我们将目标图像的4个拐角点和输入蜂鸟图像的4个拐角点作为匹配点,如下所示:

src = np.array([[ 295., 174.],
 [ 540., 146. ],
 [ 400., 777.],
 [ 60., 422.]])
dst = np.array([[ 0., 0.],
 [height-1, 0.],
 [height-1, width-1],
 [ 0., width-1]])

4.获取目标图像中每个像素索引所对应的源图像像素索引:

x, y = np.mgrid[:height, :width]
dst_indices = np.hstack((x.reshape(-1, 1), y.reshape(-1,1)))
src_indices = np.round(pt.inverse(dst_indices), 0).astype(int)
valid_idx = np.where((src_indices[:,0] < height) &
(src_indices[:,1] < width) &
                    (src_indices[:,0] >= 0) & (src_indices[:,1] >=0))
dst_indicies_valid = dst_indices[valid_idx]
src_indicies_valid = src_indices[valid_idx]

5.把像素从源图像复制到目标图像:

im_dst[dst_indicies_valid[:,0],dst_indicies_valid[:,1]] =
im_src[src_indicies_valid[:,0],src_indicies_valid[:,1]]

运行上述代码,输出如图1-7所示。

图1-7

图1-8所示的是“月球上的宇航员”的源图像和显示在画布上的目标图像。通过在源图像(拐角点)和画布上的目标图像(拐角点)之间给出4对匹配点,该操作执行起来非常简单。

图1-8

执行投影变换后的输出图像如图1-9所示。

图1-9

1.4.3 工作原理

在上述两种情况下,输入图像被投影到输出图像的理想位置。为了对图像应用透视变换,我们首先需要创建ProjectiveTransform对象。

我们需要将源图像中的一组4像素位置和相应的目标图像中匹配的4像素位置连同ProjectiveTransform对象实例一起传递给estimate()函数,后者将计算单应性矩阵H(如果单应性矩阵H可通过计算得到,则函数返回True)。

在ProjectiveTransform对象上调用inverse()函数,该函数将提供与所有目标像素索引相对应的源像素索引。

1.4.4 更多实践

warp()函数(而不是inverse()函数)可以用于实现单应性/投影变换。