17

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

来自solvePnP的平移向量是否等于欧拉角。翻译矩阵是唯一与罗德里格斯有关的东西吗?还是有与 3 个欧拉角完全不同的特殊罗德里格斯角?两者之间的数学如何?有没有我找不到的 OpenCV 函数?

4

3 回答 3

79

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

Rodrigues 参数也称为轴角旋转。它们由 4 个数字组成[theta, x, y, z],这意味着您必须围绕单位向量描述的轴旋转一个角度“theta” v=[x, y, z]。查看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 向量与欧拉角符号甚至没有一点关系,欧拉角符号表示围绕 X、Y 和 Z 轴组合的三个连续旋转。

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

  1. 将两个旋转都转换为矩阵表示法(四元数也是有效的)
    • OpenCV Rodrigues 向量可以使用cv::Rodrigues函数转换为矩阵
    • 对于将欧拉转换为矩阵,我建议您查看euclideanspace.com的转换部分
  2. 从另一个旋转中“减去”一个旋转,即将一个旋转与另一个旋转连接起来
    • 使用旋转矩阵,将一个乘以另一个的转置(逆旋转)。空旋转是单位矩阵。
    • 使用四元数,将一个乘以另一个的复共轭(否定最后三个分量)。
  3. 检查结果是否接近零旋转:
    • 空旋转矩阵是恒等式。
    • 空四元数在第一个分量中有 1 或 -1
于 2012-10-19T15:07:27.070 回答
4

添加到@dunadar 的出色答案:

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

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

于 2016-04-08T18:29:26.340 回答
1

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

// 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 旋转,否则您可能会得到奇怪的结果。

于 2017-04-04T08:43:32.880 回答