双目视觉的一些记录

    技术2022-07-31  82

    笔者是采用 Matlab 做立体标定,用 OpenCV 进行的后续操作。 1.径向畸变一般只计算前两个系数,第三个系数一般用于畸变特别大的相机。 Opencv中畸变系数排列为(k1,k2,p1,p2,k3)(其实不止五个系数,但是一般五个系数就够了), 其中ki为径向畸变系数,pi为切向畸变系数。

    2.据说重投影误差最起码要在0.5 pixels以下,标定结果才可以用来进行后续工作。

    3.Matlab 里的 Stereo Camera Calibrator应用,坐标系XcYc—Zc始终在Camera1上,而且正方向不变,不论Camera1是左摄像机还是右摄像机。(左、右是指你面对着棋盘格时的左、右方向)可以试着把两组标定图片的输入顺序对调一下,你会发现Camera1和Camera2的位置也对调了。而且两个摄像机之间的平移矩阵的每个元素都变成了原先矩阵的相反数。 因此,标定结果里的平移矩阵的正负并不重要。并且平移向量是从摄像机2指向摄像机1的。

    4.标定得到的旋转矩阵是3x3的矩阵,平移矩阵为1x3的矩阵。

    5.Matlab标定结果中的内参矩阵和OpenCV中所用的内参矩阵互为转置。

    6.标定时,可以移动标定模板,也可以移动摄像机,但要保证两个摄像机的相对位置不能改变,并且一直到重建工作结束,两个摄像机的相对位置都不能改变,否则要重新标定。

    7.stereoRectify() 函数中的输入参数摄像机1通过输入参数R、T到达摄像机2所在的位置,注意相对关系。

    8.使用SGBM算法,可以先按照如下语句进行初始化,仅供参考:

    Ptr<StereoSGBM> sgbm = StereoSGBM::create(minDisparity, numDisparities,blockSize );

    之后设置其他各项参数。

    9.SGBM算法视差输出格式是CV_16S, 需要除以16才能得到正确的视差。 此外,如果要直观的观察视差图,需要将其转化为CV_8U格式,且数据值也要进行转换,如下代码所示,仅供参考:

    g_disp2.convertTo(g_disp_2, CV_8U, 255/((numDisparities+minDisparity)*16.0));

    10.reprojectImageTo3D() 函数计算出来的三维坐标要乘以16,因为SGBM算法在计算视差时,出于精度需要,将所有视差都扩大了16倍。并且reprojectImageTo3D() 函数计算的坐标为(X/W,Y/W,Z/W), 如下OpenCV源码所示。

    for( x = 0; x < cols; x++) { double d = sptr[x]; Vec4d homg_pt = _Q*Vec4d(x, y, d, 1.0); dptr[x] = Vec3d(homg_pt.val); dptr[x] /= homg_pt[3]; if( fabs(d-minDisparity) <= FLT_EPSILON ) dptr[x][2] = bigZ; }

    在OpenCV中,转换公式如下:

    CV_EXPORTS_W void stereoRectify( InputArray cameraMatrix1, InputArray distCoeffs1, InputArray cameraMatrix2, InputArray distCoeffs2, Size imageSize, InputArray R, InputArray T, OutputArray R1, OutputArray R2, OutputArray P1, OutputArray P2, OutputArray Q, int flags = CALIB_ZERO_DISPARITY, double alpha = -1, Size newImageSize = Size(), CV_OUT Rect* validPixROI1 = 0, CV_OUT Rect* validPixROI2 = 0 );

    调节第14个参数alpha,可以增大或减小有效区域!!可以试着多调节几次,观察一下效果。 函数为每一个摄像机计算旋转矩阵,使得两个摄像机的图像平面共面。

    而且如果没有畸变,R1,R2就能实现行对准。因为在initUndistortRectifyMap()文档中,有如下陈述: R1,R2代表从尚未校正的摄像机的坐标系到校正的摄像机的坐标系的基准变换。 函数输出里的P1,P2代表从世界坐标系到像素坐标系的变换矩阵,和原先的矩阵相比会发生变化。

    矩阵Q代表从像素坐标系到世界坐标系的重投影矩阵

    CV_EXPORTS_W void initUndistortRectifyMap(InputArray cameraMatrix, InputArray distCoeffs, InputArray R, InputArray newCameraMatrix, Size size, int m1type, OutputArray map1, OutputArray map2);

    计算用于畸变矫正和立体校正的映射变换,后续可传入remap()函数内,从而生成校正完成的图像。 若参数 mltype设为CV_32FC1,则map1, map2分别存储映射变换矩阵所得到的横坐标和纵坐标。 若参数 mltype设为CV_16SC2,则map1为双通道矩阵,两个通道分别存储映射变换矩阵得到的横坐标和纵坐标。 但是根据官方文档的陈述,这个函数计算的应该是反向映射,即从畸变矫正完毕、立体校正完毕的图像到原始图像的映射。 12. 相机标定时,若两个相机联合标定,最好使得两个相机同步成像。若不能同步成像,可在成像过程中固定标定板,不宜手持,因为轻微的抖动也会带来意想不到的误差。此外,标定板要尽可能平整。 13. 相机处于连拍模式时,如果观察到图像窗口中的画面有锯齿波纹,要注意,实际图片并不一定真的存在锯齿波纹。因为连拍模式是把连续帧的画面展示出来,所观察到的锯齿波纹可能是由连续帧画面的差异造成的。

    Processed: 0.015, SQL: 9