三角测量是SLAM中,利用相机运动估计特征点空间位置的过程。
本节旨在解决以下问题:
三角测量的概念三角测量的过程及代码实现;三角测量有哪些不确定性如何提高三角测量的精度在SLAM中,利用对极几何约束估计相机运动之后,我们还需要通过三角测量来估计地图点的深度。三角测量(三角化)指的是,通过在两处观测同一个点的夹角,从而确定该点的距离。
SLAM中主要用三角化来估计像素点的距离。
按照对极几何的定义,设$x_1,x_2$为两个特征点的归一化坐标,那么他们满足:$$s_1x_1=s_2Rx_2+t.$$经过对极几何之后,已得到了运动$R,t$,需要求解两个特征点的深度$s_1$,$s_2$。
两个深度可以分开算。若先算$s_2$,那么对上市两个做成一个$x_1$^,得:
该式子左侧为0,右侧可看成是$s_2$的一个方程,可以根据它直接求$s_2$。有了$s_2$,$s_1$也非常容易求出。预测就可以得到两帧下的深度,即确定了空间坐标。
同时,在main函数中增加三角测量部分,并验证重投影关系:
int main (int argc, char∗∗ argv){ // ..... // 三角化 vector<Point3d> points; triangulation( keypoints_1, keypoints_2, matches, R, t, points ); // 验证三角化点与特征点的重投影关系 Mat K = ( Mat_<double> ( 3,3 ) << 520.9, 0, 325.1, 0, 521.0, 249.7, 0, 0, 1 ); for ( int i=0; i<matches.size(); i++ ) { Point2d pt1_cam = pixel2cam( keypoints_1[ matches[i].queryIdx ].pt, K ); Point2d pt1_cam_3d (points[i].x/points[i].z, points[i].y/points[i].z ); cout<<"point in the first camera frame: "<<pt1_cam<<endl; cout<<"point projected from 3D "<<pt1_cam_3d<<", d="<<points[i].z<<endl; // 第2幅图 Point2f pt2_cam = pixel2cam( keypoints_2[ matches[i].trainIdx ].pt, K ); Mat pt2_trans = R∗( Mat_<double>(3,1) << points[i].x, points[i].y, points[i].z ) + t; pt2_trans /= pt2_trans.at<double>(2,0); cout<<"point in the second camera frame: "<<pt2_cam<<endl; cout<<"point reprojected from second frame: "<<pt2_trans.t()<<endl; cout<<endl; }// ...}我们打印了每个空间点在两个相机坐标系下的投影坐标与像素坐标——相当于P 的投影位置与看到的特征点位置。由于误差的存在,它们会有一些微小的差异。以下是某一特征点的信息:
point in the first camera frame: [0.0844072, 0.0734976]point projected from 3D [0.0843702, 0.0743606], d=14.9895point in the second camera frame: [0.0431343, 0.0459876]point reprojected from second frame: [0.04312769812378599, 0.04515455276163744, 1]可以看到,误差的量级大约在小数点后第3 位。可以看到,三角化特征点的距离大约为15。
但由于尺度不确定性,我们并不知道这里的15 究竟是多少米。
要提高三角化的精度,主要有两种方法:
提高特征点的提取精度,也就是提高图像分辨率——但这会导致图像变大,增加计算成本。使平移量增大。但是,这会导致图像的外观发生明显的变化,比如箱子原先被挡住的侧面显示出来,又比如反射光发生变化,等等。外观变化会使得特征提取与匹配变得困难。总而言之,增大平移,会导致匹配失效;而平移太小,则三角化精度不够——这就是三角化的矛盾。