OpenCV三維解算常用方法C++

? ? 如果標定過程是通過OpenCV張正友標定法實現的,得到的內參外參保存在.txt文件中是這樣的形式:

① 內參intrinsics.txt:

?② 外參extrinsics.txt:

? ? 那么可以通過如下方法讀取.txt文件獲取左右相機內外參,主要包括三維解算需要用到的左右相機內參矩陣、畸變系數,以及左右相機構成雙目系統的旋轉矩陣和平移矩陣,具體代碼如下:

std::string intrinsicsPath{ "D:\\Program Files\\edge下載文件\\030716.16\\030716.16\\intrinsics.txt" }; // 左右相機內參數文件路徑
std::string extrinsicsPath{ "D:\\Program Files\\edge下載文件\\030716.16\\030716.16\\extrinsics.txt" }; // 左右相機外參數文件路徑// 加載左右相機內參數
cv::Mat cameraMatrixL;  // 左相機內參矩陣
cv::Mat distCoeffsL;    // 左相機畸變參數
cv::Mat cameraMatrixR;  // 右相機內參矩陣
cv::Mat distCoeffsR;    // 右相機畸變參數cv::FileStorage fs(intrinsicsPath, cv::FileStorage::READ);
fs["cameraMatrixL"] >> cameraMatrixL;
fs["cameraDistcoeffL"] >> distCoeffsL;
fs["cameraMatrixR"] >> cameraMatrixR;
fs["cameraDistcoeffR"] >> distCoeffsR;
fs.release();//std::cout << "左相機內參矩陣......" << std::endl;
//std::cout << cameraMatrixL << std::endl;
//std::cout << "左相機畸變參數......" << std::endl;
//std::cout << distCoeffsL << std::endl;
//std::cout << std::endl;
//std::cout << "右相機內參矩陣......" << std::endl;
//std::cout << cameraMatrixR << std::endl;
//std::cout << "右相機畸變參數......" << std::endl;
//std::cout << distCoeffsR << std::endl;
//std::cout << std::endl;// 加載相機外參數
cv::Mat R; // 旋轉矩陣
cv::Mat T; // 平移向量fs.open(extrinsicsPath, cv::FileStorage::READ);
fs["R"] >> R;
fs["T"] >> T;
fs.release();

? ? 在得到二維像素坐標之后可以通過畸變校正,三角測量法(Triangulation) 來計算三維點坐標。通常是基于 OpenCV 提供的 cv::triangulatePoints 進行計算,這是一個標準的立體視覺技術,用于通過兩個相機視角中的匹配點估算其三維坐標。

? ? 步驟如下代碼所示:

? ? 二維坐標→畸變校正→轉換到相機坐標系→三維解算。

        std::vector<cv::Point2f> leftPointsUndistort, rightPointsUndistort;cv::undistortPoints(targetsL, leftPointsUndistort, cameraMatrixL, distCoeffsL, cv::Mat(), cameraMatrixL);// targetsL是未做畸變矯正前處理得到的二維中心點坐標(左相機)cv::undistortPoints(targetsR, rightPointsUndistort, cameraMatrixR, distCoeffsR, cv::Mat(), cameraMatrixR);// targetsR是未做畸變矯正前處理得到的二維中心點坐標(右相機)// 轉換到相機坐標系std::vector<cv::Point2f> leftPointsCam = pixel2cam(leftPointsUndistort, cameraMatrixL);std::vector<cv::Point2f> rightPointsCam = pixel2cam(rightPointsUndistort, cameraMatrixR);// 求解三維坐標std::vector<cv::Point3f> points3d = triangulation(leftPointsCam, rightPointsCam, R, T);

調用的函數代碼:

std::vector<cv::Point3f> triangulation(const std::vector<cv::Point2f>& pts1, const std::vector<cv::Point2f>& pts2, cv::Mat& R, cv::Mat& T)
{cv::Mat T1 = (cv::Mat_<float>(3, 4) << 1, 0, 0, 0,0, 1, 0, 0,0, 0, 1, 0);R.convertTo(R, CV_64FC1);T.convertTo(T, CV_64FC1);cv::Mat T2 = (cv::Mat_<float>(3, 4) <<R.at<double>(0, 0), R.at<double>(0, 1), R.at<double>(0, 2), T.at<double>(0, 0),R.at<double>(1, 0), R.at<double>(1, 1), R.at<double>(1, 2), T.at<double>(1, 0),R.at<double>(2, 0), R.at<double>(2, 1), R.at<double>(2, 2), T.at<double>(2, 0));cv::Mat pts4d;cv::triangulatePoints(T1, T2, pts1, pts2, pts4d);std::vector<cv::Point3f> pts3d;for (int i = 0; i < pts4d.cols; ++i){float x = pts4d.at< float >(0, i) / pts4d.at< float >(3, i);float y = pts4d.at< float >(1, i) / pts4d.at< float >(3, i);float z = pts4d.at< float >(2, i) / pts4d.at< float >(3, i);pts3d.emplace_back(cv::Point3f(x, y, z));}return pts3d;
}std::vector<cv::Point2f> pixel2cam(const std::vector<cv::Point2f>& pts, const cv::Mat& cameraMatrix)
{std::vector<cv::Point2f> ptsCam;for (const auto& p : pts){cv::Point2f c((p.x - cameraMatrix.at<double>(0, 2)) / cameraMatrix.at<double>(0, 0),(p.y - cameraMatrix.at<double>(1, 2)) / cameraMatrix.at<double>(1, 1));ptsCam.emplace_back(c);}return ptsCam;
}

?注:pixel2cam 函數的作用是將像素坐標轉換為歸一化相機坐標(normalized camera coordinates)。這是必要的,因為 三角測量法 計算三維點的位置時,假設輸入的點是在無畸變的相機坐標系下。

這里的 (xc,yc) 是歸一化相機坐標,表示 光學中心?歸一化后的坐標,它們不再依賴于攝像機的焦距和像素比例,因此可以用于三角測量。?

三角測量的數學原理

  • 三角測量基于 兩個不同視角的相機投影矩陣(Projection Matrix)。

  • 如果使用 像素坐標,那么投影矩陣應該是 P=K[R∣T](包含相機內參)。

  • 但如果使用 歸一化相機坐標,那么投影矩陣可以簡化為 P=[R∣T](去除了相機內參)。

  • 這樣可以直接利用 相機外參(R, T) 進行計算,提高準確性。

三角測量計算的流程

  1. 將像素坐標轉換為歸一化相機坐標pixel2cam

  2. 構造相機投影矩陣

    • 第一個相機位于世界坐標系的原點(通常以左相機為原點):

      P1=[I∣0]
    • 第二個相機的投影矩陣由外參 旋轉矩陣 R平移向量 T 給出:

      P2=[R∣T]
  3. 使用 OpenCV 的 triangulatePoints 進行三角測量

    • 通過求解一組線性方程,得到齊次坐標 (X,Y,Z,W)

    • 通過 X′=X/W,Y′=Y/W,Z′=Z/W 得到真實的三維坐標

?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/bicheng/74498.shtml
繁體地址,請注明出處:http://hk.pswp.cn/bicheng/74498.shtml
英文地址,請注明出處:http://en.pswp.cn/bicheng/74498.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

棧和隊列相關知識題目

棧的底層原理 棧&#xff08;Stack&#xff09;是一種后進先出&#xff08;LIFO&#xff09;?的線性數據結構&#xff0c;所有操作&#xff08;如插入、刪除&#xff09;僅在棧頂進行。它的底層實現可以是數組或鏈表&#xff0c;具體取決于編程語言和應用場景。 1.基于數組實…

【實戰案例】永洪vividime:精準賦能零售行業,實現數據洞察與業務增長

