一、标定流程
双目相机标定目的:求出左、右相机的内、外参数矩阵以及畸变参数
使用软件:matlab 2016
标定过程分两步走:
图像采集
matlab工具箱标定
二、图像采集
本实例采用的双目相机如下图所示:
将双目相机打开,同时采集左右相机图像
点击Capture,即可抓拍。为了保证标定效果,笔者建议将标定棋盘放在不同位置,抓拍十张以上照片。左相机拍摄图像分别命名为01_l,…,15_l, 右相机拍摄图像分别命名为01_r,…,15_r。
三、MATLAB标定
打开matlab,在命令行窗口输入stereoCameraCalibrator,运行。
点击界面左上角的Add Images,输入左相机图片和右相机图片所在的文件夹,以及标定板的网格尺寸。(本人使用的标定板尺寸为30mm),Camera1代表左摄像头,Camera2代表右摄像头,分别选择存放着左右图像的文件夹,需要特别注意的是棋盘格的边长应该根据打印的实际大小填写,单位可以选择,然后点击OK,程序会自动检测采集的图像到底有多少可以使用,可以说MATLAB2015的这个工具十分挑剔,如果角度不好的话,将使用不了,因此在采集图像时,最好多的采集一些。
点击确定,标定板上的点就会被自动识别。
在这里插入图片描述
点击界面上方的Calibrate键,启动标定过程。在界面下方可以看到误差统计和可视化展示。
左下方的直方图为左右图像的标定误差,点击误差较大的直方图,可以直接在左边的图像对中找到对应的图像,右键选择“Remove and Recalibrate”,可以重复上述步骤,直到认为误差满足标定需求为止。
点击界面上方按钮Export Camera Parameters,即可导出标定结果。在matlab主界面可查看。
左右相机的内参数矩阵、畸变参数以及旋转矩阵、平移矩阵都可以得出。
TranslationOfCamera2:相机2相对于相机1的偏移矩阵,可以直接使用。
RotationOfCamera2:相机2相对于相机1的旋转矩阵,需要转置之后才能使用。
CameraParameters1与CameraParameters2为左右摄像头的单独标定参数。
IntrinsicMatrix存放的是摄像头的内参,只与摄像机的内部结构有关,需要先转置再使用。
RadialDistortion:径向畸变,摄像头由于光学透镜的特性使得成像存在着径向畸变,可由K1,K2,K3确定。
TangentialDistortion:切向畸变,由于装配方面的误差,传感器与光学镜头之间并非完全平行,因此成像存在切向畸变,可由两个参数P1,P2确定。
使用时,需要注意参数的排放顺序,即K1,K2,P1,P2,K3。切记不可弄错,否则后续的立体匹配会出现很大的偏差。
1内参:
2194.0374 0 1085
0 3549.8842 -2491.2731
0 0 1相机2内参
260.9973 0 426.0523
0 265.7492 377.6565
0 0 1
相机1畸变系数
相机2畸变系数
旋转矩阵
0.982202495730308 0.0864911805250721 0.166725922017345
-0.178953161969313 0.161336812150683 0.970539127941908
0.0570440461603078 -0.983102084595712 0.173943289784993平移矩阵
258.557506370963 264.451009975917 -454.967875210028第二次试验
平移矩阵
-23.3584685492320 -98.9499465703022 -257.155176711110旋转矩阵:
原始数据:
0.998544372591077 0.0111484632752088 0.0527716565335433
-0.00998411204137380 0.999701995537482 -0.0222763916539695
-0.0530042778786603 0.0217170873962663 0.998358109418452
转置数据
0.9985 -0.0099 -0.0530
0.0111 0.9997 0.0217
0.0527 -0.0222 0.9983相机1内参
原始数据4113.85440617487 0 0
11.8952154910051 4127.58781534608 0
274.491190908276 712.869235806806 13268.47251 0 639.5
0 3268.47251 479.5
0 0 1相机2内参:
3268.47251 0 639.5
0 3268.47251 479.5
0 0 1
标定结果的验证:
双目相机获取深度原理
双目相机一般由左眼和右眼两个水平放置的相机组成。当然也可以做成上下两个目,但我们见到的主流双目都是做成左右的。在左右双目的相机中,我们可以把两个相机都看作针孔相机。它们是水平放置的,意味两个相机的光圈中心都位于x轴上。它们的距离称为双目相机的基线(Baseline,记作b),是双目的重要参数。双目相机一般由左眼和右眼两个水平放置的相机组成。当然也可以做成上下两个目,但我们见到的主流双目都是做成左右的。在左右双目的相机中,我们可以把两个相机都看作针孔相机。它们是水平放置的,意味两个相机的光圈中心都位于x轴上。它们的距离称为双目相机的基线(Baseline,记作b),是双目的重要参数。
图1双目相机的成像模型。OL,OR为左右光圈中心,蓝色框为成像平面,f为焦距。uL和uR为成像平面的坐标。请注意按照图中坐标定义,uR应该是负数,所以图中标出的距离为uR。
现在,考虑一个空间点P,它在左眼和右眼各成一像,记作PL,PR。由于相机基线的存在,这两个成像位置是不同的。理想情况下,由于左右相机只有在x轴上有位移,因此 P的像也只在x轴(对应图像的u轴)上有差异。我们记它在左侧的坐标为uL,右侧坐标为uR。那么,它们的几何关系如图1右侧所示。根据三角形P−PL−PR和P−OL−OR 的相似关系,有:
(1.1)
稍加整理,得:
(1.2)
这里d为左右图的横坐标之差,称为视差(Disparity)。根据视差,我们可以估计一个像素离相机的距离。视差与距离成反比:视差越大,距离越近。同时,由于视差最小为一个像素,于是双目的深度存在一个理论上的最大值,由fb确定。我们看到,当基线越长时,双目最大能测到的距离就会变远;反之,小型双目器件则只能测量很近的距离。
虽然由视差计算深度的公式很简洁,但视差d本身的计算却比较困难。我们需要确切地知道左眼图像某个像素出现在右眼图像的哪一个位置(即对应关系),这件事亦属于“人类觉得容易而计算机觉得困难”的事务。当我们想计算每个像素的深度时,其计算量与精度都将成为问题,而且只有在图像纹理变化丰富的地方才能计算视差。由于计算量的原因,双目深度估计仍需要使用GPU或FPGA来计算。
双目图像标定后矫正解析
在双目视觉中,我们对相机进行标定和校正,最终目的是使得两个相机的光轴完全平行,这样才能够继续后续的深度计算,三维重建。这样的校正在OPencv中采用的是Bouguet的极线校正的算法。
校正前的左右相机的光心并不是平行的,两个光心的连线就叫基线(主镜头中心的连线),像平面与基线的交点就是极点,像点与极点所在的直线就是极线,左右极线与基线构成的平面就是空间点对应的极平面。
校正后,极点在无穷远处,两个相机的光轴平行。像点在左右图像上的高度一致。这也就是极线校正的目标。校正后做后续的立体匹配时,只需在同一行上搜索左右像平面的匹配点即可,能使效率大大提高。
Bouguet的方法是一种标定立体矫正方法,需要实现对左右相机进行标定,是将OPencv求解出来的旋转和平移矩阵分解成左右相机各旋转一半的旋转和平移矩阵R1,T1与R2,T2。分解的原则是使得,左右图像重投影造成的畸变最小,左右视图的共同面积最大。
1、将右图像平面相对于左图像平面的旋转矩阵分解成两个矩阵Rl和Rr,叫做左右相机的合成旋转矩阵。将左右相机各旋转一半,使得左右相机的光轴平行。此时左右相机的成像面达到平行,但是基线与成像平面不平行(行不对准)。
此时两个矩阵满足以下关系,通过这个关系可以看出来rl和rr是正交阵
2、构造变换矩阵Rrect使得基线与成像平面平行(行对准)。构造的方法是通过右相机相对于左相机的偏移矩阵T完成的。
(1)首先先创建一个由极点el方向开始的旋转矩阵,令主点(cx,cy)为左图像原点,则极点el的方向就是相机投影中心之间的平移向量方向.
(2)e2方向与主光轴方向正交,沿图像方向,与e1垂直,则知e2方向可通过e1与主光轴方向的叉积并归一化获得。
(3)获取了e1与e2后,e3与e1和e2正交,e3自然就是他们两个的叉积:
Rrect如下:
(4)通过合成旋转矩阵与变换矩阵相乘获得左右相机的整体旋转矩阵。左右相机坐标系乘以各自的整体旋转矩阵就可使得左右相机的主光轴平行,且像平面与基线平行。
3.通过上述的两个整体旋转矩阵,就能够得到理想的平行配置的双目立体系图像。校正后根据需要对图像进行裁剪,需重新选择一个图像中心,和图像边缘从而让左、右叠加部分最大。
使用MATLAB对图像进行校正
一般我们拍的双目图像不是行对齐的,存在偏差,通过使用相机标定文件对图片进行校正。
if(~exist('stereoParams.mat'))
load('stereoParams.mat');
end
load stereoParams.mat
for i = 0:22
img1=imread(['./l/00000',num2str(i),'_10.png']);
img2=imread(['./r/00000',num2str(i),'_10.png']);
[J1,J2]=rectifyStereoImages(img1,img2,stereoParams,'OutputView','valid');
imwrite(J1,['./l_rec/00000',num2str(i),'_10.png']);
imwrite(J2,['./r_rec/00000',num2str(i),'_10.png']);
end
disp("Finished! ")
% img1 = imresize(img1,[489,734]);
% img2 = imresize(img2,[489,734]);
%figure,imshow(img1);
注意两点:
- matlab中for循环编写:
循环结构:for语句
格式:
for 循环变量=表达式1:表达式2:表达式3
循环体
end
【注】:
表达式1:循环变量初值,
表达式2:步长,为1时,可省略;
表达式3:循环变量终值,会参与到计算。
2.字符串拼接
这里使用[]和,来完成。