以前作過攝像機標定的研究,不過如今忘了好多,昨天下午又撿起來,好好複習一下(主要是學習opencv一書內容)。算法
攝像機標定基本知識:函數
攝像機標定偏差包括內參(4個)、畸變參數(徑向和切向共5個)、外參(平移和旋轉共6個)。學習
偏差參數分析:攝像機模型採用針孔模型成像模型,因爲中心軸安裝問題,這就形成了精度偏差,就是所謂的相機內參數偏差,使用一個3X3的矩陣表示(A) [fx 0 cx; 0 fy cy; 0 0 1].,有四個未知參數;另因爲針孔成像採光效率不高,使用了透鏡,這就形成的畸變偏差:優化
徑向畸變:這是因爲透鏡先天條件緣由(透鏡形狀),成像儀中心(光學中心)的畸變爲0,隨着向邊緣移動,畸變越厲害。這裏有3個參數,k1,k2,k3其中k3是可選參數。spa
切向畸變:這是攝像機安裝過程形成的,如當透鏡不徹底平行於圖像平面的時候產生的。code
旋轉和平移主要針對外參數,旋轉3個角度和平移3個方向6個參數。orm
棋盤就不介紹了。主要是提取角點,便於後面計算,opencv函數都有函數。書上p423有原理介紹,感興趣的朋友能夠參考書上內容。視頻
opencv實現過程及主要函數介紹:blog
1.首先得到數據源(視頻或圖像),我讀取的一段本身錄的視頻;內存
2.初始化單幀棋盤數據,如6X4,並對棋盤操做提取角點;
用到的函數說明:
CVAPI(int) cvFindChessboardCorners( const void* image, CvSize pattern_size, CvPoint2D32f* corners, int* corner_count CV_DEFAULT(NULL), int flags CV_DEFAULT(CV_CALIB_CB_ADAPTIVE_THRESH+CV_CALIB_CB_NORMALIZE_IMAGE) );
這個函數式找到內角點位置:
image
輸入的棋盤圖,必須是8位的灰度或者彩色圖像。
pattern_size
棋盤圖中每行和每列角點的個數。
corners
檢測到的角點
corner_count
輸出,角點的個數。若是不是NULL,函數將檢測到的角點的個數存儲於此變量。
flags
各類操做標誌,能夠是0或者下面值的組合:
CV_CALIB_CB_ADAPTIVE_THRESH - 使用自適應閾值(經過平均圖像亮度計算獲得)將圖像轉換爲黑白圖,而不是一個固定的閾值。
CV_CALIB_CB_NORMALIZE_IMAGE - 在利用固定閾值或者自適應的閾值進行二值化以前,先使用cvNormalizeHist來均衡化圖像亮度。
CV_CALIB_CB_FILTER_QUADS - 使用其餘的準則(如輪廓面積,周長,方形形狀)來去除在輪廓檢測階段檢測到的錯誤方塊。
void cvFindCornerSubPix(const CvArr* image,CvPoint2D32f* corners,int count,CvSize win,CvSize zero_zone,CvTermCriteria criteria)函數 cvFindCornerSubPix 經過迭代來發現具備子象素精度的角點位置:image
輸入的圖像,必須是8位的灰度或者彩色圖像。
corners
輸入角點的初始座標,也存儲精確的輸出座標。
count
角點數目
win
搜索窗口的一半尺寸。若是win=(5,5)那麼使用(5*2+1)×(5*2+1)=11×11大小的搜索窗口
zero_zone
死區的一半尺寸,死區爲不對搜索區的中央位置作求和運算的區域。它是用來避免自相關矩陣出現的某些可能的奇異性。當值爲(-1,-1)表示沒有死區。
criteria
求角點的迭代過程的終止條件。即角點位置的肯定,要麼迭代數大於某個設定值,或者是精確懂達到某個設定值。criteria能夠是最大迭代數目,或者是設定的精確度,也能夠是它們的組合。
3.攝像機標定求參數,咱們目前求內參和畸變參數進行圖像校訂;
用到的函數說明:void cvCalibrateCamera2( const CvMat* object_points, const CvMat* image_points, const CvMat*point_counts, CvSize image_size, CvMat* intrinsic_matrix, CvMat* distortion_coeffs, CvMat* rotation_vectors=NULL, CvMat* translation_vectors=NULL, int flags=0 );
標定函數,求攝像機內參和外參數:
object_points
定標點的世界座標,爲3xN或者Nx3的矩陣,這裏N是全部視圖中點的總數。
image_points
定標點的圖像座標,爲2xN或者Nx2的矩陣,這裏N是全部視圖中點的總數。
point_counts
向量,指定不一樣視圖裏點的數目,1xM或者Mx1向量,M是視圖數目。
image_size
圖像大小,只用在初始化內參數時。
intrinsic_matrix
輸出內參矩陣(A),若是指定CV_CALIB_USE_INTRINSIC_GUESS和(或)CV_CALIB_FIX_ASPECT_RATION,fx、 fy、 cx和cy部分或者所有必須被初始化。
distortion_coeffs
輸出大小爲4x1或者1x4的向量,裏面爲形變參數[k1, k2, p1, p2]。
rotation_vectors
輸出大小爲3xM或者Mx3的矩陣,裏面爲旋轉向量(旋轉矩陣的緊湊表示方式,具體參考函數cvRodrigues2)
translation_vectors
輸出大小爲3xM或Mx3的矩陣,裏面爲平移向量。
flags
不一樣的標誌,能夠是0,或者下面值的組合:
CV_CALIB_USE_INTRINSIC_GUESS - 內參數矩陣包含fx,fy,cx和cy的初始值。不然,(cx, cy)被初始化到圖像中心(這兒用到圖像大小),焦距用最小平方差方式計算獲得。注意,若是內部參數已知,沒有必要使用這個函數,使用cvFindExtrinsicCameraParams2則可。
CV_CALIB_FIX_PRINCIPAL_POINT - 主點在全局優化過程當中不變,一直在中心位置或者在其餘指定的位置(當CV_CALIB_USE_INTRINSIC_GUESS設置的時候)。
CV_CALIB_FIX_ASPECT_RATIO - 優化過程當中認爲fx和fy中只有一個獨立變量,保持比例fx/fy不變,fx/fy的值跟內參數矩陣初始化時的值同樣。在這種狀況下, (fx, fy)的實際初始值或者從輸入內存矩陣中讀取(當CV_CALIB_USE_INTRINSIC_GUESS被指定時),或者採用估計值(後者狀況中fx和fy可能被設置爲任意值,只有比值被使用)。
CV_CALIB_ZERO_TANGENT_DIST – 切向形變參數(p1, p2)被設置爲0,其值在優化過程當中保持爲0。
4.矯正,利用上步求得的參數對圖像進行矯正。
用到的函數說明,有兩種方法進行矯正,下面都介紹一下:
a.使用cvInitUndistortMap()和cvRemap()來處理,前者用來計算畸變映射,後者把求得的映射應用到圖像。
這個函數計算畸變映射,其中intrinsic_matrix攝像機內參數矩陣(A) [fx 0 cx; 0 fy cy; 0 0 1].distortion_coeffs形變係數向量[k1, k2, p1, p2,k3],大小爲5x1或者1x5。mapx爲x座標的對應矩陣。mapy爲y座標的對應矩陣。void cvInitUndistortMap( const CvMat* intrinsic_matrix, const CvMat* distortion_coeffs, CvArr* mapx, CvArr* mapy );void cvRemap( const CvArr* src, CvArr* dst,const CvArr* mapx, const CvArr* mapy,int flags=CV_INTER_LINEAR+CV_WARP_FILL_OUTLIERS,CvScalar fillval=cvScalarAll(0) );對圖像進行普通幾何變換,求得矯正圖像:
src
輸入圖像.
dst
輸出圖像.
mapx
x座標的映射 (32fC1 image).
mapy
y座標的映射 (32fC1 image).
flags
插值方法和如下開關選項的組合:
CV_WARP_FILL_OUTLIERS - 填充邊界外的像素. 若是輸出圖像的部分象素落在變換後的邊界外,那麼它們的值設定爲 fillval。函數cvInitUndistortMap預先計算非形變對應-正確圖像的每一個像素在形變圖像裏的座標。這個對應能夠傳遞給cvRemap函數(跟輸入和輸出圖像一塊兒)。
b.使用cvUndistort2()這個函數一次完成全部事項,不推薦。
CVAPI(void) cvUndistort2( const CvArr* src, CvArr* dst, const CvMat* camera_matrix, const CvMat* distortion_coeffs, const CvMat* new_camera_matrix CV_DEFAULT(0) );
函數說明:
其中,src爲輸入圖像,dst爲輸出圖像.,camera_matrix攝像機內參數矩陣(A) [fx 0 cx; 0 fy cy; 0 0 1],distortion_coeffs形變係數向量[k1, k2, p1, p2,k3],大小爲5x1或者1x5。
建議仍是使用第一種算法,由於計算畸變映射是一個耗時的操做,當畸變映射不變的時候,使用第一種效率更高。
本人實驗效果以下:
代碼這裏就不留了,opencv也有相似的源碼,有須要的朋友留下聯繫方式能夠發給大家,共勉!