SLAM2--ORB特征提取分析(傻瓜级知识点整理)

目前,自己通过调用opencv的相关接口,想实现一个比较裸的SLAM系统,但是发现opencv在特征提取上的能力着实达不到slam的要求。

可以看到左边的opencv orb算法特征点比较集中扎堆,右边的分布均匀,这样自然,有用的特征点数量也就越多。生扒了ORBSLAM2的实现,果然,没有好的特征,在高效的算法都是徒劳的。这里就顺便整理记录下ORBSLAM2的特征提取实现过程。

流程图

1. 金字塔结构

网图

金字塔结构的目的是为了实现尺度不变性。简单的说就是如果是特征点,把图像放大还是缩小,这个点都应该是特征点。但是有时,我们在用摄像头定位的时候,有时候摄像头拍到的是近景,有时是远景,如上图,这样可能在近景是角点的特征点,在远景就不是了,在远景是的特征点,在近景又不是了,这样就会使得原本是同一个场景的两个图片,不能得到较多的特征匹配点,所以用金字塔结构,在每一层上都获取尽可能多的特征点。这样最后在做图像匹配的时候,可以有足够的特征匹配点,自然对于位姿的优化也更好。

依旧是网图

通常,金字塔是从下网上进行一定比例的缩小分辨率。ORBSLAM2中在实现每一帧图像的金字塔时还做了很多处理来尽可能多的保留图像的信息。

就是下图的形式:

2.构建特征点分布八叉树

在进行特征点树的构建前,我们需要通过ORB特征提取出图像的特征点,这里既然用了金字塔结构,自然要对所有的图像都进行特征提取。

ORBSLAM首先将所有的金字塔图片沿着threshold的边界扩展了3。其实就是下图中红色虚框的样子:

之后,将这个新的图像区域惊醒30*30的小块划分,

对每一个小块进行FAST角点检测,注意这里有个小的trick,如果FAST的阈值过于苛刻,会用second值,来在进行一次检测,确保尽可能获得角点信息,但是如果实在没有也就算了毕竟垃圾角点反而会影响质量。

将所有的特征点,转成成实际的img中的坐标位置,放入特征点容器中。

随后就是将当前level的图像中的特征点集放到树结构中,在树结构中会进行特征点的均匀分布,去掉效果不好的特这个点,留下好的。

上面的代码就是将所有level有的特征点,送入分发函数,继续看DistributeOctTree是如何分发特征点的。

上面黄色部分的代码其实就是将我们当前的图像划分成nIni份,每一份作为一个结点,创建出树的第一层。

将之前这帧图像的特征点的每一个根据位置是哪个结点来放入结点中。这很简单。

ORBSLAM对于树的结点有两点限制,如果结点中只有一个特征点,就停止分裂,如果一个特征点都没有,就将结点从树中删除。

所以以下这段代码就是干这个,

之后很长一段代码就是如何进行每一层的分裂,知道不能分裂为止。

代码片段

结束了分裂之后,对所有结点中的特征点选取出最好的那一个点作为最终的这个level图像中的特征点。

总结下八叉(其实是根据分裂结点个数命名的)的方法:

  1. 如果图片的宽度比较宽,就先把分成左右w/h份。一般的640×480的图像开始的时候只有一个node。
  2. 如果node里面的点数>1,把每个node分成四个node,如果node里面的特征点为空,就不要了,删掉。
  3. 新分的node的点数>1,就再分裂成4个node。如此,一直分裂。
  4. 终止条件为:node的总数量> [公式] ,或者无法再进行分裂。
  5. 然后从每个node里面选择一个质量最好的FAST点。

网上有个画的很好的图来解释:

这样一个 for(auto& l : levels)的循环以后,我们就有了每一帧图像的所有金字塔图的均匀分布的特征点集了。So easy吧~~

ORB的过程中还有最后一步精髓,就是做角度不变性处理。

就是通过灰度质心法计算每一个特征点的方向,用于之后计算描述子的时候,实现角度不变。