OpenCV雙目標定校正及三維重建的一些經驗之談

2021-09-19 11:54:39 字數 4009 閱讀 8306

本文主要是對之前做的關於雙目的一些工作的經驗總結,主要是關鍵流程及函式的理解,並不全面,但可以給大家提供一些參考。文中一些解釋都是基於自己的理解,沒有去看函式原始碼,有錯誤的地方還請大家指正。

影象標定是用來獲取相機內參外參的,常用的雙目標定方法是張正友標定,實現方法有matlab和opencv。

matlab有兩種標定方式,手動標定和自動標定。

手動標定:首先利用calib_gui進行單目標定,獲得了兩個相機的內參之後,利用stereo_gui進行雙目標定,該標定方法需要手動選擇棋盤上的四個點,操作比較繁瑣,但是精度較高,獲得的引數比較直觀。個人推薦這種標定方式。

自動標定:利用stereocameracalibrator工具箱進行標定,該方法操作比較簡單,不用手動選點,但是引數不是非常直觀,不適合標定畸變較大的相機。

opencv利用harris自動檢測角點,網上標定例程較多,下面主要介紹關鍵的函式及相關流程。

stereocalibrate ()

該函式第乙個輸入引數objectpoints是所有棋盤角點在世界座標系中的三維座標,該世界座標系是以棋盤平面為xoy面,原點是第乙個棋盤角點,z軸垂直於棋盤平面。即第乙個棋盤角點的座標為(0,0,0),根據棋盤格的實際大小,以此類推。

第二和第三個引數imagepoints分別表示左右影象中檢測到的棋盤角點座標。接下來的四個引數是輸入/輸出引數,也就是說可以選擇填入預先單獨標定好的兩個相機的引數,這個引數可以由calibratecamera()函式分別對兩個相機的棋盤影象進行標定獲得,此時需要設定引數flagcv_calib_use_intrinsic_guess。另外,也可以直接填入空的mat型別,不過但是這樣雙目標定引數沒有經過優化,不是很精確。

引數rt分別表示輸出的旋轉矩陣(3 * 3)和平移向量(1 * 3)。其中,matlab標定的獲得的一般是(1*3)的旋轉向量,可以利用羅德里格斯變換rodrigues()進行旋轉矩陣和相互轉換。兩種標定方式均是以左目座標系作為世界座標系,即左目的旋轉矩陣為[1,0,0;0,1,0;0,0,1],平移向量為[0,0,0],引數rt為右目相對於左目的旋轉矩陣和平移向量。舉個例子,若雙目相機比較理想,獲得的平移向量為[-80,0,0],基線大致就是8cm。

利用opencv進行標定時,盡量先對兩個相機進行單獨標定,然後再進行雙目標定,這樣標定的引數較為精確。

cvfindextrinsiecameraparams2()當然,雙目標定肯定不是只有一種方法,有的標定程式是用這個函式求解外參的,同樣是先利用calibratecamera()函式分別進行單目標定,然後用這個函式求外參。這個函式在棋盤上建立世界座標系,獲得兩個相機相對於棋盤這個座標系的旋轉平移向量,不是很常用,因為這樣座標轉化比較麻煩。

projectpoints()

該函式用來進行精度評價,所謂精度評價就是將已知的三維角點座標利用計算獲得的內參外參反投影到成像平面,這是乙個世界座標係向畫素座標系的投影過程,計算新投影角點與之前檢測得到的角點之間的歐氏距離,獲得投影誤差,可以對標定的內參外參進行評價。注意,精度評價是對每乙個相機進行評價,也就是說,不能用雙目標定的獲得的內參和外參。這個函式的世界座標系是在棋盤平面上的,所以傳入的引數是calibratecamera()計算獲得的單目內參外參,這個外參是針對每乙個棋盤影象,相機相對於世界座標系,即每乙個棋盤影象平面的位置。

由於安裝問題,兩個相機的成像平面一般不平行,雖然可以利用極線約束找到匹配點,但是由於不是行對準的,搜尋路徑就是二維的,增加了計算量。影象校正就是利用相機標定引數將兩個影象投影到乙個新的平面,構成乙個理想的雙目視覺系統,下面同樣對校正流程的函式進行介紹。

stereorectify()

