[双目视差] 立体校正源码分析(opencv)
一、源码解析
立体校正:把实际中非共面行对准的两幅图像,校正成共面行对准
stereoRectify(cameraMatrixL, distCoeffL, cameraMatrixR, distCoeffR, imageSize, R, T, Rl, Rr, Pl, Pr, Q, CALIB_ZERO_DISPARITY,0, imageSize, &validROIL, &validROIR);
为每个摄像头计算立体校正的映射矩阵。所以其运行结果并不是直接将图片进行立体矫正,而是得出进行立体矫正所需要的映射矩阵。
立体矫正前:

立体矫正后:

过程:
(1)共面:先把旋转矩阵变为旋转向量,对旋转向量的模长平分,这样使两个图像平面共面,此时行未对齐。
cvConvert(matR, &om);
cvConvertScale(&om, &om, -0.5);
(2)行对准:建立行对准换行矩阵Rrect使极点转换到无穷远处。
首先创建平移向量T方向的旋转矩阵Rrec=[e1,e2,e3],其中e1为与平移向量T同方向的极点,e2为图像与平移向量同一方向的向量,e3为垂直于e1与e2所在平面的向量,通过叉乘方式获得,RL=Rrect rl ,RRrect rr,最后转为旋转矩阵,在通过转置就得到最终的RL和RR,这里求得的RL和RR是用来校正左右图像到第三平面,进行行对齐。
cvRodrigues2(&om, &r_r); // 旋转向量转换为旋转矩阵
cvMatMul(&r_r, matT, &t); //两个数组对应元素的乘法
int idx = fabs(_t[0]) > fabs(_t[1]) ? 0 : 1;
_uu[2] = 1;
cvCrossProduct(&uu, &t, &ww); //对两个三维向量做叉乘
nt = cvNorm(&t, 0, CV_L2); //计算t的绝对范数
CV_Assert(fabs(nt) > 0); //捕获异常而不是程序崩溃
nw = cvNorm(&ww, 0, CV_L2);
CV_Assert(fabs(nw) > 0);
cvConvertScale(&ww, &ww, 1 / nw);
cvCrossProduct(&t, &ww, &w3);
nw = cvNorm(&w3, 0, CV_L2);
CV_Assert(fabs(nw) > 0);
cvConvertScale(&w3, &w3, 1 / nw);
_uu[2] = 0;
for (i = 0; i < 3; ++i)
{
_wr[idx][i] = -_t[i] / nt;
_wr[idx ^ 1][i] = -_ww[i];
_wr[2][i] = _w3[i] * (1 - 2 * idx);
}
cvGEMM(&wR, &r_r, 1, 0, 0, &Ri, CV_GEMM_B_T);
cvConvert( &Ri, _R1 );
cvGEMM(&wR, &r_r, 1, 0, 0, &Ri, 0);
cvConvert( &Ri, _R2 );
左右两个摄像机共面、行对齐后,分别计算两个相机的内参矩阵,即投影矩阵,过程为:
通过原始两相机的内参矩阵,与当前共面对齐后的图像进行比例计算,得到新的内参信息(fx,fy,这里的fx=fy)
newImgSize = newImgSize.width * newImgSize.height != 0 ? newImgSize : imageSize;
const double ratio_x = (double)newImgSize.width / imageSize.width / 2;
const double ratio_y = (double)newImgSize.height / imageSize.height / 2;
const double ratio = idx == 1 ? ratio_x : ratio_y;
fc_new = (cvmGet(_cameraMatrix1, idx ^ 1, idx ^ 1) + cvmGet(_cameraMatrix2, idx ^ 1, idx ^ 1)) * ratio;
分别对左右摄像机进行图像矫正为正常的视角,将变化后的点转换为齐次坐标系,同时改变相机内参,计算三维点在平面中的坐标,为简单起见,将两个摄影机的主要点设置为平均值。
for( k = 0; k < 2; k++ )
{
const CvMat* A = k == 0 ? _cameraMatrix1 : _cameraMatrix2;
const CvMat* Dk = k == 0 ? _distCoeffs1 : _distCoeffs2;
CvPoint2D32f _pts[4] = {};
CvPoint3D32f _pts_3[4] = {};
CvMat pts = cvMat(1, 4, CV_32FC2, _pts);
CvMat pts_3 = cvMat(1, 4, CV_32FC3, _pts_3);
for( i = 0; i &

本文详细分析了OpenCV中用于双目立体校正的源码,包括如何通过`stereoRectify`实现共面行对齐,使用旋转和平移矩阵进行校正,以及计算内参矩阵和投影矩阵。还介绍了`cvUndistortPoints`和`initUndistortRectifyMap`在图像矫正和映射变换中的应用,最后讨论了像素重映射`remap`函数在处理校正后图像中的作用。整个过程旨在消除图像畸变,实现左右图像的准确匹配,为立体视觉应用奠定基础。
最低0.47元/天 解锁文章
1万+

被折叠的 条评论
为什么被折叠?



