魚眼相機(jī)標(biāo)定以及OpenCV實現(xiàn)
在另一篇文章中我已經(jīng)寫過有關(guān)普通相機(jī)模型及其OpenCV標(biāo)定實現(xiàn),這篇文章將主要關(guān)注魚眼相機(jī)模型及其OpenCV標(biāo)定實現(xiàn)。
先看一張魚眼相機(jī)拍攝出來的結(jié)果:

從圖中可以看出很明顯的畸變。對魚眼相機(jī)標(biāo)定,有時候也可以用普通相機(jī)的標(biāo)定方法對其進(jìn)行標(biāo)定,但是卻不能保證去畸變后的效果是最好的。因此對于Gopro等魚眼鏡頭拍攝出來的圖像去畸變,最好的方法就是采用魚眼相機(jī)標(biāo)定方法進(jìn)行標(biāo)定。
在另一篇文章中我已經(jīng)寫過有關(guān)普通相機(jī)模型及其OpenCV標(biāo)定實現(xiàn),這篇文章將主要關(guān)注魚眼相機(jī)模型及其OpenCV標(biāo)定實現(xiàn)。
先看一張魚眼相機(jī)拍攝出來的結(jié)果:
從圖中可以看出很明顯的畸變。對魚眼相機(jī)標(biāo)定,有時候也可以用普通相機(jī)的標(biāo)定方法對其進(jìn)行標(biāo)定,但是卻不能保證去畸變后的效果是最好的。因此對于Gopro等魚眼鏡頭拍攝出來的圖像去畸變,最好的方法就是采用魚眼相機(jī)標(biāo)定方法進(jìn)行標(biāo)定。
魚眼相機(jī)模型
魚眼相機(jī)的內(nèi)參模型依然可以表示為:
⎧⎩⎨⎪⎪fx000fy0cxcy1⎫⎭⎬⎪⎪
這與普通鏡頭的成像模型沒有區(qū)別。兩者之間的區(qū)別主要體現(xiàn)在畸變系數(shù),魚眼相機(jī)的畸變系數(shù)為{k1,k2,k3,k4 },畸變系數(shù)不同,就導(dǎo)致魚眼相機(jī)的投影關(guān)系也發(fā)生了變化,主要變化發(fā)生在考慮畸變情況下的投影關(guān)系轉(zhuǎn)化:
設(shè)(X,Y,Z)為空間中一個三維點,它在成像平面內(nèi)的成像坐標(biāo)為(u,v),在考慮畸變的情況下,
⎧⎩⎨⎪⎪xcyczc⎫⎭⎬⎪⎪=R∗⎧⎩⎨⎪⎪XYZ⎫⎭⎬⎪⎪+T
a=xc/zc,b=yc/zc
r2=a2+b2
θ=atan(r)
θ′=θ(1+k1θ2+k2θ4+k3θ6+k4θ8)
x′=(θ′/r)xc
y′=(θ′/r)yc
u=fxx′+cx
v=fyy′+cy
魚眼相機(jī)的內(nèi)參模型依然可以表示為:
這與普通鏡頭的成像模型沒有區(qū)別。兩者之間的區(qū)別主要體現(xiàn)在畸變系數(shù),魚眼相機(jī)的畸變系數(shù)為{
設(shè)(X,Y,Z)為空間中一個三維點,它在成像平面內(nèi)的成像坐標(biāo)為(u,v),在考慮畸變的情況下,
OpenCV實現(xiàn)魚眼相機(jī)標(biāo)定
利用opencv實現(xiàn)魚眼相機(jī)的標(biāo)定和普通相機(jī)標(biāo)定的標(biāo)定流程基本一致,具體流程如下:
- 檢測角點
cv::findChessboardCorners(InputArray image, Size patternSize, OutputArray corners, int
flags=CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORMALIZE_IMAGE}
獲得棋盤標(biāo)定板的角點位置,使用cornerSubPix(InputArray image, InputOutputArray corners, Size winSize, Size zeroZone,
獲取角點更精細(xì)的檢測結(jié)果
TermCriteria criteria) - 初始化標(biāo)定板上角點的三維坐標(biāo)
- 開始標(biāo)定
double fisheye::calibrate(InputArrayOfArrays objectPoints, InputArrayOfArrays imagePoints,
const Size& image_size, InputOutputArray K, InputOutputArray D,
OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs, int flags=0,
TermCriteria criteria=TermCriteria(TermCriteria::COUNT + TermCriteria::
EPS, 100, DBL_EPSILON))
注意:K,D 分別表示內(nèi)參矩陣和畸變系數(shù)向量,在定義時要定義為double型,這里推薦使用Matx33d和Vec4d數(shù)據(jù)類型,更為方便簡單。objectPoints,imagePoints可以是float型,也可以是double型,但是再stereorectify中需要時double型。flags的可選項有很多,其中需要注意的是必須要指定CALIB_FIX_SKEW,代表求解時假設(shè)內(nèi)參中fx=fy .
4.評定誤差(可選項)for (int i = 0; i != image_count; i++){cout << "Frame #" << i + 1 << "..." << endl;string image_Name;stringstream stream;stream << (i + startNum);stream >> image_Name;image_Name = path_ChessboardImage + image_Name + ".jpg";cv::Mat image = imread(image_Name);Mat image_gray;cvtColor(image, image_gray, CV_RGB2GRAY);vector<Point2f> corners;bool patternFound = findChessboardCorners(image_gray, board_size, corners,CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE + CALIB_CB_FAST_CHECK);if (!patternFound || fullcornersNum != corners.size()){cout << "can not find chessboard corners!\n";continue;}else{cornerSubPix(image_gray, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));count = count + corners.size();corners_Seq.push_back(corners);successImageNum = successImageNum + 1;image_Seq.push_back(image);}}/************************************************************************攝像機(jī)定標(biāo)*************************************************************************/vector<vector<Point3f>> object_Points; /**** 保存定標(biāo)板上角點的三維坐標(biāo) ****/Mat image_points = Mat(1, count, CV_32FC2, Scalar::all(0)); /***** 保存提取的所有角點 *****/vector<int> point_counts;/* 初始化定標(biāo)板上角點的三維坐標(biāo) */for (int t = 0; t<successImageNum; t++){vector<Point3f> tempPointSet;for (int i = 0; i<board_size.height; i++){for (int j = 0; j<board_size.width; j++){/* 假設(shè)定標(biāo)板放在世界坐標(biāo)系中z=0的平面上 */Point3f tempPoint;tempPoint.x = i*square_size.width;tempPoint.y = j*square_size.height;tempPoint.z = 0;tempPointSet.push_back(tempPoint);}}object_Points.push_back(tempPointSet);}for (int i = 0; i< successImageNum; i++){point_counts.push_back(board_size.width*board_size.height);}/* 開始定標(biāo) */Size image_size = image_Seq[0].size();cv::Matx33d intrinsic_matrix; /***** 攝像機(jī)內(nèi)參數(shù)矩陣 ****/cv::Vec4d distortion_coeffs; /* 攝像機(jī)的4個畸變系數(shù):k1,k2,k3,k4*/std::vector<cv::Vec3d> rotation_vectors; /* 每幅圖像的旋轉(zhuǎn)向量 */std::vector<cv::Vec3d> translation_vectors; /* 每幅圖像的平移向量 */int flags = 0;flags |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC;flags |= cv::fisheye::CALIB_CHECK_COND;flags |= cv::fisheye::CALIB_FIX_SKEW;fisheye::calibrate(object_Points, corners_Seq, image_size, intrinsic_matrix, distortion_coeffs, rotation_vectors, translation_vectors, flags, cv::TermCriteria(3, 20, 1e-6));
標(biāo)定結(jié)果: