SeqSlam论文阅读和实验

  • 时间:
  • 来源:互联网
  • 文章标签:

SeqSlam论文阅读和实验

  • 简介
  • 背景
    • 目前研究不足
    • 主要工作
  • 算法原理
    • 1. 偏差矩阵
    • 2. 序列匹配
    • 3. 假阳性排除
  • 存在问题
  • 核心代码
  • 实验结果
    • 闭环检测
    • PR曲线
    • Demo Video

简介

       2020快结束了,赶紧码一篇收尾。最近我确认了毕业设计选题,是做slam中闭环检测或场景识别这一块,因此后面有空会陆续写一点论文理解和实验结果。

       第一篇读后感是读 《SeqSLAM: Visual Route-Based Navigation for Sunny Summer Days and Stormy Winter Nights》 。这是2012年的成果,虽然距离2020有点远了,但是这篇论文是第一篇挑战场景中具有日夜和季节性能剧烈变化而效果还不错的论文,因此在当时是具有里程碑意义的。区别于当时对场景提取局部特征描述生成BOW的传统方法,seqslam别具一格使用图片序列进行场景识别,现在看seqslam的方法是很简单的,但却简单有效(虽然看完论文我也是很懵,但看完源码后才算比较懂这个算法)。

       再放一个小视频,简述SeqSlam走过的7年历程,视频里说这个牛逼的方法发表的过程也是历经坎坷的哈哈。但直至2019年这篇论文已成为ICRA第二高引的论文了。—> video

背景

目前研究不足

  • 虽然SIFT、SURF等描述子在旋转和尺度不变性上做的很好,但在极端环境变化(如日夜更替或季节变化)时表现会变差。

在这里插入图片描述

  • 为了降低环境变化的影响,还有些学者在路标或深度图层面进行传感器融合。但这种方法需要矫正,以保证不同传感器得到的特征表达在同一坐标系。而且这些特征的可靠性在剧烈变化的环境也很难得到保证。

主要工作

  • 提出了一种图像序列匹配算法,该算法对极端环境变化下表现依然鲁棒。
  • 作者为验证算法,使用了Nurburgring racing circuit
    in Germany多季节图片序列和suburb of Brisbane的日夜图片序列进行验证。
  • 作者和当时先进的FAB-MAB1.0算法进行对比,在同一数据集SeqSlam保持准确率在100%的情况下有高达60%的召回率,而FAB-MAP1.0在此数据集完全失效。

算法原理

1. 偏差矩阵

在这里插入图片描述
        首先构造图片序列间的偏差矩阵。x轴(Recent video frame)是当前观察到的图片,也就是待匹配的图片序列。y轴(learned image templetes)就是把观察到的图片存起来,用于和观察到的图片对比。从上图观察到,目前观察到的图片位于t,作者指定匹配的图片序列长度ds=4,所以匹配 (t-3) ~ t的序列。

       红色箭头指的方格就是两个图片的偏差值,计算方法很简单,就是两个图像像素值绝对值偏差在平均:
在这里插入图片描述
        接着作者对偏差矩阵进行增强,对了提高辨识度。偏差矩阵增强的方法如下:


在这里插入图片描述
自定义一个窗宽,最好围绕一列左右对称,如橙色窗,对应处理的是t-2列的偏差向量,处理方法为:
在这里插入图片描述
简单来说就是这一列向量减窗口内元素的均值再除以这个窗的方差。

2. 序列匹配

        首先作者假设,当相机重复回到之前走过的场景时,速度和之前也差不多。意思就是,现在我用时a秒经过场景A,拍下了4张照片,基于以上假设,我以前经过这个场景也应该拍过4张(在4旁边浮动)照片。因此,我就在y轴找3~5张(可自定义)照片分别和这4四张现拍的照片序列匹配。

在这里插入图片描述
       这里的v就是速度,在ds时间内,不同速度可能造成匹配的图片序列长度不同。Recent templetes excluded from search的意思时,y轴从存的第一张图片开始搜索序列,搜索到这个区域就可以停止了,因为这段时刚刚存进来的图片,不需要进行比较搜索。

        从y轴每张图片开始,进行多个设定速度的搜索。如y轴存储了待比较的图片n张,则对每张图片都要考察一个序列。例如从图片i开始,需要考察i往后的i+1,i+2…一共ds*v张图片序列,用这个序列去匹配最新的t-ds…t这个观察到的图片序列。而假定的速度如果有多个,则意味着每张图片要比较多个速度下哪个序列更好,重复n次。因为用偏差最小的想法一定能找到一个最好的序列,因此作者称其为force to find a local best match。

3. 假阳性排除

        强制性搜索局部匹配带来的结果是,存在大量的假阳性(没有闭环却检测为闭环)。作者用了简单的排除算法得到最终结果:

在这里插入图片描述
        继续沿用上面提到的例子,n个待匹配图像,必然得到n个local best match,这n个得分如上图的红点。现在假设一个窗口,如上宽度为3。寻找这n个得分的最小值 s 0 s_0 s0(偏差最小),已其为中点放置窗口,如图窗口内有3个点。再计算窗口外的点的最小值 s 1 s_1 s1,再假定一个阈值 μ \mu μ:如果满足:
s 0 s 1 < μ \frac{s_0}{s_1} < \mu s1s0<μ
那么判断这个序列为闭环。

存在问题

        本人认为作者忽略了一个小问题,这个问题在作者给出的数据集是不会出现的,因为作者在用到的数据集均为车辆在一个方向行驶而采集的图片。例如一段几十公里的单向公路,或者在一个环形公路顺时针或逆时针单向形式来检测闭环。然而当行驶轨迹轨迹存在冲突,例如图像采集车向东行驶10km,再反向向西行驶10km,这时候应该检测到闭环,然而,向东的时候图像序列和反向时观察的图片序列刚好是相反的,虽然可能最佳匹配仍然是真实位置所对应的图片,但两组匹配是刚好对称的,这样很容易出错(检测不到闭环或者出现假阴性)。改进的方法是每次使用顺向匹配时同时考虑逆向匹配,取最优即可,我在实验中发现双向的考虑才能使SeqSlam正常运作。

核心代码

源代码我是在github下的 --> github,这是一个源码的python实现,但代码中存在诸多问题,我已经改进了很多地方,下面放出闭环检测部分主要代码:

 def getLoopClosure(self, DD):
      # DD: 偏差矩阵,此处是方阵,但不是必选项
      n, n = DD.shape
      # 最大和最小移动速度
      move_min = int(self.params.matching.vmin * self.params.matching.ds)
      move_max = int(self.params.matching.vmax * self.params.matching.ds)
      move = np.arange(move_min, move_max + 1)
      v = move.astype(float) / self.params.matching.ds
	  # 这里检查y轴存的图片数量,小于下面的条件是不可能存在闭环的,不用检测
      if n < move_min + 2*self.params.matching.Rwindow + self.params.matching.no_seq + self.params.matching.ds or n < self.params.matching.ds:
          return None
	  
	  # 遍历所有y轴图片,强制计算最佳局部匹配序列,保存索引和得分
      matches = np.nan * np.ones((n, 2))
      for N in range(move_min + 2*self.params.matching.Rwindow + self.params.matching.no_seq + self.params.matching.ds -1, n):
		  # 这里计算不同速度下匹配得分
          # 0 ~ ds-1 --> ds items
          idx_add = np.tile(np.arange(0, self.params.matching.ds), (len(v), 1))
          idx_add = np.floor(idx_add * np.tile(v, (idx_add.shape[1], 1)).T)
		  # 这里是本人改进点,逆向匹配也需要考虑
          idx_add1 = np.tile(idx_add[:,-1], (self.params.matching.ds, 1)).T - idx_add

          # this is where our trajectory starts
          n_start = N + 1 - self.params.matching.ds
          if n_start < self.params.matching.no_seq:
              continue

          x = np.tile(np.arange(n_start, n_start + self.params.matching.ds), (len(v), 1))

          # I think y_max should be min(N + self.param, DD.shape[0])
          y_max = n_start - self.params.matching.no_seq
          xx = x * n

          score = []
          final_idx = []
          flatDD = DD.flatten('F')
          # 遍历不同速度下,计算最佳匹配序列
          for s in range(y_max+1 - move_min + 1):  # 0 ~ N+1-move_min
              y = np.copy(idx_add + s)
              y1 = np.copy(idx_add1 + s)
              y[y > y_max] = y_max
              y1[y1 > y_max] = y_max
              idx = (xx + y).astype(int)
              idx1 = (xx + y1).astype(int)
              ds = np.sum(flatDD[idx], 1)
              ds1 = np.sum(flatDD[idx1], 1)
              tmp = np.argmin(ds)
              tmp1 = np.argmin(ds1)
              # 如果顺向序列好于逆向
              if tmp <= tmp1:
                  score.append(ds[tmp])
                  final_idx.append(min(n-1, s + int(idx_add[tmp, -1])))
              else:
                  score.append(ds1[tmp1])
                  final_idx.append(s)

          score = np.array(score)
          min_idx = np.argmin(np.array(score))
          min_value = score[min_idx]
          # 假阳性排除
          window = np.arange(np.max((0, min_idx - self.params.matching.Rwindow // 2)),
                             np.min((len(score), min_idx + self.params.matching.Rwindow // 2)))
          not_window = list(set(range(len(score))).symmetric_difference(set(window)))  # xor
          if len(not_window) < self.params.matching.Rwindow:
              continue
          min_value_2nd = np.min(score[not_window])
          match = [final_idx[min_idx], min_value / min_value_2nd]
          matches[N, :] = match

      return matches

实验结果

        我使用了New College数据集,本来想同时对比FAB-MAP的效果的,然而水平有限,后面有空再补上。

        再看一下论文中使用的参数:

在这里插入图片描述
本人修改了上面部分参数,在下面会列出。


闭环检测

        首先试一下闭环检测的效果,和数据集的GroudTruth对比一下,使用的参数如下:

Parametervalue
R x , R y R_x, R_y Rx,Ry128, 96
R w i n d o w R_{window} Rwindow10
R r e c e n t R_{recent} Rrecent10
d s d_s ds16
V m i n V_{min} Vmin0.8
V m a x V_{max} Vmax1.2
P P P8
μ \mu μ0.8

得到的检测效果如下:
在这里插入图片描述

        图中蓝色点代表在groundtruth中,也就是真阳性,而红色点表示假阳性,由图中可见,准确率为100%。但还有很多没有检测到,这还归因于算法的一个缺点,也就是对于每个观察图片,都会只匹配一个图片,也就是一个地点。而数据集给的GroudTruth允许几个图片对应同一个地点(同理也存在一个观察图片对应几个地点),只要GPS不是偏移很多,这在现实中也是合理的。只要闭环没有被定义清楚,就会存在这样的模糊。但我们姑且就先这样继续下去。

PR曲线


在这里插入图片描述
        由于上面提及的原因,造成低召回率。但目测即使召回率正常,效果好像还是不及FAB-MAP,起码在这个数据集(溜。。)。

Demo Video

本文链接http://www.taodudu.cc/news/show-1944780.html