opencv Vec3d到Eigen :: Quaternion,euler在结果上翻转

时间:2018-03-17 16:08:57

标签: opencv eigen quaternions opencv-solvepnp

我使用opencv :: solvePnP来返回相机姿势。我运行PnP,它返回rvec和tvec值。(旋转矢量和位置)。

然后我运行此函数将值转换为相机姿势:

void GetCameraPoseEigen(cv::Vec3d tvecV, cv::Vec3d rvecV, Eigen::Vector3d &Translate, Eigen::Quaterniond &quats)
{
    Mat R;
    Mat tvec, rvec;

    tvec = DoubleMatFromVec3b(tvecV);
    rvec = DoubleMatFromVec3b(rvecV);

    cv::Rodrigues(rvec, R); // R is 3x3
    R = R.t();                 // rotation of inverse
    tvec = -R*tvec;           // translation of inverse

    Eigen::Matrix3d mat;
    cv2eigen(R, mat);

    Eigen::Quaterniond EigenQuat(mat);

    quats = EigenQuat;


    double x_t = tvec.at<double>(0, 0);
    double y_t = tvec.at<double>(1, 0);
    double z_t = tvec.at<double>(2, 0);

    Translate.x() = x_t * 10;
    Translate.y() = y_t * 10;
    Translate.z() = z_t * 10;   

}

这是有效的,但在某些旋转角度,转换的旋转值在正值和负值之间随机翻转。然而,源rvecV值却没有。我认为这意味着我的转换出错了。如何从PnP返回cv :: Vec3d?

获得稳定的Quaternion 编辑:这似乎是四元数翻转,如下所述:

Quaternion is flipping sign for very similar rotations?

基于此,我尝试添加:

if(quat.w() < 0)
 {
 quat = quat.Inverse();
 } 

但我看到同样的翻转。

2 个答案:

答案 0 :(得分:1)

quat-quat代表相同的轮播。您可以通过获取单位四元数,将其转换为旋转矩阵,然后执行

来检查
quat.coeffs() = -quat.coeffs();

并将其转换为旋转矩阵。 如果由于某种原因您始终需要正w值,则在w为负数时否定所有系数。

答案 1 :(得分:0)

标志无关紧要......

...旋转方式,只要4D四元数的所有四个字段都被翻转。还有更多内容在这里解释: Quaternion to EulerXYZ, how to differentiate the negative and positive quaternion

这样想: Angle/axis both flipped mean the same thing 并注意在镜像中顺时针到逆时针过渡,如

可能会有惯例保持quat.w()quat[0]组件为正,并相应地将其他组件更改为相反。假设w = cos(angle/2)然后设置w > 0只是意味着:我希望angle(-pi, pi)范围内。这样-270度旋转变为+90度旋转。

执行quat.Inverse()可能不是您想要的,因为这会在相反的方向上创建旋转。那是-quat != quat.Inverse()

另外:检查两个系统是否具有相同的灵活性(chirality)!测试旋转矩阵行列式是否为+1或-1。

(对于图片链接,我没有足够的声誉嵌入它们。)