标签: 机器视觉
本文CameraCalibrator
类源代码来自于OpenCV2 计算机视觉编程手册(Robert Laganiere 著 张静 译)
阅读本文之前请先阅读以下三篇博文:
机器视觉学习笔记(4)——单目摄像机标定参数说明
机器视觉学习笔记(5)——基于OpenCV的单目摄像机标定
机器视觉学习笔记(6)——双目摄像机标定参数说明
双目摄像机标定最主要的目的就是要得出左右两个摄像机的相对位置关系,但是在OpenCV中,计算表示左右摄像机位置的矩阵R和T的同时,也可以求出每个摄像机的相机内参数矩阵M和畸变系数矩阵D。
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
,该参数表示cameraMatrix1
,distCoeffs1
,cameraMatrix2
,distCoeffs2
这4个矩阵已经是准确值了,不需要再计算了。即单独对两个摄像机标定后,选择默认参数即可cameraMatrix1
,distCoeffs1
,cameraMatrix2
,distCoeffs2
这4个矩阵。例如官方文档推荐的CV_CALIB_SAME_FOCAL_LENGTH | CV_CALIB_ZERO_TANGENT_DIST
,表示强制左右摄像机的 f x f_x fx和 f y f_y fy相等,左右摄相机切向畸变系数为零double stereoCalibrate()
一次标定所有的参数会有较大的误差,但是根据博主的实验,效果相差也不是很大。实际 T x T_x Tx是62mm,先单目后双目结果为62.2mm,双目一次标定结果为62.3mmA:博主从10+到40+都试了,感觉图像张数对于精度的影响没有想象中的大,一般左右相机的图像加起来一共30张左右就差不多了。最重要的是图像中标定板与相机的相对位姿,一般要让标定板占据整张图像一半左右的面积,并且标定板相对于相机要有正视,俯视,仰视,左斜视和右斜视等姿态
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));
A:标定时的照片必须是左右相机同时拍摄的,因为只有同时拍摄才能得到同一物理点在左右相机图像平面上的投影。有一个检测相机是否同步的好方法,那就是打开手机的秒表,然后同时拍照,这样就知道拍照的时间差了。还需要注意的是double stereoCalibrate()
参数中物理点和图像点顺序必须保持一致。
A:使用一个vector
变量保存保存图片的路径和名称信息即可,使用下面的函数生成路径和名称信息:
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());
}
}
此处主要分析R和T矩阵,我的标定结果如下: