使用相機以前,首先要進行相機標定,其原因是我們通過標定知道相機的內外參、得到內外參矩陣後可對相機拍攝的照片進行矯正,可以得到畸變較小的影像。而相機標定的輸入就是相機所拍的多幀圖片的角點座標,以及標定板影像上所有角點的空間座標(一般Z軸假設為Z=0)。相機標定後的輸出就是相機的內外引數。
針對張正友標定相機的標定流程:1、獲得多幀圖片的角點座標 2、獲取標定板影像上所有角點的空間座標 3、進行相機標定 4、對標定結果進行評價 5、再次利用標定板影像進行矯正 6、 影像座標系轉世界座標系
1、獲得多幀圖片的角點座標
對標定圖片連續拍照,選擇10-20幀圖片,然後對其提取角點資訊。(在此需要注意標定圖片需要清晰)
提取圖片角點選用的函式為:findChessboardCorners函式提取角點
findChessboardCorners函式原型:
- //! finds checkerboard pattern of the specified size in the image
- CV_EXPORTS_W bool findChessboardCorners( InputArray image, Size patternSize,
- OutputArray corners,
- int flags=CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORMALIZE_IMAGE );
引數解析:①Image,傳入拍攝的棋盤圖Mat影像,必須是8位的灰度或者彩色影像;
②patternSize,每個棋盤圖上內角點的行列數,一般情況下,行列數不要相同,便於後續標定程式識別標定板的方向;
③corners,用於儲存檢測到的內角點影像座標位置,一般用元素是Point2f的向量來表示:vector<Point2f> image_points_buf;
④flags:用於定義棋盤圖上內角點查詢的不同處理方式,有預設值。
2、對每一幀圖片進一步提取亞畫素角點資訊
為了提高標定精度,需要在初步提取的角點資訊上進一步提取亞畫素資訊,降低相機標定偏差,常用的方法是cornerSubPix
cornerSubPix函式原型:
- CV_EXPORTS_W void cornerSubPix( InputArray image, InputOutputArray corners,
- Size winSize, Size zeroZone,
- TermCriteria criteria );
引數解析:①Image,傳入拍攝的棋盤圖Mat影像,最好是8位灰度影像,檢測效率更高;
②corners,初始的角點座標向量,同時作為亞畫素座標位置的輸出,所以需要是浮點型資料,一般用元素是Pointf2f/Point2d的向量來表示:vector<Point2f/Point2d> imagePointsBuf
③winSize,大小為搜尋視窗的一半;
④zeroZone,死區的一半尺寸,死區為不對搜尋區的中央位置做求和運算的區域。它是用來避免自相關矩陣出現某些可能的奇異性。當值為(-1,-1)時表示沒有死區;
⑤criteria,定義求角點的迭代過程的終止條件,可以為迭代次數和角點精度兩者的組合;
3、獲取標定板影像上所有角點的空間座標(即物體的實際座標)
以和步驟一相同的方法獲取世界座標系的三維座標即objectPoints,其用向量來表示vector<vector<Point3f>> object_points
4、進行相機標定
獲取到棋盤標定圖的內角點影像座標以及標定板影像的空間座標之後,就可以使用calibrateCamera函式進行標定,計算相機內參和外參係數,
calibrateCamera函式原型:
- CV_EXPORTS_W double calibrateCamera( InputArrayOfArrays objectPoints,
- InputArrayOfArrays imagePoints,
- Size imageSize,
- CV_OUT InputOutputArray cameraMatrix,
- CV_OUT InputOutputArray distCoeffs,
- OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,
- int flags=0, TermCriteria criteria = TermCriteria(
- TermCriteria::COUNT+TermCriteria::EPS, 30, DBL_EPSILON) );
引數解析:①objectPoints,為世界座標系中的三維點。在使用時,應該輸入一個三維座標點的向量的向量,
即vector<vector<Point3f>> object_points。需要依據棋盤上單個黑白矩陣的大小,
計算出(初始化)每一個內角點的世界座標;
②imagePoints,為每一個內角點對應的影像座標點。和objectPoints一樣,應該輸入vector<vector<Point2f>> image_points_seq形式的變數;
③imageSize,為影像的畫素尺寸大小,在計算相機的內參和畸變矩陣時需要使用到該引數;
④cameraMatrix為相機的內參矩陣。輸入一個Mat cameraMatrix即可,如Mat cameraMatrix=Mat(3,3,CV_32FC1,Scalar::all(0));
⑤distCoeffs為畸變矩陣。輸入一個Mat distCoeffs=Mat(1,5,CV_32FC1,Scalar::all(0));
⑥rvecs為旋轉向量;應該輸入一個Mat型別的vector,即vector<Mat>rvecs;
⑦tvecs為位移向量,和rvecs一樣,應該為vector<Mat> tvecs;
⑧flags為標定時所採用的演算法。有如下幾個引數:
CV_CALIB_USE_INTRINSIC_GUESS:使用該引數時,在cameraMatrix矩陣中應該有fx,fy,u0,v0的估計值。否則的話,將初始化(u0,v0)影像的中心點,使用最小二乘估算出fx,fy。
CV_CALIB_FIX_PRINCIPAL_POINT:在進行優化時會固定光軸點。當CV_CALIB_USE_INTRINSIC_GUESS引數被設定,光軸點將保持在中心或者某個輸入的值。
CV_CALIB_FIX_ASPECT_RATIO:固定fx/fy的比值,只將fy作為可變數,進行優化計算。當CV_CALIB_USE_INTRINSIC_GUESS沒有被設定,fx和fy將會被忽略。只有fx/fy的比值在計算中會被用到。
CV_CALIB_ZERO_TANGENT_DIST:設定切向畸變引數(p1,p2)為零。
CV_CALIB_FIX_K1,…,CV_CALIB_FIX_K6:對應的徑向畸變在優化中保持不變。
CV_CALIB_RATIONAL_MODEL:計算k4,k5,k6三個畸變引數。如果沒有設定,則只計算其它5個畸變引數。
5、對標定結果進行評價
對標定結果進行評價的方法是通過得到的攝像機內外引數,對空間的三維點進行重新投影計算,得到空間三維點在影像上新的投影點的座標,計算投影座標和亞畫素角點座標之間的偏差,偏差越小,標定結果越好。
對空間三維座標點進行反向投影的函式是projectPoints,函式原型是:
- CV_EXPORTS_W void projectPoints( InputArray objectPoints,
- InputArray rvec, InputArray tvec,
- InputArray cameraMatrix, InputArray distCoeffs,
- OutputArray imagePoints,
- OutputArray jacobian=noArray(),
- double aspectRatio=0 );
引數解析:①objectPoints,為相機座標系中的三維點座標;
②rvec為旋轉向量,每一張影像都有自己的選擇向量;
③tvec為位移向量,每一張影像都有自己的平移向量;
④cameraMatrix為求得的相機的內引數矩陣;
⑤distCoeffs為相機的畸變矩陣;
⑥imagePoints為每一個內角點對應的影像上的座標點;
⑦jacobian是雅可比行列式;
⑧aspectRatio是跟相機感測器的感光單元有關的可選引數,如果設定為非0,則函式預設感光單元的dx/dy是固定的,會依此對雅可比矩陣進行調整;
6、再次利用標定板影像進行矯正
利用求得的相機的內參和外引數據,可以對影像進行畸變的矯正,使用undistort函式實現。
undistort函式原型:
- CV_EXPORTS_W void undistort( InputArray src, OutputArray dst,
- InputArray cameraMatrix,
- InputArray distCoeffs,
- InputArray newCameraMatrix=noArray() );
引數解析:①src,輸入引數,代表畸變的原始影像;
②dst,矯正後的輸出影像,跟輸入影像具有相同的型別和大小;
③cameraMatrix為之前求得的相機的內參矩陣;
④distCoeffs為之前求得的相機畸變矩陣;
⑤newCameraMatrix,預設跟cameraMatrix保持一致;
7、影像座標系轉世界座標系
影像座標系轉為世界座標系採用的是透視變換,由張正友標定法單應性矩陣,再通過透視變換原理便可得到世界座標系。
參考大佬部落格:張正友標定:
http://blog.csdn.net/dcrmg/article/details/52939318
透視變換原理可參考如下部落格:
http://blog.csdn.net/guduruyu/article/details/72518340