机器视觉学习笔记(7)——基于OpenCV的双目摄像机标定

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/xuelabizp/article/details/50432715

机器视觉学习笔记(7)——基于OpenCV的双目摄像机标定

标签: 机器视觉

本文CameraCalibrator类源代码来自于OpenCV2 计算机视觉编程手册(Robert Laganiere 著 张静 译)

阅读本文之前请先阅读以下三篇博文:
机器视觉学习笔记(4)——单目摄像机标定参数说明
机器视觉学习笔记(5)——基于OpenCV的单目摄像机标定
机器视觉学习笔记(6)——双目摄像机标定参数说明


1.双目摄像机标定目的

双目摄像机标定最主要的目的就是要得出左右两个摄像机的相对位置关系,但是在OpenCV中,计算表示左右摄像机位置的矩阵R和T的同时,也可以求出每个摄像机的相机内参数矩阵M和畸变系数矩阵D。

2.Q&A

Q1:双目标定之前需要单目标定吗?

A:推荐先进行单目标定,但不是必须,具体取决于精度要求以及程序实现方式。OpenCV中双目标定的关键函数是double stereoCalibrate()

double stereoCalibrate(
    InputArrayOfArrays objectPoints,
    InputArrayOfArrays imagePoints1,
    InputArrayOfArrays imagePoints2,
    CV_OUT InputOutputArray cameraMatrix1,
    CV_OUT InputOutputArray distCoeffs1,
    CV_OUT InputOutputArray cameraMatrix2,
    CV_OUT InputOutputArray distCoeffs2,
    Size imageSize, OutputArray R,
    OutputArray T, OutputArray E, OutputArray F,
    TermCriteria criteria =
    TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 30, 1e-6),
    int flags=CALIB_FIX_INTRINSIC );

该函数最后一个参数flags表示参数中标定矩阵的一些限定:

  • 默认的参数是CV_CALIB_FIX_INTRINSIC,该参数表示cameraMatrix1distCoeffs1cameraMatrix2distCoeffs2这4个矩阵已经是准确值了,不需要再计算了。即单独对两个摄像机标定后,选择默认参数即可
  • 其它的参数表示在某种限定情况下计算cameraMatrix1distCoeffs1cameraMatrix2distCoeffs2这4个矩阵。例如官方文档推荐的CV_CALIB_SAME_FOCAL_LENGTH | CV_CALIB_ZERO_TANGENT_DIST,表示强制左右摄像机的 fx fy 相等,左右摄相机切向畸变系数为零
  • 虽然在别的博客和官方文档中看到直接使用double stereoCalibrate()一次标定所有的参数会有较大的误差,但是根据博主的实验,效果相差也不是很大。实际 Tx 是62mm,先单目后双目结果为62.2mm,双目一次标定结果为62.3mm
  • 由于标定摄像机还需要提取角点,记录标定点在{world}坐标系下的坐标等辅助操作,而封装好单目标定类的话,单目标定双目标定都好用,所以博主采取的方法是先单目分别标定,再双目标定

Q2:双目标定几张图像合适?

A:博主从10+到40+都试了,感觉图像张数对于精度的影响没有想象中的大,一般左右相机的图像加起来一共30张左右就差不多了。最重要的是图像中标定板与相机的相对位姿,一般要让标定板占据整张图像一半左右的面积,并且标定板相对于相机要有正视,俯视,仰视,左斜视和右斜视等姿态

Q3:标定板的黑白格大小与程序有什么关系?

A:因为单目相机无法检测物体的深度信息,所以单目相机的标定板黑白格大小可以随意指定却不影响单目标定的结果,每一个{world}点的坐标以黑白格的边长为x,y方向的单位向量。但是双目系统需要检测物体的深度信息,而深度信息的单位就是{world}坐标系下的坐标单位,所以在输入{world}的点时,需要说明其在{world}下的具体坐标,我们把{world}原点定在标定板的左上角(此时所有点的Z坐标为0),标定板的黑白格边长为squareSize

const double squareSize = 20.64;//mm
for (int i=0; i<boardSize.height; i++)
    for (int j=0; j<boardSize.width; j++)
        objectCorners.push_back(cv::Point3f(i * squareSize, j * squareSize, 0.0f));

Q4:标定时拍摄的照片有什么要求吗?

A:标定时的照片必须是左右相机同时拍摄的,因为只有同时拍摄才能得到同一物理点在左右相机图像平面上的投影。有一个检测相机是否同步的好方法,那就是打开手机的秒表,然后同时拍照,这样就知道拍照的时间差了。还需要注意的是double stereoCalibrate()参数中物理点和图像点顺序必须保持一致。

Q5:如何自动载入和保存图片?

A:使用一个vector<string>变量保存保存图片的路径和名称信息即可,使用下面的函数生成路径和名称信息:

void generate_image_filename(string filePath, int imageCount, vector<string>& fileList)
{
    Mat image;
    for (int i=1; i<=imageCount; i++)
    {
        std::stringstream str;
        str << filePath << std::setw(2) << std::setfill('0') << i << ".jpg";//图片的相对路径
        fileList.push_back(str.str());
    }
}

3.标定结果分析

此处主要分析R和T矩阵,我的标定结果如下:

  • T矩阵描述了左右摄像机{camera}坐标原点的相对关系,x方向实际62mm,测得62.28mm,精度基本满足要求
  • R矩阵描述了左右摄像机{camera}坐标轴的相对关系,试验的左右相机{camera}坐标系位姿几乎相同,根据机器人学的知识,基本应该是 [[100]T,[010]T,[001]T] 的形式
  • 可以看出左相机M矩阵标定还是有问题,可以增加不同位置的图像进行优化
  • 博主使用的是普通摄像头,如果使用工业相机,同样的方法可以将精度提高至少一个数量级
  • 其实 fx,fy 也是可以算出来的, fy 应该在1250左右,只不过略微麻烦而已

4.总结

  • 源码放在GitHub托管,会随着项目的进度更新
  • 虽然单双目标定的流程其实已经固定化了,但是操作的方法会影响标定的最终精度
  • 标定是否正确可以通过 Tx (左右相机光轴的距离)直接看出来
  • 以下措施都可以提高精度:
    • 使用高分辨率的工业相机
    • 先单目标定,再双目标定
    • 标定的图像中标定板要占据一半左右的面积
    • 两台摄像机的拍照时间要尽量同步,尤其是在运动中
    • 标定板的黑白格大一些,测量多个黑白格长度取平均值
    • 标定的图像多一些,标定板的位姿多一些

猜你喜欢

转载自blog.csdn.net/xuelabizp/article/details/50432715