我想对此示例数据集执行转换 在一个坐标[primary_system]系统中有四个已知的坐标为x,y,z的点和接下来的四个已知的坐标为x,y,h的点属于另一个坐标系[secondary_system]。 那些点对应;例如,primary_system1 point和secondary_system1点完全相同,但我们在两个不同的坐标系中有它的坐标。 所以我这里有四对调整点,并希望根据调整将另一个点坐标从主系统转换为二次系统。
primary_system1 = (3531820.440, 1174966.736, 5162268.086)
primary_system2 = (3531746.800, 1175275.159, 5162241.325)
primary_system3 = (3532510.182, 1174373.785, 5161954.920)
primary_system4 = (3532495.968, 1175507.195, 5161685.049)
secondary_system1 = (6089665.610, 3591595.470, 148.810)
secondary_system2 = (6089633.900, 3591912.090, 143.120)
secondary_system3 = (6089088.170, 3590826.470, 166.350)
secondary_system4 = (6088672.490, 3591914.630, 147.440)
#transform this point
x = 3532412.323
y = 1175511.432
z = 5161677.111<br>
目前我尝试使用四对点中的每一对来平均x,y和z轴的平移,例如:
#x axis
xt1 = secondary_system1[0] - primary_system1[0]
xt2 = secondary_system2[0] - primary_system2[0]
xt3 = secondary_system3[0] - primary_system3[0]
xt4 = secondary_system4[0] - primary_system4[0]
xt = (xt1+xt2+xt3+xt4)/4 #averaging
......依此类推y轴和z轴
#y axis
yt1 = secondary_system1[1] - primary_system1[1]
yt2 = secondary_system2[1] - primary_system2[1]
yt3 = secondary_system3[1] - primary_system3[1]
yt4 = secondary_system4[1] - primary_system4[1]
yt = (yt1+yt2+yt3+yt4)/4 #averaging
#z axis
zt1 = secondary_system1[2] - primary_system1[2]
zt2 = secondary_system2[2] - primary_system2[2]
zt3 = secondary_system3[2] - primary_system3[2]
zt4 = secondary_system4[2] - primary_system4[2]
zt = (zt1+zt2+zt3+zt4)/4 #averaging
所以上面我试图计算每个轴的平均平移向量
答案 0 :(得分:9)
如果它只是翻译和旋转,那么这是一种称为affine transformation的转换。
它基本上采用以下形式:
secondary_system = A * primary_system + b
其中A
是一个3x3矩阵(因为你是3D),而b
是一个3x1的翻译。
这可以等同地写成
secondary_system_coords2 = A2 * primary_system2,
其中
secondary_system_coords2
是向量[secondary_system,1]
,primary_system2
是向量[primary_system,1]
和 A2
是4x4矩阵:
[ A b ]
[ 0,0,0,1 ]
(有关详情,请参阅维基页面)。
所以基本上,你想要解决这个等式:
y = A2 x
代表A2
,其中y
由来自secondary_system
的点组成,其中1个卡在最后,而x
是来自primary_system
的点,其中1个卡在上面最后,A2
是一个4x4矩阵。
现在,如果x
是一个方阵,我们可以解决它:
A2 = y*x^(-1)
但是x
是4x1。但是,你很幸运,拥有{em> 4个的x
套{4}套y
,所以你可以构建一个像{4}这样的x
:< / p>
x = [ primary_system1 | primary_system2 | primary_system3 | primary_system4 ]
其中每个primary_systemi
是4x1列向量。与y
相同。
获得A2
后,要将一个点从system1转换为系统2,您只需执行以下操作:
transformed = A2 * point_to_transform
你可以这样设置(例如在numpy
中):
import numpy as np
def solve_affine( p1, p2, p3, p4, s1, s2, s3, s4 ):
x = np.transpose(np.matrix([p1,p2,p3,p4]))
y = np.transpose(np.matrix([s1,s2,s3,s4]))
# add ones on the bottom of x and y
x = np.vstack((x,[1,1,1,1]))
y = np.vstack((y,[1,1,1,1]))
# solve for A2
A2 = y * x.I
# return function that takes input x and transforms it
# don't need to return the 4th row as it is
return lambda x: (A2*np.vstack((np.matrix(x).reshape(3,1),1)))[0:3,:]
然后像这样使用它:
transformFn = solve_affine( primary_system1, primary_system2,
primary_system3, primary_system4,
secondary_system1, secondary_system2,
secondary_system3, secondary_system4 )
# test: transform primary_system1 and we should get secondary_system1
np.matrix(secondary_system1).T - transformFn( primary_system1 )
# np.linalg.norm of above is 0.02555
# transform another point (x,y,z).
transformed = transformFn((x,y,z))
注意:这里当然有数字错误,这可能不是解决转换的最佳方式(你可能能做某种最小二乘的事情)。
此外,将primary_systemx
转换为secondary_systemx
的错误(对于此示例)为10 ^( - 2)。
你必须考虑这是否可以接受(它确实看起来很大,但与你的输入点相比,这可能是可以接受的,这些输入点都是10 ^ 6的顺序)。
答案 1 :(得分:0)
您要查找的映射似乎是仿射变换。未位于一个平原中的四个3D点是恢复仿射变换所需的确切点数。从广义上讲,后者是矩阵相乘并加上一个向量
secondary_system = A * primary_system + t
现在,该问题减少为找到合适的矩阵A和向量t。我认为,这段代码可能会对您有所帮助(对不起,不好的代码风格-我是数学家,而不是程序员)
import numpy as np
# input data
ins = np.array([[3531820.440, 1174966.736, 5162268.086],
[3531746.800, 1175275.159, 5162241.325],
[3532510.182, 1174373.785, 5161954.920],
[3532495.968, 1175507.195, 5161685.049]]) # <- primary system
out = np.array([[6089665.610, 3591595.470, 148.810],
[6089633.900, 3591912.090, 143.120],
[6089088.170, 3590826.470, 166.350],
[6088672.490, 3591914.630, 147.440]]) # <- secondary system
p = np.array([3532412.323, 1175511.432, 5161677.111]) #<- transform this point
# finding transformation
l = len(ins)
entry = lambda r,d: np.linalg.det(np.delete(np.vstack([r, ins.T, np.ones(l)]), d, axis=0))
M = np.array([[(-1)**i * entry(R, i) for R in out.T] for i in range(l+1)])
A, t = np.hsplit(M[1:].T/(-M[0])[:,None], [l-1])
t = np.transpose(t)[0]
# output transformation
print("Affine transformation matrix:\n", A)
print("Affine transformation translation vector:\n", t)
# unittests
print("TESTING:")
for p, P in zip(np.array(ins), np.array(out)):
image_p = np.dot(A, p) + t
result = "[OK]" if np.allclose(image_p, P) else "[ERROR]"
print(p, " mapped to: ", image_p, " ; expected: ", P, result)
# calculate points
print("CALCULATION:")
P = np.dot(A, p) + t
print(p, " mapped to: ", P)
此代码演示了如何将仿射变换恢复为矩阵+向量,并测试了初始点已映射到其应有的位置。您可以使用Google colab测试此代码,因此无需安装任何程序。
关于此代码背后的理论:它基于“ Beginner's guide to mapping simplexes affinely”中给出的等式,在“规范表示法的恢复”部分描述了矩阵恢复,并在其中讨论了确定精确仿射变换所需的点数。 “我们需要多少点?”部分。同一作者发表了“ Workbook on mapping simplexes affinely”,其中包含许多此类实际示例。