鱼眼摄像头标定与畸变校正(双OPENCV版本)
- 轉載請注明作者和出處:http://blog.csdn.net/u011475210
- 代碼地址:https://github.com/WordZzzz/fisheye_calibration
- 軟件版本:VS2013+OPENCV2.4.13 OR VS2013+OPENCV3.4.0
- 編??者:WordZzzz
- 我的代碼
- 可供參考資料
- FishEye模型的畸變校正
- 普通相機模型的畸變校正
我的代碼
??最近在整理自己以前做過的一些東西,這是基于opencv的魚眼攝像頭畸變校正程序的github地址。
其中:
- normal_calibrate:基于OPENCV2與OPENCV3通用的函數實現,可實現USB攝像頭實時畸變校正;
- fishey_calibrate:基于OPENCV3獨有的fishyey結構體實現,可實現USB攝像頭實時畸變校正;
- fishey_calibrate_img:基于OPENCV3獨有的fishyey結構體實現,可實現單張圖片畸變校正;
??opencv1.0 2.0版只有一種攝像機標定模型,就是普通的小孔成像模型,在cv::空間下。而從opencv3.0開始,新增了一種魚眼相機標定模型,在fisheye::空間下。兩種模型的主要區別在于像與物的投影關系不同,具體的文獻資料依然是數不勝數,這里就不贅述。根據opencv官方文檔的建議,在畸變程度較大的廣角鏡頭(比如:魚眼鏡頭)上進行攝像機標定和畸變校正,最好是用fisheye模型,該模型在圖像邊緣畸變程度很大的地方比普通相機模型的效果要好。
??當然,還是要貼上官方文檔的:
- Camera calibration With OpenCV2;
- Camera calibration With OpenCV3;
華麗的分割線
可供參考資料
??以下是在寫這篇博客的時候偶然發現的對opencv兩個版本標定過程的講解,這里直接copy過來并稍微做了一下排版,因為自己忙于為找工作做準備,實在是沒時間自己整理了。原文鏈接。
??圖像算法中會經常用到攝像機的畸變校正,有必要總結分析OpenCV中畸變校正方法,其中包括普通針孔相機模型和魚眼相機模型fisheye兩種畸變校正方法。
??普通相機模型畸變校正函數針對OpenCV中的cv::initUndistortRectifyMap(),魚眼相機模型畸變校正函數對應OpenCV中的cv::fisheye::initUndistortRectifyMap()。兩種方法算出映射Mapx和Mapy后,統一用cv::Remap()函數進行插值得到校正后的圖像。
FishEye模型的畸變校正。
??方便起見,直接貼出OpenCV源碼,我在里面加了注釋說明。建議參考OpenCV官方文檔看畸變模型原理會更清楚。
??簡要流程就是:
1.求內參矩陣的逆,由于攝像機坐標系的三維點到二維圖像平面,需要乘以旋轉矩陣R和內參矩陣K。那么反向投影回去則是二維圖像坐標乘以 K*R的逆矩陣。
2.將目標圖像中的每一個像素點坐標(j,i),乘以1中求出的逆矩陣iR,轉換到攝像機坐標系(_x,_y,_w),并歸一化得到z=1平面下的三維坐標(x,y,1)。
3.求出平面模型下像素點對應魚眼半球模型下的極坐標(r, theta)。
4.利用魚眼畸變模型求出擁有畸變時像素點對應的theta_d。
5.利用求出的theta_d值將三維坐標點重投影到二維圖像平面得到(u,v),(u,v)即為目標圖像對應的畸變圖像中像素點坐標。
6.使用cv::Remap()函數,根據mapx,mapy取出對應坐標位置的像素值賦值給目標圖像,一般采用雙線性插值法,得到畸變校正后的目標圖像。
普通相機模型的畸變校正
??同樣建議參考OpenCV官方文檔閱讀代碼。
??主要流程和上面Fisheye模型差不多,只有第4部分的畸變模型不一樣,普通相機的畸變模型如下:
??同樣把源代碼貼上,并加上注解:
#include <opencv2\opencv.hpp>void cv::initUndistortRectifyMap( InputArray _cameraMatrix, InputArray _distCoeffs,InputArray _matR, InputArray _newCameraMatrix,Size size, int m1type, OutputArray _map1, OutputArray _map2 ) {Mat cameraMatrix = _cameraMatrix.getMat(), distCoeffs = _distCoeffs.getMat();Mat matR = _matR.getMat(), newCameraMatrix = _newCameraMatrix.getMat();if( m1type <= 0 )m1type = CV_16SC2;CV_Assert( m1type == CV_16SC2 || m1type == CV_32FC1 || m1type == CV_32FC2 );_map1.create( size, m1type );Mat map1 = _map1.getMat(), map2;if( m1type != CV_32FC2 ){_map2.create( size, m1type == CV_16SC2 ? CV_16UC1 : CV_32FC1 );map2 = _map2.getMat();}else_map2.release();Mat_<double> R = Mat_<double>::eye(3, 3);Mat_<double> A = Mat_<double>(cameraMatrix), Ar;if( !newCameraMatrix.empty() )Ar = Mat_<double>(newCameraMatrix);elseAr = getDefaultNewCameraMatrix( A, size, true );if( !matR.empty() )R = Mat_<double>(matR);if( !distCoeffs.empty() )distCoeffs = Mat_<double>(distCoeffs);else{distCoeffs.create(14, 1, CV_64F);distCoeffs = 0.;}CV_Assert( A.size() == Size(3,3) && A.size() == R.size() );CV_Assert( Ar.size() == Size(3,3) || Ar.size() == Size(4, 3));//LU分解求新的內參矩陣Ar與旋轉矩陣R乘積的逆矩陣iRMat_<double> iR = (Ar.colRange(0,3)*R).inv(DECOMP_LU);const double* ir = &iR(0,0);//從舊的內參矩陣中取出光心位置u0,v0,和歸一化焦距fx,fydouble u0 = A(0, 2), v0 = A(1, 2);double fx = A(0, 0), fy = A(1, 1);//尼瑪14個畸變系數,不過大多用到的只有(k1,k2,p1,p2),最多加一個k3,用不到的置為0CV_Assert( distCoeffs.size() == Size(1, 4) || distCoeffs.size() == Size(4, 1) ||distCoeffs.size() == Size(1, 5) || distCoeffs.size() == Size(5, 1) ||distCoeffs.size() == Size(1, 8) || distCoeffs.size() == Size(8, 1) ||distCoeffs.size() == Size(1, 12) || distCoeffs.size() == Size(12, 1) ||distCoeffs.size() == Size(1, 14) || distCoeffs.size() == Size(14, 1));if( distCoeffs.rows != 1 && !distCoeffs.isContinuous() )distCoeffs = distCoeffs.t();const double* const distPtr = distCoeffs.ptr<double>();double k1 = distPtr[0];double k2 = distPtr[1];double p1 = distPtr[2];double p2 = distPtr[3];double k3 = distCoeffs.cols + distCoeffs.rows - 1 >= 5 ? distPtr[4] : 0.;double k4 = distCoeffs.cols + distCoeffs.rows - 1 >= 8 ? distPtr[5] : 0.;double k5 = distCoeffs.cols + distCoeffs.rows - 1 >= 8 ? distPtr[6] : 0.;double k6 = distCoeffs.cols + distCoeffs.rows - 1 >= 8 ? distPtr[7] : 0.;double s1 = distCoeffs.cols + distCoeffs.rows - 1 >= 12 ? distPtr[8] : 0.;double s2 = distCoeffs.cols + distCoeffs.rows - 1 >= 12 ? distPtr[9] : 0.;double s3 = distCoeffs.cols + distCoeffs.rows - 1 >= 12 ? distPtr[10] : 0.;double s4 = distCoeffs.cols + distCoeffs.rows - 1 >= 12 ? distPtr[11] : 0.;double tauX = distCoeffs.cols + distCoeffs.rows - 1 >= 14 ? distPtr[12] : 0.;double tauY = distCoeffs.cols + distCoeffs.rows - 1 >= 14 ? distPtr[13] : 0.;//tauX,tauY這個是什么梯形畸變,用不到的話matTilt為單位陣// Matrix for trapezoidal distortion of tilted image sensorcv::Matx33d matTilt = cv::Matx33d::eye();cv::detail::computeTiltProjectionMatrix(tauX, tauY, &matTilt);for( int i = 0; i < size.height; i++ ){float* m1f = map1.ptr<float>(i);float* m2f = map2.empty() ? 0 : map2.ptr<float>(i);short* m1 = (short*)m1f;ushort* m2 = (ushort*)m2f;//利用逆矩陣iR將二維圖像坐標(j,i)轉換到攝像機坐標系(_x,_y,_w)double _x = i*ir[1] + ir[2], _y = i*ir[4] + ir[5], _w = i*ir[7] + ir[8];for( int j = 0; j < size.width; j++, _x += ir[0], _y += ir[3], _w += ir[6] ){//攝像機坐標系歸一化,令Z=1平面double w = 1./_w, x = _x*w, y = _y*w;//這一部分請看OpenCV官方文檔,畸變模型部分double x2 = x*x, y2 = y*y;double r2 = x2 + y2, _2xy = 2*x*y;double kr = (1 + ((k3*r2 + k2)*r2 + k1)*r2)/(1 + ((k6*r2 + k5)*r2 + k4)*r2);double xd = (x*kr + p1*_2xy + p2*(r2 + 2*x2) + s1*r2+s2*r2*r2);double yd = (y*kr + p1*(r2 + 2*y2) + p2*_2xy + s3*r2+s4*r2*r2);//根據求取的xd,yd將三維坐標重投影到二維畸變圖像坐標(u,v)cv::Vec3d vecTilt = matTilt*cv::Vec3d(xd, yd, 1);double invProj = vecTilt(2) ? 1./vecTilt(2) : 1;double u = fx*invProj*vecTilt(0) + u0;double v = fy*invProj*vecTilt(1) + v0;//保存u,v的值到Mapx,Mapy中if( m1type == CV_16SC2 ){int iu = saturate_cast<int>(u*INTER_TAB_SIZE);int iv = saturate_cast<int>(v*INTER_TAB_SIZE);m1[j*2] = (short)(iu >> INTER_BITS);m1[j*2+1] = (short)(iv >> INTER_BITS);m2[j] = (ushort)((iv & (INTER_TAB_SIZE-1))*INTER_TAB_SIZE + (iu & (INTER_TAB_SIZE-1)));}else if( m1type == CV_32FC1 ){m1f[j] = (float)u;m2f[j] = (float)v;}else{m1f[j*2] = (float)u;m1f[j*2+1] = (float)v;}}} }希望對需要的人能有所幫助,歡迎訂閱、關注、收藏、評論、點贊哦~~( ̄▽ ̄~)~
完的汪(∪。∪)。。。zzz
總結
以上是生活随笔為你收集整理的鱼眼摄像头标定与畸变校正(双OPENCV版本)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: oracle11g的g什么意思,orac
- 下一篇: 华为LAB实验室3-机器学习实验:(线性