序:

记录学习过程中自己的理解以及遇到的问题,慢慢补充。
若有错误,还希望各位大佬不吝赐教。

0. 零零散散

0.1 公开数据集

Middlebury:https://vision.middlebury.edu/stereo/data/(室内)
KITTI:http://www.cvlibs.net/datasets/kitti/stereo(室外驾驶)
SceneFlow:https://lmb.informatik.uni-freiburg.de/resources/datasets

0.2 左、右手坐标系

左手、右手坐标系
伸出大拇指,食指和中指,自然摆成三指互相垂直的状态。
中指:X轴
大拇指:Y轴
食指:Z轴

左手建成的坐标系就是左手坐标系,右手建成的坐标系就是右手坐标系。

1. 四个经典的坐标系

1.1 世界坐标系

暂时不重要

1.2 相机坐标系

图中的(Oc-XcYcZc)。

1.3 图像坐标系

图中的(o-xy)

1.4 像素坐标系

图中的(ouv-uv)

2. 理想的单目成像模型

三维空间点P,在相机坐标系下的坐标为P(Xc, Yc, Zc),它在图像坐标系下的成像点为p(x, y)。

这里存在两组相似三角形:△ABOc ∽ △oCOc 和 △PBOc ∽ △pCOc

(1) 由△ABOc ∽ △oCOc,可知:

$$ \frac{AB}{oC} = \frac{AO_c}{oO_c} = \frac{BO_c}{CO_c} $$


(2) 由△PBOc ∽ △pCOc,可知:

$$ \frac{PB}{pC} = \frac{PO_c}{pO_c} = \frac{BO_c}{CO_c} $$

联立上边两个等式,可以得到:

$$ \frac{AB}{oC} = \frac{AO_c}{oO_c} = \frac{PB}{pC} $$

根据点的坐标,可以将上式转换为:

$$ \frac{X_c}{x} = \frac{Z_c}{f} = \frac{Y_c}{y} $$

变一下型可以得到:

$$ x = f \frac{X_c}{Z_c},y = f \frac{Y_c}{Z_c} $$


写成矩阵的形式,并且用齐次坐标的话,就可以写成常见的那个矩阵关系:

$$ Z_c\left[ \begin{matrix} x \\ y \\ 1 \end{matrix} \right] = \left[ \begin{matrix} f & 0 & 0 & 0 \\ 0 & f & 0 & 0 \\ 0 & 0 & 1 & 0 \end{matrix} \right] \left[ \begin{matrix} X_c \\ Y_c \\ Z_c \\ 1 \end{matrix} \right] $$

3. 理想的双目成像模型

在上边的单目成像模型中,式子

$$ x = f \frac{X_c}{Z_c},y = f \frac{Y_c}{Z_c} $$


可以变形为:

$$ X_c = \frac{Z_c}{f}x,Y_c = \frac{Z_c}{f}y $$

式中,x和y都是图像坐标系下的坐标,将x和y转成像素坐标系下的坐标,代入像素坐标转图像坐标公式可以得到:

$$ X_c = \frac{Z_c}{f}d_x(u-u_0),Y_c = \frac{Z_c}{f}d_y(v-v_0) $$


至此,可以得到点P的Xc和Yc的表达式,式中除了Zc都是已知量。

此时,引入下图中的理想双目成像模型:

点P在两个平面上的投影点分别为$P_L$和$P_R$,b为基线长度,$X_L$和$X_R$分别是两个成像点距离各自所在成像平面左边的距离,两个成像平面的像主点在 X 方向上的坐标为X0L和X0R 则可以得到点P在左右相机中的视差:

$$ d = X_L - X_R(如果计算左图视差,就是左减右,计算右图视差就是右减左) $$


两个成像点$P_L$和$P_R$之间的物理距离为:

$$ P_LP_R = b-(X_L - X_{0L}) - (X_{0R} -X_R ) = b - X_L + X_{0L} -X_{0R} + X_R = b - d + X_{0L} - X_{0R} $$


上图中存在一组相似三角形:△PPLPR ∽ △POLOR。可以得到下式:

$$ \frac{P_LP_R}{Z_c-f} = \frac{b}{Z_c} $$


代入$P_LP_R$,可以得到:

$$ \frac{ b - d + X_{0L} - X_{0R} }{Z_c-f} = \frac{b}{Z_c} $$


变形,可以得到:

$$ Z_c = \frac{b f}{ d + X_{0R} - X_{0L} } $$

当$X_{0R} 与 X_{0L}相等时$,上式简化为:

$$ Z_c = \frac{b f}{ d } $$

至此,Zc也得到了,物点P的三维坐标都得到了:

$$ \left\{ \begin{aligned} X_c & = & \frac{Z_c}{f}d_x(u-u_0) \\ Y_c & = & \frac{Z_c}{f}d_y(v-v_0) \\ Z_c & = & \frac{b f}{ d + X_{0R} - X_{0L} } \end{aligned} \right. $$

式中的$f、b、d_x、d_y、u_0、v_0、X_{0L}、X_{0R}$都是可以通过标定得到的,$u$和$v$是该点在左图中的像素坐标,视差$d$可以通过立体匹配得到。所以,点P的相机坐标可以得到。

注:

opencv中使用函数stereoRectify()时,如果参数flags设置为CV_CALIB_ZERO_DISPARITY ,则该函数会让两幅校正后的图像的主点有相同的像素坐标,也就是上边的$X_{0R}$ 与 $X_{0L}$相等,否则该函数会水平或垂直的移动图像,以使得其有用的范围最大。

上式当中焦距 f 的单位 mm,不便于后边计算,所有在双目视觉领域中,出现了“等效焦距",也就是经常见到的$f_x = \frac{f}{dx}和f_y = \frac{f}{dy}$。

其中,$d_x$表示一个像素在 x 方向有多少mm,$d_y$表示一个像素在 y 方向有多少mm。而且,在标定的结果当中,一般也是直接得到$f_x$和f$_y$。一般的工业相机会在详细的资料介绍中,会给出$d_x$和$d_y$的值,可以手动计算验证一下。

引入等效焦距后,物点P的三维坐标可以写成:

$$ \left\{ \begin{aligned} X_c & = & \frac{Z_c}{f_x}(u-u_0) \\ Y_c & = & \frac{Z_c}{f_y}(v-v_0) \\ Z_c & = & \frac{b f}{ d + X_{0R} - X_{0L} } \end{aligned} \right. $$

4. 非理想的双目成像模型

上边都是理想的情况,而现实的情况是,两个相机各自都存在畸变,并且在安装双目时,既做不到让两个相机的光轴完全平行,也做不到让两个相机的成像平面平行。

4.1 存在畸变,怎么办?

通过标定得到畸变系数,采集到双目图像后,通过畸变校正,在一定程度上消除畸变,得到较为理想的左图和右图。

4.2 无法做到共面行对准,怎么办?

在畸变校正之后,通过使用立体校正算法,将两幅非共面行对准的图像 校正成为 共面行对准的左右图像。

5. 为什么距离越远,误差越大?

深度的公式:

$$ Z_c = \frac{b f}{ d } $$


可以的得出两个结论:

  • 视差与深度成反比
  • 同样的视差间隔,距离越远,两个视差所对应的深度间隔越大。

对于第二点,可以举例:
假定,$bf=1000$,

$$ \left\{ \begin{aligned} Z_c & = & \frac{1000}{1} & = 1000.0\\ Z_c & = & \frac{1000}{2} & = 500.0\\ Z_c & = & \frac{1000}{79} & = 12.6582 \\ Z_c & = & \frac{1000}{80} & = 12.5 \\ \end{aligned} \right. $$


1和2,79和80,两组数,都是间隔1个像素的视差,但是第一组的深度相差了500,第二组的深度差了0.1582。目标物离相机越远时,视差越小,对应第一组数据的情形,所以说,同样的视差间隔,距离越远,两个视差所对应的深度间隔越大。所以在距离较远时,视差引起的误差更大。

OpenCV中的一些操作

1. 基本数据

首先由双目标定,可以得到左相机的内参M1和畸变系数D1,可以得到右相机的内参M2和畸变系数D2,以及两个相机之间的旋转矩阵R和平移矩阵T。

2.立体校正

使用stereoRectify函数主要包含两个步骤:畸变校正、立体矫正,还有一些方便后续计算的矩阵R1、R2、P1、P2、Q。

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 );

cameraMatrix1、distCoeffs1为相机1的内参数M1和畸变系数D1。

cameraMatrix2、distCoeffs2为相机2的内参数M2和畸变系数D2。

imageSize为用于校正的图像尺寸。

R1、R2为两个相机进行共面行对准时所用的旋转矩阵(使用这两个旋转矩阵,相当于把两个实际的相机坐标系转换到理想的两个坐标系了),换一种说法:R1和R2分别为左右相机消除畸变后的像平面投影到公共像平面的旋转矩阵。

P1,P2为两个相机的理想投影矩阵,可以将相机坐标系(O-XcYcZc)投影到像素坐标系(O-uv),这两个坐标系都是校正后的,理想的。

P1,P2分别为左右相机的投影矩阵,其作用是将世界坐标系的点转换到像素坐标系下(左相机光心为世界坐标系原点,所以,这里可以直接认为是完成相机坐标系转像素坐标系):

Q为重投影矩阵,可以把像素坐标系重投影为世界坐标系(相机坐标系,因为此时,世界坐标系与相机坐标系重合),这两个坐标系都是校正后的,理想的。

。。。。 P1和P2的验证
(挖坑, 待填)

。。。 。 Q矩阵的用法
(挖坑, 待填)

P1和P2在理想状态下,其实内部只差一个数字,P2比P1多了一个$-b·f$,

其他一些注意点

MATLAB标定结果中。