Quaternions

Mindmap

What's that?

  • quaternions have 4 parameters
  • they form an algebra with 3 operations
  • while the addition and the scalar multiplication is as in R^4
  • the multiplication of two quaternions is non-commutative
  • as the 3D rotations in space!
  • unit quaternions can be used to represent 3D rotations

Pros/Cons for quaternions?

Advantages compared to Euler angles:

  • no gimbal lock
  • no singularities
  • successive rotations can be expressed by multiplication of quaternions
  • rotate a vector x given a quaternion q: q * x * q^(-1)
  • interpolating rotations can also be done easily with quaternions (SLERP)

Disadvantages compared to Euler angles:

  • non-minimal representation: we have 4 numbers to encode a 3DOF rotation

Was is a good intiution for quaternions?

There is a strong connection between the (i) axis-angle and the (ii) quaternions representation for 3D rotations.

Axis-angle to quaternions

Assume you have an axis-angle representation of a 3D rotation given by some unit vector v=(x,y,z) and an angle alpha.

Then

q = cos(alpha/2) + i (x*sin(alpha/2)) + j (y*sin(alpha/2)) + k (z*sin(alpha/2))

is the corresponding unit quaternion that represents the same 3D rotation.

So you can think of a quaternion to be similar to an axis-angle representation except that the real part is equal to cos(alpha/2) and the imaginery part is made up of the axis vector times sin(angle/2).

Quaternion to axis-angle

Given q = [a,b,c,d], we can compute the axis-angle representation by

alpha = 2*acos(a)

axis = (b,c,d)^T / ||(b,c,d)^T||

Source

Quotations about quaternions


Quaternions are a cool mathematical construct that lets you represent an arbitrary rotation as a 4D vector. The 3D XYZ parts of the vector give the rotation axis for the direction. The magnitude of the 3D part is the sine of half the rotation angle; the cosine of half the rotation angle is stored in the final W component of the vector.

It's a strange definition, but the neat part is that 'multiplying' quaternions (using a cross product looking formula) gives you the composition of the underlying rotations.

Source

Good sources to read further

Conversion code: rotation matrix to quaternion

Here I found C++ code that works stable:

inline float SIGN(float x)
             {return (x >= 0.0f) ? +1.0f : -1.0f;}
inline float NORM(float a, float b, float c, float d)
             {return sqrt(a * a + b * b + c * c + d * d);}
 
static quaternion get_quaternion_from_rot_mat(cv::Mat& rotMat)
{
	float r11 = rotMat.at<float>(0,0);
	float r21 = rotMat.at<float>(1,0);
	float r31 = rotMat.at<float>(2,0);
 
	float r12 = rotMat.at<float>(0,1);
	float r22 = rotMat.at<float>(1,1);
	float r32 = rotMat.at<float>(2,1);
 
	float r13 = rotMat.at<float>(0,2);
	float r23 = rotMat.at<float>(1,2);
	float r33 = rotMat.at<float>(2,2);
 
	float q0 = ( r11 + r22 + r33 + 1.0f) / 4.0f;
	float q1 = ( r11 - r22 - r33 + 1.0f) / 4.0f;
	float q2 = (-r11 + r22 - r33 + 1.0f) / 4.0f;
	float q3 = (-r11 - r22 + r33 + 1.0f) / 4.0f;
	if(q0 < 0.0f) q0 = 0.0f;
	if(q1 < 0.0f) q1 = 0.0f;
	if(q2 < 0.0f) q2 = 0.0f;
	if(q3 < 0.0f) q3 = 0.0f;
	q0 = sqrt(q0);
	q1 = sqrt(q1);
	q2 = sqrt(q2);
	q3 = sqrt(q3);
	if(q0 >= q1 && q0 >= q2 && q0 >= q3) {
	    q0 *= +1.0f;
	    q1 *= SIGN(r32 - r23);
	    q2 *= SIGN(r13 - r31);
	    q3 *= SIGN(r21 - r12);
	} else if(q1 >= q0 && q1 >= q2 && q1 >= q3) {
	    q0 *= SIGN(r32 - r23);
	    q1 *= +1.0f;
	    q2 *= SIGN(r21 + r12);
	    q3 *= SIGN(r13 + r31);
	} else if(q2 >= q0 && q2 >= q1 && q2 >= q3) {
	    q0 *= SIGN(r13 - r31);
	    q1 *= SIGN(r21 + r12);
	    q2 *= +1.0f;
	    q3 *= SIGN(r32 + r23);
	} else if(q3 >= q0 && q3 >= q1 && q3 >= q2) {
	    q0 *= SIGN(r21 - r12);
	    q1 *= SIGN(r31 + r13);
	    q2 *= SIGN(r32 + r23);
	    q3 *= +1.0f;
	} else {
	    printf("coding error\n");
	}
	float r = NORM(q0, q1, q2, q3);
	q0 /= r;
	q1 /= r;
	q2 /= r;
	q3 /= r;
 
	quaternion q;
	q.x = q0;
	q.y = q1;
	q.z = q2;
	q.w = q3;
 
	return q;
 
} // get_quaternion_from_rot_mat

Conversion code: quaternion to rotation matrix

static cv::Mat get_rot_mat_from_quaternion_values
               (float q0, float q1, float q2, float q3)
{
	cv::Mat rotMat(3,3, CV_32FC1);
 
	float q0q0 = q0*q0;
	float q1q1 = q1*q1;
	float q2q2 = q2*q2;
	float q3q3 = q3*q3;
 
	rotMat.at<float>(0,0) = q0q0 + q1q1 - q2q2 -q3q3;
	rotMat.at<float>(1,0)	= 2*(q1*q2 + q0*q3);
	rotMat.at<float>(2,0)	= 2*(q1*q3 - q0*q2);
 
	rotMat.at<float>(0,1)	= 2*(q1*q2 - q0*q3);
	rotMat.at<float>(1,1)	= q0q0 - q1q1 + q2q2 - q3q3;
	rotMat.at<float>(2,1)	= 2*(q2*q3 + q0*q1);
 
	rotMat.at<float>(0,2)	= 2*(q1*q3 + q0*q2);
	rotMat.at<float>(1,2)	= 2*(q2*q3 - q0*q1);
	rotMat.at<float>(2,2)	= q0q0 - q1q1 -q2q2 + q3q3;
 
	return rotMat;
 
} // get_rot_mat_from_quaternion

Videos

Gives some intuition

… and underlines the similarities of quaternions to the axis-angle representation.

Performing successive rotations by computing the product of quaternions

 
public/quaternions.txt · Last modified: 2014/01/18 13:53 (external edit) · []
Recent changes RSS feed Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki