11

I want to multiply 2 quaternions, which are stored in a cv::Mat structure. I want the function to be as efficient as possible. I have the following code so far:

/** Quaternion multiplication
 *
 */
void multiplyQuaternion(const Mat& q1,const Mat& q2, Mat& q)
{
    // First quaternion q1 (x1 y1 z1 r1)
    const float x1=q1.at<float>(0);
    const float y1=q1.at<float>(1);
    const float z1=q1.at<float>(2);
    const float r1=q1.at<float>(3);

    // Second quaternion q2 (x2 y2 z2 r2)
    const float x2=q2.at<float>(0);
    const float y2=q2.at<float>(1);
    const float z2=q2.at<float>(2);
    const float r2=q2.at<float>(3);


    q.at<float>(0)=x1*r2 + r1*x2 + y1*z2 - z1*y2;   // x component
    q.at<float>(1)=r1*y2 - x1*z2 + y1*r2 + z1*x2;   // y component
    q.at<float>(2)=r1*z2 + x1*y2 - y1*x2 + z1*r2;   // z component
    q.at<float>(3)=r1*r2 - x1*x2 - y1*y2 - z1*z2;   // r component
}

Is this the fastest way with OpenCV? Would it be fastest using fixed-point arithmetic?

Martin B
  • 23,670
  • 6
  • 53
  • 72
Jav_Rock
  • 22,059
  • 20
  • 123
  • 164
  • 3
    16 multiplications and 12 additions -- there does not seem to be much room for improvement to me. Make the function inline! I hope these "at" calls are not function calls (i.e., they should be inline). – JohnB May 28 '12 at 07:54
  • It is an openCV member of the Mat class. I think it is the quickest method to acces a Mat elment, but I am not sure. http://opencv.willowgarage.com/documentation/cpp/basic_structures.html#mat – Jav_Rock May 28 '12 at 08:35
  • 4
    As efficient as possible? Don't use a matrix class that does dynamic memory allocation and reference counting for something as trivial as a four-component array in the first place. That's exactly a perfect use case for the new `Matx` class, in reference to one of your other questions. – Christian Rau Jun 08 '12 at 19:29
  • mmm, I have to try that new class, thanks – Jav_Rock Jun 11 '12 at 06:14
  • 1
    It -might- be worth setting up a 4X4 from shuffled versions of q2, and matrix multiply; kind of emulate what the bullet physics code does. With SSE4, opencv -should- have a pretty tight matrix multiply. – Bobbi Bennett Jun 12 '12 at 03:23
  • It might be a bit faster with the quaternions stored in cv::Vec4f, which is just an array of 4 floats, no overhead. If you need to still have some stored in cv::Mat (1 row, 4 col, CV_32FC1) you can convert by using `mat.at(0,0)` which gives a ref to the same data as a cv::Vec4f (Vec4f is just a specialization of subclass of Matx which @ChristianRau refers to) – greggo Feb 28 '17 at 17:54

3 Answers3

4

In this tutorial different ways to access different pixels are covered. The Mat::at function was found to be about 10% slower in comparison to direct pixel access, probably due to the extra check in debug mode.

If you are really off for performance, you should rewrite your method with the 3 different methods mentioned in the text and then profile to find the one which is best in your situation.

Stephan Dollberg
  • 32,985
  • 16
  • 81
  • 107
2

There -had- been an ARM vector floating point quaternion multiply out there I can not find now. I could find this SIMD library:

Bullet 3D Game Multiphysics Library

Bobbi Bennett
  • 1,636
  • 1
  • 11
  • 13
0

Quaternions are often used to rotate 3D vectors so you might consider checking that one quaternion is a pure vector (i.e., the scalar or real part is zero). This could cut your work to 12 multiplies, 8 adds/subtracts and one sign flip.

You can also use quaternion multiplication on two pure vectors to compute their dot and cross products simultaneously, so testing for this special case may also be worth it. If both quaternions are pure vectors, you only need do 9 multiplies, 5 add/subtracts and one sign flip.

Phil Karn
  • 101
  • 1
  • Indeed, or write and use a routine which does the whole op: ` vec_rotated = q * (0,vec)*q.conj()` in one function call, some operations are saved compared to doing two full quaternion products (the second prod always has a zero real part). If you need to rotate a lot of vectors by the same quaternion - especially if they are stored in a matrix - it's faster to convert the quaternion to a 3x3 rotation matrix and use that on the vectors. – greggo Feb 28 '17 at 18:04