OpenCV cv::Mat到 Eigen 的正确转换——cv2eigen

在进行计算机视觉项目时,我们经常需要处理相机位姿的变换。最近,我在项目中遇到了一个看似简单但实际上颇具挑战性的问题:从 OpenCV 的 cv::Mat 格式转换到 Eigen 库的格式。这个过程中遇到了一些问题,但最终找到了一个稳健的解决方案。

问题描述: 我们有两个表示相机位姿的 4x4 变换矩阵,格式为 cv::Mat。目标是计算这两个位姿之间的变换,并提取出平移向量。

初始尝试: 最初,我们尝试直接从 cv::Mat 中提取平移向量:

Eigen::Vector3d transLast(mLastFrameTcw.at<double>(0, 3),mLastFrameTcw.at<double>(1, 3),mLastFrameTcw.at<double>(2, 3)
);
Eigen::Vector3d transCurrent(mCurrentFrameTcw.at<double>(0, 3),mCurrentFrameTcw.at<double>(1, 3),mCurrentFrameTcw.at<double>(2, 3)
);
TRANS_PRED = transCurrent - transLast;

遇到的问题: 针对简单的工程,代码运行完全没有问题,但是放到复杂工程里面,代码就会输出莫名其妙的结果!!!!!这种方法可能会导致错误,原因如下:

  1. 直接访问 cv::Mat 的元素可能不安全,特别是当矩阵的存储格式不确定时。
  2. 这种方法忽略了旋转部分的影响,可能导致计算结果不准确。
  3. 在某些情况下,可能会出现索引错误或类型不匹配的问题。

改进的解决方案: 经过多次尝试和改进,我们最终采用了以下方法:

// 直接相减 cv::Mat
cv::Mat diff = mCurrentFrameTcw - mLastFrameTcw;// 将 cv::Mat 转换为 Eigen 矩阵
Eigen::MatrixXd eigenDiff;
cv::cv2eigen(diff, eigenDiff);// 从 eigenDiff 的最后一列提取前三个元素赋值给 TRANS_PRED
TRANS_PRED = eigenDiff.block<3,1>(0, eigenDiff.cols()-1);

这个解决方案的优点:

  1. 使用 cv::Mat 的矩阵减法,保持了原始数据的完整性。
  2. 利用 OpenCV 提供的 cv2eigen 函数,安全地将 cv::Mat 转换为 Eigen 矩阵。
  3. 使用 Eigen 的 block 操作,精确地提取所需的平移向量。

结论: 在处理计算机视觉中的坐标变换问题时,正确地在不同库(如 OpenCV 和 Eigen)之间转换数据格式是至关重要的。通过采用矩阵减法和适当的类型转换,我们可以准确地计算相机位姿之间的变换。这个经验教训提醒我们,在处理不同库之间的数据转换时,要特别注意数据类型的一致性和操作的正确性。在future类似的问题中,我们可以借鉴这种方法,确保在不同数学库之间进行安全和准确的数据转换。

下面给出完整的代码(注意:下面的两个版本都可以用,只是区分两个中哪个更鲁棒!!!)

#include <iostream>
#include <iomanip>
#include <opencv2/core.hpp>
#include <Eigen/Dense>
#include <opencv2/core/eigen.hpp>void CalculateTransPred_Method1(const cv::Mat& mLastFrameTcw, const cv::Mat& mCurrentFrameTcw, Eigen::Vector3d& TRANS_PRED) {std::cout << "Method 1: Direct extraction from cv::Mat" << std::endl;Eigen::Vector3d transLast(mLastFrameTcw.at<double>(0, 3),mLastFrameTcw.at<double>(1, 3),mLastFrameTcw.at<double>(2, 3));Eigen::Vector3d transCurrent(mCurrentFrameTcw.at<double>(0, 3),mCurrentFrameTcw.at<double>(1, 3),mCurrentFrameTcw.at<double>(2, 3));std::cout << "transLast: " << transLast.transpose() << std::endl;std::cout << "transCurrent: " << transCurrent.transpose() << std::endl;TRANS_PRED = transCurrent - transLast;std::cout << "TRANS_PRED: " << TRANS_PRED.transpose() << std::endl;
}void CalculateTransPred_Method2(const cv::Mat& mLastFrameTcw, const cv::Mat& mCurrentFrameTcw, Eigen::Vector3d& TRANS_PRED) {std::cout << "\nMethod 2: Using cv::Mat subtraction and Eigen conversion" << std::endl;cv::Mat diff = mCurrentFrameTcw - mLastFrameTcw;Eigen::MatrixXd eigenDiff;cv::cv2eigen(diff, eigenDiff);std::cout << "Difference (diff) in Eigen::MatrixXd format:" << std::endl;std::cout << eigenDiff << std::endl;TRANS_PRED = eigenDiff.block<3,1>(0, eigenDiff.cols()-1);std::cout << "TRANS_PRED: " << TRANS_PRED.transpose() << std::endl;
}int main() {cv::Mat mLastFrameTcw = (cv::Mat_<double>(4, 4) -0.1642483, 0.094168551, -0.98191381, 0.90703607,0.0095526827, 0.99553794, 0.093877248, -0.038507219,0.98637277, 0.0060392693, -0.164415, -3.4207926,0, 0, 0, 1);cv::Mat mCurrentFrameTcw = (cv::Mat_<double>(4, 4) -0.16892175, 0.093616515, -0.98117346, 0.92409742,0.009967736, 0.99559039, 0.093275994, -0.039425559,0.98557907, 0.0059762667, -0.16911002, -3.4853551,0, 0, 0, 1);Eigen::Vector3d TRANS_PRED;std::cout << std::fixed << std::setprecision(6);std::cout << "mLastFrame.mTcw:" << std::endl;std::cout << mLastFrameTcw << std::endl;std::cout << "\nmCurrentFrame.mTcw:" << std::endl;std::cout << mCurrentFrameTcw << std::endl;CalculateTransPred_Method1(mLastFrameTcw, mCurrentFrameTcw, TRANS_PRED);CalculateTransPred_Method2(mLastFrameTcw, mCurrentFrameTcw, TRANS_PRED);return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/37814.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

镂空的文字?分享 1 段优质 CSS 代码片段!

大家好&#xff0c;我是大澈&#xff01; 本文约 800 字&#xff0c;整篇阅读约需 1 分钟。 每日分享一段优质代码片段。 今天分享一段优质 CSS 代码片段&#xff0c;实现 CSS 文字镂空的效果。 老规矩&#xff0c;先阅读代码片段并思考&#xff0c;再看代码解析再思考&#…

nginx本地域名配置

修改hosts文件&#xff08;仅限本地测试&#xff09;&#xff1a; 在Windows上&#xff0c;hosts文件位于C:\Windows\System32\drivers\etc\hosts。 打开hosts文件&#xff0c;添加一行&#xff1a;127.0.0.1 xxx.com &#xff08;xxx.com为自己设定的域名&#xff09; 如果修…

Leetcode3190. 使所有元素都可以被 3 整除的最少操作数

Every day a Leetcode 题目来源&#xff1a;3190. 使所有元素都可以被 3 整除的最少操作数 解法1&#xff1a;遍历 遍历数组&#xff0c;累加最少操作数&#xff0c;即 min(num % 3, 3 - num % 3)。 代码&#xff1a; /** lc appleetcode.cn id3190 langcpp** [3190] 使所…

uniapp+vue3开发微信小程序踩坑集

本文主要记录使用uniappvue3开发微信小程序遇见的各种常见问题及注意点。&#xff08;持续更新&#xff09; 问题&#xff1a; 自定义组件为什么有些样式加不上去 给自定义组件增加class的时候&#xff0c;有时候不生效有时候生效&#xff0c;一度让我怀疑自己记忆错乱。后来…

C++枚举

C枚举 枚举的基础用法不不再赘述枚举的三点问题1、作用域问题解决思路1解决思路2 2、隐式转换成int3、枚举变量的实际类型无法明确指定 枚举的基础用法不不再赘述 枚举的三点问题 1、作用域问题 举个例子&#xff0c;颜色有blue代表蓝色&#xff0c;心情有blue代表忧郁。 以…

mysql安装配置教程

mysql安装配置教程 MySQL是一个流行的关系型数据库管理系统&#xff0c;用于存储和管理数据。下面是简要的MySQL安装配置教程&#xff1a; 步骤1&#xff1a;下载MySQL 访问MySQL官方网站&#xff08;https://dev.mysql.com/downloads/mysql/&#xff09;下载适合您操作系统…

Java冒泡排序实现及应用解析

Java冒泡排序实现及应用解析 冒泡排序是计算机科学中最基本的排序算法之一&#xff0c;尽管它的效率不是最高的&#xff0c;但由于其实现简单&#xff0c;它在教学和某些特定场景下仍然具有不可替代的作用。本文将从Java语言的角度&#xff0c;深入探讨冒泡排序的基本原理、实…

全国31省细分产品出口数据集(2002-2022年)

数据简介&#xff1a;整理全国31个省直辖市自治区按hs码分的22类细分产品的出口数据&#xff0c;只包含22类的细分&#xff0c;不包含更细的类目。可用来计算出口产品质量&#xff0c;出口产品技术复杂度等指标&#xff0c;数据区间为2002-2022年。 数据名称&#xff1a;31省细…

《昇思25天学习打卡营第11天 | 昇思MindSpore基于 MindSpore 实现 BERT 对话情绪识别》

11天本节学习到BERT全称是来自变换器的双向编码器表征量&#xff0c;它是Google于2018年末开发并发布的一种新型语言模型。BERT模型的主要创新点都在pre-train方法上&#xff0c;即用了Masked Language Model和Next Sentence Prediction两种方法分别捕捉词语和句子级别的repres…

【SGX系列教程】(五)Intel-SGX 官方示例分析(SampleCode)——RemoteAttestation

文章目录 一.RemoteAttestation原理介绍1.1 远程认证原理1.2 远程认证步骤1.3 远程认证基本流程1.4 IAS通过以下步骤验证报告的签名1.5 关键术语1.6 总结二.源码分析2.1 README2.1.1 README给出的编译流程2.2 重点代码分析2.2.0 主要代码模块交互流程分析2.2.1 isv_app文件夹2.…

python-18-零基础自学python-用类创建冰淇凌小店的口味

学习内容&#xff1a;《python编程&#xff1a;从入门到实践》第二版 知识点&#xff1a; 类、子类、继承、调用函数 练习内容&#xff1a; 练习9-6&#xff1a;冰激凌小店 冰激凌小店是一种特殊的餐馆。编写一个名为IceCreamStand的类&#xff0c;让它继承为完成练习9-1或…

YonBIP 获取项目代码配置(图文)

项目开发文件在本地环境重新部署后&#xff0c;开发端机器需要重新部署&#xff0c;在此记录一下操作过程。 1. 新建项目目录&#xff0c;在目录下点鼠标右键&#xff0c;选 Git Bash Here 2. 开始下载代码&#xff0c;根据代码量多少&#xff0c;几分钟就能下载完成。 3. 下载…

任意密码重置漏洞

文章目录 1. 任意密码重置漏洞原理2. 任意密码重置漏洞产生原因3. 任意密码重置漏洞场景3.1 验证码爆破3.2 验证凭证回传3.3 验证凭证未绑是用户3.4 跳过验证步骤3.5 凭证可预测3.6 同时向多个账户发送凭证 4. 任意密码重置经典案例4.1 中国人寿某重要系统任意账户密码重置4.2 …

【单元测试】Controller、Service、Repository 层的单元测试

Controller、Service、Repository 层的单元测试 1.Controller 层的单元测试1.1 创建一个用于测试的控制器1.2 编写测试 2.Service 层的单元测试2.1 创建一个实体类2.2 创建服务类2.3 编写测试 3.Repository 1.Controller 层的单元测试 下面通过实例演示如何在控制器中使用 Moc…

什么是死锁以及如何避免

什么是死锁&#xff1f; 死锁是指两个或两个以上的进程在执行过程中&#xff0c;由于竞争资源或者由于彼此通信而造成的一种阻塞的现象&#xff0c;若无外力作用&#xff0c;它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁&#xff0c;这些永远在互相等待的进…

关于配置webpack eslint插件版本问题说明

webpack相关版本说明 按照当前情况下&#xff0c;以及eslint-webpack-plugin的官方版本使用的是8.x版本的eslint,我们进行如下依赖安装 npm i -D eslint8 eslint-webpack-plugin "devDependencies": {"eslint": "^8.57.0","eslint-webpac…

简单了解下Java中锁的概念和原理

你好&#xff0c;这里是codetrend专栏“高并发编程基础”。 Java提供了很多种锁的接口和实现&#xff0c;通过对各种锁的使用发现理解锁的概念是很重要的。 Java的锁通过java代码实现&#xff0c;go语言的锁通过go实现&#xff0c;python语言的锁通过python实现。它们都实现的…

Apache Calcite Linq4j学习

Lin4j简介 Linq4j是Apache Calcite项目中的一个模块&#xff0c;它提供了类似于LINQ&#xff08;Language-Integrated Query&#xff09;的功能&#xff0c;用于在Java中进行数据查询和操作。Linq4j可以将逻辑查询转换为物理查询&#xff0c;支持对集合进行筛选、映射、分组等…

python自动例化verilog

python自动例化verilog 使用方法&#xff1a;在gvim页面&#xff0c;使用命令自动例化 :r !AUTO_inst xxx.v #python import re import sysmdl_re r"\s*module\s*(?P<mname>\w) *" port_re r"\s*(?P<dir>input|output)\s(?P<typ>wire|re…

API-节点操作

学习目标&#xff1a; 掌握节点操作 学习内容&#xff1a; DOM节点查找节点增加节点删除节点 DOM节点&#xff1a; DOM树里每一个内容都称之为节点。 节点类型 元素节点所有的标签比如body、div&#xff1b;html是根节点属性节点所有的属性&#xff0c;比如href文本节点所有…