OpenCV中initUndistortRectifyMap ()函数与十四讲中去畸变公式的区别探究 |
您所在的位置:网站首页 › 正反比例函数图像的区别是什么 › OpenCV中initUndistortRectifyMap ()函数与十四讲中去畸变公式的区别探究 |
文章目录
1.十四讲中的去畸变公式2. OpenCV中的去畸变公式3. 4个参数和8个参数之间的区别4.initUndistortRectifyMap()函数源码
最近在使用OpenCV对鱼眼相机图像去畸变时发现一个问题,基于针孔模型去畸变时所使用的参数和之前十四讲以及视觉SLAM中的畸变系数有一点不一样。
1.十四讲中的去畸变公式
首先是十四讲或者视觉SLAM中的方法,针孔模型的畸变系数为[k1, k2, p1, p2],使用以下去畸变公式计算: 在OpenCV中可以通过initUndistortRectifyMap()函数获得原始图像和矫正图像之间的映射表,然后remap()函数根据映射表对整个图像进行映射处理实现去畸变。 cv::fisheye::initUndistortRectifyMap(K, D, cv::Mat(), K, imageSize, CV_16SC2, map1, map2); cv::remap(raw_image, undistortImg, map1, map2, cv::INTER_LINEAR, cv::BORDER_CONSTANT);具体实现可以见文章《对鱼眼相机图像进行去畸变处理》 initUndistortRectifyMap()函数的声明如下: void cv::initUndistortRectifyMap ( InputArray cameraMatrix, // 原相机内参矩阵 InputArray distCoeffs, // 原相机畸变参数 InputArray R, // 可选的修正变换矩阵 InputArray newCameraMatrix, // 新相机内参矩阵 Size size, // 去畸变后图像的尺寸 int m1type, // 第一个输出的映射(map1)的类型,CV_32FC1 or CV_16SC2 OutputArray map1, // 第一个输出映射 OutputArray map2 // 第二个输出映射 )有意思的是,这里的相机畸变参数是可选的,可以是4个参数k1, k2, p1, p2,可以是5个参数k1, k2, p1, p2, k3,也可以是8个参数k1, k2, p1, p2, k3, k4, k5, k6。 后来检索了一下initUndistortRectifyMap()函数中的畸变公式,如下: 推导过程的核心是: 已经说过,initUndistortRectifyMap()函数中的去畸变参数可以是4个参数k1, k2, p1, p2,可以是5个参数k1, k2, p1, p2, k3,也可以是8个参数k1, k2, p1, p2, k3, k4, k5, k6。 对于普通的广角相机图像,径向畸变和切向畸变一般都比较小,所以仅使用k1, k2, p1, p2就可以完成去畸变过程,对应十四讲中的去畸变公式。 对于鱼眼相机,一般会存在比较大的径向畸变,所以需要更高阶的径向畸变系数k3, k4, k5, k6,至于为什么是 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 1 + k 4 r 2 + k 5 r 4 + k 6 r 6 \frac{1+k_1r^2+k_2r^4+k_3r^6}{1+k_4r^2+k_5r^4+k_6r^6} 1+k4r2+k5r4+k6r61+k1r2+k2r4+k3r6这种比值形式,暂时为找到公式的设计原理,应该是基于对径向畸变的某种考量进行的设计。 根据标定工具和相机模型的不同,获取的鱼眼相机畸变系数可能有多种形式,需要知道的是都可以在OpenCV去畸变函数中使用。而且有时通过标定得到完整的8个去畸变参数k1, k2, p1, p2, k3, k4, k5, k6,这就使得在调用OpenCV函数去畸变事需要使用完整的参数,只使用k1, k2, p1, p2会得到失败的结果。 4.initUndistortRectifyMap()函数源码 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 distCoeffs.create(8, 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)); //摄像机坐标系第四列参数 旋转向量转为旋转矩阵 Mat_ iR = (Ar.colRange(0,3)*R).inv(DECOMP_LU); //ir IR矩阵的指针 const double* ir = &iR(0,0); //获取相机的内参 u0 v0 为主坐标点 fx fy 为焦距 double u0 = A(0, 2), v0 = A(1, 2); double fx = A(0, 0), fy = A(1, 1); CV_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)); if( distCoeffs.rows != 1 && !distCoeffs.isContinuous() ) distCoeffs = distCoeffs.t(); //畸变参数计算 double k1 = ((double*)distCoeffs.data)[0]; double k2 = ((double*)distCoeffs.data)[1]; double p1 = ((double*)distCoeffs.data)[2]; double p2 = ((double*)distCoeffs.data)[3]; double k3 = distCoeffs.cols + distCoeffs.rows - 1 >= 5 ? ((double*)distCoeffs.data)[4] : 0.; double k4 = distCoeffs.cols + distCoeffs.rows - 1 >= 8 ? ((double*)distCoeffs.data)[5] : 0.; double k5 = distCoeffs.cols + distCoeffs.rows - 1 >= 8 ? ((double*)distCoeffs.data)[6] : 0.; double k6 = distCoeffs.cols + distCoeffs.rows - 1 >= 8 ? ((double*)distCoeffs.data)[7] : 0.; //图像高度 for( int i = 0; i //获取摄像机坐标系第四列参数 double w = 1./_w, x = _x*w, y = _y*w; 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 u = fx*(x*kr + p1*_2xy + p2*(r2 + 2*x2)) + u0; double v = fy*(y*kr + p1*(r2 + 2*y2) + p2*_2xy) + v0; if( m1type == CV_16SC2 ) { int iu = saturate_cast(u*INTER_TAB_SIZE); int iv = saturate_cast(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; } } } } |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |