2013-05-20 56 views
6

我有與已知的單位矢量2個笛卡兒座標系統:2三維笛卡爾之間變換計算四元數座標系統

系統A(x_A,Y_A,z_A)

體系B(x_B ,y_B,z_B)

兩個系統共享相同的原點(0,0,0)。我試圖計算一個四元數,以便系統B中的向量可以在系統A中表示。

我熟悉四元數的概念。我已經從這裏實施了所需的數學計算:http://content.gpwiki.org/index.php/OpenGL%3aTutorials%3aUsing_Quaternions_to_represent_rotation

一個可能的解決方案可能是計算歐拉角並將它們用於3個四元數。將它們相乘將導致最後一節,這樣我就可以改變我的載體:

V(A)= Q * V(B)* q_conj

但是,這將再次納入萬向鎖,這是原因不要在開始時使用歐拉角。

任何idead如何解決這個問題?

回答

1

什麼語言是您使用?如果C++,隨意使用我的開源庫:

http://sourceforge.net/p/transengine/code/HEAD/tree/transQuaternion/

這樣做的缺點是,你需要將自己的向量轉換爲四元數,做你的計算,然後你的四元數轉換爲轉型矩陣。

這裏有一個代碼片段:

cQuat nTrans::quatFromVec(Vec vec) { 
    float angle = vec.v[3]; 
    float s_angle = sin(angle/2); 
    float c_angle = cos(angle/2); 
    return (cQuat(c_angle, vec.v[0]*s_angle, vec.v[1]*s_angle, 
        vec.v[2]*s_angle)).normalized(); 
} 

而且從四元數矩陣:

Matrix nTrans::matFromQuat(cQuat q) { 
    Matrix t; 
    q = q.normalized(); 
    t.M[0][0] = (1 - (2*q.y*q.y + 2*q.z*q.z)); 
    t.M[0][1] = (2*q.x*q.y + 2*q.w*q.z);   
    t.M[0][2] = (2*q.x*q.z - 2*q.w*q.y); 
    t.M[0][3] = 0; 
    t.M[1][0] = (2*q.x*q.y - 2*q.w*q.z);   
    t.M[1][1] = (1 - (2*q.x*q.x + 2*q.z*q.z)); 
    t.M[1][2] = (2*q.y*q.z + 2*q.w*q.x);   
    t.M[1][3] = 0; 
    t.M[2][0] = (2*q.x*q.z + 2*q.w*q.y);  
    t.M[2][1] = (2*q.y*q.z - 2*q.w*q.x);   
    t.M[2][2] = (1 - (2*q.x*q.x + 2*q.y*q.y)); 
    t.M[2][3] = 0; 
    t.M[3][0] = 0;     
    t.M[3][1] = 0;     
    t.M[3][2] = 0;    
    t.M[3][3] = 1; 
    return t; 
} 
+0

雖然你的代碼很有趣,但它並沒有真正解決我的問題。最後,我使用了方向餘弦矩陣(DCM)來完成這項工作。如果有人能夠提供獲取轉換四元數的方法,我仍然感興趣,但我不確定是否可以直接獲取這個四元數而不使用Euler或DCM。 – Mo3bius

4

可以計算出四元代表來自一個最佳的轉型

從向量四元通過本文描述的方法將座標系統轉換爲另一個座標系統:

Paul J.Besl和Neil D.McKay 「三維形狀的配準方法」,Sensor Fusion IV:Control Paradigms and Data Structures,586(1992年4月30日); http://dx.doi.org/10.1117/12.57955

本文不開放訪問,但我可以告訴你的Python實現:

def get_quaternion(lst1,lst2,matchlist=None): 
if not matchlist: 
    matchlist=range(len(lst1)) 
M=np.matrix([[0,0,0],[0,0,0],[0,0,0]]) 

for i,coord1 in enumerate(lst1): 
    x=np.matrix(np.outer(coord1,lst2[matchlist[i]])) 
    M=M+x 

N11=float(M[0][:,0]+M[1][:,1]+M[2][:,2]) 
N22=float(M[0][:,0]-M[1][:,1]-M[2][:,2]) 
N33=float(-M[0][:,0]+M[1][:,1]-M[2][:,2]) 
N44=float(-M[0][:,0]-M[1][:,1]+M[2][:,2]) 
N12=float(M[1][:,2]-M[2][:,1]) 
N13=float(M[2][:,0]-M[0][:,2]) 
N14=float(M[0][:,1]-M[1][:,0]) 
N21=float(N12) 
N23=float(M[0][:,1]+M[1][:,0]) 
N24=float(M[2][:,0]+M[0][:,2]) 
N31=float(N13) 
N32=float(N23) 
N34=float(M[1][:,2]+M[2][:,1]) 
N41=float(N14) 
N42=float(N24) 
N43=float(N34) 

