罗德里格斯进入Eulerangles,反之亦然

时间:2012-10-17 11:28:41

标签: c++ opencv rotation

我正在使用solvePnP,我正在使用翻译向量。 现在我需要将一些euler角度与solvePnP的结果进行比较。 我希望/需要将欧拉角转换为“罗德里格斯”;

solvePnP的平移向量是否等于欧拉角。 翻译矩阵是唯一与Rodrigues有关的东西吗? 或者是否有特殊的罗德里格角,它们与3个欧拉角完全不同? 两者之间的数学如何? 是否有OpenCV功能,我找不到?

3 个答案:

答案 0 :(得分:55)

首先,忘记翻译矢量,因为它与旋转无关:翻译会移动物体,旋转会改变它们的方向。

罗德里格斯参数也称为axis-angle rotation。它们由4个数字[theta, x, y, z]组成,这意味着您必须围绕单位向量v=[x, y, z]描述的轴旋转角度“theta”。 查看cv::Rodrigues函数引用,似乎OpenCV使用Rodrigues表示法的“紧凑”表示作为具有3个元素rod2=[a, b, c]的向量,其中:

  • 要旋转的角度theta是输入向量theta = sqrt(a^2 + b^2 + c^2)
  • 的模块
  • 旋转轴v是规范化的输入向量:v = rod2/theta = [a/theta, b/theta, c/theta]

因此,来自solvePnP的 Rodrigues矢量与Euler angles 表示法甚至没有多少关系,表示围绕X,Y和Z轴的三个连续旋转。

如何比较两种旋转?这是一个很好的问题。 Euler和Rodrigues表示都有奇点和其他问题。例如,如果比较两个Euler燕鸥或两个Rodrigues参数,它们看起来可能完全不同,但实际上代表几乎相同的旋转。 如果你只是需要检查两个旋转是否相同(或大约),你可以按照下一个方法:

  1. 将两次旋转转换为矩阵表示法(四元数也有效)
    • 可以使用cv::Rodrigues函数
    • 将OpenCV Rodrigues矢量转换为矩阵
    • 为了将Euler转换为矩阵,我建议你看看euclideanspace.com的conversions section
  2. 从另一个“减去”一个旋转,即将一个旋转与另一个旋转连接
    • 使用旋转矩阵,乘以另一个的转置(反向旋转)。空旋转是单位矩阵。
    • 使用四元数,将一个乘以另一个的复共轭(否定最后三个成分)。
  3. 检查结果是否接近空转:
    • 空旋转矩阵是身份。
    • Null quaternion在第一个组件中有1或-1

答案 1 :(得分:3)

添加@dunadar的优秀答案:

Rodriguesrvec转换为旋转矩阵R(反之亦然)。你可以直接使用R,就像使用由欧拉角构造的旋转矩阵一样,通过将点积与你正在旋转的(平移)矢量一起使用:v_rotate = R*v

可以从罗德里格斯旋转矩阵转换为欧拉角,但有多种解决方案。原因是你的欧拉旋转(俯仰,偏航,滚转)的顺序很重要,所以有不止一种方法来表示罗德里格斯旋转。请参阅:http://www.staff.city.ac.uk/~sbbh653/publications/euler.pdf

答案 2 :(得分:0)

在此处添加更具体的答案以补充其他答案。如果你想要一个方向向量而不是欧拉角,那么这个过程确实可以通过矩阵乘法来简化,这是一个快速的解决方案:

// 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) };
}

如果您将此用于头部姿势估计,请确保在{0,0,0}附近正确形成Rodrigues 1x3旋转,否则您可能会得到奇怪的结果。