牛顿的描述是正确的,但实际查看转换以了解正在发生的事情以及它们如何与转换矩阵中的其他值一起工作以更有意义可能会有所帮助。我将给出一些带有动画的 python/OpenCV 示例来展示这些值的作用。
import numpy as np
import cv2
img = cv2.imread('img1.png')
h, w = img.shape[:2]
# initializations
max_m20 = 2e-3
nsteps = 50
M = np.eye(3)
所以在这里我将转换矩阵设置为恒等式(无转换)。我们希望看到在变换矩阵 (2, 0) 处更改元素的效果M
,因此我们将通过在 to 之间线性间隔循环来制作nsteps
动画。0
max_m20
for m20 in np.linspace(0, max_m20, nsteps):
M[2, 0] = m20
warped = cv2.warpPerspective(img, M, (w, h))
cv2.imshow('warped', warped)
k = cv2.waitKey(1)
if k == ord('q') & 0xFF:
break
我将其应用于从牛津视觉几何组拍摄的图像上。
所以实际上,我们可以看到这类似于围绕与图像左边缘对齐的点旋转相机,或者围绕轴旋转图像本身。但是,它与此略有不同。请注意,顶部边缘始终保持在顶部,这有点奇怪。我们不会像上面那样绕轴旋转,而是想象顶部边缘也会开始下降到右侧边缘。像这样:
好吧,如果您正在考虑转换,获得此转换的一种简单方法是采用上面的转换,并添加一些倾斜失真,以便在右下角被向上推时,右上侧被向下推。实际上,这正是创建此视图的方式:
M = np.eye(3)
max_m20 = 2e-3
max_m10 = 0.6
for m20, m10 in zip(np.linspace(0, max_m20, nsteps), np.linspace(0, max_m10, nsteps)):
M[2, 0] = m20
M[1, 0] = m10
warped = cv2.warpPerspective(img, M, (w, h))
cv2.imshow('warped', warped)
k = cv2.waitKey(1)
if k == ord('q') & 0xFF:
break
因此,在这些矩阵中考虑视角的正确方法是,IMO,将倾斜条目和最后一行放在一起。这些是单应矩阵中实际修改角度的两个位置*;否则,它只是旋转、缩放和平移——所有这些都是角度保持的。
*注意:实际上,可以通过我没有提到的另一种方式更改角度。仿射变换允许非均匀缩放,这意味着您可以拉伸形状的宽度而不是高度,反之亦然,这也会改变角度。想象一下,如果你有一个三角形并且只拉伸它的宽度;角度会改变。所以事实证明,非均匀缩放(即当变换矩阵的第一个和中间元素是不同的值时)除了透视变化和剪切失真之外,还可以修改角度。
请注意,在这些示例中,这同样适用于最后一行中具有另一个偏移位置的第二个条目;唯一的区别是它发生在顶部而不是左侧。这两种情况下的负值类似于沿该轴将平面旋转到而不是远离相机。