N=np.matrix([[N11,N12,N13,N14],\ 
       [N21,N22,N23,N24],\ 
       [N31,N32,N33,N34],\ 
       [N41,N42,N43,N44]]) 


values,vectors=np.linalg.eig(N) 
w=list(values) 
mw=max(w) 
quat= vectors[:,w.index(mw)] 
quat=np.array(quat).reshape(-1,).tolist() 
return quat 

這個函數返回你要找的四元數。參數lst1和lst2是numpy列表。每個數組代表一個3D矢量的數組。如果兩個列表的長度都是3(並且包含正交單位矢量),則四元數應該是確切的變換。如果你提供更長的列表,你會得到四元數,這是最小化兩個點集之間的差異。 可選的matchlist參數用於告訴函數lst2中的哪個點應該轉換爲lst1中的哪個點。如果沒有提供matchlist,函數假定在LST1第一點應該與LST2等等第一點...

爲套在C++ 3點A類似的功能如下:

#include <Eigen/Dense> 
#include <Eigen/Geometry> 

using namespace Eigen; 

/// Determine rotation quaternion from coordinate system 1 (vectors 
/// x1, y1, z1) to coordinate system 2 (vectors x2, y2, z2) 
Quaterniond QuaternionRot(Vector3d x1, Vector3d y1, Vector3d z1, 
          Vector3d x2, Vector3d y2, Vector3d z2) { 

    Matrix3d M = x1*x2.transpose() + y1*y2.transpose() + z1*z2.transpose(); 

    Matrix4d N; 
    N << M(0,0)+M(1,1)+M(2,2) ,M(1,2)-M(2,1)   , M(2,0)-M(0,2)   , M(0,1)-M(1,0), 
     M(1,2)-M(2,1)   ,M(0,0)-M(1,1)-M(2,2) , M(0,1)+M(1,0)   , M(2,0)+M(0,2), 
     M(2,0)-M(0,2)   ,M(0,1)+M(1,0)   ,-M(0,0)+M(1,1)-M(2,2) , M(1,2)+M(2,1), 
     M(0,1)-M(1,0)   ,M(2,0)+M(0,2)   , M(1,2)+M(2,1)   ,-M(0,0)-M(1,1)+M(2,2); 

    EigenSolver<Matrix4d> N_es(N); 
    Vector4d::Index maxIndex; 
    N_es.eigenvalues().real().maxCoeff(&maxIndex); 

    Vector4d ev_max = N_es.eigenvectors().col(maxIndex).real(); 

    Quaterniond quat(ev_max(0), ev_max(1), ev_max(2), ev_max(3)); 
    quat.normalize(); 

    return quat; 
} 
+0

btw,https://scholar.google.com/scholar?q="Method+for+registration+of+3-D+shapes「似乎在網絡上找到大量副本;不幸的是,我沒有在作者的網站上發現任何信息,也沒有發現一個開放獲取的檔案(可能會保留一段時間),主要是在課程網站上。 – SamB

1

我剛碰到這個相同的問題。我正在尋找解決方案,但我陷入困境。

所以,你需要兩個座標系中已知的向量。在我的情況下,我在設備的座標系(重力和磁場)中有2個正交向量,我想要找到四元數從設備座標旋轉到全局方向(其中,北是正Y,「向上」是正Z)。所以,就我而言,我測量了設備座標空間中的矢量,並且我定義了矢量本身以形成全局系統的標準正交基。

考慮到這一點,考慮四元數的軸角解釋,有一些向量V,器件的座標可以通過某個角度旋轉以匹配全局座標。我會打電話給我的(負)重力矢量G和磁場M(均歸一化)。

V,G和M都描述了單位球面上的點。 所以Z_dev和Y_dev(Z和Y是我設備座標系的基礎)。 目標是找到將G映射到Z_dev並將M映射到Y_dev的旋轉。 對於V將G旋轉到Z_dev上,由G和V定義的點之間的距離必須與由V和Z_dev定義的點之間的距離相同。在等式中:

| V-G | = | V - Z_dev |

該等式的解決方案形成一個平面(所有點與G和Z_dev等距)。但是,V被限制爲單位長度,這意味着解決方案是一個以原點爲中心的環 - 仍然是無限多個點。

但是,同樣的情況是Y_dev,男和V的真實:

| V - M | = | V - Y_dev |

對此的解決方案也是一個以原點爲中心的環。這些環有兩個交點,其中一個是另一個的負值。要麼是有效的旋轉軸(在一種情況下,旋轉角度只是負值)。

使用上述兩個方程,而事實上,每個這些載體是單位長度,你應該能夠以求解V.

然後,你只需要找到該角度通過旋轉,這應該是能夠使用從V到你的對應基地(G和Z_dev對我來說)的載體。

最終,我在代數的最後解決了V ..但無論如何,我認爲你需要的一切都在這裏 - 也許你會比我有更好的運氣。

相關問題