można obliczyć kwaternion reprezentującej najlepszą możliwą przemianę z jednego układ współrzędnych do innego metodą opisaną w tym dokumencie:
Paul J. Besl i Neil D. McKay "Metoda rejestracji kształtów 3D", Sensor Fusion IV: Paradygmaty sterowania i struktury danych, 586 (30 kwietnia 1992 r.); http://dx.doi.org/10.1117/12.57955
Papier nie jest otwarty dostęp, ale mogę pokazać realizację 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
ta funkcja zwraca kwaternion że szukaliśmy. Argumenty lst1 i lst2 są listami numpy.tablice, w których każda tablica reprezentuje wektor 3D. Jeżeli obie listy mają długość 3 (i zawierają ortogonalne wektory jednostkowe), kwaternionem powinna być dokładna transformacja. Jeśli podajesz dłuższe listy, otrzymujesz kwaternion, który minimalizuje różnicę między obydwoma zestawami punktów. Opcjonalny argument listy meczowej służy do informowania funkcji, który punkt lst2 powinien zostać przekształcony, do którego punktu w lst1. Jeśli nie matchlist jest funkcja zakłada, że pierwszy punkt w lst1 powinien pasować pierwszy punkt w lst2 i tak dalej ...
Podobna funkcja do zestawów 3 punkty w C++ jest następujący:
#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;
}
Chociaż twój kod był interesujący, to tak naprawdę nie rozwiązał mojego problemu. W końcu użyłem do tego celu Direction Cosinus Matrix (DCM).Nadal jestem zainteresowany, jeśli ktoś może zapewnić metodę uzyskiwania przekształceń kwaterunkowych, ale nie jestem pewien, czy możliwe jest uzyskanie tego quaternion bezpośrednio, bez użycia Eulera lub DCM. – Mo3bius