如何获得一个表示所有变换(缩放、旋转)的 3x3 矩阵,以应用于画布上绘制的图像,给定 4 个点 x1,y1...x4,y4 表示我想要的 ROI(子图像)缩放和旋转?
第一个坐标 x1,y1 应该转换为画布的左上角(0,0),x2,y2 应该转换为画布的右下角(canvas.width, canvas.height)。
非常感谢您的帮助!
这个功能其实还是蛮有用的。确实,您只需要 3 个值。但是,4 在概念上更好,因为您将一个四边形映射到另一个四边形。
def perspective(p1, p2, p3, p4):
x1, y1 = p1
x2, y2 = p2
x3, y3 = p3
x4, y4 = p4
j = x1 - x2 - x3 + x4
k = -x1 - x2 + x3 + x4
l = -x1 + x2 - x3 + x4
m = y1 - y2 - y3 + y4
n = -y1 - y2 + y3 + y4
o = -y1 + y2 - y3 + y4
i = 1.0
try:
h = (j * o - m * l) * i / (m * k - j * n)
except ZeroDivisionError:
h = 0
try:
g = (k * h + l * i) / j
except ZeroDivisionError:
g = 0
f = (y1 * (g + h + i) + y3 * (-g - h + i)) / 2.0
e = (y1 * (g + h + i) - y2 * (g - h + i)) / 2.0
d = y1 * (g + h + i) - f - e
c = (x1 * (g + h + i) + x3 * (-g - h + i)) / 2.0
b = (x1 * (g + h + i) - x2 * (g - h + i)) / 2.0
a = x1 * (g + h + i) - c - b
return Matrix(a, d, b, e, c, f)
这是 [1, 1], [1, -1], [-1, -1], [-1, 1] 到 P1, P2, P3, P4 给出的空间的映射。
要使其真正有用,您需要的是更有用的映射矩阵函数:
def map(p1, p2, p3, p4, p5, p6, p7, p8):
m1 = perspective(p1, p2, p3, p4)
m2 = perspective(p5, p6, p7, p8)
return ~m1 * m2
这里的
~
表示矩阵求逆,乘法是矩阵串联。这为您提供了将 4 点映射到 4 点的非常有用的功能。并求解实现这一点的矩阵。
现在,有一些注意事项。首先,您实际上可以将其写为整个矩阵。我们在许多变换中看到的 3x3 矩阵实际上通常有一个第三行,即
0,0,1
许多系统现在会给你一个 3x2 矩阵,这里的代码正在处理仿射矩阵,这就是区别。
当
g, h, i
等于0, 0, 1
时,矩阵是仿射的。如果我们有 g 和 h 的实际值,这些值有时在列出它们的某些矩阵公式中称为 PERSPECTIVE_X 和 PERSPECTIVE_Y。原因是,只有在矩阵不是仿射的情况下,它们才是实际给定的值,也就是说,应用矩阵之前的平行线在应用矩阵之后仍然是平行线。
您实际上还可以在完整的 3x3 矩阵中使用这组附加值,它可以让您进行视角更改。因此,如果移动一个角,它仍然会解出完整的 3x3 矩阵。
这实际上解决了点从一个空间到另一个空间的投影。如果变换是仿射的,您将得到
g
和 h
的零。如果没有,您将在那里获得价值。这仍然是一个常规变换矩阵,将您的点乘以矩阵将得到结果点,但该变换中的线可能不会保持平行。但是,如果将第一组点映射到第二组点,使得它们“仅”保持仿射,则这将仅求解变换矩阵。这也非常有用。
另请参阅:
https://math.stackexchange.com/questions/186286/get-transformation-matrix-from-points如果您实际上关心仿射矩阵,您实际上可以使用单位平方并简化事情。因此,如果您的角点在仿射空间中为:(0,0)、(1, 0)、(1, 1)、(0, 1),并且您将其映射到您的点,则方程为:
a = x4 - x1
b = x2 - x1
c = x1
d = y4 - y1
e = y2 - y1
f = y1
记住 x3,y3 从未被使用过。如果我们说这是一个仿射矩阵,那么该点绝对必须位于给定位置并不重要,因为在仿射空间中线保持平行。请参阅:数学证明
来证明这些方程。在上面给出的过程中,您可以将 8 个点映射在一起(或者实际上是 6 个点,因为仿射不需要最后一个点)。 如果添加的话,
rw (by ring: x4 - x1 + (x2 - x1) + x1 = x4 - x1 + x2) at h5,
rw (by ring: y4 - y1 + (y2 - y1) + y1 = y4 - y1 + y2) at h6,
rw eq_comm at h6 h5,
在位之后,它将最终方程重写为:
h5 : x3 = x4 - x1 + x2,
h6 : y3 = y4 - y1 + y2
这本质上是对 x3 和 y3 位置的要求,以使目标保持正确。 h5 和 h6 是真实的当且仅当空间该空间是仿射的。