È possibile calcolare il quaternione che rappresenta la migliore trasformazione possibile da una sistema di coordinate a un altro con il metodo descritto in questo documento:
Paul J. Besl e Neil D. McKay "Metodo per la registrazione di forme 3D", Sensor Fusion IV: Paradigmi di controllo e strutture dati, 586 (30 aprile 1992); http://dx.doi.org/10.1117/12.57955
La carta non è l'accesso aperto, ma posso mostrarvi l'implementazione di 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
Questa funzione restituisce il quaternione che stavate cercando. Gli argomenti lst1 e lst2 sono elenchi di numpy.array in cui ogni matrice rappresenta un vettore 3D. Se entrambe le liste sono di lunghezza 3 (e contengono vettori di unità ortogonali), il quaternione dovrebbe essere la trasformazione esatta. Se fornisci elenchi più lunghi, ottieni il quaternione che riduce al minimo la differenza tra entrambi i gruppi di punti. L'argomento della lista di corrispondenze opzionale viene utilizzato per indicare alla funzione quale punto di lst2 deve essere trasformato in quale punto in lst1. Se non viene fornito matchlist, la funzione presuppone che il primo punto in LST1 dovrebbe corrispondere al primo punto LST2 ecc ...
Una funzione analoga per gruppi di 3 punti in C++ è il seguente:
#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;
}
sebbene il codice fosse interessante, in realtà non risolveva il mio problema. Alla fine ho usato una Direction Cosinus Matrix (DCM) per fare il lavoro.Sono ancora interessato se qualcuno è in grado di fornire un metodo per ottenere il quaternario di trasformazione, ma non sono sicuro che sia possibile ottenere direttamente questo quaternion senza utilizzare Euler o DCM. – Mo3bius