日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 人文社科 > 生活经验 >内容正文

生活经验

OpenCV 【十一】—— 图像去畸变,对极约束之undistort,initUndistortRectifyMap,undistort

發(fā)布時(shí)間:2023/11/27 生活经验 27 豆豆
生活随笔 收集整理的這篇文章主要介紹了 OpenCV 【十一】—— 图像去畸变,对极约束之undistort,initUndistortRectifyMap,undistort 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

目錄

0.極限約束,對(duì)極校正

1.攝像機(jī)成像原理簡(jiǎn)述

2.成像畸變

2.1. 畸變數(shù)學(xué)模型

2.2. 公式推導(dǎo)

3.畸變校正

3.1. 理論推導(dǎo)

4. 圖像去畸變**

5. 圖像尺度縮放與內(nèi)參的關(guān)系**

5.1 undistortPoints()

5.2 initUndistortRectifyMap()

5.3 undistort()

6.UndistortPoints源碼


?

0.極限約束,對(duì)極校正


?

?

1.攝像機(jī)成像原理簡(jiǎn)述

成像的過程實(shí)質(zhì)上是幾個(gè)坐標(biāo)系的轉(zhuǎn)換。首先空間中的一點(diǎn)由 世界坐標(biāo)系 轉(zhuǎn)換到 攝像機(jī)坐標(biāo)系 ,然后再將其投影到成像平面 ( 圖像物理坐標(biāo)系 ) ,最后再將成像平面上的數(shù)據(jù)轉(zhuǎn)換到圖像平面 ( 圖像像素坐標(biāo)系 )

圖像像素坐標(biāo)系 (uOv坐標(biāo)系) 下的無畸變坐標(biāo) (U, V),經(jīng)過 經(jīng)向畸變切向畸變 后落在了uOv坐標(biāo)系(Ud, Vd) 上。即就是說,真實(shí)圖像 imgR畸變圖像 imgD 之間的關(guān)系為: imgR(U, V) = imgD(Ud, Vd)

2.成像畸變

2.1. 畸變數(shù)學(xué)模型

攝像頭成像畸變的數(shù)學(xué)模型 (符合的對(duì)應(yīng)關(guān)系有問題,可能會(huì)造成一些干擾,公式主要看后面推導(dǎo)的過程)

?

2.2. 公式推導(dǎo)

公式推導(dǎo):

3.畸變校正

3.1. 理論推導(dǎo)

我們已知的是畸變后的圖像,要得到?jīng)]有畸變的圖像就要通過畸變模型推導(dǎo)其映射關(guān)系。 真實(shí)圖像 imgR畸變圖像 imgD 之間的關(guān)系為: imgR(U, V) = imgD(Ud, Vd) 。通過這個(gè)關(guān)系,找出所有的 imgR(U, V)(U, V) 映射到 (Ud, Vd) 中的 (Ud, Vd) 往往不是整數(shù) (U和V是整數(shù),因?yàn)樗俏覀円M成圖像的像素坐標(biāo)位置,以這正常圖像的坐標(biāo)位置去求在畸變圖像中的坐標(biāo)位置,取出對(duì)應(yīng)的像素值,這也是正常圖像的像素值)。 但是畸變的像素往往不是整數(shù),所以需要通過插值來進(jìn)行求解,詳細(xì)見我之前的博客 [圖像]圖像縮放算法-雙線性內(nèi)插法 。

?

?

?

4. 圖像去畸變**

圖像去畸變的思路是:對(duì)于目標(biāo)圖像(無畸變)上的每個(gè)像素點(diǎn),轉(zhuǎn)換到normalize平面,再進(jìn)行畸變并投影到源圖像(帶畸變), 獲取原圖對(duì)應(yīng)位置的像素值作為目標(biāo)圖像該點(diǎn)的像素值。

這里容易有一個(gè)誤解,以為去畸變是對(duì)畸變圖像進(jìn)行畸變逆變換得到無畸變圖像,實(shí)際不是的,畸變模型太復(fù)雜了,很難求逆變換,所以是將無畸變圖像進(jìn)行畸變變換到原圖像去獲得對(duì)應(yīng)像素值

?

圖像去畸變流程如下:

