我正在使用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 中获得稳定的四元数?
编辑:这似乎是四元数翻转,如下所述:
四元数是非常相似的旋转的翻转符号?
基于此,我尝试添加:
if(quat.w() < 0)
{
quat = quat.Inverse();
}
但我看到了同样的翻转。
quat
和-quat
都表示相同的旋转。您可以通过取一个单位四元数,将其转换为旋转矩阵,然后执行
quat.coeffs() = -quat.coeffs();
并将其转换为旋转矩阵。 如果出于某种原因您总是想要一个正w
值,如果w
为负,则否定所有系数。
符号应该无关紧要...
。旋转方面,只要 4D 四元数的所有四个场都被翻转。这里还有更多解释: 四元数到欧拉XYZ,如何区分负四元数和正四元数
可以这样想: 两个翻转的角度/轴意味着同样的事情 并注意顺时针到逆时针的过渡,就像在镜像中一样。
可能有惯例使quat.w()
或quat[0]
组件保持正数,并相应地将其他组件更改为相反的组件。假设w = cos(angle/2)
然后设置w > 0
只是意味着:我希望angle
在(-pi, pi)
范围内。使-270度旋转变为+90度旋转。
做quat.Inverse()
可能不是你想要的,因为这会在相反的方向上产生旋转。那是-quat != quat.Inverse()
.
另外:检查两个系统是否具有相同的惯用手性(手性)!测试旋转矩阵行列式是 +1 还是 -1。
(对于图像链接,我没有足够的声誉来嵌入它们)。