看了好几天的双目视觉标定,还是没有完全掌握。现在把已经了解到的整理下,方便后面进一步的学习掌握。
双目视觉标定就是通过求解实际三维空间中坐标点和摄像机二维图像坐标点的对应关系,在双目视觉中,三维空间坐标系一般是以左相机坐标系作为基准坐标系。利用棋盘板获取到的用于计算的二维图像坐标和三维空间的物理坐标,再通过一定的算法,求解出变换矩阵,则解决了基础的双目视觉标定的过程。
实际标定过程中需要考虑镜头的畸变:包括径向畸变及切向畸变。因为切向畸变很小,所以通常主要考虑的就是径向畸变。求解畸变的方法后面再讨论。
下面结合OpenCV自带双目标定的例程来学习掌握下双目视觉的标定过程:
a. 输入准备:14(数字可调)对棋盘图、标定板的尺寸(widthxheight格数)及棋盘格物理尺寸、stereo_calib.xml(输入图片的列表)
b. 立体标定。主要可分为4个部分:
- 输入检测与变量初始化
角点存储矩阵
vector<vector<Point2f> > imagePoints[2];//这个是左右图像中的二维点 vector<vector<Point3f> > objectPoints;//由上面的二维点得到的三维点
- 角点及亚像素角点检测,获取角点的2D图像坐标和3D物理坐标
对左右相机的每一幅图像单独处理。要注意处理的图像必须含有相同的大小。此外,为了准确的检测出角点,部分图像可能需要进行scale缩放调整。
findChessboardCorners()
函数用于检测角点,需要输入目标图像,标定板大小,角点存储矩阵,及最后的算法设置变量,例程中为CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_NORMALIZE_IMAGE
表示使用直方图均衡算法和自适应二值化的法。返回bool值。具体的函数使用见
棋盘格角点检测与绘制——cv::findChessboardCorners()与cv::drawChessboardCorners()详解
cornerSubPix()
函数根据已经得到的corners坐标计算更加精确的亚像素corners坐标。该函数需要输入目标图像,corners坐标矩阵,搜索窗口大小(Size()类型),死区窗口大小(Size()类型,目的是避免可能出现的自相关矩阵的奇点,不明白这一参数,可以设为默认值Size(-1,-1)),终止迭代的criteria,本文中为TermCriteria(TermCriteria::COUNT+TermCriteria::EPS,30, 0.01)
,表示当迭代次数大于30或当角点坐标变化小于0.01时停止。
通过上述三个函数的使用,便可以准确的检测出所有图像的亚像素角点。
然后根据输入的标定板大小和棋盘格格子的物理长度大小,便可以计算出角点的物理坐标,单位毫米。标定板的空间坐标系假设是以左上角第一个点为原点,棋盘格两边为x,y方向,垂直棋盘格为z方向。所以所有角点的空间坐标的z值均为0。
3. 双目标定主模块,计算内参数矩阵,对标定结果进行验证
stereoCalibrate()
函数计算双目标定中的内参数矩阵,相对于1st相机的旋转平移矩阵,还有本征矩阵E和基础矩阵F。E包含在物理空间中两个摄像机相关的旋转和平移信息,F除了包含E的信息外还包括了两个摄像机的内参数。E是将左摄像机观测到的点P的物理坐标和右摄像机观察到的相同点的位置关联起来。F是将一台摄像机的像平面的点在像平面上的坐标和另一台摄像机的像平面上的点关联起来。
关于本征矩阵和基础矩阵的详细介绍参考博客本征矩阵与基础矩阵。
立体标定完成后,通过对极几何约束公式m2TFm1可以检查校准的质量(检查图像上点与另一幅图像的极线的距离的远近来评定标定的精度),理想情况下点和线的点积为0,累计后的绝对距离形成了误差。可用于衡量标定结果。
(这块不是很理解。。。。)
- 对标定后的结果进行立体校正,计算外参数矩阵
利用stereoRectify()
函数进行立体校正,这样做的目的是为了使得两个相机的光轴共面,极线平行。这样,就可以将二维的图像搜索简化为一维的图像检索,同时确保了极线匹配的精度。
立体标定结束后,将相应的参数写入intrinsics.yml和extrinsics.yml中,则完成了双目视觉的标定。即双目标定最后获得的是相机内参和外参变换的文件。
关于对极几何的相关知识可以参考博客对极几何
Bouguet极线校正的方法。
源码如下,代码学习这块参考的是博客:
https://blog.csdn.net/qq_35971623/article/details/78196399
#include "stdafx.h"
#include "opencv2/calib3d.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/imgproc.hpp"
#include <vector>
#include <string>
#include <algorithm>
#include <iostream>
#include <iterator>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
using namespace cv;
using namespace std;
//左图中的同一目标比右图中的同一目标偏右,即左右图命名不要弄反,与人眼视觉一致。
static void
StereoCalib(const vector<string>& imagelist, Size boardSize, float squareSize, bool display