注意:源相機(jī)和目標(biāo)相機(jī)使用的內(nèi)參矩陣不一定是一樣的。如果是調(diào)用opencv的undistort()函數(shù),cameraMatrix是源相機(jī)的內(nèi)參矩陣,newCameraMatrix是目標(biāo)相機(jī)的內(nèi)參矩陣,如果不設(shè)置newCameraMatrix,則默認(rèn)與源相機(jī)內(nèi)參一樣,即去畸變后,相機(jī)的內(nèi)參矩陣不變。

5. 圖像尺度縮放與內(nèi)參的關(guān)系**

結(jié)論:圖像分辨率縮放比例k, 相機(jī)焦距光心等比例縮放k, 畸變系數(shù)不變。

證明:圖像縮放k倍后,圖像平面所有的像素點(diǎn)坐標(biāo)變?yōu)?#xff1a;

而圖像畸變是發(fā)生在normalize平面,不管圖像分辨率如何改變,normalize平面(只取決于焦距光心)是不變的,所以畸變系數(shù)不變。

?

5.1 undistortPoints()

1.1功能: 從觀測(cè)點(diǎn)坐標(biāo)計(jì)算理想點(diǎn)坐標(biāo)。

void cv::undistortPoints(InputArraysrc,
??OutputArraydst,
??InputArraycameraMatrix,
??InputArraydistCoeffs,
??InputArrayR = noArray(),
??InputArrayP = noArray()
?)??

?

5.2 initUndistortRectifyMap()

2.1功能 Computes the undistortion and rectification transformation map. 計(jì)算去畸變和校正變換映射。

void cv::initUndistortRectifyMap(InputArraycameraMatrix,
??InputArraydistCoeffs,
??InputArrayR,
??InputArraynewCameraMatrix,
??Sizesize,
??intm1type,
??OutputArraymap1,
??OutputArraymap2
?)??

模型見4去畸變

5.3 undistort()

void cv::undistort(InputArraysrc,
??OutputArraydst,
??InputArraycameraMatrix,
??InputArraydistCoeffs,
??InputArraynewCameraMatrix = noArray()
?)??

3.1 功能 Transforms an image to compensate for lens distortion. , 對(duì)圖像進(jìn)行變換以補(bǔ)償鏡頭失真。

The function transforms an image to compensate radial and tangential lens distortion.

The function is simply a combination of cv::initUndistortRectifyMap (with unity R ) and cv::remap (with bilinear interpolation). See the former function for details of the transformation being performed.

6.UndistortPoints源碼

?