這個函式的輸入就是雙目的內參和外參,輸出的引數plpr一說是左右影象投影矩陣,另一種說法是新的相機引數矩陣。由於之前跑orb-slam2的時候需要相機引數yaml檔案,裡面的引數就是用此函式計算,plpr和輸入的相機內參形式一樣,數值也差別不大,並且plpr兩個矩陣的fx,fy的位置數值是相等的,即fx1=fy1=fx2=fy2,如下圖。(其中fx和fy分別代表相機的有效焦距,一般相機的畫素單元接近正方形,所以兩個數值應該是相差不大,但是不會絕對相等。)我的理解是:這個數值就是校正後雙目相機焦距,因為雙目經過校正後的焦距應該是一樣的,但這個理論沒有找到明確的解釋。

pr第(1,4)個引數理論上是- bf,基線*焦距,單位是m。這是我之前看orb-slam2的一篇部落格中提到的,我在orb-slam2中輸入的是62.687,獲得的點雲是正確的。實際中,我的相機平移向量第乙個引數,即基線為81.982,乘以上面的764.1899***結果是62649.***,兩者相差不大。還有,從上圖可以看到,兩個畫素的尺寸引數也都是相同的。

另外乙個要注意的地方就是倒數第四個引數alpha,它可以取-1,0,1,其中alpha=1時,校正後的影象不經過裁剪,此時校正後的變形比較大,alpha=-1時取預設值,但仍會存在部分變形。alpha=1時,函式會對校正後的影象進行裁剪,鋪滿整個檢視,影象無變形。三種方法獲取的prpl也是不同的,在slam中一般令alpha=1

initundistortrectifymap() & remap()

相機校正後,需要利用兩個initundistortrectifymap()函式分別對左右相機進行校正查詢對映表,這個函式前兩個引數輸入是相機的內參和畸變係數,之後的兩個引數是stereorectify()計算獲得的修正變換矩陣p和引數矩陣r,最後兩個引數輸出對映矩陣。remap()函式根據對映矩陣對原圖進行畫素的重對映,得到校正後的影象。之後就是對兩幅影象進行劃線顯示了。這樣就完成了影象的校正。

雙目的三維重建有很多形式及應用,最主要的就是測距和場景恢復。

一、測距另外還有一種測距方法,可以對指定的一點求三維座標,對於畸變不大的相機精度也在厘公尺級。這種方法不需要影象校正,直接用最小二乘法(svd分解)求變換方程組,獲得一點的距離。這種方法用來測距也不錯,非常的實時,但是需要獲取兩幅影象中目標的二維座標,對目標檢測演算法要求較高,要求實時的話可以用yolo

二、場景恢復

當然sift、surf、orb等特徵檢測演算法也可以用來測距,但是一般它們還是用來對場景進行重建比較好。利用特徵點實現雙目三維重建的方法很簡單,首先對校正後的影象檢測特徵點並進行描述,利用匹配演算法進行匹配,篩選特徵點後利用基線和焦距進行三角測量獲得所有點三維座標,形成稀疏的點雲,可以利用opengl或者matalb進行顯示。

利用這些演算法實現的sfmslam、傾斜攝影等都屬於場景恢復的範疇,這幾種方法原理大同小異,但是用在不同的場景。orb_slam是乙個比較優秀的實時slam,它有雙目的介面,直接輸入雙目影象,進行校正,輸入slam就可以了。

opencv雙目標定

有 解釋 opencv有自帶的雙目標定例子。下邊opencv雙目相機校正的 是在自帶的程式stereo calib.cpp基礎上修改的,位置在 xx opencv sources samples cpp 使用時拷貝目錄下的26張和stereo calib.xml到當前工程目錄下,並在工程除錯 命令引...

opencv 單目雙目標定錯誤集錦

一.對於物點像點不匹配的問題 opencv 4.2.0 error unspecified error number of object and image points must be equal expected numberofobjectpoints numberofimagepoints ...

OpenCV實現SfM(二) 雙目三維重建

目錄 在三維重建前,我們先研究一下同一點在兩個相機中的像的關係。假設在世界座標系中有一點 p 座標為 x 它在1相機中的像為x1 在2相機中的像為x2 注意x1 和x2 為齊次座標,最後乙個元素是1 如下圖。到兩個相機像面的垂直距離分別為s1 和s2 且這兩個相機具有相同的內參矩陣 k 與世界座標系...