提起來雙目定位,相信許多人像現在的我一樣,緊緊會用現成的公式,了解一些定義,明白那些參數的含義,但是深入的來說,估計連張正友教授的标定算法都沒有推明白。因為其中涉及一些矩陣運算的技巧,沒有數學基礎,或者基礎不牢,都無法深度了解。搞雙目兩年了,以前就是生成一張深度圖,或者進行一下雙目測距,網上的代碼複制粘貼修改一下就能用了,但是現在要搞高精度的雙目視覺定位,就必須深挖下去,搞清楚成像光路的方方面面。這裡,我提供一些網上總結比較好的部落格給新來的朋友鋪墊一下:https://www.cnblogs.com/zyly/p/9366080.html ;這篇部落格不僅系統的講解了成像坐标過程,而且在博文最後列舉了一系列參考部落格,感謝他把!“大奧特曼打小怪獸”;
今天,先說說鏡頭畸變吧,因為沒有一個鏡頭沒有不畸變的,不過是畸變的大小不同,例如你用4.3mm的攝像頭(小型USB相機),基本上是平光鏡頭,其他的規格的,你就不能不考慮鏡頭畸變了。如果你搞搞深度圖,測測距離,基本也沒事那些都是低精度的,誤差大點無所謂,了不起用個張正友标定法,或者Matlib雙目标定一下,精度就不錯了。但是如果你要搞精密測量,糾結mm及的精度,那些方法就總是不能滿足你了。比如現在就不能滿足我了!怎麼辦,深挖技術細節,找到根!
張氏标定法的偉大,在于将标定過程簡化到列印一張A4紙的棋盤格就能獲得比較高的精度,在攝影測量相機标定場總不能還貼A4紙吧!但是,但是,我們還可以用張正友标定法!不過是更加認真的考慮各個因素的用這個方法處理标定問題。這就是方法創新的意義!
說了這麼多多餘的話,就是為了抛出兩個相機标定的函數:OPENCV函數:
【A】CV_EXPORTS_AS(calibrateCameraExtended) double calibrateCamera( InputArrayOfArrays objectPoints,
InputArrayOfArrays imagePoints, Size imageSize,
InputOutputArray cameraMatrix, InputOutputArray distCoeffs,
OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,
OutputArray stdDeviationsIntrinsics,
OutputArray stdDeviationsExtrinsics,
OutputArray perViewErrors,
int flags = 0, TermCriteria criteria = TermCriteria(
TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON) );
這個【A】函數,是一個支援分析标定的函數,輸出的參數中給出了評估結果。
【B】CV_EXPORTS_W double calibrateCamera( InputArrayOfArrays objectPoints,
InputArrayOfArrays imagePoints, Size imageSize,
InputOutputArray cameraMatrix, InputOutputArray distCoeffs,
OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,
int flags = 0, TermCriteria criteria = TermCriteria(
TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON) );
這個【B】函數,與【A】僅有功能差別。
以下是一些關于這兩個函數怎麼用的介紹,直接從OPENCV函數翻譯過來的,翻譯有誤差,這裡說一下自己的了解:
1.InputArrayOfArrays objectPoints
這個objectPoints 就是所用的棋盤格角點的世界坐标,當然這裡由你用的标定闆給出。當然你如果自建标定規則要,注意他的資料類型是std :: vector <std :: vector <cv :: Vec3f >>,這意味着你照相多少次就生成多少次,其中的z坐标都為0;2.InputArrayOfArrays imagePoints
這個imagePoints顧名思義就是在圖像中提取棋盤格的角點的像點坐标,注意這是個資料類型是std :: vector <std :: vector <cv :: Vec2f >>,這個給你照相那些坐标都對照,一一對應
3. InputOutputArray cameraMatrix
這個好說就是相機内參數矩陣,可以初始化也可以不,與你後面選擇的計算模式有關系。
4.InputOutputArray distCoeffs
這個就是今天的重點,畸變參數。可以是4,5,8,12或14個元素。一般大家都用5參數,一般精度這個就夠了。至于高精度時候是不是參數越多越好,有人說多了容易不穩定,這一點我可以肯定的告訴你,對于描述一個模型參數越多肯定會越好,你想想現在的深度學習,那個網絡模型參數不是成千上萬!但是,但是,你參數多你需要拍的圖像就越多,而且你的标定場要建的的好!如果還拿個A4紙當标定闆,那就每必要設那麼多參數了。想想為啥?你的資料品質都不構,怎麼平差解方程!是以,這個地方就是一個分水領,不過對于一般計算機視覺需求,5個參數也就差不多了。
5. OutputArrayOfArrays rvecs,6.OutputArrayOfArrays tvecs
這兩個參數是标定過程中以标定闆為參考,相機的旋轉、平移參數,想想Matlib标定過程中最後給你一個鏡頭的大緻方向顯示。
7.OutputArray stdDeviationsIntrinsics 8.OutputArray stdDeviationsExtrinsics 9.OutputArray perViewErrors
這些個參數是對這次标定結果的評價,值越小代表你标定的越好。
10. int flags = 0,
flags這個參數一般都設成0了,技巧也就在這裡。按說一般要精密标定,一般都要标定好幾次。控制一些置信度較高的參數不變,然後解算其他的。如果畸變參數選用過的不是5參數模型,則這個設定參考函數解釋。
11.TermCriteria criteria = TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON)
這個設定是一個計算疊代的設定,一般不改變。如果高精度标定,也要好好研究一下,第一個參數是類型就是計算疊代的終止條件,第二個是疊代次數,第三個是設定的門檻值。預設的意思是疊代終止條件看後面的兩個參數,最大疊代次數30,最小門檻值是DBL_EPSILON。
标定函數技術細節如此,如有見解歡迎讨論,個人目前研究方向精密視覺測量!
參考如下:
/ ** @brief從校準圖案的多個視圖中查找相機的内部和外部參數。
@param objectPoints在新界面中,它是校準模式點矢量的矢量
校準模式坐标空間(例如std :: vector <std :: vector <cv :: Vec3f >>)。外面的
vector包含與模式視圖的數量一樣多的元素。如果校準模式相同
在每個視圖中顯示并且它是完全可見的,所有向量将是相同的。雖然如此
可以使用部分遮擋的圖案,甚至不同視圖中的不同圖案。然後,
向量将是不同的。這些點是3D,但由于它們處于圖案坐标系中,
那麼,如果鑽機是平面的,那麼将模型放到XY坐标平面上是有意義的
每個輸入對象點的Z坐标為0。
在舊界面中,來自不同視圖的對象點的所有向量被連接配接
一起。
@param imagePoints在新界面中,它是校準投影向量的向量
模式點(例如std :: vector <std :: vector <cv :: Vec2f >>)。 imagePoints.size()和
objectPoints.size()和imagePoints [i] .size()必須等于每個i的objectPoints [i] .size()。
在舊界面中,來自不同視圖的對象點的所有向量被連接配接
一起。
@param imageSize僅用于初始化内在相機矩陣的圖像大小。
@param cameraMatrix輸出3x3浮點相機矩陣
\ f $ A = \ vecthreethree {f_x} {0} {c_x} {0} {f_y} {c_y} {0} {0} {1} \ f $。如果CV \ _CALIB \ _USE \ _INTRINSIC \ _GUESS
和/或CV_CALIB_FIX_ASPECT_RATIO被指定,fx,fy,cx,cy中的部分或全部必須是
在調用函數之前初始化。
@param distCoeffs失真系數的輸出向量
\ f $(k_1,k_2,p_1,p_2 [,k_3 [,k_4,k_5,k_6 [,s_1,s_2,s_3,s_4 [,\ tau_x,\ tau_y]]]])\ f $ of
4,5,8,12或14個元素。
@param rvecs為每個模式視圖估計的旋轉矢量的輸出矢量(參見Rodrigues)
(例如std :: vector <cv :: Mat >>)。也就是說,每個第k個旋轉矢量與相應的一起
第k個平移向量(參見下一個輸出參數描述)帶來校準模式
從模型坐标空間(指定了對象點)到世界坐标
空間,即第k個模式視圖中校準圖案的實際位置(k = 0 .. * M * -1)。
@param tvecs為每個模式視圖估計的平移向量的輸出向量。
@param stdDeviationsIntrinsics為内在參數估算的标準差的輸出向量。
偏內插補點的順序:
\ f $(f_x,f_y,c_x,c_y,k_1,k_2,p_1,p_2,k_3,k_4,k_5,k_6,s_1,s_2,s_3,
s_4,\ tau_x,\ tau_y)\ f $如果沒有估計其中一個參數,它的偏差等于零。
@param stdDeviationsExtrinsics對外部參數估計的标準差的輸出向量。
偏內插補點的順序:\ f $(R_1,T_1,\ dotsc,R_M,T_M)\ f $其中M是模式視圖的數量,
\ f $ R_i,T_i \ f $連接配接1x3向量。
@param perViewErrors為每個模式視圖估計的RMS重新投影誤差的輸出向量。
@param flags可能為零的不同标志或以下值的組合:
- ** CV_CALIB_USE_INTRINSIC_GUESS ** cameraMatrix包含有效的初始值
fx,fy,cx,cy進一步優化。否則,(cx,cy)最初設定為圖像
中心(使用imageSize),并以最小二乘方式計算焦距。
注意,如果已知内部參數,則不需要僅使用此函數
估計外在參數。請改用solvePnP。
- ** CV_CALIB_FIX_PRINCIPAL_POINT **全局期間主要點未更改
優化。它停留在中心或指定的不同位置
CV_CALIB_USE_INTRINSIC_GUESS也已設定。
- ** CV_CALIB_FIX_ASPECT_RATIO **函數僅将fy視為自由參數。該
比率fx / fy保持與輸入cameraMatrix相同。什麼時候
未設定CV_CALIB_USE_INTRINSIC_GUESS,fx和fy的實際輸入值為
忽略,隻計算它們的比率并進一步使用。
- ** CV_CALIB_ZERO_TANGENT_DIST **設定切向失真系數\ f $(p_1,p_2)\ f $
為零并保持為零。
- ** CV_CALIB_FIX_K1,...,CV_CALIB_FIX_K6 **相應的徑向失真
優化期間系數不變。如果CV_CALIB_USE_INTRINSIC_GUESS是
設定,使用提供的distCoeffs矩陣的系數。否則,它被設定為0。
- ** CV_CALIB_RATIONAL_MODEL **啟用系數k4,k5和k6。提供
向後相容性,應該明确指定這個額外的标志來制作
校準函數使用有理模型并傳回8個系數。如果标志不是
設定,該函數僅計算并傳回5個失真系數。
- ** CALIB_THIN_PRISM_MODEL **啟用系數s1,s2,s3和s4。
為了提供向後相容性,應該明确指定這個額外的标志來制作
校準功能使用薄棱鏡模型并傳回12個系數。如果标志不是
設定,該函數僅計算并傳回5個失真系數。
- ** CALIB_FIX_S1_S2_S3_S4 **薄棱鏡失真系數在此期間不會改變
優化。如果設定了CV_CALIB_USE_INTRINSIC_GUESS,則系數來自
提供了distCoeffs矩陣。否則,它被設定為0。
- ** CALIB_TILTED_MODEL **系數tauX和tauY已啟用。提供
向後相容性,應該明确指定這個額外的标志來制作
校準功能使用傾斜傳感器模型并傳回14個系數。如果标志不是
設定,該函數僅計算并傳回5個失真系數。
- ** CALIB_FIX_TAUX_TAUY **傾斜傳感器模型的系數在此期間不會改變
優化。如果設定了CV_CALIB_USE_INTRINSIC_GUESS,則系數來自
提供了distCoeffs矩陣。否則,它被設定為0。
@param criteria疊代優化算法的終止标準。
該函數估計兩個制作立體聲對的相機之間的轉換。如果你有一個立體聲
錄影機,兩個錄影機的相對位置和方向是固定的,如果你計算
相對于第一相機和第二相機(R1,T1)和(R2,T2)的物體姿勢,
分别(這可以用solvePnP完成),那些姿勢肯定是彼此相關的。
這意味着,給定(\ f $ R_1 \ f $,\ f $ T_1 \ f $),應該可以計算(\ f $ R_2 \ f $,\ f $ T_2 \ f $)。隻有你
需要知道第二台錄影機相對于第一台錄影機的位置和方向。這是
所述功能的作用。它計算(\ f $ R \ f $,\ f $ T \ f $),以便:
\ F [R_2 = R * R_1
T_2 = R * T_1 + T,\ f]
可選地,它計算基本矩陣E:
\ f [E = \ vecthreethree {0} { - T_2} {T_1} {T_2} {0} { - T_0} { - T_1} {T_0} {0} * R \ f]
其中\ f $ T_i \ f $是翻譯向量的組成部分\ f $ T \ f $:\ f $ T = [T_0,T_1,T_2] ^ T \ f $。而且功能
也可以計算基本矩陣F:
\ f [F = cameraMatrix2 ^ { - T} E cameraMatrix1 ^ { - 1} \ f]
除了立體聲相關資訊,該功能還可以執行每個的完整校準
兩個相機。但是,由于參數空間的高次元和輸入中的噪聲
資料,該功能可以偏離正确的解決方案。如果内在參數可以
每個錄影機單獨估算高精度(例如,使用
calibrateCamera),建議您這樣做,然後将CV_CALIB_FIX_INTRINSIC标志傳遞給
函數以及計算的内部參數。否則,如果所有參數都是
一次估計,限制一些參數是有意義的,例如,通過
CV_CALIB_SAME_FOCAL_LENGTH和CV_CALIB_ZERO_TANGENT_DIST标志,通常是
合理的假設。
與calibrateCamera類似,該功能最大限度地減少了所有的重新投影誤差
指向兩個攝像頭的所有可用視圖。該函數傳回的最終值
重新投影錯誤。
* /