OpenCV在未知相機內參數情況下的立體圖像矯正方法及注意事項

很多時候我們不知道攝像機的內參數矩陣,並且我們也不太關注內參數到底是多少,因爲我們僅僅關心如何得到兩幅圖像的稠密匹配,或者兩幅圖像的差別——例如我們只想計算兩幅圖像的視差圖,或者說得到兩幅立體圖像對的深度圖就足夠了。既然不知道攝像機的內參數,那麼就只能藉助對極約束來達到目的了。通過計算兩幅圖像的基礎矩陣F,然後利用對極約束矯正極線爲平行線的方法,可以很好的實現這個目標,該方法也被稱爲Hartly方法,在OpenCV中由cv::stereoRectifyUncalibrated函數實現。

    立體圖像的極線矯正需要三個步驟:

(1)提取特徵點並匹配,參考http://blog.sina.com.cn/s/blog_4298002e01013w4z.html

(2)計算基本矩陣F,參考http://blog.sina.com.cn/s/blog_4298002e01013w9a.html

(3)極線矯正。

    Hartly方法的函數原型如下:

//! computes the rectification transformation for an uncalibrated stereo camera (zero distortion is assumed)
CV_EXPORTS_W bool stereoRectifyUncalibrated( const Mat& points1, const Mat& points2,
                                             const Mat& F, Size imgSize,
                                             CV_OUT Mat& H1, CV_OUT Mat& H2,
                                             double threshold=5 );

該函數輸入參數爲兩幅圖像的匹配特徵點,基本矩陣F以及圖像的尺寸,返回的參數是兩幅圖像各自對應的單應變換矩陣H1和H2。只需要對兩幅圖像按照H1和H2做單應變換,即可得到矯正後圖像。假設I爲圖像,變換如下:

I_recty = H*I

 

    需要說明一點,該函數的前兩個參數Mat& points1, Mat& points2與cv::findFundamentalMat的前兩個參數並不是相同的數據結構。它們雖然可以是同一個匹配點集,但是他們的數據結構是完全不同的!cv::findFundamentalMat中傳入的匹配點集要求是2xN或者Nx2的矩陣,但是cv::stereoRectifyUncalibrated中要求傳入的匹配點集必須是1x2N或者2Nx1的矩陣!在很多文檔中都說他們的參數是一樣的,這其實是一個天大的錯誤,如果用計算F的匹配點集直接傳給圖像矯正函數,程序將直接崩潰。正確的做法是利用cv::Mat的構造函數,直接從vector<Point2f>構造一個cv::Mat傳入。

    cv::stereoRectifyUncalibrated函數默認原始圖像是沒有徑向畸變的,因此在矯正圖像之前,最好先對原始圖像做徑向矯正。

    另外需要注意的一點,函數返回的單應變換矩陣H1和H2都是double類型,也即CV_64F類型,若不是該類型的矩陣,與之相乘會報錯。下面是示例代碼:

 

// 假設前面我們已經得到兩幅圖像的匹配特徵點,並計算出了基本矩陣F,同時得到了匹配特徵點的inlier

// Mat m_matLeftImage;
// Mat m_matRightImage;

// vector<Point2f> m_LeftInlier;
// vector<Point2f> m_RightInlier;

// Mat m_Fundamental;

 

// 計算圖像矯正的單應變換矩陣

Mat m_LeftH;
Mat m_RightH;

stereoRectifyUncalibrated(Mat(m_LeftInlier), Mat(m_RightInlier), m_Fundamental,
                          Size(m_matLeftImage.cols, m_matLeftImage.rows),
                          m_LeftH, m_RightH);

 

// 任意指定一個內參數矩陣K,不會影響計算結果,此處設爲單位陣。

Mat K = Mat::eye(3, 3, CV_64F); // 注意一定是double類型
Mat invK = K.inv(DECOMP_SVD);
Mat LeftR = invK*m_LeftH*K;     // 根據單應變換矩陣計算左圖攝像機在空間中的變換矩陣R1
Mat RightR = invK*m_RightH*K;   // 計算右圖攝像機在空間中的變換矩陣R2
Mat LeftMap1, LeftMap2;
Mat RightMap1, RightMap2;

Mat Distort;                    // 徑向畸變爲0,設爲空矩陣
Size UndistSize(m_matLeftImage.cols, m_matLeftImage.rows);

 

// 計算左右兩幅圖像的映射矩陣

initUndistortRectifyMap(K, Distort, LeftR, K, UndistSize, CV_32FC1, LeftMap1, LeftMap2);
initUndistortRectifyMap(K, Distort, RightR, K, UndistSize, CV_32FC1, RightMap1, RightMap2);

 

// 把原始圖像投影到新圖像上,得到矯正圖像

Mat m_LeftRectyImage;
Mat m_RightRectyImage;

remap(m_matLeftImage, m_LeftRectyImage, LeftMap1, LeftMap2, INTER_LINEAR);
remap(m_matRightImage, m_RightRectyImage, RightMap1, RightMap2, INTER_LINEAR);

 

// 顯示結果

cvNamedWindow( "left image", 1);
cvShowImage("left image", &(IplImage(m_LeftRectyImage)));
cvNamedWindow( "right image", 1);
cvShowImage("right image", &(IplImage(m_RightRectyImage)));
cvWaitKey( 0 );
cvDestroyWindow( "left image" );
cvDestroyWindow( "right image" );

 

程序計算的結果如下圖所示:

原始圖像對:

OpenCV在未知相機內參數情況下的立體圖像矯正方法及注意事項

極線矯正後的圖像:
OpenCV在未知相機內參數情況下的立體圖像矯正方法及注意事項

    得到上面的矯正圖像之後,就可以計算視差或者進行稠密匹配了。下面以視差計算的應用爲例,分別用GC和SGBM算法計算視差,結果如下圖:

 

SGBM算法:

OpenCV在未知相機內參數情況下的立體圖像矯正方法及注意事項

GC算法:
OpenCV在未知相機內參數情況下的立體圖像矯正方法及注意事項

from: http://blog.sina.com.cn/s/blog_4298002e01013yb8.html


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章