牛顿的描述是正确的,但实际上看到转换可能更有帮助,以便理解正在发生的事情,以及它们如何与变换矩阵中的其他值一起工作,使更有意义。我将给出一些带有动画的python/OpenCV示例,展示这些值的作用。
import numpy as np
import cv2
img = cv2.imread('img1.png')
h, w = img.shape[:2]
max_m20 = 2e-3
nsteps = 50
M = np.eye(3)
因此,我将变换矩阵设置为恒等矩阵(无变换)。我们希望看到更改变换矩阵 M
中 (2,0) 元素的影响,因此我们将通过循环遍历从 0
到 max_m20
线性间隔的nsteps
来进行动画。
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
我在从牛津大学视觉几何组获取的图像上应用了这个技术。
![m20](https://istack.dev59.com/LYYkJ.gif)
我们可以看到,这与围绕与图像左边缘对齐的点旋转相似,或者将图像本身围绕轴旋转。然而,它确实有一些不同。请注意,顶部边缘始终沿着顶部移动,这有点奇怪。如果我们像上面那样围绕轴旋转,我们会想象顶部边缘也会开始下降到右侧边缘。就像这样:
![m20m10](https://istack.dev59.com/mjDKE.gif)
好吧,如果你考虑变换,一种简单的方法是采用上述变换,并添加一些倾斜畸变,使右上侧被向下推动,同时底部右侧角被向上推动。这正是创建此视图的确切方式:
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
因此,在这些矩阵中,正确思考角度的方式是将斜向条目和最后一行放在一起。这是单应矩阵中实际修改角度的两个地方;否则,它只是旋转、缩放和平移——所有这些都是保持角度不变的操作。
注意:实际上,还有一种我没有提到的方法可以改变角度。仿射变换允许非均匀缩放,这意味着你可以在宽度上拉伸形状而不拉伸高度,反之亦然,这也会改变角度。想象一下如果你有一个三角形,只在宽度上拉伸;那么角度会改变。因此,非均匀缩放(即变换矩阵的第一个和中间元素是不同值)除了透视变换和倾斜扭曲外,还可以改变角度。
请注意,在这些示例中,最后一行的第二个条目与其他倾斜位置相同;唯一的区别是它发生在顶部而不是左侧。在这两种情况下的负值类似于沿该轴旋转平面以朝向相机,而不是远离相机。
i
,并将该索引添加到文件名中),则可以使用任意数量的工具将每个帧组合为gif
。我使用 ImageMagick,这是一个非常棒的用于图像处理的 Unix 命令行工具。调整图像大小,使它们足够小,并像正常图像一样拖放它们到 Stack! - alkasm