在零售食品行業變革加速、市場競爭白熱化的背景下&#xff0c;XX集團作為休閑食品領域頭部企業&#xff0c;面臨消費趨勢變化、宏觀經濟承壓及業績增長乏力的多重挑戰。為破解增長困境&#xff0c;集團將“收入增長金額”確立為核心戰略指標&#xff08;北極星指標&#xff09;…

一些題目記錄

別人面經題目記錄 https://zhuanlan.zhihu.com/p/32626732052 實現 NMS&#xff0c;七八次&#xff0c;很高頻&#xff1b; 實現 MultiHeadSelfAttention&#xff0c;大概 三四次&#xff1b; 用 Numpy 或者 List 實現MLP 的前向和反向&#xff0c;4次&#xff1b; Leetcode …

面試題分享-多線程順序打印奇偶數

目錄 1.題目詳情 2.解題思路 2.1.分析題目 2.2.解析思路 3.代碼實現 4.運行結果 1.題目詳情 昨天刷抖音&#xff0c;遇到一個面試題&#xff0c;描述如下&#xff1a; 請使用兩個線程&#xff0c;分別順序交替打印奇數和偶數&#xff0c;直到10為止。例如有兩個線程&#…

模型 杜根定律

系列文章分享模型&#xff0c;了解更多&#x1f449; 模型_思維模型目錄。信心>能力、行動導向、未來時態。 1 杜根定律的應用 1.1 公共政策博弈——底特律市長杜根的保險改革攻堅戰 核心挑戰&#xff1a;底特律市長Mike Duggan面臨汽車保險費率畸高導致居民陷入貧困循環的…

關于在vscode中的Linux 0.11 應用程序項目的生成和運行

首先我們需要需要查看鏡像文件 查看軟盤鏡像文件 floppyb.img 中的內容 在 VSCode 的“Terminal”菜單中選擇“Run Build Task...”&#xff0c;會在 VSCode 的頂部中間位置彈出一個 可以執行的 Task 列表&#xff0c;選擇其中的“打開 floppyb.img”后會使用 Floppy Editor …

使用CSS3實現炫酷的3D視差滾動效果

使用CSS3實現炫酷的3D視差滾動效果 這里寫目錄標題 使用CSS3實現炫酷的3D視差滾動效果項目概述核心技術實現1. 3D空間的創建2. 視差層級設置3. 動畫效果實現流星動畫月亮發光效果 技術難點與解決方案1. 層級重疊問題2. 性能優化3. 響應式適配 開發心得總結 項目概述 在這個項目…

作業12 (2023-05-15 指針概念)

第1題/共11題【單選題】 關于指針的概念,錯誤的是:( ) A.指針變量是用來存放地址的變量 B.指針變量中存的有效地址可以唯一指向內存中的一塊區域 C.野指針也可以正常使用 D.局部指針變量不初始化就是野指針 回答正確 答案解析: A:正確,指針變量中存儲的是一個地址,指…

【ESP32S3】esp32獲取串口數據并通過http上傳到前端

通過前面的學習&#xff08;前面沒發過&#xff0c;因為其實就是跑它的demo&#xff09;了解到串口配置以及開啟線程實現功能的工作流程&#xff0c;與此同時還有esp32作為STA節點&#xff0c;將數據通過http發送到服務器。 將這兩者聯合 其實是可以得到一個&#xff1a;esp32獲…

《鴻蒙攜手AI:解鎖智慧出行底層邏輯》

在科技飛速發展的當下&#xff0c;智慧出行成為人們對未來交通的美好期許&#xff0c;而鴻蒙系統與人工智能的深度融合&#xff0c;正為這一愿景的實現提供強大助力。從技術原理角度深入剖析&#xff0c;鴻蒙系統究竟如何支撐人工智能在智慧出行場景中的應用呢&#xff1f;這背…

MyBatis-Plus緩存機制深度解析與SpringBoot整合實戰

一、MyBatis-Plus緩存機制全景解析 MyBatis-Plus在MyBatis原生緩存基礎上進行了深度增強,形成了多層次的緩存體系: 1. 緩存層級架構 應用層 ├── MP擴展緩存(多租戶/邏輯刪除) ├── 二級緩存(Mapper級別,跨Session共享) └── 一級緩存(SqlSession級別,默認開…

Day38 | 1365. 有多少小于當前數字的數字、941. 有效的山脈數組、1207. 獨一無二的出現次數、283. 移動零、189. 輪轉數組

1365. 有多少小于當前數字的數字 題目鏈接&#xff1a;1365. 有多少小、于當前數字的數字 - 力扣&#xff08;LeetCode&#xff09; 題目難度&#xff1a;簡單 代碼&#xff1a; class Solution {public int[] smallerNumbersThanCurrent(int[] nums) {Map<Integer,Inte…

數據人的進階之路:四年數倉實踐與成長思考

前言 在數據倉庫開發的過程中&#xff0c;常常會遇到很多值得思考的問題&#xff0c;它們不僅關乎技術的深度&#xff0c;也涉及業務理解、個人的成長&#xff0c;甚至是數據行業未來的價值。回顧過去的經歷&#xff0c;有很多問題反復出現&#xff0c;甚至成為繞不開的課題&am…

大文件分片上傳及斷點續傳實現

使用 支持分片上傳及斷點續傳 前端使用 vue 2 后端使用 springboot 源碼在私信

圖解AUTOSAR_SWS_IOHardwareAbstraction

AUTOSAR IO硬件抽象層詳解 基于AUTOSAR標準的IO硬件抽象層設計與實現指南 目錄 1. 概述2. 架構設計 2.1 模塊架構概覽2.2 內部組件結構2.3 與其他模塊的交互接口 3. 狀態機 3.1 狀態定義3.2 狀態轉換3.3 狀態行為 4. ADC信號處理流程 4.1 初始化流程4.2 轉換請求和處理4.3 通知…

Python正則表達式(一)

目錄 一、正則表達式的基本概念 1、基本概念 2、正則表達式的特殊字符 二、范圍符號和量詞 1、范圍符號 2、匹配漢字 3、量詞 三、正則表達式函數 1、使用正則表達式&#xff1a; 2、re.match()函數 3、re.search()函數 4、findall()函數 5、re.finditer()函數 6…

北京交通大學第三屆C語言積分賽

作者有言在先&#xff1a; 題解的作用是交流思路&#xff0c;不是抄作業的。可以把重點放在思路分析上而不是代碼上&#xff0c;畢竟每個人的代碼風格是不一樣的&#xff0c;看別人的代碼就跟做程序填空題一樣。先看明白思路再看代碼。 還有就是&#xff0c;deepseek真的很好用…

機器學習之條件概率

1. 引言 概率模型在機器學習中廣泛應用于數據分析、模式識別和推理任務。本文將調研幾種重要的概率模型,包括EM算法、MCMC、樸素貝葉斯、貝葉斯網絡、概率圖模型(CRF、HMM)以及最大熵模型,介紹其基本原理、算法流程、應用場景及優勢。 2. EM算法(Expectation-Maximizati…

硬件基礎--03_電流

電流 十九世紀初:[電流方向]是指正電荷的移動方向。 后來:對于金屬導體&#xff0c;正電荷沒移動&#xff0c;其實是電子在移動。 為了定義的統一性[電流方向]仍然定義為正電荷的移動方向 所以:[電流方向]與[電子移動方向]是相反的。 概念:電荷的定向移動&#xff0c;形成了電…

multi paxos協議

1. Redo Log 同步的核心目標 ?數據一致性&#xff1a;確保所有副本在事務提交后具有相同的數據視圖。?容錯性&#xff1a;在主副本故障時&#xff0c;從副本能快速接管并恢復數據。?高吞吐&#xff1a;通過批量同步和并行處理提升效率。 2. Multi Paxos 協議的同步流程 M…