OpenCV Vec3d转Eigen四元数时欧拉角翻转问题咨询
解决OpenCV solvePnP转Eigen位姿时欧拉角翻转的问题
首先得明确solvePnP返回的rvec和tvec的物理意义,这是解决问题的核心:
solvePnP给出的是世界坐标系到相机坐标系的变换,公式为:P_cam = R_w2c * P_world + t_w2c,其中R_w2c是世界到相机的旋转矩阵,t_w2c是对应位移向量。
我们通常需要的相机位姿是相机坐标系到世界坐标系的变换(即相机在世界中的位置和朝向),公式为:P_world = R_c2w * P_cam + t_c2w。你代码里的逆变换逻辑(R转置、tvec = -R*tvec)是对的,但细节和坐标系/欧拉角顺序问题导致了翻转,下面一步步解决:
1. 补全正确的OpenCV到Eigen转换代码
你的代码片段不完整,还存在一个小错误(DoubleMatFromVec3b是针对Vec3b的,但你的输入是Vec3d),先给出完整的正确转换函数:
#include <Eigen/Core> #include <Eigen/Geometry> #include <opencv2/core/eigen.hpp> void GetCameraPoseEigen(cv::Vec3d tvecV, cv::Vec3d rvecV, Eigen::Vector3d &Translate, Eigen::Quaterniond &quats) { // 将Vec3d转为OpenCV Mat(直接构造即可,无需额外转换函数) cv::Mat rvec(rvecV); cv::Mat tvec(tvecV); cv::Mat R_w2c; cv::Rodrigues(rvec, R_w2c); // 从旋转向量得到世界到相机的旋转矩阵 // 计算相机到世界的逆变换 cv::Mat R_c2w = R_w2c.t(); cv::Mat t_c2w = -R_c2w * tvec; // 转换为Eigen格式 Eigen::Matrix3d R_eigen; cv::cv2eigen(R_c2w, R_eigen); quats = Eigen::Quaterniond(R_eigen); // 从旋转矩阵初始化四元数 cv::cv2eigen(t_c2w, Translate); }
2. 欧拉角翻转的核心原因:坐标系或欧拉角顺序不匹配
欧拉角翻转几乎都是坐标系定义不一致或者欧拉角分解顺序不同导致的,下面分别解决:
情况A:欧拉角分解顺序不一致
OpenCV默认的欧拉角分解通常是**Z-Y-X(Yaw-Pitch-Roll)**顺序,如果你在Eigen中错误使用了其他顺序(比如X-Y-Z),就会出现翻转。
正确的Z-Y-X顺序欧拉角获取方式:
// 参数(2,1,0)对应Z-Y-X的内在旋转顺序 Eigen::Vector3d euler_angles = quats.matrix().eulerAngles(2, 1, 0); // euler_angles[0]是Yaw(绕Z轴),[1]是Pitch(绕Y轴),[2]是Roll(绕X轴)
如果你之前用的是eulerAngles(0,1,2)(X-Y-Z顺序),结果自然会和预期不符,看起来像是翻转。
情况B:坐标系定义不一致
OpenCV的相机坐标系规则:
- X轴:向右
- Y轴:向下
- Z轴:向前(朝向拍摄方向)
而很多SLAM系统或可视化工具的坐标系可能是:
- X轴:向前
- Y轴:向右
- Z轴:向上
这种情况下需要做坐标系转换,将OpenCV的位姿适配到目标坐标系:
// 定义OpenCV相机坐标系到目标坐标系的变换矩阵 Eigen::Matrix3d cv_to_target; cv_to_target << 0, 0, 1, -1, 0, 0, 0, -1, 0; // 转换旋转矩阵和位移向量 Eigen::Matrix3d R_c2w_target = cv_to_target * R_eigen * cv_to_target.transpose(); Eigen::Vector3d Translate_target = cv_to_target * Translate; // 更新四元数和位移向量 quats = Eigen::Quaterniond(R_c2w_target); Translate = Translate_target;
3. 验证变换正确性
可以用已知点验证转换是否正确:
- 世界原点
(0,0,0)经过相机到世界的变换后,应该等于Translate(相机原点在世界中的位置就是Translate)。 - 相机坐标系中的点
(0,0,1)(正前方),经过变换后应该是Translate + quats * Eigen::Vector3d(0,0,1),这个点应该指向世界坐标系中相机的前方方向。
通过以上步骤,就能解决欧拉角翻转的问题了。
内容的提问来源于stack exchange,提问作者anti
相关产品推荐
相关产品推荐

