简体   繁体   中英

Rodrigues into Eulerangles and vice versa

I am useing solvePnP and i am getting a translation vector. Now i need to compare some euler angles with those results from solvePnP. And i want/need to transfer the euler angles into "rodrigues";

Is the translation vector from solvePnP equal to euler angles. Is the translation matrix the only thing what has to do with Rodrigues? or are there special rodrigues angles which are totaly different to the 3 euler angles? How is the math between both? Is there an OpenCV function which i couldn't find?

First, forget about translation vector, because it is not related with rotation : translation moves things around, rotation changes their orientation.

Rodrigues parameters are also called axis-angle rotation . They are formed by 4 numbers [theta, x, y, z] , which means that you have to rotate an angle "theta" around the axis described by unit vector v=[x, y, z] . Looking at cv::Rodrigues function reference, it seems that OpenCV uses a "compact" representation of Rodrigues notation as vector with 3 elements rod2=[a, b, c] , where:

  • Angle to rotate theta is the module of input vector theta = sqrt(a^2 + b^2 + c^2)
  • Rotation axis v is the normalized input vector: v = rod2/theta = [a/theta, b/theta, c/theta]

So, Rodrigues vector from solvePnP is not even slightly related with Euler angles notation, which represent three consecutive rotations around a combination of X, Y and Z axes.

How to compare both rotations? This is a good question. Both Euler- and Rodrigues- representations have singularities and other problems. For instance, if you compare two Euler terns, or two Rodrigues parameters, they can look completely different but actually represent almost the same rotation. If you just need to check if both rotations are the same (or approx.), you can follow the next approach:

  1. Transform both rotations to matrix notation (quaternions are also valid)
    • OpenCV Rodrigues vector can be transformed to matrix using cv::Rodrigues function
    • For transforming Euler to matrix, I suggest you to take a look to conversions section of euclideanspace.com
  2. "Subtract" one rotation from the other, that is concatenating one with the inverse of the other
    • Using rotation matrices, multiply one by the transpose (inverse rotation) of the other one. Null rotation is the identity matrix.
    • Using quaternions, multiply one by the complex conjugate of the other (negate the three last components).
  3. Check if the result is close to a null rotation:
    • Null rotation matrix is the identity.
    • Null quaternion has a 1 or a -1 in the first component

Adding to @dunadar's excellent answer:

Rodrigues converts rvec into the rotation matrix R (and vice versa). You can directly use R in the same way you would use a rotation matrix constructed from Euler angles by taking the dot product with the (translation) vector you are rotating: v_rotate = R*v

You can convert from a Rodrigues rotation matrix into Euler angles, but there are multiple solutions. The reason is that the order of your Euler rotations (pitch, yaw, roll) matters, so there is more than one way to represent a Rodrigues rotation. See: http://www.staff.city.ac.uk/~sbbh653/publications/euler.pdf

Adding a more concrete answer to supplement the other answers here. If you desire a direction vector instead of Euler angles, the process can indeed be simplified with a matrix multiplication, here's a quick solution:

// The output is a direction vector in OpenGL coordinate system:
// +X is Right on the screen, +Y is Up, +Z is INTO the screen
static Vector3 ToDirectionVectorGL(const Mat& rodrigues1x3) noexcept
{
    Mat rotation3x3;
    cv::Rodrigues(rodrigues1x3, rotation3x3);

    // direction OUT of the screen in CV coordinate system, because we care
    // about objects facing towards us - you can change this to anything
    // OpenCV coordsys: +X is Right on the screen, +Y is Down on the screen,
    //                  +Z is INTO the screen
    Vec3d axis{ 0, 0, -1 }; 
    Mat direction = rotation3x3 * Mat(axis, false);

    // normalize to a unit vector
    double dirX = direction.at<double>(0);
    double dirY = direction.at<double>(1);
    double dirZ = direction.at<double>(2);
    double len = sqrt(dirX*dirX + dirY*dirY + dirZ*dirZ);
    dirX /= len;
    dirY /= len;
    dirZ /= len;
    // Convert from OpenCV to OpenGL 3D coordinate system
    return { float(dirX), float(-dirY), float(dirZ) };
}

If you are using this for head pose estimation, ensure the Rodrigues 1x3 rotation is formed properly around {0,0,0} or you might get odd results.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM