回环检测(Loop Closure)判断相机 (agent) 是否曾经到过此刻经过的位置,是在视觉 slam 下消除累计误差的一种重要手段。
1. 为何需要回环?
在引入回环前, SLAM 优化是在一条链上做的,故后一刻的状态预估肯定受前面时刻的影响。随时间推移,这种前面影响后面带来的误差,就是累计误差。在没有引入更多信息的情况下,这种误差难以消除。而回环检测通过判断当前时刻的地点是否曾经来过,进而关联当前帧和历史帧,从而让链表成环。这引入了额外的信息(新的约束),故可以优化估计效果,缓解累计误差。
2. 基于词袋模型(BOW, Bag of Words) 怎么做回环检测?
回环检测主要通过视觉信息找到与当前时刻最接近的历史帧。这是一个匹配问题。从 ML 的角度看,肯定是要 编码向量 + ANN 检索的。目前(高博写书的时刻)最常见的方法就是用 BOW 方法将图片编码为向量,再用基于树的方式做 ANN 最近邻检索。BOW 理论上应该只是描述编码方法,但书里把这整个流程统称为 BOW 词袋模型,感觉也没啥太大问题吧……
Loop Closure 里的 BOW,和文本分类里的 BOW 其实一样的(不然为啥名都一样呢)。流程为
- 先基于所有的图片(训练数据,或者大数据集),建一个字典。即确定好向量的定义(多少维、每个维表示什么特征、特征值是 bool 还是浮点、相似度度量方式等)、特征值计算方法
- 然后对每张图,基于向量定义和特征计算方式,就可以计算输入图片的向量表示
- 基于定义好的相似度度量,就可以计算向量间相似度,即用来表达原始图片间的相似程度
字典/特征向量的定义,需要重点说下。在 NLP 里,words 本身就是离散的,所以向量的特征定义,重点就是选哪些 words 作为特征域;但图片怎么定义 words 呢? 是通过聚类图片特征的描述子。假设我们用 ORB 特征抽取器,则图片里相似的特征点可以抽出近似的描述子向量(这是必然的,否则描述子没有意义)。基于此,我们就把相似的描述子聚类起来,作为 words. 假设聚类有 K 个,则特征向量的维度就是 K。每一维特征,用属于这一个聚类的所有描述子来定义特征的含义(可能是可解释的,也可能不行)。特征值选择上,可以用 bool, 也可以选择 tf-idf. 特征值的计算按特征值定义来即可。书上给了一个具体的 BOW 特征定义的例子:聚类用 K-Means, 定义聚类个数 K;使用 tf-idf 方法作为特征值:tf 定义为属于此特征域的描述子个数;idf 定义为整个数据集上的描述子数量除以属于此域的描述子数量的对数( idf 似乎也可以在图片粒度上定义?)
计算一个图片对应的特征向量:对一张图片,先初始化一个 K 维的零向量;然后抽取出它所有的描述子,然后看每个描述子应该放到哪个聚类中,也即确定了对应的特征域位置。计算此描述子对应的特征值,累加到相应特征域上。处理完所有的描述子,则图片的特征向量就计算完成了。
相似度本没什么可说的,但书上用的 L1 范数 自己之前倒没有见过。
基于相似度,我们可以找到跟当前帧最接近的历史帧,但如何判断它就是我们要的回环帧?
书上列了几个要考虑的点:
-
卡阈值。超过某个阈值的,才可能是回环帧
不过向量相似度计算的结果,是由具体度量公式算出的绝对值,并不好设定一个阈值来说超过它就是回环了。书上提到了用相对值的方法来设定阈值(前面特征匹配时,也是通过这种方式来定义的 good match 阈值)。选定一个与当前帧在时间上比较临近的帧,理论上它和当前帧的向量会比较接近。于是用回环检测算出的相似度,比上与相邻帧的相似度,基于这个比值来设置阈值。书上也称为相似度的归一化。这里又涉及到一个问题,就是“临近”帧选哪个呢?这似乎是一个比较偏经验的问题?
-
避免时间维度太接近的帧。这个好理解,时间很近的,相似度肯定高,但显然不是我们期望的回环结果
-
结合其他信息做进一步校验。书上列了几种方法:可以多次检测,如果每次检测它都是回环,那就算校验通过(这个不知道具体咋弄?要是多跑几圈,那一帧的回环可能有多个了吧;如果跑1圈,那多次检测好像并没有意义?),此为时间上的一致性检测。也可以对这两帧做直接的位姿估计,再和链上的位姿估计结果做比较,如果接近就算通过校验,这是空间上的一致性检测。