void cvUndistortPointsInternal( const CvMat* _src, CvMat* _dst, const CvMat* _cameraMatrix,const CvMat* _distCoeffs,const CvMat* matR, const CvMat* matP, cv::TermCriteria criteria)
{// 判斷迭代條件是否有效CV_Assert(criteria.isValid());// 定義中間變量--A相機(jī)內(nèi)參數(shù)組,和matA共享內(nèi)存;RR-矯正變換數(shù)組,和_RR共享內(nèi)存// k-畸變系數(shù)數(shù)組double A[3][3], RR[3][3], k[14]={0,0,0,0,0,0,0,0,0,0,0,0,0,0};CvMat matA=cvMat(3, 3, CV_64F, A), _Dk;CvMat _RR=cvMat(3, 3, CV_64F, RR);cv::Matx33d invMatTilt = cv::Matx33d::eye();cv::Matx33d matTilt = cv::Matx33d::eye();// 檢查輸入變量是否有效CV_Assert( CV_IS_MAT(_src) && CV_IS_MAT(_dst) &&(_src->rows == 1 || _src->cols == 1) &&(_dst->rows == 1 || _dst->cols == 1) &&_src->cols + _src->rows - 1 == _dst->rows + _dst->cols - 1 &&(CV_MAT_TYPE(_src->type) == CV_32FC2 || CV_MAT_TYPE(_src->type) == CV_64FC2) &&(CV_MAT_TYPE(_dst->type) == CV_32FC2 || CV_MAT_TYPE(_dst->type) == CV_64FC2));CV_Assert( CV_IS_MAT(_cameraMatrix) &&_cameraMatrix->rows == 3 && _cameraMatrix->cols == 3 );cvConvert( _cameraMatrix, &matA );// _cameraMatrix <--> matA / A// 判斷輸入的畸變系數(shù)是否有效if( _distCoeffs ){CV_Assert( CV_IS_MAT(_distCoeffs) &&(_distCoeffs->rows == 1 || _distCoeffs->cols == 1) &&(_distCoeffs->rows*_distCoeffs->cols == 4 ||_distCoeffs->rows*_distCoeffs->cols == 5 ||_distCoeffs->rows*_distCoeffs->cols == 8 ||_distCoeffs->rows*_distCoeffs->cols == 12 ||_distCoeffs->rows*_distCoeffs->cols == 14));_Dk = cvMat( _distCoeffs->rows, _distCoeffs->cols,CV_MAKETYPE(CV_64F,CV_MAT_CN(_distCoeffs->type)), k);// _Dk和數(shù)組k共享內(nèi)存指針cvConvert( _distCoeffs, &_Dk );if (k[12] != 0 || k[13] != 0){cv::detail::computeTiltProjectionMatrix<double>(k[12], k[13], NULL, NULL, NULL, &invMatTilt);cv::detail::computeTiltProjectionMatrix<double>(k[12], k[13], &matTilt, NULL, NULL);}}if( matR ){CV_Assert( CV_IS_MAT(matR) && matR->rows == 3 && matR->cols == 3 );cvConvert( matR, &_RR );// matR和_RR共享內(nèi)存指針}elsecvSetIdentity(&_RR);if( matP ){double PP[3][3];CvMat _P3x3, _PP=cvMat(3, 3, CV_64F, PP);CV_Assert( CV_IS_MAT(matP) && matP->rows == 3 && (matP->cols == 3 || matP->cols == 4));cvConvert( cvGetCols(matP, &_P3x3, 0, 3), &_PP );// _PP和數(shù)組PP共享內(nèi)存指針cvMatMul( &_PP, &_RR, &_RR );// _RR=_PP*_RR 放在一起計(jì)算比較高效}const CvPoint2D32f* srcf = (const CvPoint2D32f*)_src->data.ptr;const CvPoint2D64f* srcd = (const CvPoint2D64f*)_src->data.ptr;CvPoint2D32f* dstf = (CvPoint2D32f*)_dst->data.ptr;CvPoint2D64f* dstd = (CvPoint2D64f*)_dst->data.ptr;int stype = CV_MAT_TYPE(_src->type);int dtype = CV_MAT_TYPE(_dst->type);int sstep = _src->rows == 1 ? 1 : _src->step/CV_ELEM_SIZE(stype);int dstep = _dst->rows == 1 ? 1 : _dst->step/CV_ELEM_SIZE(dtype);double fx = A[0][0];double fy = A[1][1];double ifx = 1./fx;double ify = 1./fy;double cx = A[0][2];double cy = A[1][2];int n = _src->rows + _src->cols - 1;// 開始對(duì)所有點(diǎn)開始遍歷for( int i = 0; i < n; i++ ){double x, y, x0 = 0, y0 = 0, u, v;if( stype == CV_32FC2 ){x = srcf[i*sstep].x;y = srcf[i*sstep].y;}else{x = srcd[i*sstep].x;y = srcd[i*sstep].y;}u = x; v = y;x = (x - cx)*ifx;//轉(zhuǎn)換到歸一化圖像坐標(biāo)系(含有畸變)y = (y - cy)*ify;//進(jìn)行畸變矯正if( _distCoeffs ) {// compensate tilt distortion--該部分系數(shù)用來彌補(bǔ)沙氏鏡頭畸變??// 如果不懂也沒管,因?yàn)槠胀ㄧR頭中沒有這些畸變系數(shù)cv::Vec3d vecUntilt = invMatTilt * cv::Vec3d(x, y, 1);double invProj = vecUntilt(2) ? 1./vecUntilt(2) : 1;x0 = x = invProj * vecUntilt(0);y0 = y = invProj * vecUntilt(1);double error = std::numeric_limits<double>::max();// error設(shè)定為系統(tǒng)最大值// compensate distortion iteratively// 迭代去除鏡頭畸變// 迭代公式 ?  x′= (x?2p1 xy?p2 (r^2 + 2x^2))∕( 1 + k1*r^2 + k2*r^4 + k3*r^6)// ? ? ? ? ? ? y′= (y?2p2 xy?p1 (r^2 + 2y^2))∕( 1 + k1*r^2 + k2*r^4 + k3*r^6)for( int j = 0; ; j++ ){if ((criteria.type & cv::TermCriteria::COUNT) && j >= criteria.maxCount)// 迭代最大次數(shù)為5次break;if ((criteria.type & cv::TermCriteria::EPS) && error < criteria.epsilon)// 迭代誤差閾值為0.01break;double r2 = x*x + y*y;double icdist = (1 + ((k[7]*r2 + k[6])*r2 + k[5])*r2)/(1 + ((k[4]*r2 + k[1])*r2 + k[0])*r2);double deltaX = 2*k[2]*x*y + k[3]*(r2 + 2*x*x)+ k[8]*r2+k[9]*r2*r2;double deltaY = k[2]*(r2 + 2*y*y) + 2*k[3]*x*y+ k[10]*r2+k[11]*r2*r2;x = (x0 - deltaX)*icdist;y = (y0 - deltaY)*icdist;// 對(duì)當(dāng)前迭代的坐標(biāo)加畸變,計(jì)算誤差error用于判斷迭代條件if(criteria.type & cv::TermCriteria::EPS){double r4, r6, a1, a2, a3, cdist, icdist2;double xd, yd, xd0, yd0;cv::Vec3d vecTilt;r2 = x*x + y*y;r4 = r2*r2;r6 = r4*r2;a1 = 2*x*y;a2 = r2 + 2*x*x;a3 = r2 + 2*y*y;cdist = 1 + k[0]*r2 + k[1]*r4 + k[4]*r6;icdist2 = 1./(1 + k[5]*r2 + k[6]*r4 + k[7]*r6);xd0 = x*cdist*icdist2 + k[2]*a1 + k[3]*a2 + k[8]*r2+k[9]*r4;yd0 = y*cdist*icdist2 + k[2]*a3 + k[3]*a1 + k[10]*r2+k[11]*r4;vecTilt = matTilt*cv::Vec3d(xd0, yd0, 1);invProj = vecTilt(2) ? 1./vecTilt(2) : 1;xd = invProj * vecTilt(0);yd = invProj * vecTilt(1);double x_proj = xd*fx + cx;double y_proj = yd*fy + cy;error = sqrt( pow(x_proj - u, 2) + pow(y_proj - v, 2) );}}}// 將坐標(biāo)從歸一化圖像坐標(biāo)系轉(zhuǎn)換到成像平面坐標(biāo)系double xx = RR[0][0]*x + RR[0][1]*y + RR[0][2];double yy = RR[1][0]*x + RR[1][1]*y + RR[1][2];double ww = 1./(RR[2][0]*x + RR[2][1]*y + RR[2][2]);x = xx*ww;y = yy*ww;if( dtype == CV_32FC2 ){dstf[i*dstep].x = (float)x;dstf[i*dstep].y = (float)y;}else{dstd[i*dstep].x = x;dstd[i*dstep].y = y;}}
}

