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()函数)可以用于实现单应性/投影变换。