ORB-SLAM2的最大贡献就是把原来的系统扩展到了双目,rgbd上,这一篇也主要讲的是怎么使用双目或者深度相机的信息,以及他们和单目的区别。
扩充传感器之后,整体的流程图为:
1. 三个平行的主线程是:
1)追踪:每一帧都去找和局部地图的特征匹配来定位相机,并使用motion only BA来最小化重投影误差。
2)局部建图:管理局部地图并优化,使用局部BA
3)回环:检测大回环,通过位姿图优化修正累计漂移(~)。这个线程还启动了第四个线程在位姿图优化之后进行全局BA。
2. 需要用到重定位的场合:
从前面的流程图可以看到,后续双目和rgbd其实是没有区别的。所以这里重点说双目关键点和单目关键点。
双目关键点的深度如果小于40倍基线长度的值,就被叫做近关键点,否则就是远关键点。近关键点可以较好的被三角化,并提供尺度,平移,旋转信息。而远关键点可以提供比较好的旋转信息,但只能有比较差的尺度和平移信息,远点用多视角进行三角化。
定义: 用 ( u L , v L , u R ) (u_L, v_L, u_R) (uL,vL,uR)表示。前两个就是在左图像的特征点坐标, u R u_R uR是在右图像匹配特征点的水平坐标。对于双目相机,利用双目的校正后图像进行搜索(此时极线水平,搜索很快)。对于RGB-D相机,就计算出一个虚拟的右坐标:
u R = u L − f x b d u_R = u_L - \frac{f_xb}{d} uR=uL−dfxb
f x f_x fx是水平焦距,b是结构光投影和红外线相机的基线,深度传感器的不确定度就是用虚拟右坐标的不确定度表示。
定义: 对于ORB特征点中,那些没有对应双目匹配的,或者是没有有效深度值的特征点,取他们在左图像中的点坐标作为单目关键点,即 ( u L , v L ) (u_L, v_L) (uL,vL)。
如何三角化: 只能通过多视角三角化,不提供尺度信息,只提供旋转和平移估计。
不需要像单目那样进行系统初始化了。第一帧时就可以创建一个关键帧,把它的pose设置到起点,从所有双目关键点创建出一个初始地图。
追踪线程:用BA优化相机位姿(motion only BA)
局部建图线程:局部BA,优化一个局部窗口内的关键帧和点
闭环之后:全局BA,优化所有关键帧和点
使用的是g2o的LM方法
最小化匹配的世界坐标系3D点 X i ∈ R 3 X^i \in \mathbb R^3 Xi∈R3和关键点 x ( ⋅ ) i x^i_{(·)} x(⋅)i之间的重投影误差。对于单目关键点 x m i ∈ R 2 x_m^i \in \mathbb R^2 xmi∈R2或者双目关键点 x s i ∈ R 3 x^i_s \in \mathbb R^3 xsi∈R3, 都满足下面的式子:
{ R , t } = arg min R , t ∑ ρ ( ∥ x ( ⋅ ) i − π ( ⋅ ) ( R X i + t ) ∥ ∑ 2 ) \{ R,t \} = \mathop{\arg\min_{R,t}} \sum \rho (\Vert x^i_{(·)} - \pi_{(·)}(RX^i + t) \Vert _{\sum} ^2) {R,t}=argR,tmin∑ρ(∥x(⋅)i−π(⋅)(RXi+t)∥∑2)
这里的i就是所有匹配集合中的某一个; ρ \rho ρ就是鲁棒的Huber cost function; ∑ \sum ∑是关键点尺度相关的协方差矩阵;对于投影方程 π ( ⋅ ) \pi_{(·)} π(⋅),单目和双目的都有各自的定义:
π m ( [ X Y Z ] ) = [ f x X Z + c x f y Y Z + c y ] , π s ( [ X Y Z ] ) = [ f x X Z + c x f y Y Z + c y f x X − b Z + c x ] \pi_m(\begin{bmatrix} X\\ Y\\ Z\\ \end{bmatrix}) = \begin{bmatrix} f_x \frac{X}{Z} + c_x\\ f_y \frac{Y}{Z} + c_y\\ \end{bmatrix}, \pi_s(\begin{bmatrix} X\\ Y\\ Z\\ \end{bmatrix}) = \begin{bmatrix} f_x \frac{X}{Z} + c_x\\ f_y \frac{Y}{Z} + c_y\\ f_x \frac{X-b}{Z} + c_x\\\end{bmatrix} πm(⎣⎡XYZ⎦⎤)=[fxZX+cxfyZY+cy],πs(⎣⎡XYZ⎦⎤)=⎣⎡fxZX+cxfyZY+cyfxZX−b+cx⎦⎤
优化共视的关键帧 K L K_L KL和这些关键帧中的所有点 P L P_L PL。那些没有共视的关键帧 K F K_F KF,其中被观察到的 P L P_L PL对cost函数有贡献,但是在优化过程中保持不变(??)。定义 χ k \chi_k χk是在 P L P_L PL中的点和一个关键帧k中关键点之间的匹配集合,优化问题如下:
{ X i , R l , t l ∣ i ∈ P L , l ∈ K L } = arg min X i , R l , t l ∑ k ∈ K L ∪ K F ∑ j ∈ χ k ρ ( E k j ) E k j = ∥ x ( ⋅ ) i − π ( ⋅ ) ( R k X j + t k ) ∥ ∑ 2 \{X^i, R_l, t_l \vert i \in P_L, l \in K_L\} = \mathop{\argmin_{X^i, R_l, t_l} \sum_{k\in K_L \cup K_F} \sum_{j \in \chi_k}\rho (E_{kj})} \\E_{kj} = \Vert x^i_{(·)} - \pi_{(·)}(R_kX^j + t_k) \Vert _{\sum} ^2 {Xi,Rl,tl∣i∈PL,l∈KL}=Xi,Rl,tlargmink∈KL∪KF∑j∈χk∑ρ(Ekj)Ekj=∥x(⋅)i−π(⋅)(RkXj+tk)∥∑2
这个就是Local BA的特例,此时所有的关键帧和地图中的所有点都会被优化,除了被固定的初始关键帧(固定是为了消除gauge freedom)。
对于双目和rgbd的情况,不会有尺度漂移,而且双目或者深度信息是基于刚体转换的而不是相似度(~)。
在 ORB-SLAM2 中,在位姿图之后加入了完整的 BA 优化以实现最佳解决方案。这种优化可能很耗时,所以在单独的线程中执行,这样就可以让系统继续创建地图和检测回环。但是,这让BA输出和地图当前状态的合并造成了困难。
和单目的一样,都是尽可能多的加入关键帧,然后再去掉冗余的关键帧。
但考虑到近关键点和远关键点,这里还引入了一个新的条件:如果跟踪的近点的数量小于阈值 τ t \tau_t τt且这一帧可以创造至少 τ c \tau_c τc个近双目点,那么就插入一个新关键帧。经验值 τ t = 100 , τ c = 70 \tau_t=100, \tau_c=70 τt=100,τc=70
局部建图和回环线程是不激活的,只有追踪线程工作,而追踪线程使用视觉里程计匹配和地图点匹配。
对于kitti的01序列(高速公路场景)来说,平移的结果是比较不好的,原因就是能被追踪的近点太少了(汽车高速运动,而相机低帧率),但角度还是能估计的比较准。和单目相比,双目的效果更好,一是因为近点更好追踪,因为从一个双目关键帧就可以创建点,而不用像单目那样弄延迟的初始化(要在俩关键帧之间匹配),双目的情况更不容易出现track lost;二是双目可以带尺度的估计地图和轨迹,没有轨迹漂移。(可以明显看出左边图中,路程后段的尺度漂移)
对于EuRoC数据集,由于严重的运动模糊会使track lost出现。论文提到的一个解决办法是使用imu信息,之前在github看到有人提到的一个解决办法是,把track lost部分的图像进行锐化的预处理(没有证实过是否有效)
对于时效性。回环中关键帧的数量就可以对应出回环的耗时。关键帧越多,共视图就会越密集,回环的融合,位姿优化,全局BA也就会更加耗时。高密度的共视图会让局部地图包含更多关键帧和点,因此局部地图的追踪和局部BA会更耗时。