双目立体图像矫正方法简述
/**好記性不如爛筆頭,將自己之前做的一些工作做一個簡單總結**/
在立體視覺中只有當兩個相機成像平面完全平行且行對準時,在立體匹配計算立體視差過程中是最簡單的,為了使相機兩成像平面完全平行且行對準,OpenCV提供了非標定和標定的方法來計算左右相機的校正矩陣。
一、非標定方法:
非標定方法也稱為(Hartley)方法,有時候我們不知道相機的內參矩陣,而且也不用知道內參數具體是多少,因為我們僅關心如何得到兩幅圖像的稠密匹配,或者兩幅圖像之間的視差圖或者深度圖就足夠了。因為不知道相機的內參數,所以只能借助對極約束來解決問題了,通過計算兩幅圖像的基礎矩陣F,然后利用對極約束條件中對極線為平行且行對準,可以很好的實現目標。在opencv中接口函數為:cvStereoRectifyUncalibrated(),具體如下:
(摘自:http://blog.sina.com.cn/s/blog_4298002e01013yb8.html)
//! computes the rectification transformation for an uncalibrated stereo camera (zero distortion is assumed) 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為圖像,變換如下:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?
需要說明一點,該函數的前兩個參數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" );二、標定方法:
標定方法也稱為(Bouguet)方法,需要先分別對兩個相機進行標定,分別得出兩個相機的內參數矩陣,然后再進行立體標定,進行立體圖像的矯正。在opencv中用cvStereoRectify()函數來計算相機矯正矩陣。簡單實用如下:
/* 計算 3D 坐標點 */vector<vector<Point3f>> objRealPoint; //標定板上世界坐標系下3D點的坐標calRealPoint(objRealPoint,boardSize,squareSize,goodFrame);/* 雙目標定 */cv::Mat R, T, E, F; //兩個相機平面之間的 旋轉矩陣 平移矩陣 本征矩陣 基礎矩陣double rms = stereoCalibrate(objRealPoint, imagePointL, imagePointR, cameraMatrixL, distCoeffL, cameraMatrixR, distCoeffR, imageSize, R, T, E, F, CALIB_USE_INTRINSIC_GUESS, TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 100, 1e-5));std::cout << "Stereo Calibration RMSE is : " << rms << std::endl;/*立體校正的時候需要兩幅圖像共面并且行對準,以使得立體匹配更方便使的兩幅圖像共面的方法就是把兩個相機平面投影到一個公共的成像平面上,這樣每幅圖像投影到公共平面就需要一個旋轉矩陣R, stereoRectify()這個函數計算的就是從圖像平面投影到公共成像平面的的旋轉矩陣Rl,Rr.RlRr就是左右相機平面共面的校正旋轉矩陣,左相機經過Rl旋轉,右相機經過Rr旋轉之后,兩幅圖像就已經共面了;其中Pl Pr為兩個相機的校正內參矩陣(3x4,最后一列為0),也可以稱為相機坐標系到像素坐標系的投影矩陣,Q 為像素坐標系與相機坐標系之間的重投影矩陣;*/Rect validROIL, validROIR;cv::Mat Rl, Pl, Rr, Pr, Q;stereoRectify(cameraMatrixL, distCoeffL, cameraMatrixR, distCoeffR, imageSize, R, T, Rl, Rr, Pl, Pr, Q, CALIB_ZERO_DISPARITY, -1, imageSize, &validROIL, &validROIR);/*根據stereoRectify 計算出來的R 和 P 來計算圖像的映射表 mapx, mapymapx, mapy這兩個映射表接下來可以給remap()函數調用,來校正圖像,使得兩幅圖像共面并且行對準*/ cv::Mat mapLx, mapLy, mapRx, mapRy;initUndistortRectifyMap(cameraMatrixL, distCoeffL, Rl, Pl, imageSize, CV_32FC1, mapLx, mapLy);initUndistortRectifyMap(cameraMatrixR, distCoeffR, Rr, Pr, imageSize, CV_32FC1, mapRx, mapRy);Mat rectifyImageL, rectifyImageR;cvtColor(imgGrayL, rectifyImageL, CV_GRAY2BGR);cvtColor(imgGrayR, rectifyImageR, CV_GRAY2BGR);DisplayScreen(rectifyImageL, rectifyImageR, validROIL, validROIR, false,"rectiftBefor");/*經過remap之后,左右相機的圖像已經共面并且行對準了*/remap(rectifyImageL, rectifyImageL, mapLx, mapLy, INTER_LINEAR);remap(rectifyImageR, rectifyImageR, mapRx, mapRy, INTER_LINEAR);DisplayScreen(rectifyImageL,rectifyImageR,validROIL,validROIR,true);PrintParem(R,T,Rl,Rr,Pl,Pr);參考博客:
https://blog.csdn.net/laobai1015/article/details/54575839
?
?
?
總結
以上是生活随笔為你收集整理的双目立体图像矫正方法简述的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java IO练习--在程序中写一个“H
- 下一篇: python 疯狂讲义 笔记(变量和基本