ORB 特征点检测匹配算法

一、ORB算法
  ORB是是ORiented Brief的简称。这个算法是由Ethan Rublee, Vincent Rabaud, Kurt Konolige以及Gary R.Bradski在2011年一篇名为“ORB:An Efficient Alternative to SIFTor SURF”的文章中提出。ORB算法分为两部分,分别是特征点提取和特征点描述。在ORB算法中,是用FAST特征点检测算法来进行特征点提取,利用BRIEF特征描述子算法来进行特征点描述,并将两者结合起来,在两者原有的基础上做了改进与优化的算法。ORB算法的速度是sift的100倍,是surf的10倍。

二、FAST特征点提取算法的改进
  要想详细了解FAST算法的原理请参考FAST特征点检测算法这篇文章。这里面我们详细聊一下ORB算法跟FAST算法在特征点提取上的不同。
  ORB算法的特征提取是由FAST算法改进的,这里也叫oFAST(FASTKeypoint Orientation)。也就是说,在使用FAST提取出特征点之后,给其定义一个特征点方向,以此来实现特征点的旋转不变形。具体实现如下:
  (1)实现特征点的尺度不变形。建立金字塔,来实现特征点的多尺度不变性。设置一个比例因子scaleFactor(opencv默认为1.2)和金字塔的层数nlevels(opencv默认为8)。将原图像按比例因子缩小成nlevels幅图像。缩放后的图像为:I’= I/scaleFactork(k=1,2,…, nlevels)。nlevels幅不同比例的图像提取特征点总和作为这幅图像的oFAST特征点。
  (2)实现特征点的旋转不变性。ORB算法提出使用矩(moment)法来确定FAST特征点的方向。也就是说通过矩来计算特征点以r为半径范围内的质心,特征点坐标到质心进行连线,求出该直线与横坐标轴的夹角,即为该特征点的方向。那么,怎么求取这个邻域的质心呢?
  矩定义如下:

这里写图片描述

  然后质心定义如下:

这里写图片描述

  然后求取向量OC的方向,同时如果把x,y的范围保持在[−r,r]之间(r为该特征点邻域的半径),以特征点为坐标原点,则得到的方向角(即FAST特征点的方向)为:

这里写图片描述

三、BRIEF特征描述子算法的改进
  要想详细了解BRIEF特征描述子算法的原理请参考BRIEF 特征点描述算法这篇文章。接下来我们详细讲解ORB算法跟BRIEF特征描述子算法在特征点描述子上的不同。
  由上面的文章可知,BRIEF算法形成的描述符对于旋转操作非常敏感,当旋转的角度增大时,利用BRIEF算法的描述符进行匹配的结果极大的降低。如下图所示:

这里写图片描述

  图中x轴表示的是旋转的角度,y轴表示匹配结果中正确匹配所占的百分比。可以看出,随着旋转角度的增大,BRIEF算法的匹配效果迅速的降低,旋转角度在45度以上时,正确率几乎为0。所以我需要针对BRIEF算法的不足进行改进,下面介绍ORB算法中的Steered BRIEF算法。
  想要让BRIEF算法具有旋转不变性,那么我们需要使特征点的邻域旋转一个角度,该角度就是我们上面求得的特征点的方向角θ。但是这样整体旋转一个邻域的开销是比较大的,一个更加高效的做法就是旋转我们前面得到的那些邻域中的匹配点xi、yi。 设生成特征点描述符的n个测试点对为(xi,yi),定义一个2×n的矩阵:

这里写图片描述

  利用角度θ形成的旋转矩阵为Rθ,那么旋转后匹配点的坐标为:

这里写图片描述

  其中Rθ如下:

这里写图片描述

  其中θ为特征点求得的主方向。这样,在求取特征点描述符的时候,将原描述符转化成Sθ即可。改描述符具有旋转不变性。

四、rBRIEF-改进特征点描述子的相关性
  使用steeredBRIEF方法得到的特征描述子具有旋转不变性,但是却在另外一个性质上不如原始的BRIEF算法。是什么性质呢,是描述符的可区分性,或者说是相关性。这个性质对特征匹配的好坏影响非常大。描述子是特征点性质的描述。描述子表达了特征点不同于其他特征点的区别。我们计算的描述子要尽量的表达特征点的独特性。如果不同特征点的描述子的可区分性比较差,匹配时不容易找到对应的匹配点,引起误匹配。ORB论文中,作者用不同的方法对100k个特征点计算二进制描述符,对这些描述符进行统计,如下表所示:

这里写图片描述

  其中X轴代表距离均值0.5的距离,y轴是相应均值下的特征点数量统计。
  我们先不看rBRIEF的分布。对BRIEF和steeredBRIEF两种算法的比较可知,BRIEF算法落在0上的特征点数较多,因此BRIEF算法计算的描述符的均值在0.5左右,每个描述符的方差较大,可区分性较强。而steeredBRIEF失去了这个特性。至于为什么均值在0.5左右,方差较大,可区分性较强的原因,这里大概分析一下。这里的描述子是二进制串,里面的数值不是0就是1,如果二进制串的均值在0.5左右的话,那么这个串有大约相同数目的0和1,那么方差就较大了。用统计的观点来分析二进制串的区分性,如果两个二进制串的均值都比0.5大很多,那么说明这两个二进制串中都有较多的1时,在这两个串的相同位置同时出现1的概率就会很高。那么这两个特征点的描述子就有很大的相似性。这就增大了描述符之间的相关性,减小之间的可区分性。
  下面我们介绍解决上面这个问题的方法:rBRIEF。
  原始的BRIEF算法有5种取点对的方法,原文作者使用了方法2。为了解决描述子的可区分性和相关性的问题,ORB论文中没有使用5种方法中的任意一种,而是使用统计学习的方法来重新选择点对集合。
  首先建立300k个特征点测试集。对于测试集中的每个点,考虑其31x31邻域。这里不同于原始BRIEF算法的地方是,这里在对图像进行高斯平滑之后,使用邻域中的某个点的5x5邻域灰度平均值来代替某个点对的值,进而比较点对的大小。这样特征值更加具备抗噪性。另外可以使用积分图像加快求取5x5邻域灰度平均值的速度。从上面可知,在31x31的邻域内共有(31-5+1)x(31-5+1)=729个这样的子窗口,那么取点对的方法共有M=265356种,我们就要在这M种方法中选取256种取法,选择的原则是这256种取法之间的相关性最小。怎么选取呢?
  (1)在300k特征点的每个31x31邻域内按M种方法取点对,比较点对大小,形成一个300kxM的二进制矩阵Q。矩阵的每一列代表300k个点按某种取法得到的二进制数。
  (2)对Q矩阵的每一列求取平均值,按照平均值到0.5的距离大小重新对Q矩阵的列向量排序,形成矩阵T。
  (3)将T的第一列向量放到R中。
  (4)取T的下一列向量和R中的所有列向量计算相关性,如果相关系数小于设定的阈值,则将T中的该列向量移至R中。
  (5)按照(4)的方式不断进行操作,直到R中的向量数量为256。
  通过这种方法就选取了这256种取点对的方法。这就是rBRIEF算法。至此我们讲的oFAST + rBRIEF即为ORB算法。

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ORB-SLAM是一种基于特征点的视觉SLAM算法,它使用ORB特征点来进行特征匹配ORB特征点是一种既能够快速检测又能够准确描述图像特征算法ORB特征点的检测和描述分别使用了FAST点检测算法和BRIEF描述子算法ORB-SLAM使用了基于词袋模型的方法来进行特征匹配,具体来说,ORB-SLAM将所有的ORB特征点分成若干个不同的视觉词汇,然后使用BoW(Bag of Words)模型来描述每个图像。在ORB-SLAM中,特征匹配主要分为两个步骤:词袋匹配和光流法匹配。词袋匹配是通过计算两个图像的词袋向量之间的距离来进行的,而光流法匹配则是通过计算两个图像中的特征点在相邻帧之间的运动来进行的。 以下是一个ORB-SLAM特征匹配算法的示例代码: ```c++ // ORB特征点检测和描述 cv::Ptr<cv::ORB> orb = cv::ORB::create(); std::vector<cv::KeyPoint> keypoints1, keypoints2; cv::Mat descriptors1, descriptors2; orb->detectAndCompute(img1, cv::noArray(), keypoints1, descriptors1); orb->detectAndCompute(img2, cv::noArray(), keypoints2, descriptors2); // 词袋匹配 cv::Ptr<cv::DescriptorMatcher> matcher = cv::DescriptorMatcher::create("BruteForce-Hamming"); std::vector<cv::DMatch> matches; matcher->match(descriptors1, descriptors2, matches); // 光流法匹配 std::vector<cv::Point2f> points1, points2; for (auto match : matches) { points1.push_back(keypoints1[match.queryIdx].pt); points2.push_back(keypoints2[match.trainIdx].pt); } std::vector<uchar> status; std::vector<float> err; cv::calcOpticalFlowPyrLK(img1, img2, points1, points2, status, err); // 输出匹配结果 for (int i = 0; i < matches.size(); i++) { if (status[i]) { cv::DMatch match = matches[i]; cv::Point2f pt1 = keypoints1[match.queryIdx].pt; cv::Point2f pt2 = keypoints2[match.trainIdx].pt; std::cout << "Match " << i << ": (" << pt1.x << ", " << pt1.y << ") -> (" << pt2.x << ", " << pt2.y << ")" << std::endl; } } ```

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值