You can calculate the quaternion representing the best possible transformation from one coordinate system to another, using the method described in this article:
Paul J. Besle and Neil D. Mackay, βMethod for Recording Three-Dimensional Figures,β Sensor Fusion IV: Paradigms of Control and Data Structure, 586 (April 30, 1992); http://dx.doi.org/10.1117/12.57955
The document is not open access, but I can show you a Python implementation:
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
This function returns the quaternion you were looking for. The arguments lst1 and lst2 are lists of numpy.arrays, where each array represents a three-dimensional vector. If both lists have a length of 3 (and contain orthogonal unit vectors), the quaternion must be an exact transformation. If you provide longer lists, you will get a quaternion that minimizes the difference between both sets of points. The optional matchlist argument is used to tell the function which point lst2 should be converted to which point in lst1. If no match list is provided, the function assumes that the first point in lst1 must match the first point in lst2, and so on ...
A similar function for 3-point sets in C ++ is as follows:
#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; }