(请参阅此问题的底部以获取更新)
我绝不是数学专家,所以请原谅术语等方面的错误
在我的应用程序 (Python) 中,总是有一个稍微独特的可能输入坐标空间,可以用 4 边多边形来描述,这里显示了一个示例(预先调整为将质心直接放在原点上):
我想弄清楚如何描述将该空间转换为该受限空间的转换(或系列转换):
如果我能找到那个变换,那么稍后,当我在程序的使用过程中从用户那里得到一个单独的输入坐标时,我将应用相同的变换来给我一个单独的坐标值,该值将被约束到变换最后一张图片中描绘的坐标空间。
为了让最后一部分更清楚,这里是我所描述的图形,不按比例:
我不太精通线性代数(也许线性代数甚至都不是可行的方法?),所以也许我遗漏了一些明显的东西。我的计划如下:
设T为我要找的变换矩阵
设A为原始坐标矩阵
设 A_T 为变换后的坐标矩阵
A_T = T * A
因此,我认为我会通过说来隔离T:
T = A_T * 逆(A)
问题是,A 不是正方形,(因为它包含 4 个 2D 点),所以我无法计算它的逆。
基本上,我想描述从 (ax, ay) (bx, by) (cx, cy) (dx, dy) 到 (1, 0) (0, 1) (-1, 0) (0 , -1) 我现在没主意了。
更新
我一直在尝试改编@wychmaster 对这个问题的回答:
import numpy as np
x_all = [x - x_center for x in x_all]
y_all = [y - y_center for y in y_all]
# All x coordinates
x_all = [258.75, -401.25, -741.25, 883.75]
# All y coordinates
y_all = [156.25, 171.25, -188.75, -138.75]
# original coordinate matrix
A = np.array([x_all, y_all, [1, 1, 1, 1], [1, 1, 1, .9999999]])
# transformed coordinate matrix
A_T = np.array([[1, 0, -1, 0], [0, 1, 0, -1], [1, 1, 1, 1], [1, 1, 1, 1]])
# Solve for T where A_T = T @ A
T_1 = np.linalg.solve(A.transpose(), A_T.transpose()[:, 0])
T_2 = np.linalg.solve(A.transpose(), A_T.transpose()[:, 1])
T_3 = np.linalg.solve(A.transpose(), A_T.transpose()[:, 2])
T_4 = np.linalg.solve(A.transpose(), A_T.transpose()[:, 3])
T = np.array([T_1, T_2, T_3, T_4])
# Check to see if T @ A = A_T
print((T @ A).round(decimals=3))
# Multiply each original coordinate pair of the original coordinate space to see if they are correctly transformed
for i in range(4):
print((T @ np.matrix([[x_all[i]], [y_all[i]], [1], [1]])).round(decimals=3))
这实际上几乎有效,但有一个问题!
您会在第 12 行注意到,我在 A 矩阵的最后一行的最后一个元素中放入了一些可怕的 hackiness,这是我为了让它运行而添加的;否则 Python 会正确地抱怨这是一个奇异矩阵。当我乘以 T @ A 时,它正确地吐出 A_T。然而,当我单独乘以每个向量时,这类似于我将如何在程序中使用这个矩阵(将单个输入坐标转换为受限空间),.999999 值搞砸了最后一个坐标,这是输出打印乘法结果的 for 循环:
[[1.]
[0.]
[1.]
[1.]]
[[-0.]
[ 1.]
[ 1.]
[ 1.]]
[[-1.]
[ 0.]
[ 1.]
[ 1.]]
[[ 1.577]
[-2.104]
[ 1. ]
[ 1. ]]
如您所见,它几乎有效,只需要一种方法将任意值添加到最后一行。
在
对于任意大小的点集,使用
lstsq
。变换矩阵将是近似的。
import numpy as np
px_space = np.array((
( 487.5, 200),
(-412.5, 200),
(-762.5, -200),
( 687.5, -200),
))
px_space_augmented = np.hstack((px_space, np.ones((px_space.shape[0], 1))))
norm_space = np.array((
( 1, 0),
( 0, 1),
(-1, 0),
( 0, -1),
))
T, *_ = np.linalg.lstsq(px_space_augmented, norm_space)
print(T)
[[ 8.06866953e-04 -8.06866953e-04]
[ 2.34871245e-03 2.65128755e-03]
[-1.91559047e-36 -2.77555756e-17]]