簡(jiǎn)化版ubdistortpoint

//for (size_t u = 0; u < ir_image_height; u++)//{//    for (size_t v = 0; v < ir_image_width; v++)//    {//(u,v) undistort//        float x = (u - cx) * fx_inv;//        float y = (v - cy) * fy_inv;
?//        float r2 = (x*x + y*y);//        float r = std::sqrt(r2);//        float r4 = r2 * r2;//        float x_distort = x*(1 + k1*r2 + k2 * r4) + 2 * p1*x*y + p2*(r2 + 2 * x*x);//        float y_distort = y*(1 + k1*r2 + k2 * r4) + p1*(r2 + 2 * y*y) + 2 * p2*x*y;
?//        float X = ir_depth_rx.at<float>(0, 0) * x_distort + ir_depth_rx.at<float>(0, 1)*y_distort +ir_depth_rx.at<float>(0, 2) * 1;//        float Y = ir_depth_rx.at<float>(1, 0) * x_distort + ir_depth_rx.at<float>(1, 1)*y_distort +ir_depth_rx.at<float>(1, 2) * 1;//        float W = ir_depth_rx.at<float>(2, 0) * x_distort + ir_depth_rx.at<float>(2, 1)*y_distort +ir_depth_rx.at<float>(2, 2) * 1;//        //        float x_camera = X / W;//        float y_camera = Y / W;//        //        float u_distort = fx*x_camera + cx;//        float v_distort = fy*y_camera + cy;
?//        calib_params->updated_ir_depth_forward_map_x->operator()(v, u) = u_distort;//        calib_params->updated_ir_depth_forward_map_y->operator()(v, u) = v_distort;
?//    }//}

?

?

總結(jié)

以上是生活随笔為你收集整理的OpenCV 【十一】—— 图像去畸变,对极约束之undistort,initUndistortRectifyMap,undistort的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。