簡體   English   中英

如何使用python執行坐標仿射變換?

[英]how to perform coordinates affine transformation using python?

我想為此示例數據集執行轉換。
在一個坐標[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

所以上面我嘗試計算每個軸的平均平移向量

如果它只是一個平移和旋轉,那么這就是一個稱為仿射變換的變換

它基本上采取以下形式:

secondary_system = A * primary_system + b

其中A是3x3矩陣(因為你是3D), b是3x1平移。

這可以等效地寫出來

secondary_system_coords2 = A2 * primary_system2,

哪里

  • secondary_system_coords2是vector [secondary_system,1]
  • primary_system2是vector [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。 但是,你很幸運,有4x和4個相應的y ,所以你可以像這樣構造一個4x4的x

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的順序)。

您正在尋找的映射似乎是仿射變換。 不在一個平原中的四個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測試此代碼,因此您無需安裝任何內容。

關於這段代碼背后的理論:它基於“ 初學者關於映射單純形的指南 ”中提出的等式,矩陣恢復在“規范符號的恢復”一節中描述,精確仿射變換所需的點數在“如何”中討論我們需要多少點?“ 部分。 同一作者發表了“ 關於映射單純形的工作手冊 ”,其中包含許多此類實例。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM