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.pswp.cn/diannao/37814.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/37814.shtml
英文地址,請注明出處:http://en.pswp.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文本節點所有…