深度分析 ORB-SLAM3 中的数据挖掘与知识发现应用

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

本报告根据 IEEE Transactions on Robotics 期刊的 2021 年文章 ORB-SLAM3: An
Accurate Open-Source Library for Visual, Visual-Inertial and Multi-Map SLAM 的
内容并复现代码总结而成。

代码地址为:https://github.com/UZ-SLAMLab/ORB_SLAM3
文章地址为:[2007.11898] ORB-SLAM3: An Accurate Open-Source Library for Visual,
Visual-Inertial and Multi-Map SLAM (arxiv.org)


提示:以下是本篇文章正文内容,下面案例可供参考

一、ORB-SLAM3 中的数据挖掘应用

数据挖掘,是从大量的、有噪声的、不完全的、模糊和随机的数据中,提取出隐含在其中的、人们事先不知道的、具有潜在利用价值的信息和知识的过程。而在 ORB-SLAM3 中有许多数据挖掘的应用,例如特征点提取器 ORBextractor、提取关键帧(KeyFrame)。在 slam中视频形成很多帧图片,这些图片就相当于海量数据,通过这些图片提取特征点、从大量帧中提取关键帧,便是数据挖掘。下面是对提取器、关键帧的从理论到代码的数据挖掘过程应用分析。

1.特征点提取器(ORBextractor)中的数据挖掘应用

下图1为通过ORB-SLAM3代码为河工大北辰图书馆的一帧图片的特征点提取。
在这里插入图片描述
图1 河工大图书馆特征点图
ORB(Oriented FAST and Rotated BRIEF)是一种快速特征点提取和描述的算法。这个算法是由Ethan Rublee, Vincent Rabaud, Kurt Konolige以及Gary R.Bradski在2011年一篇名为“ORB:An Efficient Alternative to SIFTor SURF”的文章中提出。ORB算法分为两部分,分别是特征点提取和特征点描述。特征提取是由FAST(Features from Accelerated Segment Test)算法发展来的,特征点描述是根据BRIEF(Binary Robust IndependentElementary Features)特征描述算法改进的。ORB特征是将FAST特征点的检测方法与BRIEF特征描述子结合起来,并在它们原来的基础上做了改进与优化。
ORB算法的特征提取是由FAST算法改进的,这里成为FAST(FASTKeypoint Orientation)。也就是说,在使用FAST提取出特征点之后,给其定义一个特征点方向,以此来实现特征点的旋转不变形。FAST算法是公认的最快的特征点提取方法。FAST算法提取的特征点非常接近角点类型。FAST算法如下图2:
在这里插入图片描述
图2 FAS算法图

  1. 粗提取。该步能够提取大量的特征点,但是有很大一部分的特征点的质量不高。下面介绍提取方法。从图像中选取一点P,如上图,我们判断该点是不是特征点的方法是,以P为圆心画一个半径为3pixel的圆。圆周上如果有连续n个像素点的灰度值比P点的灰度值大或者小,则认为P为特征点。一般n设置为12。为了加快特征点的提取,快速排出非特征点,首先检测1、9、5、13位置上的灰度值,如果P是特征点,那么这四个位置上有3个或3个以上的的像素值都大于或者小于P点的灰度值。如果不满足,则直接排出此点;
  2. 机器学习的方法筛选最优特征点。简单来说就是使用ID3算法训练一个决策树,将特征点圆周上的16个像素输入决策树中,以此来筛选出最优的FAST特征点;
  3. 非极大值抑制去除局部较密集特征点。使用非极大值抑制算法去除临近位置多个特征点的问题。为每一个特征点计算出其响应大小。计算方式是特征点P和其周围16个特征点偏差的绝对值和。在比较临近的特征点中,保留响应值较大的特征点,删除其余的特征点;
  4. 特征点的尺度不变形。建立金字塔,来实现特征点的多尺度不变性。设置一个比例因子scaleFactor(opencv默认为1.2)和金字塔的层数nlevels(pencv默认为8)。将原图像按比例因子缩小成nlevels幅图像。缩放后的图像为:I’= I/scaleFactork(k=1,2,…, nlevels)。nlevels幅不同比例的图像提取特征点总和作为这幅图像的oFAST特征点;
  5. 特征点的旋转不变性。ORB算法提出使用矩(moment)法来确定FAST特征点的方向。也就是说通过矩来计算特征点以r为半径范围内的质心,特征点坐标到质心形成一个向量作为该特征点的方向。矩定义如下:
    m_pq=∑_(x,y)▒〖x^p y^q 〗 I(x,y) p,q={0,1}

其中,I(x,y)为图像灰度表达式。该矩的质心为:
C=(m_10/m_00 ,m_01/m_00 )

假设角点坐标为O,则向量的角度即为该特征点的方向。计算公式如下:

θ=arctan((m_01/m_00 )/(m_10/m_00 ))=arctan⁡(m_01/m_10 )

BRIEF算法计算出来的是一个二进制串的特征描述符。它是在一个特征点的邻域内,选择n对像素点pi、qi(i=1,2,…,n)。然后比较每个点对的灰度值的大小。如果I(pi)> I(qi),则生成二进制串中的1,否则为0。所有的点对都进行比较,则生成长度为n的二进制串。一般n取128、256或512,opencv默认为256。另外,值得注意的是为了增加特征描述符的抗噪性,算法首先需要对图像进行高斯平滑处理。在ORB算法中,在这个地方进行了改进,在使用高斯函数进行平滑后,又用了其他操作,使其更加的具有抗噪性。具体方法下面将会描述。
关于在特征点SxS的区域内选取点对的方法,BRIEF论文中测试了五种方法:
1)在图像块内平均采样;
2)p和q都符合(0,S2/25)的高斯分布;
3)p符合(0,S2/25)的高斯分布,而q符合(0,S2/100)的高斯分布;
4)在空间量化极坐标下的离散位置随机采样;
5)把p固定为(0,0),q在周围平均采样。
其中两种采样方法的如下图3:
在这里插入图片描述
图3 采样方法图
论文指出,第二种方法可以取得较好的匹配结果。在旋转不是非常厉害的图像里,用BRIEF生成的描述子的匹配质量非常高,作者测试的大多数情况中都超越了SURF。但在旋转大于30°后,BRIEF的匹配率快速降到0左右。BRIEF的耗时非常短,在相同情形下计算512个特征点的描述子时,SURF耗时335ms,BRIEF仅8.18ms;匹配SURF描述子需28.3ms,BRIEF仅需2.19ms。在要求不太高的情形下,BRIEF描述子更容易做到实时。
FAST特征点和ORB描述子本身不具有尺度信息,ORBextractor通过构建图像金字塔来得到特征点尺度信息.将输入图片逐级缩放得到图像金字塔,金字塔层级越高,图片分辨率越低,ORB特征点越大。如下图4为图像金字塔模型图:

在这里插入图片描述
图4 图像金字塔模型
初始化用于计算描述子的pattern变量,pattern是用于计算描述子的256对坐标,其值写死在源码文件ORBextractor.cc里,在构造函数里做类型转换将其转换为const cv::Point*变量。
后面计算的是特征点主方向上的描述子,计算过程中要将特征点周围像素旋转到主方向上,因此计算一个半径为16的圆的近似坐标,用于后面计算描述子时进行旋转操作。
在这里插入图片描述
图5 图像金字塔模型
成员变量std::vector umax里存储的实际上是逼近圆的第一象限内四分之一圆周上每个v坐标对应的u坐标.为保证严格对称性,先计算下45°圆周上点的坐标,再根据对称性补全上45°圆周上点的坐标。

2.特征点提取器(ORBextractor)的代码注释分析

代码如下(示例):

void ORBextractor::ComputeKeyPointsOctTree(vector<vector<KeyPoint> >& allKeypoints)	{
    for (int level = 0; level < nlevels; ++level)
        // 计算图像边界
        const int minBorderX = EDGE_THRESHOLD-3;		
        const int minBorderY = minBorderX;				
        const int maxBorderX = mvImagePyramid[level].cols-EDGE_THRESHOLD+3;
        const int maxBorderY = mvImagePyramid[level].rows-EDGE_THRESHOLD+3;
        const float width = (maxBorderX-minBorderX);
        const float height = (maxBorderY-minBorderY);
        const int nCols = width/W;				// 每一列有多少cell
        const int nRows = height/W;				// 每一行有多少cell
        const int wCell = ceil(width/nCols);	// 每个cell的宽度
        const int hCell = ceil(height/nRows);	// 每个cell的高度

        // 存储需要进行平均分配的特征点
        vector<cv::KeyPoint> vToDistributeKeys;
		
    	// step1. 遍历每行和每列,依次分别用高低阈值搜索FAST特征点
        for(int i=0; i<nRows; i++) {
            const float iniY = minBorderY + i * hCell;
            const float maxY = iniY + hCell + 6;
            for(int j=0; j<nCols; j++) {
                const float iniX =minBorderX + j * wCell;
                const float maxX = iniX + wCell + 6;
                vector<cv::KeyPoint> vKeysCell;
				
                // 先用高阈值搜索FAST特征点
                FAST(mvImagePyramid[level].rowRange(iniY,maxY).colRange(iniX,maxX),	vKeysCell, iniThFAST, true);
                // 高阈值搜索不到的话,就用低阈值搜索FAST特征点
                if(vKeysCell.empty()) {
                    FAST(mvImagePyramid[level].rowRange(iniY,maxY).colRange(iniX,maxX),	vKeysCell, minThFAST, true);
                }
				// 把 vKeysCell 中提取到的特征点全添加到 容器vToDistributeKeys 中
                for(KeyPoint point :vKeysCell) {
                    point.pt.x+=j*wCell;
                    point.pt.y+=i*hCell;
                    vToDistributeKeys.push_back(point);
                }
            }
        }
		
    	// step2. 对提取到的特征点进行八叉树筛选,见 DistributeOctTree() 函数
        keypoints = DistributeOctTree(vToDistributeKeys, minBorderX, maxBorderX, minBorderY, maxBorderY, mnFeaturesPerLevel[level], level);
    }
	// 计算每个特征点的方向
    for (int level = 0; level < nlevels; ++level)
        computeOrientation(mvImagePyramid[level], allKeypoints[level], umax);				
	}
}


  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值