[編輯] 針孔相機模型和變形這一節(jié)里的函數(shù)都使用針孔攝像機模型,這就是說,一幅視圖是通過透視變換將三維空間中的點投影到圖像平面。投影公式如下: 或者
這里(X, Y, Z)是一個點的世界坐標(biāo),(u, v)是點投影在圖像平面的坐標(biāo),以像素為單位。A被稱作攝像機矩陣,或者內(nèi)參數(shù)矩陣。(cx, cy)是基準(zhǔn)點(通常在圖像的中心),fx, fy是以像素為單位的焦距。所以如果因為某些因素對來自于攝像機的一幅圖像升采樣或者降采樣,所有這些參數(shù)(fx, fy, cx和cy)都將被縮放(乘或者除)同樣的尺度。內(nèi)參數(shù)矩陣不依賴場景的視圖,一旦計算出,可以被重復(fù)使用(只要焦距固定)。旋轉(zhuǎn)-平移矩陣[R|t]被 稱作外參數(shù)矩陣,它用來描述相機相對于一個固定場景的運動,或者相反,物體圍繞相機的的剛性運動。也就是[R|t]將點(X, Y, Z)的坐標(biāo)變換到某個坐標(biāo)系,這個坐標(biāo)系相對于攝像機來說是固定不變的。上面的變換等價與下面的形式(z≠0):
x' = x / z y' = y / z
真正的鏡頭通常有一些形變,主要的變形為徑向形變,也會有輕微的切向形變。所以上面的模型可以擴展為:
x' = x / z y' = y / z
這里 r2 = x'2 + y'2
k1和k2是徑向形變系數(shù),p1和p1是切向形變系數(shù)。OpenCV中沒有考慮高階系數(shù)。形變系數(shù)跟拍攝的場景無關(guān),因此它們是內(nèi)參數(shù),而且與拍攝圖像的分辨率無關(guān)。 后面的函數(shù)使用上面提到的模型來做如下事情:
[編輯] 照相機定標(biāo)[編輯] ProjectPoints2 //本函數(shù)實現(xiàn)由現(xiàn)實中的點的坐標(biāo)找到圖像中的點的坐標(biāo)
投影三維點到圖像平面 void cvProjectPoints2( const CvMat* object_points, const CvMat* rotation_vector, const CvMat* translation_vector, const CvMat* intrinsic_matrix, const CvMat* distortion_coeffs, CvMat* image_points, CvMat* dpdrot=NULL, CvMat* dpdt=NULL, CvMat* dpdf=NULL, CvMat* dpdc=NULL, CvMat* dpddist=NULL );
函數(shù)cvProjectPoints2通過給定的內(nèi)參數(shù)和外參數(shù)計算三維點投影到二維圖像平面上的坐標(biāo)。另外,這個函數(shù)可以計算關(guān)于投影參數(shù)的圖像 點偏導(dǎo)數(shù)的雅可比矩陣。雅可比矩陣可以用在cvCalibrateCamera2和cvFindExtrinsicCameraParams2函數(shù)的全局 優(yōu)化中。這個函數(shù)也可以用來計算內(nèi)參數(shù)和外參數(shù)的反投影誤差。 注意,將內(nèi)參數(shù)和(或)外參數(shù)設(shè)置為特定值,這個函數(shù)可以用來計算外變換(或內(nèi)變換)。 [編輯] FindHomography計算兩個平面之間的透視變換 void cvFindHomography( const CvMat* src_points, const CvMat* dst_points, CvMat* homography );
函數(shù)cvFindHomography計算源平面和目標(biāo)平面之間的透視變換.
使得反投影錯誤最小:
這個函數(shù)可以用來計算初始的內(nèi)參數(shù)和外參數(shù)矩陣。由于Homography矩陣的尺度可變,所以它被規(guī)一化使得h33 = 1 [編輯] CalibrateCamera2利用定標(biāo)來計算攝像機的內(nèi)參數(shù)和外參數(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 );
函數(shù)cvCalibrateCamera2從每個視圖中估計相機的內(nèi)參數(shù)和外參數(shù)。3維物體上的點和它們對應(yīng)的在每個視圖的2維投影必須被指定。這 些可以通過使用一個已知幾何形狀且具有容易檢測的特征點的物體來實現(xiàn)。這樣的一個物體被稱作定標(biāo)設(shè)備或者定標(biāo)模式,OpenCV有內(nèi)建的把棋盤當(dāng)作定標(biāo)設(shè) 備方法(參考cvFindChessboardCorners)。目前,傳入初始化的內(nèi)參數(shù)(當(dāng) CV_CALIB_USE_INTRINSIC_GUESS不被設(shè)置時)只支持平面定標(biāo)設(shè)備(物體點的Z坐標(biāo)必須為全0或者全1)。不過3維定標(biāo)設(shè)備依然 可以用在提供初始內(nèi)參數(shù)矩陣情況。在內(nèi)參數(shù)和外參數(shù)矩陣的初始值都計算出之后,它們會被優(yōu)化用來減小反投影誤差(圖像上的實際坐標(biāo)跟 cvProjectPoints2計算出的圖像坐標(biāo)的差的平方和)。 [編輯] FindExtrinsicCameraParams2計算指定視圖的攝像機外參數(shù) void cvFindExtrinsicCameraParams2( const CvMat* object_points, const CvMat* image_points, const CvMat* intrinsic_matrix, const CvMat* distortion_coeffs, CvMat* rotation_vector, CvMat* translation_vector );
函數(shù)cvFindExtrinsicCameraParams2使用已知的內(nèi)參數(shù)和某個視圖的外參數(shù)來估計相機的外參數(shù)。3維物體上的點坐標(biāo)和相應(yīng)的2維投影必須被指定。這個函數(shù)也可以用來最小化反投影誤差。 [編輯] Rodrigues2進(jìn)行旋轉(zhuǎn)矩陣和旋轉(zhuǎn)向量間的轉(zhuǎn)換 int cvRodrigues2( const CvMat* src, CvMat* dst, CvMat* jacobian=0 );
函數(shù)轉(zhuǎn)換旋轉(zhuǎn)向量到旋轉(zhuǎn)矩陣,或者相反。旋轉(zhuǎn)向量是旋轉(zhuǎn)矩陣的緊湊表示形式。旋轉(zhuǎn)向量的方向是旋轉(zhuǎn)軸,向量的長度是圍繞旋轉(zhuǎn)軸的旋轉(zhuǎn)角。旋轉(zhuǎn)矩陣R,與其對應(yīng)的旋轉(zhuǎn)向量r,通過下面公式轉(zhuǎn)換:
反變換也可以很容易的通過如下公式實現(xiàn):
旋轉(zhuǎn)向量是只有3個自由度的旋轉(zhuǎn)矩陣一個方便的表示,這種表示方式被用在函數(shù)cvFindExtrinsicCameraParams2和cvCalibrateCamera2內(nèi)部的全局最優(yōu)化中。 [編輯] Undistort2校正圖像因相機鏡頭引起的變形 void cvUndistort2( const CvArr* src, CvArr* dst, const CvMat* intrinsic_matrix, const CvMat* distortion_coeffs );
函數(shù)cvUndistort2對圖像進(jìn)行變換來抵消徑向和切向鏡頭變形。相機參數(shù)和變形參數(shù)可以通過函數(shù)cvCalibrateCamera2取 得。使用本節(jié)開始時提到的公式,對每個輸出圖像像素計算其在輸入圖像中的位置,然后輸出圖像的像素值通過雙線性插值來計算。如果圖像得分辨率跟定標(biāo)時用得 圖像分辨率不一樣,fx、fy、cx和cy需要相應(yīng)調(diào)整,因為形變并沒有變化。 [編輯] InitUndistortMap計算形變和非形變圖像的對應(yīng)(map) void cvInitUndistortMap( const CvMat* intrinsic_matrix, const CvMat* distortion_coeffs, CvArr* mapx, CvArr* mapy );
函數(shù)cvInitUndistortMap預(yù)先計算非形變對應(yīng)-正確圖像的每個像素在形變圖像里的坐標(biāo)。這個對應(yīng)可以傳遞給cvRemap函數(shù)(跟輸入和輸出圖像一起)。 [編輯] FindChessboardCorners尋找棋盤圖的內(nèi)角點位置 int cvFindChessboardCorners( const void* image, CvSize pattern_size, CvPoint2D32f* corners, int* corner_count=NULL, int flags=CV_CALIB_CB_ADAPTIVE_THRESH );
函數(shù)cvFindChessboardCorners試圖確定輸入圖像是否是棋盤模式,并確定角點的位置。如果所有角點都被檢測到且它們都被以一定 順序排布(一行一行地,每行從左到右),函數(shù)返回非零值,否則在函數(shù)不能發(fā)現(xiàn)所有角點或者記錄它們地情況下,函數(shù)返回0。例如一個正常地棋盤圖右8x8個 方塊和7x7個內(nèi)角點,內(nèi)角點是黑色方塊相互聯(lián)通地位置。這個函數(shù)檢測到地坐標(biāo)只是一個大約地值,如果要精確地確定它們的位置,可以使用函數(shù) cvFindCornerSubPix。 [編輯] DrawChessBoardCorners繪制檢測到的棋盤角點 void cvDrawChessboardCorners( CvArr* image, CvSize pattern_size, CvPoint2D32f* corners, int count, int pattern_was_found );
當(dāng)棋盤沒有完全檢測出時,函數(shù)cvDrawChessboardCorners以紅色圓圈繪制檢測到的棋盤角點;如果整個棋盤都檢測到,則用直線連接所有的角點。 [編輯] 姿態(tài)估計[編輯] CreatePOSITObject初始化包含對象信息的結(jié)構(gòu) CvPOSITObject* cvCreatePOSITObject( CvPoint3D32f* points, int point_count );
函數(shù) cvCreatePOSITObject 為對象結(jié)構(gòu)分配內(nèi)存并計算對象的逆矩陣。 預(yù)處理的對象數(shù)據(jù)存儲在結(jié)構(gòu)CvPOSITObject中,只能在OpenCV內(nèi)部被調(diào)用,即用戶不能直接讀寫數(shù)據(jù)結(jié)構(gòu)。用戶只可以創(chuàng)建這個結(jié)構(gòu)并將指針傳遞給函數(shù)。 對象是在某坐標(biāo)系內(nèi)的一系列點的集合,函數(shù) cvPOSIT計算從照相機坐標(biāo)系中心到目標(biāo)點points[0] 之間的向量。 一旦完成對給定對象的所有操作,必須使用函數(shù)cvReleasePOSITObject釋放內(nèi)存。 [編輯] POSIT執(zhí)行POSIT算法 void cvPOSIT( CvPOSITObject* posit_object, CvPoint2D32f* image_points, double focal_length, CvTermCriteria criteria, CvMatr32f rotation_matrix, CvVect32f translation_vector );
函數(shù) cvPOSIT 執(zhí)行POSIT算法。圖像坐標(biāo)在攝像機坐標(biāo)系統(tǒng)中給出。焦距可以通過攝像機標(biāo)定得到。算法每一次迭代都會重新計算在估計位置的透視投影。 兩次投影之間的范式差值是對應(yīng)點中的最大距離。如果差值過小,參數(shù)criteria.epsilon就會終止程序。 [編輯] ReleasePOSITObject釋放3D對象結(jié)構(gòu) void cvReleasePOSITObject( CvPOSITObject** posit_object );
函數(shù) cvReleasePOSITObject 釋放函數(shù) cvCreatePOSITObject分配的內(nèi)存。 [編輯] CalcImageHomography計算長方形或橢圓形平面對象(例如胳膊)的Homography矩陣 void cvCalcImageHomography( float* line, CvPoint3D32f* center, float* intrinsic, float* homography );
函數(shù) cvCalcImageHomography 為從圖像平面到圖像平面的初始圖像變化(defined by 3D oblong object line)計算Homography矩陣。 [編輯] 對極幾何(雙視幾何)[編輯] FindFundamentalMat由兩幅圖像中對應(yīng)點計算出基本矩陣 int cvFindFundamentalMat( const CvMat* points1, const CvMat* points2, CvMat* fundamental_matrix, int method=CV_FM_RANSAC, double param1=1., double param2=0.99, CvMat* status=NULL);
對極幾何可以用下面的等式描述:
其中 F 是基本矩陣,p1 和 p2 分別是兩幅圖上的對應(yīng)點。 函數(shù) FindFundamentalMat 利用上面列出的四種方法之一計算基本矩陣,并返回基本矩陣的值:沒有找到矩陣,返回0,找到一個矩陣返回1,多個矩陣返回3。 計算出的基本矩陣可以傳遞給函數(shù)cvComputeCorrespondEpilines來計算指定點的對極線。 例子1:使用 RANSAC 算法估算基本矩陣。 int numPoints = 100; CvMat* points1; CvMat* points2; CvMat* status; CvMat* fundMatr; points1 = cvCreateMat(2,numPoints,CV_32F); points2 = cvCreateMat(2,numPoints,CV_32F); status = cvCreateMat(1,numPoints,CV_32F); /* 在這里裝入對應(yīng)點的數(shù)據(jù)... */ fundMatr = cvCreateMat(3,3,CV_32F); int num = cvFindFundamentalMat(points1,points2,fundMatr,CV_FM_RANSAC,1.0,0.99,status); if( num == 1 ) printf("Fundamental matrix was found\n"); else printf("Fundamental matrix was not found\n"); 例子2:7點算法(3個矩陣)的情況。 CvMat* points1; CvMat* points2; CvMat* fundMatr; points1 = cvCreateMat(2,7,CV_32F); points2 = cvCreateMat(2,7,CV_32F); /* 在這里裝入對應(yīng)點的數(shù)據(jù)... */ fundMatr = cvCreateMat(9,3,CV_32F); int num = cvFindFundamentalMat(points1,points2,fundMatr,CV_FM_7POINT,0,0,0); printf("Found %d matrixes\n",num); [編輯] ComputeCorrespondEpilines為一幅圖像中的點計算其在另一幅圖像中對應(yīng)的對極線。 void cvComputeCorrespondEpilines( const CvMat* points, int which_image, const CvMat* fundamental_matrix, CvMat* correspondent_lines);
函數(shù) ComputeCorrespondEpilines 根據(jù)外級線幾何的基本方程計算每個輸入點的對應(yīng)外級線。如果點位于第一幅圖像(which_image=1),對應(yīng)的對極線可以如下計算 :
其中F是基本矩陣,p1 是第一幅圖像中的點, l2 - 是與第二幅對應(yīng)的對極線。如果點位于第二副圖像中 which_image=2),計算如下:
其中p2 是第二幅圖像中的點,l1 是對應(yīng)于第一幅圖像的對極線,每條對極線都可以用三個系數(shù)表示 a, b, c:
歸一化后的對極線系數(shù)存儲在correspondent_lines 中。 [編輯] ConvertPointsHomogeniousConvert points to/from homogenious coordinates void cvConvertPointsHomogenious( const CvMat* src, CvMat* dst );
The function cvConvertPointsHomogenious converts 2D or 3D points from/to homogenious coordinates, or simply copies or transposes the array. In case if the input array dimensionality is larger than the output, each point coordinates are divided by the last coordinate:
If the output array dimensionality is larger, an extra 1 is appended to each point. (x,y[,z]) -> (x,y[,z],1) Otherwise, the input array is simply copied (with optional tranposition) to the output. Note that, because the function accepts a large variety of array layouts, it may report an error when input/output array dimensionality is ambiguous. It is always safe to use the function with number of points N>=5, or to use multi-channel Nx1 or 1xN arrays. |
|