这篇文章主要提出了结合语义信息和运动特征点检测,来滤除每一帧中的动态物体,从而提高位姿估计的准确性。同时建立了语义八叉树地图。
在高运动的场景中,与ORB SLAM2相比提升明显。但也存在不足,如仅能识别20种物体,并只认为人是移动的类别;八叉树地图的作用不知道是干嘛的,闭环时要重新建图,并且类别概率关联不清楚。
contribution:
在这里插入图片描述
系统共有五个独立线程并行:
slam框架是ORB SLAM2,使用Kinect2分别捕捉彩色图和深度图。RGB图送入semantic线程和tracking线程。tracking线程中,首先提取ORB特征点,然后检查这些特征点的移动一致性(moving consistency),并记录潜在的外点。同时,semantic线程并行运行,其pixel wise的分割结果于tracking线程的ORB特征结合,将移动物体的特征点定为外点。这些外点和上一步的潜在外点都被丢弃。根据剩余的稳定内点,计算转换矩阵。
注意这里semantic线程运行比tracking满,一致性检测后,要等待semantic的结果。
后头说semantic的时间约等于feature extraction+consistency check的时间。
使用的网络结构是SegNet,在caffe上使用VOC训练,共20个类别。
认为标签为行人的特征点最有可能是外点。(先验?)
这步的目的是:检查分割结果中的关键点是否是动态的。(大概是,当前帧有语义标签之后,它提取的特征点,是不是动态的?)
论文说思想很简单,不太懂: If some points are determined to be dynamic within a segmented object, then the object could be regarded as a dynamic object。
如果这个点的语义标签是动态类别,那么它所属的物体的点就都是动态的?
检测流程是:
理解一下:基础矩阵(3,3)的功能是,将参考帧中的特征点,映射到当前帧的对应搜索域中, p 2 T F p 1 = 0 p_2^{T}Fp_1=0 p2TFp1=0。这里的 p p p,是像素平面上的点(2,1)。极线表示对应特征点可能出现的位置,计算公式为: I = F P 1 I=FP_1 I=FP1, P 1 P_1 P1是一对匹配中,参考帧中的点(3,1),并且,它是归一化平面上的点。将极线(3,1)与归一化平面上的匹配点 P 2 P_2 P2计算距离,如果过大,则表示它移动的过多?
(这里计算极线和计算距离的意义不太懂)
到现在为止,系统进行了语义分割和动态点检查两个步骤,但是都存在问题:
因此,将这两个步骤的结果结合起来,如果在一个物体被分类为可移动类别,且在它的语义分割边界内,有足够数量的由移动一致性检测得到的移动点,那么这个物体的所有点都被视为动态的。
流程是:在matching前,并行进行语义分割和特征点提取&动态点检测,如果存在物体被分类为可移动类别,检测落在这个物体边界内的动态点数量,如果这个数量超过一定值,这个物体边界内的所有点都认为是动的,(这个物体就被认为是动的,但仅在这一帧让认为是动的),然后这个物体的所有点都看作外点。如果没有检测出来可移动物体,就直接进行位姿估计,否则,刨除外点再进行位姿估计。
实验中,仅将行人类别设定为可移动类别。
系统额外建立了一个建图的线程,使用八叉树语义地图。
tracking线程的关键帧的转换矩阵和深度图用来建立局部点云,这些点云再转换为全局的八叉树地图。同时,为每一个voxel添加语义信息。
没说语义信息是怎么维护的,难道是每一帧都重新赋值一次?
语义结果除了建图,还用来滤除动态物体,让它不出现在地图中。
建图过程和普通八叉树地图一样,使用 p ∈ [ 0 , 1 ] p∈[0,1] p∈[0,1]代表这个voxel的占有概率。它是log odd score l l l的反变换。
l = l o g i t ( p ) = l o g ( p 1 − p ) l=logit(p)=log(\frac {p}{1-p}) l=logit(p)=log(1−pp)
p = l o g i t ( l ) − 1 = e x p ( l ) e x p ( l ) + 1 p=logit(l)^{-1}=\frac{exp(l)}{exp(l)+1} p=logit(l)−1=exp(l)+1exp(l)
voxel n的l又写成 L ( N ∣ Z 1 : t ) L(N|Z_{1:t}) L(N∣Z1:t)的形式,表示前t帧的log odd score。
L ( N ∣ Z 1 : t + 1 ) = L ( N ∣ Z 1 : t − 1 ) + L ( n ∣ Z t ) L(N|Z_{1:t+1})=L(N|Z_{1:t-1})+L(n|Z_t) L(N∣Z1:t+1)=L(N∣Z1:t−1)+L(n∣Zt)
其中, L ( n ∣ Z t ) L(n|Z_t) L(n∣Zt)代表当前帧是否被占有,若是,则值为预设值 t a o tao tao,否则为0。
每一帧建图时,对每一个voxel,把它的 L ( N ∣ Z 1 : t ) L(N|Z_{1:t}) L(N∣Z1:t)用反变换转为 p p p,若 p p p大于一个阈值,就显示这个voxel。