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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 人文社科 > 生活经验 >内容正文

生活经验

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

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

目錄

0.極限約束,對極校正

1.攝像機成像原理簡述

2.成像畸變

2.1. 畸變數學模型

2.2. 公式推導

3.畸變校正

3.1. 理論推導

4. 圖像去畸變**

5. 圖像尺度縮放與內參的關系**

5.1 undistortPoints()

5.2 initUndistortRectifyMap()

5.3 undistort()

6.UndistortPoints源碼


?

0.極限約束,對極校正


?

?

1.攝像機成像原理簡述

成像的過程實質上是幾個坐標系的轉換。首先空間中的一點由 世界坐標系 轉換到 攝像機坐標系 ,然后再將其投影到成像平面 ( 圖像物理坐標系 ) ,最后再將成像平面上的數據轉換到圖像平面 ( 圖像像素坐標系 )

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

2.成像畸變

2.1. 畸變數學模型

攝像頭成像畸變的數學模型 (符合的對應關系有問題,可能會造成一些干擾,公式主要看后面推導的過程)

?

2.2. 公式推導

公式推導:

3.畸變校正

3.1. 理論推導

我們已知的是畸變后的圖像,要得到沒有畸變的圖像就要通過畸變模型推導其映射關系。 真實圖像 imgR畸變圖像 imgD 之間的關系為: imgR(U, V) = imgD(Ud, Vd) 。通過這個關系,找出所有的 imgR(U, V)(U, V) 映射到 (Ud, Vd) 中的 (Ud, Vd) 往往不是整數 (U和V是整數,因為它是我們要組成圖像的像素坐標位置,以這正常圖像的坐標位置去求在畸變圖像中的坐標位置,取出對應的像素值,這也是正常圖像的像素值)。 但是畸變的像素往往不是整數,所以需要通過插值來進行求解,詳細見我之前的博客 [圖像]圖像縮放算法-雙線性內插法 。

?

?

?

4. 圖像去畸變**

圖像去畸變的思路是:對于目標圖像(無畸變)上的每個像素點,轉換到normalize平面,再進行畸變并投影到源圖像(帶畸變), 獲取原圖對應位置的像素值作為目標圖像該點的像素值。

這里容易有一個誤解,以為去畸變是對畸變圖像進行畸變逆變換得到無畸變圖像,實際不是的,畸變模型太復雜了,很難求逆變換,所以是將無畸變圖像進行畸變變換到原圖像去獲得對應像素值

?

圖像去畸變流程如下:

注意:源相機和目標相機使用的內參矩陣不一定是一樣的。如果是調用opencv的undistort()函數,cameraMatrix是源相機的內參矩陣,newCameraMatrix是目標相機的內參矩陣,如果不設置newCameraMatrix,則默認與源相機內參一樣,即去畸變后,相機的內參矩陣不變。

5. 圖像尺度縮放與內參的關系**

結論:圖像分辨率縮放比例k, 相機焦距光心等比例縮放k, 畸變系數不變。

證明:圖像縮放k倍后,圖像平面所有的像素點坐標變為:

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

?

5.1 undistortPoints()

1.1功能: 從觀測點坐標計算理想點坐標。

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

?

5.2 initUndistortRectifyMap()

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

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. , 對圖像進行變換以補償鏡頭失真。

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相機內參數組,和matA共享內存;RR-矯正變換數組,和_RR共享內存// k-畸變系數數組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// 判斷輸入的畸變系數是否有效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和數組k共享內存指針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共享內存指針}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和數組PP共享內存指針cvMatMul( &_PP, &_RR, &_RR );// _RR=_PP*_RR 放在一起計算比較高效}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;// 開始對所有點開始遍歷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;//轉換到歸一化圖像坐標系(含有畸變)y = (y - cy)*ify;//進行畸變矯正if( _distCoeffs ) {// compensate tilt distortion--該部分系數用來彌補沙氏鏡頭畸變??// 如果不懂也沒管,因為普通鏡頭中沒有這些畸變系數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設定為系統最大值// 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)// 迭代最大次數為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;// 對當前迭代的坐標加畸變,計算誤差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) );}}}// 將坐標從歸一化圖像坐標系轉換到成像平面坐標系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;}}
}

簡化版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;
?//    }//}

?

?

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。