双目摄像头立体成像(二)畸变矫正与立体校正
一、立體校正的原因
**原因一:**當畸變系數和內外參數矩陣標定完成后,就應該進行畸變矯正,以達到消除畸變的目的。
**原因二:**在立體成像原理中提到,要通過兩幅圖像估計物點的深度信息,就必須在兩幅圖像中準確的匹配到同一物點,這樣才能根據該物點在兩幅圖像中的位置關系,計算物體深度。
為了降低匹配的計算量,兩個攝像頭的成像平面應處于同一平面。但是,單單依靠嚴格的擺放攝像頭來達到這個目的顯然有些困難。立體校正就是利用幾何圖形變換(Geometric Image Transformation)關系,使得原先不滿足上述位置關系的兩幅圖像滿足該條件。
二、畸變校正(compensate lens distortion)和立體校正(stereo rectify)的數學原理
(一)畸變校正(compensate lens distortion)
畸變矯正的方法就是用上一篇博文給出的公式對像素位置進行重新映射。這里重新寫出重新映射的公式。
先矯正徑向畸變
再矯正切向畸變
(二)立體校正(stereo rectify)
立體矯正能夠有效降低立體匹配的計算量,立體矯正的具體作用見下圖,
立體矯正前,
立體矯正后,
立體矯正的算法原理沒有詳細了解,此處從略。
OpenCV相關函數說明
一、畸變矯正函數 undistort( )
undistort() 是獨立的一個畸變矯正函數,一次性可以完成映射矩陣的求解和重新映射。下面我們還會看到把這兩步分開來做的函數。
調用方法:略
參數介紹:
1. src-輸入未經過矯正的圖像
2. dst-經過矯正后輸出的圖像
3. cameraMatrix-標定而得到的攝像機矩陣
4. distCoeffs-標定得到的攝像機畸變矩陣
5. newCameraMatrix-輸入矯正后的攝像機矩陣(可以省略)
二、立體標定函數 stereoCalibrate()
stereoCalibrate( ) 是用來標定一個立體攝像頭的,也就是同時標定兩個攝像頭。標定的結果除了能夠求出兩個攝像頭的內外參數矩陣,跟能夠得出兩個攝像頭的位置關系R,T。
調用方法:
double stereoCalibrate(InputArrayOfArrays objectPoints,InputArrayOfArrays imagePoints1, InputArrayOfArrays imagePoints2, InputOutputArray cameraMatrix1,InputOutputArray distCoeffs1, InputOutputArray cameraMatrix2, InputOutputArray distCoeffs2, Size imageSize, OutputArray R,OutputArray T, OutputArray E, OutputArray F, TermCriteria criteria=TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 1e-6), int flags=CALIB_FIX_INTRINSIC )參數介紹:
14.1 CV_CALIB_FIX_INTRINSIC 如果該標志被設置,那么就會固定輸入的cameraMatrix和distCoeffs不變,只求解 $R,T,E,F
$.
14.2 CV_CALIB_USE_INTRINSIC_GUESS 根據用戶提供的cameraMatrix和distCoeffs為初始值開始迭代
14.3 CV_CALIB_FIX_PRINCIPAL_POINT 迭代過程中不會改變主點的位置
14.4. CV_CALIB_FIX_FOCAL_LENGTH 迭代過程中不會改變焦距
14.5 CV_CALIB_SAME_FOCAL_LENGTH 強制保持兩個攝像機的焦距相同
14.6 CV_CALIB_ZERO_TANGENT_DIST 切向畸變保持為零
14.7 CV_CALIB_FIX_K1,…,CV_CALIB_FIX_K6 迭代過程中不改變相應的值。如果設置了 CV_CALIB_USE_INTRINSIC_GUESS 將會使用用戶提供的初始值,否則設置為零
14.8 CV_CALIB_RATIONAL_MODEL 畸變模型的選擇,如果設置了該參數,將會使用更精確的畸變模型,distCoeffs的長度就會變成8
三、立體校正函數 stereoRectify()
stereoRectify() 的作用是為每個攝像頭計算立體校正的映射矩陣。所以其運行結果并不是直接將圖片進行立體矯正,而是得出進行立體矯正所需要的映射矩陣。
調用方法:
void stereoRectify( InputArray cameraMatrix1, InputArray distCoeffs1, InputArray cameraMatrix2, InputArray distCoeffs2, Size imageSize, InputArray R, InputArray T,OutputArray R1, OutputArray R2, OutputArray P1, OutputArray P2, OutputArray Q, int flags=CALIB_ZERO_DISPARITY, double alpha=-1, Size newImageSize=Size(), Rect* validPixROI1=0, Rect* validPixROI2=0 )參數介紹:
四、映射變換計算函數 initUndistortRectifyMap()
該函數功能是計算畸變矯正和立體校正的映射變換。
調用方法:
void initUndistortRectifyMap(InputArray cameraMatrix, InputArray distCoeffs, InputArray R,InputArray newCameraMatrix, Size size, int m1type, OutputArray map1, OutputArray map2)調用方法:
五、像素重映射函數 remap()
調用方法:
第五個參數:插值方式,有四中插值方式:
(1)INTER_NEAREST——最近鄰插值
(2)INTER_LINEAR——雙線性插值(默認)
(3)INTER_CUBIC——雙三樣條插值(默認)
(4)INTER_LANCZOS4——lanczos插值(默認)
基于OpenCV的仿真
仿真程序
int main() {//initialize some parametersbool okcalib = false;Mat intrMatFirst, intrMatSec, distCoeffsFirst, distCoffesSec;Mat R, T, E, F, RFirst, RSec, PFirst, PSec, Q;vector<vector<Point2f>> imagePointsFirst, imagePointsSec;vector<vector<Point3f>> ObjectPoints(1);Rect validRoi[2];Size imageSize;int cameraIdFirst = 0, cameraIdSec = 1;double rms = 0;//get pictures and calibratevector<string> imageList;string filename = "stereo_calib.xml";bool okread = readStringList(filename, imageList);if (!okread || imageList.empty()){cout << "can not open " << filename << " or the string list is empty" << endl;return false;}if (imageList.size() % 2 != 0){cout << "Error: the image list contains odd (non-even) number of elements\n";return false;}//calibratecout << "calibrate left camera..." << endl;okcalib = calibrate(intrMatFirst, distCoeffsFirst, imagePointsFirst, ObjectPoints,imageSize, cameraIdFirst, imageList);if (!okcalib){cout << "fail to calibrate left camera" << endl;return -1;}else{cout << "calibrate the right camera..." << endl;}okcalib = calibrate(intrMatSec, distCoffesSec, imagePointsSec, ObjectPoints,imageSize, cameraIdSec, imageList);if (!okcalib){cout << "fail to calibrate the right camera" << endl;return -1;}destroyAllWindows();//estimate position and orientationcout << "estimate position and orientation of the second camera" << endl<< "relative to the first camera..." << endl;rms = stereoCalibrate(ObjectPoints, imagePointsFirst, imagePointsSec,intrMatFirst, distCoeffsFirst, intrMatSec, distCoffesSec,imageSize, R, T, E, F, CV_CALIB_FIX_INTRINSIC,TermCriteria(TermCriteria::COUNT + TermCriteria::EPS, 30, 1e-6));cout << "done with RMS error=" << rms << endl;//stereo rectifycout << "stereo rectify..." << endl;stereoRectify(intrMatFirst, distCoeffsFirst, intrMatSec, distCoffesSec, imageSize, R, T, RFirst,RSec, PFirst, PSec, Q, 0, 1, imageSize, &validRoi[0], &validRoi[1]);//read pictures for 3d-reconstructionnamedWindow("canvas", 1);cout << "read the picture for 3d-reconstruction...";Mat canvas(imageSize.height, imageSize.width * 2, CV_8UC3), viewLeft, viewRight;Mat canLeft = canvas(Rect(0, 0, imageSize.width, imageSize.height));Mat canRight = canvas(Rect(imageSize.width, 0, imageSize.width, imageSize.height));viewLeft = imread(imageList[cameraIdFirst], 1);viewRight = imread(imageList[cameraIdSec], 1);viewLeft.copyTo(canLeft);viewRight.copyTo(canRight);cout << "done" << endl;imshow("canvas", canvas);waitKey(50);//stereoRectifyMat rmapFirst[2], rmapSec[2], rviewFirst, rviewSec;initUndistortRectifyMap(intrMatFirst, distCoeffsFirst, RFirst, PFirst,imageSize, CV_16SC2, rmapFirst[0], rmapFirst[1]);initUndistortRectifyMap(intrMatSec, distCoffesSec, RSec, PSec,imageSize, CV_16SC2, rmapSec[0], rmapSec[1]);remap(viewLeft, rviewFirst, rmapFirst[0], rmapFirst[1], INTER_LINEAR);remap(viewRight, rviewSec, rmapSec[0], rmapSec[1], INTER_LINEAR);rviewFirst.copyTo(canLeft);rviewSec.copyTo(canRight);rectangle(canLeft, validRoi[0], Scalar(255, 0, 0), 3, 8);rectangle(canRight, validRoi[1], Scalar(255, 0, 0), 3, 8);for (int j = 0; j <= canvas.rows; j += 16)line(canvas, Point(0, j), Point(canvas.cols, j), Scalar(0, 255, 0), 1, 8);cout << "stereo rectify done" << endl;imshow("canvas", canvas);waitKey(50);子函數calibrate()和calcChessboardCorners()分別是用來表達相機和計算objectPoints的。函數體如下,
bool calibrate(Mat& intrMat, Mat& distCoeffs, vector<vector<Point2f>>& imagePoints, vector<vector<Point3f>>& ObjectPoints, Size& imageSize,const int cameraId , vector<string> imageList) { int w = 6;int h = 9; double rms = 0;Size boardSize; boardSize.width = w; boardSize.height = h; vector<Point2f> pointBuf; float squareSize = 1.f; vector<Mat> rvecs, tvecs; bool ok = false;int nImages = (int)imageList.size() / 2; namedWindow("View", 1); for (int i = 0; i<nImages ; i++){ Mat view, viewGray; view = imread(imageList[i*2+cameraId], 1); imageSize = view.size(); cvtColor(view, viewGray, COLOR_BGR2GRAY);bool found = findChessboardCorners(view, boardSize, pointBuf, CV_CALIB_CB_ADAPTIVE_THRESH | CV_CALIB_CB_FAST_CHECK | CV_CALIB_CB_NORMALIZE_IMAGE);if (found) {cornerSubPix(viewGray, pointBuf, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1)); drawChessboardCorners(view, boardSize, Mat(pointBuf), found);bitwise_not(view, view); imagePoints.push_back(pointBuf); cout << '.'; } imshow("View", view); waitKey(50); } //calculate chessboardCorners calcChessboardCorners(boardSize, squareSize, ObjectPoints[0]); ObjectPoints.resize(imagePoints.size(), ObjectPoints[0]);rms = calibrateCamera(ObjectPoints, imagePoints, imageSize, intrMat, distCoeffs, rvecs, tvecs); ok = checkRange(intrMat) && checkRange(distCoeffs);if (ok){cout << "done with RMS error=" << rms << endl; return true;}elsereturn false;} static void calcChessboardCorners(Size boardSize, float squareSize, vector<Point3f>& corners) {corners.resize(0); for (int i = 0; i < boardSize.height; i++) //height和width位置不能顛倒for (int j = 0; j < boardSize.width; j++){corners.push_back(Point3f(j*squareSize, i*squareSize, 0));} }仿真結果
轉載自:https://www.cnblogs.com/german-iris/p/5199203.html
總結
以上是生活随笔為你收集整理的双目摄像头立体成像(二)畸变矫正与立体校正的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 年薪50万PM总结的20个成功项目管理经
- 下一篇: Verilog HDL 编程规范