OpenCV中的旋转矩阵转欧拉角

5
我正在进行一个涉及Aruco标记和OpenCV的项目。 我已经在项目进展中相当远了。我可以读取旋转向量并使用OpenCV中的rodrigues()将其转换为rodrigues矩阵。
这是我得到的一种rodrigues矩阵示例:
[0,1,0;
1,0,0;
0,0,-1]
我使用以下代码。
Mat m33(3, 3, CV_64F);
Mat measured_eulers(3, 1, CV_64F);
Rodrigues(rotationVectors, m33);

measured_eulers = rot2euler(m33);

Degree_euler = measured_eulers * 180 / CV_PI;

我使用预定义的rot2euler将罗德里格斯矩阵转换为欧拉角。 并将接收到的弧度转换为角度。
rot2euler看起来像下面这样。
Mat rot2euler(const Mat & rotationMatrix)
{
    Mat euler(3, 1, CV_64F);

    double m00 = rotationMatrix.at<double>(0, 0);
    double m02 = rotationMatrix.at<double>(0, 2);
    double m10 = rotationMatrix.at<double>(1, 0);
    double m11 = rotationMatrix.at<double>(1, 1);
    double m12 = rotationMatrix.at<double>(1, 2);
    double m20 = rotationMatrix.at<double>(2, 0);
    double m22 = rotationMatrix.at<double>(2, 2);

    double x, y, z;

    // Assuming the angles are in radians.
    if (m10 > 0.998) { // singularity at north pole
        x = 0;
        y = CV_PI / 2;
        z = atan2(m02, m22);
    }
    else if (m10 < -0.998) { // singularity at south pole
        x = 0;
        y = -CV_PI / 2;
        z = atan2(m02, m22);
    }
    else
    {
        x = atan2(-m12, m11);
        y = asin(m10);
        z = atan2(-m20, m00);
    }

    euler.at<double>(0) = x;
    euler.at<double>(1) = y;
    euler.at<double>(2) = z;

    return euler;
}

如果我使用作为示例的Rodrigues矩阵,我会得到以下欧拉角。
[0; 90; -180]
但是我应该得到以下结果。
[-180; 0; 90]
当我使用此工具http://danceswithcode.net/engineeringnotes/rotations_in_3d/demo3D/rotations_in_3d_tool.html时,您可以看到[0; 90; -180]与Rodrigues矩阵不匹配,但[-180; 0; 90]匹配。(我知道该工具使用ZYX坐标)
因此,问题在于我得到了正确的值,但顺序错误。
另一个问题是这并不总是这种情况。 例如,Rodrigues矩阵:
[1,0,0;
0,-1,0;
0,0,-1]
提供了正确的欧拉角。
如果有人知道如何解决这个问题或者能够向我提供一个关于rot2euler函数的详细解释,那将不胜感激。
顺祝商祺,
Brent Convens

1
两个不同的欧拉旋转可以表示相同的旋转。尝试使用反转换获取3x3矩阵。 - hiroki
看起来你遇到了奇异性的情况。据我所知,对于像90度或180度这样的角度,使用旋转矩阵并不方便(无论它们是正数还是负数),因为你有可能会遇到奇异性问题。而且公式似乎是错误的...可以参考这篇论文 - marcoresk
3个回答

4
我想我可能有点晚了,但我仍然会回答。 不要引用我的话,即我不能百分之百确定,但是这是一个文件({OPENCV_INSTALLATION_DIR}/apps/interactive-calibration/rotationConverters.cpp),来自OpenCV 3.3的源代码之一。

enter image description here

在我看来,openCV给出的是Y-Z-X(类似于上面代码中显示的内容)

我说我不确定的原因是因为我刚刚查看了cv :: Rodrigues的源代码,它似乎没有调用我上面展示的代码。Rodrigues函数将数学硬编码到其中(我认为可以通过取2个旋转矩阵并将它们相乘-R = Ry * Rz * Rx,然后查看代码中有一个acos(R(2,0))或asin(R(0,2)或类似的东西,因为“R”的元素通常是cos()或sin(),这将为您提供找到的角度的解决方案。


你是否发现openCV是否使用Y-Z-X? - john

2

不仅限于OpenCV,但你可以编写类似以下的内容:

cosine_for_pitch = math.sqrt(pose_mat[0][0] ** 2 + pose_mat[1][0] ** 2)
is_singular = cosine_for_pitch < 10**-6
if not is_singular:
    yaw = math.atan2(pose_mat[1][0], pose_mat[0][0])
    pitch = math.atan2(-pose_mat[2][0], cosine_for_pitch)
    roll = math.atan2(pose_mat[2][1], pose_mat[2][2])
else:
    yaw = math.atan2(-pose_mat[1][2], pose_mat[1][1])
    pitch = math.atan2(-pose_mat[2][0], cosine_for_pitch)
    roll = 0

在这里,您可以进一步探索:

https://www.learnopencv.com/rotation-matrix-to-euler-angles/ http://www.staff.city.ac.uk/~sbbh653/publications/euler.pdf


FYI,这种方法的顺序是先绕Z轴旋转(俯仰),然后绕Y轴旋转(偏航),最后绕X轴旋转(滚转)。 - undefined

0

我建议使用PCL库来用这个公式实现。

pcl::getEulerAngles(transformatoin,roll,pitch,yaw);

你只需要初始化俯仰、横滚、偏航和一个预先计算好的变换矩阵就可以了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接