【问题标题】:how to perform coordinates affine transformation using python?如何使用python执行坐标仿射变换?
【发布时间】:2012-01-15 21:20:39
【问题描述】:

我想对此示例数据集执行转换。
在一个坐标系[primary_system]中有四个坐标为x、y、z的已知点,接下来有四个坐标为x、y、h的已知点属于另一个坐标系[secondary_system]。 这些点对应;例如 primary_system1 点和 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

所以上面我尝试计算每个轴的平均平移向量

【问题讨论】:

  • 你的问题很模糊!这些数字是多少?
  • 那么,您尝试过什么?你有什么代码?
  • 问题不清楚。你到底想做什么?请编辑您的问题以澄清。
  • 这取决于两个坐标系是如何关联的——是旋转还是平移?或者更复杂的东西,比如 GPS -> UTM?
  • 我赞成这个问题以抵消反对票,因为这对我来说很清楚:)

标签: python coordinate-transformation


【解决方案1】:

如果只是平移和旋转,那么这就是称为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 ]
    

(有关更多信息,请参阅 wiki 页面)。

所以基本上,你想解方程:

y = A2 x

对于A2,其中y 由来自secondary_system 的点组成,1 卡在末端,x 是来自primary_system 的点,1 卡在末端,A2 是 4x4矩阵。

现在如果x 是一个方阵,我们可以像这样解决它:

A2 = y*x^(-1)

但是x 是 4x1。但是,您很幸运,拥有 4x 和 4 组对应的 y,因此您可以构造一个 4x4 的 x,如下所示:

x = [ primary_system1 | primary_system2 | primary_system3 | primary_system4 ]

primary_systemi 中的每一个都是一个 4x1 列向量。与y 相同。

一旦你有了A2,你就可以将一个点从系统1转换到系统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))

注意:这里当然存在数值错误,这可能不是解决变换的最佳方法(您也许可以做某种最小二乘法)。 p>

此外,将primary_systemx 转换为secondary_systemx 的错误(对于本示例)为 10^(-2) 阶。

您必须考虑这是否可以接受(它看起来确实很大,但与您的输入点相比可能是可以接受的,这些输入点都是 10^6 阶)。

【讨论】:

  • 非常感谢您的完整回答!
  • 可能是我见过的对这个问题最完整的答案之一。干得好。
【解决方案2】:

您正在寻找的映射似乎是仿射变换。不在一个平原上的四个 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”,其中包含许多此类实际示例。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2022-01-17
    • 1970-01-01
    • 1970-01-01
    • 2010-12-17
    • 1970-01-01
    • 2020-02-11
    相关资源
    最近更新 更多