摄像机标定矫正畸变
http://www.lxway.com/49508214.htm
攝像機(jī)標(biāo)定誤差包括內(nèi)參(4個(gè))、畸變參數(shù)(徑向和切向共5個(gè))、外參(平移和旋轉(zhuǎn)共6個(gè))。
誤差參數(shù)分析:攝像機(jī)模型采用針孔模型成像模型,由于中心軸安裝問題,這就造成了精度誤差,就是所謂的相機(jī)內(nèi)參數(shù)誤差,使用一個(gè)3X3的矩陣表示(A) [fx 0 cx; 0 fy cy; 0 0 1].,有四個(gè)未知參數(shù);另由于針孔成像采光效率不高,使用了透鏡,這就造成的畸變誤差:
徑向畸變:這是由于透鏡先天條件原因(透鏡形狀),成像儀中心(光學(xué)中心)的畸變?yōu)?,隨著向邊緣移動,畸變越厲害。這里有3個(gè)參數(shù),k1,k2,k3其中k3是可選參數(shù)。
切向畸變:這是攝像機(jī)安裝過程造成的,如當(dāng)透鏡不完全平行于圖像平面的時(shí)候產(chǎn)生的。
旋轉(zhuǎn)和平移主要針對外參數(shù),旋轉(zhuǎn)3個(gè)角度和平移3個(gè)方向6個(gè)參數(shù)。
棋盤就不介紹了。主要是提取角點(diǎn),便于后面計(jì)算,opencv函數(shù)都有函數(shù)。書上p423有原理介紹,感興趣的朋友可以參考書上內(nèi)容。
opencv實(shí)現(xiàn)過程及主要函數(shù)介紹:
1.首先獲得數(shù)據(jù)源(視頻或圖像),我讀取的一段自己錄的視頻;
2.初始化單幀棋盤數(shù)據(jù),如6X4,并對棋盤操作提取角點(diǎn);
用到的函數(shù)說明:?
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) );這個(gè)函數(shù)式找到內(nèi)角點(diǎn)位置:
-
image
-
輸入的棋盤圖,必須是8位的灰度或者彩色圖像。
-
pattern_size
-
棋盤圖中每行和每列角點(diǎn)的個(gè)數(shù)。
-
corners
-
檢測到的角點(diǎn)
-
corner_count
-
輸出,角點(diǎn)的個(gè)數(shù)。如果不是NULL,函數(shù)將檢測到的角點(diǎn)的個(gè)數(shù)存儲于此變量。
-
flags
-
各種操作標(biāo)志,可以是0或者下面值的組合:
-
CV_CALIB_CB_ADAPTIVE_THRESH - 使用自適應(yīng)閾值(通過平均圖像亮度計(jì)算得到)將圖像轉(zhuǎn)換為黑白圖,而不是一個(gè)固定的閾值。
-
CV_CALIB_CB_NORMALIZE_IMAGE - 在利用固定閾值或者自適應(yīng)的閾值進(jìn)行二值化之前,先使用cvNormalizeHist來均衡化圖像亮度。
-
CV_CALIB_CB_FILTER_QUADS - 使用其他的準(zhǔn)則(如輪廓面積,周長,方形形狀)來去除在輪廓檢測階段檢測到的錯(cuò)誤方塊。
-
image
輸入的圖像,必須是8位的灰度或者彩色圖像。
corners
輸入角點(diǎn)的初始坐標(biāo),也存儲精確的輸出坐標(biāo)。
count
角點(diǎn)數(shù)目
win
搜索窗口的一半尺寸。如果win=(5,5)那么使用(5*2+1)×(5*2+1)=11×11大小的搜索窗口
zero_zone
死區(qū)的一半尺寸,死區(qū)為不對搜索區(qū)的中央位置做求和運(yùn)算的區(qū)域。它是用來避免自相關(guān)矩陣出現(xiàn)的某些可能的奇異性。當(dāng)值為(-1,-1)表示沒有死區(qū)。
criteria
求角點(diǎn)的迭代過程的終止條件。即角點(diǎn)位置的確定,要么迭代數(shù)大于某個(gè)設(shè)定值,或者是精確懂達(dá)到某個(gè)設(shè)定值。criteria可以是最大迭代數(shù)目,或者是設(shè)定的精確度,也可以是它們的組合。
3.攝像機(jī)標(biāo)定求參數(shù),我們目前求內(nèi)參和畸變參數(shù)進(jìn)行圖像校正;
用到的函數(shù)說明: 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 );標(biāo)定函數(shù),求攝像機(jī)內(nèi)參和外參數(shù):
-
object_points
-
定標(biāo)點(diǎn)的世界坐標(biāo),為3xN或者Nx3的矩陣,這里N是所有視圖中點(diǎn)的總數(shù)。
-
image_points
-
定標(biāo)點(diǎn)的圖像坐標(biāo),為2xN或者Nx2的矩陣,這里N是所有視圖中點(diǎn)的總數(shù)。
-
point_counts
-
向量,指定不同視圖里點(diǎn)的數(shù)目,1xM或者M(jìn)x1向量,M是視圖數(shù)目。
-
image_size
-
圖像大小,只用在初始化內(nèi)參數(shù)時(shí)。
-
intrinsic_matrix
-
輸出內(nèi)參矩陣(A),如果指定CV_CALIB_USE_INTRINSIC_GUESS和(或)CV_CALIB_FIX_ASPECT_RATION,fx、 fy、 cx和cy部分或者全部必須被初始化。
-
distortion_coeffs
-
輸出大小為4x1或者1x4的向量,里面為形變參數(shù)[k1, k2, p1, p2]。
-
rotation_vectors
-
輸出大小為3xM或者M(jìn)x3的矩陣,里面為旋轉(zhuǎn)向量(旋轉(zhuǎn)矩陣的緊湊表示方式,具體參考函數(shù)cvRodrigues2)
-
translation_vectors
-
輸出大小為3xM或Mx3的矩陣,里面為平移向量。
-
flags
-
不同的標(biāo)志,可以是0,或者下面值的組合:
-
CV_CALIB_USE_INTRINSIC_GUESS - 內(nèi)參數(shù)矩陣包含fx,fy,cx和cy的初始值。否則,(cx, cy)被初始化到圖像中心(這兒用到圖像大小),焦距用最小平方差方式計(jì)算得到。注意,如果內(nèi)部參數(shù)已知,沒有必要使用這個(gè)函數(shù),使用cvFindExtrinsicCameraParams2則可。
-
CV_CALIB_FIX_PRINCIPAL_POINT - 主點(diǎn)在全局優(yōu)化過程中不變,一直在中心位置或者在其他指定的位置(當(dāng)CV_CALIB_USE_INTRINSIC_GUESS設(shè)置的時(shí)候)。
-
CV_CALIB_FIX_ASPECT_RATIO - 優(yōu)化過程中認(rèn)為fx和fy中只有一個(gè)獨(dú)立變量,保持比例fx/fy不變,fx/fy的值跟內(nèi)參數(shù)矩陣初始化時(shí)的值一樣。在這種情況下, (fx, fy)的實(shí)際初始值或者從輸入內(nèi)存矩陣中讀取(當(dāng)CV_CALIB_USE_INTRINSIC_GUESS被指定時(shí)),或者采用估計(jì)值(后者情況中fx和fy可能被設(shè)置為任意值,只有比值被使用)。
-
CV_CALIB_ZERO_TANGENT_DIST – 切向形變參數(shù)(p1, p2)被設(shè)置為0,其值在優(yōu)化過程中保持為0。
-
4.矯正,利用上步求得的參數(shù)對圖像進(jìn)行矯正。
用到的函數(shù)說明,有兩種方法進(jìn)行矯正,下面都介紹一下:
a.使用cvInitUndistortMap()和cvRemap()來處理,前者用來計(jì)算畸變映射,后者把求得的映射應(yīng)用到圖像。
void cvInitUndistortMap( const CvMat* intrinsic_matrix, const CvMat* distortion_coeffs, CvArr* mapx, CvArr* mapy ); 這個(gè)函數(shù)計(jì)算畸變映射,其中intrinsic_matrix攝像機(jī)內(nèi)參數(shù)矩陣(A) [fx 0 cx; 0 fy cy; 0 0 1].distortion_coeffs形變系數(shù)向量[k1, k2, p1, p2,k3],大小為5x1或者1x5。mapx為x坐標(biāo)的對應(yīng)矩陣。mapy為y坐標(biāo)的對應(yīng)矩陣。 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) );對圖像進(jìn)行普通幾何變換,求得矯正圖像:
???? src
???? 輸入圖像.
dst
輸出圖像.
? mapx
x坐標(biāo)的映射 (32fC1 image).
mapy
y坐標(biāo)的映射 (32fC1 image).
flags
插值方法和以下開關(guān)選項(xiàng)的組合:
? CV_WARP_FILL_OUTLIERS - 填充邊界外的像素. 如果輸出圖像的部分象素落在變換后的邊界外,那么它們的值設(shè)定為 fillval。
函數(shù)cvInitUndistortMap預(yù)先計(jì)算非形變對應(yīng)-正確圖像的每個(gè)像素在形變圖像里的坐標(biāo)。這個(gè)對應(yīng)可以傳遞給cvRemap函數(shù)(跟輸入和輸出圖像一起)。
b.使用cvUndistort2()這個(gè)函數(shù)一次完成所有事項(xiàng),不推薦。
CVAPI(void) cvUndistort2( const CvArr* src, CvArr* dst,const CvMat* camera_matrix,const CvMat* distortion_coeffs,const CvMat* new_camera_matrix CV_DEFAULT(0) );函數(shù)說明:
??? 其中,src為輸入圖像,dst為輸出圖像.,camera_matrix攝像機(jī)內(nèi)參數(shù)矩陣(A) [fx 0 cx; 0 fy cy; 0 0 1],distortion_coeffs形變系數(shù)向量[k1, k2, p1, p2,k3],大小為5x1或者1x5。
建議還是使用第一種算法,因?yàn)橛?jì)算畸變映射是一個(gè)耗時(shí)的操作,當(dāng)畸變映射不變的時(shí)候,使用第一種效率更高。
本人實(shí)驗(yàn)效果如下:
? ? ? ??
???????????????????????????????????????????????
代碼這里就不留了,opencv也有類似的源碼,有需要的朋友留下聯(lián)系方式可以發(fā)給你們,共勉!
總結(jié)
- 上一篇: Facebook发布人工智能产品Deep
- 下一篇: 如何让Ubuntu系统支持WebP图片格