如何实现CvMat到Sophus::SE3的转换?解决ORB_SLAM3类型匹配错误
问题描述
基于ROS2 Humble + C++搭建单目惯性ORB_SLAM3节点时,遇到类型转换编译错误:
在ImageGrabber::SyncWithImu()函数中,mpSLAM->TrackMonocular(im,tIm,vImuMeas)返回Sophus::SE3f类型,但被直接赋值给cv::Mat类型变量T_,触发报错:
error: no match for ‘operator=’ (operand types are ‘cv::Mat’ and ‘Sophus::SE3f’)
需要实现cv::Mat与Sophus::SE3(含SE3f)的双向转换函数,同时纠结是在ORB_SLAM3原生的Converter类中添加,还是单独创建文件实现。
一、双向转换函数实现
1. Sophus::SE3f 转 cv::Mat
直接提取SE3的变换矩阵,转成OpenCV格式:
cv::Mat SE3fToCvMat(const Sophus::SE3f &se3) { Eigen::Matrix4f eigen_mat = se3.matrix(); // 克隆避免Eigen与cv::Mat共享内存导致的生命周期问题 return cv::Mat(4, 4, CV_32F, eigen_mat.data()).clone(); }
如果使用双精度的Sophus::SE3d,把CV_32F改成CV_64F即可。
2. cv::Mat 转 Sophus::SE3f
从4x4变换矩阵中解析出SE3结构,注意数据类型和维度校验:
Sophus::SE3f CvMatToSE3f(const cv::Mat &cv_mat) { if (cv_mat.type() != CV_32F || cv_mat.size() != cv::Size(4,4)) { throw std::runtime_error("输入矩阵必须是4x4单精度浮点类型"); } Eigen::Matrix4f eigen_mat; memcpy(eigen_mat.data(), cv_mat.data(), sizeof(float)*16); return Sophus::SE3f(eigen_mat); }
双精度版本替换CV_32F为CV_64F,SE3f为SE3d,float为double。
二、代码放置方案选择
方案1:扩展ORB_SLAM3原生Converter类
ORB_SLAM3的Converter类(路径:include/Converter.h、src/Converter.cc)本身就是负责各类SLAM数据类型转换的模块,把上面的函数加进去最贴合原有架构:
- 在
Converter.h中添加静态函数声明:class Converter { // ... 原有函数声明 ... static cv::Mat SE3fToCvMat(const Sophus::SE3f &se3); static Sophus::SE3f CvMatToSE3f(const cv::Mat &cv_mat); }; - 在
Converter.cc中实现函数,记得引入Sophus头文件:#include <Sophus/se3.hpp>
方案2:单独创建工具类文件
如果不想修改ORB_SLAM3源码(比如要保持源码纯净方便后续升级),可以单独新建SLAMTypeConverter.h和SLAMTypeConverter.cc,把转换函数放在这个独立模块里,按需引入即可。
实际使用示例
在SyncWithImu()里替换原来的错误赋值:
// 把TrackMonocular返回的SE3f转成cv::Mat T_ = SE3fToCvMat(mpSLAM->TrackMonocular(im,tIm,vImuMeas)); // 后续如果需要把cv::Mat转回SE3f,直接调用 // Sophus::SE3f se3_pose = CvMatToSE3f(T_);
内容的提问来源于stack exchange,提问作者Macedon971
相关产品推荐
相关产品推荐

