双相机立体重建时,利用物体点-光心-像点三者共线的原理,在找到左右匹配的像点并且完成去畸变之后(OpenCV去畸变undistortPoints原理解析),就能够在三维空间中形成两条直线,物体点就是这两个直线的“交点”,“交点”指最小二乘交点,因为这两个直线由于偏差通常不会交于一点。共线方程描述了物体点-光心-像点三者共线的含义,也相当于三维点到二维点的投影过程,该投影过程可表达为
[ x c y c z c ] = [ R 11 R 12 R 13 T x R 21 R 22 R 23 T y R 31 R 32 R 33 T z ] [ x w y w z w 1 ] (1) \begin{bmatrix} x_c \\ y_c \\ z_c \\ \end{bmatrix}=\begin{bmatrix} R_{11} & R_{12} & R_{13} & T_x \\ R_{21} & R_{22} & R_{23} & T_y\\ R_{31} & R_{32} & R_{33} & T_z \\ \end{bmatrix}\begin{bmatrix} x_w \\ y_w \\ z_w \\1\\ \end{bmatrix}\tag{1} ⎣⎡xcyczc⎦⎤=⎣⎡R11R21R31R12R22R32R13R23R33TxTyTz⎦⎤⎣⎢⎢⎡xwywzw1⎦⎥⎥⎤(1)
z c [ u v 1 ] = [ f x α c x 0 f y c y 0 0 1 ] [ x c y c z c ] (2) z_c \begin{bmatrix} u \\ v \\ 1 \\ \end{bmatrix}=\begin{bmatrix} f_x & \alpha & c_x \\ 0 & f_y & c_y \\ 0 & 0 & 1 \\ \end{bmatrix}\begin{bmatrix} x_c \\ y_c \\ z_c \\ \end{bmatrix}\tag{2} zc⎣⎡uv1⎦⎤=⎣⎡fx00αfy0cxcy1⎦⎤⎣⎡xcyczc⎦⎤(2)
根据式(1)能够得到
{ x c = R 11 x w + R 12 y w + R 13 z w + T x y c = R 21 x w + R 22 y w + R 23 z w + T y z c = R 31 x w + R 32 y w + R 33 z w + T z (3) \left\{ \begin{array}{c} x_c=R_{11}x_w+R_{12}y_w+R_{13}z_w+T_x \\ y_c=R_{21}x_w+R_{22}y_w+R_{23}z_w+T_y \\ z_c=R_{31}x_w+R_{32}y_w+R_{33}z_w+T_z \\ \end{array} \right.\tag{3} ⎩⎨⎧xc=R11xw+R12yw+R13zw+Txyc=R21xw+R22yw+R23zw+Tyzc=R31xw+R32yw+R33zw+Tz(3)
进一步地,
{ x c ′ = x c / z c = R 11 x w + R 12 y w + R 13 z w + T x R 31 x w + R 32 y w + R 33 z w + T z y c ′ = y c / z c = R 21 x w + R 22 y w + R 23 z w + T y R 31 x w + R 32 y w + R 33 z w + T z (4) \left\{ \begin{array}{c} x'_c=x_c/z_c=\frac{R_{11}x_w+R_{12}y_w+R_{13}z_w+T_x}{R_{31}x_w+R_{32}y_w+R_{33}z_w+T_z} \\ y'_c=y_c/z_c=\frac{R_{21}x_w+R_{22}y_w+R_{23}z_w+T_y}{R_{31}x_w+R_{32}y_w+R_{33}z_w+T_z} \\ \end{array} \right.\tag{4} {xc′=xc/zc=R31xw+R32yw+R33zw+TzR11xw+R12yw+R13zw+Txyc′=yc/zc=R31xw+R32yw+R33zw+TzR21xw+R22yw+R23zw+Ty(4)
opencv的坐标经过了相机归一化平面的处理,也就是上式中 x c / z c , y c / z c x_c/z_c, y_c/z_c xc/zc,yc/zc的处理。已知左右相机上匹配的同名点 u 1 , v 1 u_1, v_1 u1,v1和 u 2 , v 2 u_2,v_2 u2,v2, 根据式 (2) 能够得到分别在左右相机下的坐标 ( x c 1 , y c 1 , z c 1 ) (x_{c1},y_{c1},z_{c1}) (xc1,yc1,zc1)和 ( x c 2 , y c 2 , z c 2 ) (x_{c2},y_{c2},z_{c2}) (xc2,yc2,zc2)。经过归一化处理后,可以知道在相机归一化平面上的坐标 ( x c 1 ′ , y c 1 ′ , 1 ) (x'_{c1},y'_{c1},1) (xc1′,yc1′,1)和 ( x c 2 ′ , y c 2 ′ , 1 ) (x'_{c2},y'_{c2},1) (xc2′,yc2′,1)。根据式(4),分别列出左右相机的等式如下
{ x c 1 ′ = R 11 1 x w + R 12 1 y w + R 13 1 z w + T x 1 R 31 1 x w + R 32 1 y w + R 33 1 z w + T z 1 y c 1 ′ = R 21 1 x w + R 22 1 y w + R 23 1 z w + T y 1 R 31 1 x w + R 32 1 y w + R 33 1 z w + T z 1 (5) \left\{ \begin{array}{c} x'_{c1}=\frac{R^1_{11}x_w+R^1_{12}y_w+R^1_{13}z_w+T^1_x}{R^1_{31}x_w+R^1_{32}y_w+R^1_{33}z_w+T^1_z} \\ y'_{c1}=\frac{R^1_{21}x_w+R^1_{22}y_w+R^1_{23}z_w+T^1_y}{R^1_{31}x_w+R^1_{32}y_w+R^1_{33}z_w+T^1_z} \\ \end{array} \right.\tag{5} ⎩⎨⎧xc1′=R311xw+R321yw+R331zw+Tz1R111xw+R121yw+R131zw+Tx1yc1′=R311xw+R321yw+R331zw+Tz1R211xw+R221yw+R231zw+Ty1(5)
{ x c 2 ′ = R 11 2 x w + R 12 2 y w + R 13 2 z w + T x 2 R 31 2 x w + R 32 2 y w + R 33 2 z w + T z 2 y c 2 ′ = R 21 2 x w + R 22 2 y w + R 23 2 z w + T y 2 R 31 2 x w + R 32 2 y w + R 33 2 z w + T z 2 (6) \left\{ \begin{array}{c} x'_{c2}=\frac{R^2_{11}x_w+R^2_{12}y_w+R^2_{13}z_w+T^2_x}{R^2_{31}x_w+R^2_{32}y_w+R^2_{33}z_w+T^2_z} \\ y'_{c2}=\frac{R^2_{21}x_w+R^2_{22}y_w+R^2_{23}z_w+T^2_y}{R^2_{31}x_w+R^2_{32}y_w+R^2_{33}z_w+T^2_z} \\ \end{array} \right.\tag{6} ⎩⎨⎧xc2′=R312xw+R322yw+R332zw+Tz2R112xw+R122yw+R132zw+Tx2yc2′=R312xw+R322yw+R332zw+Tz2R212xw+R222yw+R232zw+Ty2(6)
联立式(5)和(6)可以看出,这是一个已知左右相机的点、已知相机之间位姿关系,求解三维点坐标 ( x w , y w , z w ) (x_w,y_w,z_w) (xw,yw,zw)的问题。因为未知数是3,方程组的数量是4,这是一个超定问题,opencv将其转换为“Ax=0"的矩阵形式,利用SVD分解解算未知数。根据式(5)和(6)分别得到
{ ( x c 1 ′ R 31 1 − R 11 1 ) x w + ( x c 1 ′ R 32 1 − R 12 1 ) y w + ( x c 1 ′ R 33 1 − R 13 1 ) z w + ( x c 1 ′ T z 1 − T x 1 ) = 0 ( y c 1 ′ R 31 1 − R 21 1 ) x w + ( y c 1 ′ R 32 1 − R 22 1 ) y w + ( y c 1 ′ R 33 1 − R 23 1 ) z w + ( y c 1 ′ T z 1 − T y 1 ) = 0 (7) \left\{ \begin{array}{c} (x'_{c1}R^1_{31}-R^1_{11})x_w+(x'_{c1}R^1_{32}-R^1_{12})y_w+(x'_{c1}R^1_{33}-R^1_{13})z_w +(x'_{c1}T^1_z-T^1_x)= 0 \\ (y'_{c1}R^1_{31}-R^1_{21})x_w+(y'_{c1}R^1_{32}-R^1_{22})y_w+(y'_{c1}R^1_{33}-R^1_{23})z_w +(y'_{c1}T^1_z-T^1_y)= 0\\ \end{array} \right.\tag{7} {(xc1′R311−R111)xw+(xc1′R321−R121)yw+(xc1′R331−R131)zw+(xc1′Tz1−Tx1)=0(yc1′R311−R211)xw+(yc1′R321−R221)yw+(yc1′R331−R231)zw+(yc1′Tz1−Ty1)=0(7)
{ ( x c 2 ′ R 31 2 − R 11 2 ) x w + ( x c 2 ′ R 32 2 − R 12 2 ) y w + ( x c 2 ′ R 33 2 − R 13 2 ) z w + ( x c 2 ′ T z 2 − T x 2 ) = 0 ( y c 2 ′ R 31 2 − R 21 2 ) x w + ( y c 2 ′ R 32 2 − R 22 2 ) y w + ( y c 2 ′ R 33 2 − R 23 2 ) z w + ( y c 2 ′ T z 2 − T y 2 ) = 0 (8) \left\{ \begin{array}{c} (x'_{c2}R^2_{31}-R^2_{11})x_w+(x'_{c2}R^2_{32}-R^2_{12})y_w+(x'_{c2}R^2_{33}-R^2_{13})z_w +(x'_{c2}T^2_z-T^2_x)= 0 \\ (y'_{c2}R^2_{31}-R^2_{21})x_w+(y'_{c2}R^2_{32}-R^2_{22})y_w+(y'_{c2}R^2_{33}-R^2_{23})z_w +(y'_{c2}T^2_z-T^2_y)= 0 \\ \end{array} \right.\tag{8} {(xc2′R312−R112)xw+(xc2′R322−R122)yw+(xc2′R332−R132)zw+(xc2′Tz2−Tx2)=0(yc2′R312−R212)xw+(yc2′R322−R222)yw+(yc2′R332−R232)zw+(yc2′Tz2−Ty2)=0(8)
转换为矩阵形式为
[ x c 1 ′ R 31 1 − R 11 1 x c 1 ′ R 32 1 − R 12 1 x c 1 ′ R 33 1 − R 13 1 x c 1 ′ T z 1 − T x 1 y c 1 ′ R 31 1 − R 21 1 y c 1 ′ R 32 1 − R 22 1 y c 1 ′ R 33 1 − R 23 1 y c 1 ′ T z 1 − T y 1 x c 2 ′ R 31 2 − R 11 2 x c 2 ′ R 32 2 − R 12 2 x c 2 ′ R 33 2 − R 13 2 x c 2 ′ T z 2 − T x 2 y c 2 ′ R 31 2 − R 21 2 y c 2 ′ R 32 2 − R 22 2 y c 2 ′ R 33 2 − R 23 2 y c 2 ′ T z 2 − T y 2 ] [ x w y w z w 1 ] = [ 0 0 0 0 ] (9) \begin{bmatrix} x'_{c1}R^1_{31}-R^1_{11} & x'_{c1}R^1_{32}-R^1_{12} &x'_{c1}R^1_{33}-R^1_{13} & x'_{c1}T^1_z-T^1_x \\ y'_{c1}R^1_{31}-R^1_{21} & y'_{c1}R^1_{32}-R^1_{22} & y'_{c1}R^1_{33}-R^1_{23} & y'_{c1}T^1_z-T^1_y \\ x'_{c2}R^2_{31}-R^2_{11} & x'_{c2}R^2_{32}-R^2_{12} & x'_{c2}R^2_{33}-R^2_{13} & x'_{c2}T^2_z-T^2_x \\ y'_{c2}R^2_{31}-R^2_{21} & y'_{c2}R^2_{32}-R^2_{22} & y'_{c2}R^2_{33}-R^2_{23} & y'_{c2}T^2_z-T^2_y \\ \end{bmatrix} \begin{bmatrix} x_w \\ y_w \\ z_w \\ 1 \\ \end{bmatrix} = \begin{bmatrix} 0 \\ 0 \\ 0 \\ 0 \\ \end{bmatrix} \tag{9} ⎣⎢⎢⎡xc1′R311−R111yc1′R311−R211xc2′R312−R112yc2′R312−R212xc1′R321−R121yc1′R321−R221xc2′R322−R122yc2′R322−R222xc1′R331−R131yc1′R331−R231xc2′R332−R132yc2′R332−R232xc1′Tz1−Tx1yc1′Tz1−Ty1xc2′Tz2−Tx2yc2′Tz2−Ty2⎦⎥⎥⎤⎣⎢⎢⎡xwywzw1⎦⎥⎥⎤=⎣⎢⎢⎡0000⎦⎥⎥⎤(9)
该式子就是形如 A X = 0 AX=0 AX=0,其中,
A = [ x c 1 ′ R 31 1 − R 11 1 x c 1 ′ R 32 1 − R 12 1 x c 1 ′ R 33 1 − R 13 1 x c 1 ′ T z 1 − T x 1 y c 1 ′ R 31 1 − R 21 1 y c 1 ′ R 32 1 − R 22 1 y c 1 ′ R 33 1 − R 23 1 y c 1 ′ T z 1 − T y 1 x c 2 ′ R 31 2 − R 11 2 x c 2 ′ R 32 2 − R 12 2 x c 2 ′ R 33 2 − R 13 2 x c 2 ′ T z 2 − T x 2 y c 2 ′ R 31 2 − R 21 2 y c 2 ′ R 32 2 − R 22 2 y c 2 ′ R 33 2 − R 23 2 y c 2 ′ T z 2 − T y 2 ] (10) A = \begin{bmatrix} x'_{c1}R^1_{31}-R^1_{11} & x'_{c1}R^1_{32}-R^1_{12} &x'_{c1}R^1_{33}-R^1_{13} & x'_{c1}T^1_z-T^1_x \\ y'_{c1}R^1_{31}-R^1_{21} & y'_{c1}R^1_{32}-R^1_{22} & y'_{c1}R^1_{33}-R^1_{23} & y'_{c1}T^1_z-T^1_y \\ x'_{c2}R^2_{31}-R^2_{11} & x'_{c2}R^2_{32}-R^2_{12} & x'_{c2}R^2_{33}-R^2_{13} & x'_{c2}T^2_z-T^2_x \\ y'_{c2}R^2_{31}-R^2_{21} & y'_{c2}R^2_{32}-R^2_{22} & y'_{c2}R^2_{33}-R^2_{23} & y'_{c2}T^2_z-T^2_y \\ \end{bmatrix} \tag{10} A=⎣⎢⎢⎡xc1′R311−R111yc1′R311−R211xc2′R312−R112yc2′R312−R212xc1′R321−R121yc1′R321−R221xc2′R322−R122yc2′R322−R222xc1′R331−R131yc1′R331−R231xc2′R332−R132yc2′R332−R232xc1′Tz1−Tx1yc1′Tz1−Ty1xc2′Tz2−Tx2yc2′Tz2−Ty2⎦⎥⎥⎤(10)
对该系数矩阵进行SVD分解, V V V矩阵的最后一列 [ X , Y , Z , W ] [X,Y,Z,W] [X,Y,Z,W]就是方程的解,但是SVD的解是一个模为1的特征向量,最终的三维坐标需要将特征向量的前三个除以最后一个[X/W,Y/W,Z/W,1], 即三维坐标为 ( x w , y w , z w ) = ( X / W , Y / W , Z / W ) (x_w,y_w,z_w)=(X/W,Y/W,Z/W) (xw,yw,zw)=(X/W,Y/W,Z/W)
附上opencv三角测量函数的主要代码和注释
cvTriangulatePoints(CvMat* projMatr1, CvMat* projMatr2, CvMat* projPoints1, CvMat* projPoints2, CvMat* points4D)
{
// preallocate SVD matrices on stack
cv::Matx<double, 4, 4> matrA;
cv::Matx<double, 4, 4> matrU;
cv::Matx<double, 4, 1> matrW;
cv::Matx<double, 4, 4> matrV;
CvMat* projPoints[2] = {projPoints1, projPoints2};
CvMat* projMatrs[2] = {projMatr1, projMatr2};
/* Solve system for each point */
for( int i = 0; i < numPoints; i++ )/* For each point */
{
/* Fill matrix for current point */
for( int j = 0; j < 2; j++ )/* For each view */
{
double x,y;
x = cvmGet(projPoints[j],0,i);
y = cvmGet(projPoints[j],1,i);
// 注1:构造系数矩阵A
for( int k = 0; k < 4; k++ )
{
matrA(j*2+0, k) = x * cvmGet(projMatrs[j],2,k) - cvmGet(projMatrs[j],0,k);
matrA(j*2+1, k) = y * cvmGet(projMatrs[j],2,k) - cvmGet(projMatrs[j],1,k);
}
}
// 注2:SVD分解A矩阵
/* Solve system for current point */
cv::SVD::compute(matrA, matrW, matrU, matrV);
/* Copy computed point */
cvmSet(points4D,0,i,matrV(3,0));/* X */
cvmSet(points4D,1,i,matrV(3,1));/* Y */
cvmSet(points4D,2,i,matrV(3,2));/* Z */
cvmSet(points4D,3,i,matrV(3,3));/* W */
}
}