ORB特征提取、匹配

ORB(Oriented FAST and Rotated BRIEF)是一种局部不变特征,从名字可以看出ORB具有FAST和旋转不变的特性。相比于经典的SIFT、SURF,ORB具备了实时使用能力。我的三维重构任务对于实时性具有较高的要求,且三维重构的最为重要的任务就是如何找到对应的特征点,所以ORB如何应用值得好好研究一下。
ORB的介绍看这里,对于ORB的介绍我不再进行过多的说明,本博客主要看看OpenCV中与ORB相关的库函数是如何应用的。

ORB特征的提取

已知对于ORB特征的描述主要包括两个部分:特征点(keypoint),描述(descriptor)。一般定义为:

vector<KeyPoint> key_points;
Mat descriptor;

而目前我见到的创建ORB的特征对象的方式有三种,如:

Ptr<ORB> orb = ORB::create();

或者:

Ptr<FeatureDetector> orb1 = ORB::create();
Ptr<DescriptorExtractor> orb2 = ORB::create();

上述三种声明的意义是一样的,无论是FeatureDetector还是DescriptorExtractor都是类Feature2D别名。而类ORB是类Feature2D的公有继承。具体OpenCV中的定义如下:

typedef Feature2D FeatureDetector;
typedef Feature2D DescriptorExtractor;
class CV_EXPORTS_W ORB : public Feature2D{}

所以无论哪种声明本质上都是一样的,可能ORB类中存在别的函数实现。类的别名主要是为了开发方便。

声明了Feature2D的对象之后,就可以直接调用detectcompute或者detectAndCompute进行计算“重要的” keypoint descriptor了。
计算方式有两种:

//分开计算
orb->detect(img, key_points);
orb->compute(img, key_points, descriptor);
//一起计算
orb->detectAndCompute(img, noArray(),key_points, descriptor);

至此ORB特征提取完毕。

ORB特征匹配

匹配器matcher声明与ORB特征对象声明一样也存在多种声明方式如:

Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce-Hamming");

或者:

BFMatcher matcher(NORM_L2);

在OpenCV中我们发现BFMatcherDescriptorMatcher的公有继承:

class CV_EXPORTS_W BFMatcher : public DescriptorMatcher{}

这样上述不同的matcher声明就容易理解了。

匹配器matcher是用于计算特征点的匹配情况的,而计算的结果通常保存在vector<DMatch> matches中。
匹配函数的调用如下:

matcher->match(descriptor1, descriptor2, matches);

其中descriptor1, descriptor2分别代表两张不同的图片的特征点(descriptor用于描述特征点),matches中保存匹配信息。
此时matches中保存的匹配点中存在匹配不准确的情况,为了提高匹配的精度,通常需要对这些匹配点进行筛选。筛选的方式多种多样,但基本思想都是保留distance满足一定条件的点对,例如:
找出匹配点之间的最大距离和最小距离,也就是匹配最相似和最不相似的点对。选择一个点对的距离阈值对点对进行筛选。

double min_dist = 10000, max_dist = 0;
//查找距离最小和距离最大的点
for (int i = 0; i < query.rows; i++)
{double dist = matches[i].distance;if (dist < min_dist) min_dist = dist;if (dist > max_dist) max_dist = dist;
}std::vector< DMatch > good_matches;
//对匹配的点对进行筛选
for (int i = 0; i < query.rows; i++)
{if (matches[i].distance <= max(2 * min_dist, 30.0)){good_matches.push_back(matches[i]);}
}
good_matches.swap(matches);

或者:
对在knnMatch中得到的knn_matches的筛选时,除了distance不能过大,还需要考虑Ratio test(KNN为特征点保留了两个待选匹配点,第一匹配点与第二匹配点的比,越接近1,匹配点越模糊,则被排除)。

 vector<vector<DMatch>> knn_matches;BFMatcher matcher(NORM_L2);matcher.knnMatch(query, train, knn_matches, 2);//获取满足Ratio Test的最小匹配的距离float min_dist = FLT_MAX;for (int r = 0; r < knn_matches.size(); ++r){//Ratio Testif (knn_matches[r][0].distance > 0.6*knn_matches[r][1].distance)continue;float dist = knn_matches[r][0].distance;if (dist < min_dist) min_dist = dist;}matches.clear();for (size_t r = 0; r < knn_matches.size(); ++r){//排除不满足Ratio Test的点和匹配距离过大的点if (knn_matches[r][0].distance > 0.6*knn_matches[r][1].distance ||knn_matches[r][0].distance > 5 * max(min_dist, 10.0f))continue;//保存匹配点matches.push_back(knn_matches[r][0]);}

对匹配点进行筛选之后,就解决了三维重构中最为棘手的问题。

tips:
在匹配ORB特征时,我发现网上一般使用的筛选方式都是基于距离的。从我的仿真实验中发现,由于ORB检测到的匹配点较少,使用距离筛选ORB匹配点较为合理,因为使用KNN的方式排除的特征点对较多,导致我的匹配结果无法正常使用SFM三维重构。

三维重构学习笔记(4):坚实的后盾OpenCV(ORB)相关推荐

  1. 三维重构学习笔记(3):坚实的后盾 OpenCV3

    三维重构学习笔记(3):坚实的后盾+OpenCV3 前面两篇笔记分别记录了关于三维重构中,有关相机标定.SFM流程的问题.除了公式的推倒和理解,仿真时始终仰仗OpenCV3大法,为了以后学习使用方便, ...

  2. 基于结构光的三维测量学习笔记

    基于结构光的三维测量学习笔记 1.几种比较成熟的方法 1.1飞行时间发 原理:通过直接测量光传播的时间,确定物体的面型.发射脉冲信号,接受发射回的光,计算距离. 精度:毫米级 优点:原理简单,可避免阴 ...

  3. 步步为营 .NET 代码重构学习笔记 九

    步步为营 .NET 代码重构学习笔记系列 步步为营 .NET 代码重构学习笔记 一.为何要代码重构 步步为营 .NET 代码重构学习笔记 二.提炼方法(Extract Method) 步步为营 .NE ...

  4. 步步为营 .NET 代码重构学习笔记 十一

    步步为营 .NET 代码重构学习笔记系列 步步为营 .NET 代码重构学习笔记 一.为何要代码重构 步步为营 .NET 代码重构学习笔记 二.提炼方法(Extract Method) 步步为营 .NE ...

  5. 31 天重构学习笔记索引

    由于最近在做重构的项目,所以对重构又重新进行了一遍学习和整理,对31天重构最早接触是在2009年10月份,由于当时没有订阅Sean Chambers的blog,所以是在国外的社区上闲逛的时候链接过去的 ...

  6. 31天重构学习笔记下载

    前言 前两天写了一篇程序猿也爱学英语(上),有图有真相的文章,写作那篇文章只是自己一时兴起,或者说是自己的兴趣使然.文中的观点只是自己的学习心得和体会,属一家之言且鉴于本人不是学英语出身,所以也肯定有 ...

  7. 步步为营 .NET 代码重构学习笔记 十

    步步为营 .NET 代码重构学习笔记系列 步步为营 .NET 代码重构学习笔记 一.为何要代码重构 步步为营 .NET 代码重构学习笔记 二.提炼方法(Extract Method) 步步为营 .NE ...

  8. Java 3D编程实践_Java 3D编程实践——网络上的三维动画[学习笔记]

    评论 # re: Java 3D编程实践--网络上的三维动画[学习笔记] 2006-08-24 23:41 gy # re: Java 3D编程实践--网络上的三维动画[学习笔记] 2007-03-2 ...

  9. UE4蓝图制作三维弹球学习笔记(二)

    UE4蓝图制作三维弹球学习笔记(二) 1.BP_Fliper Viewport 使用Static Mesh导入Fliper. Construction 使用同一个蓝图表示左右不同的Fliper.在蓝图 ...

最新文章

  1. wxWidgets搜索事件处理函数顺序
  2. 机器人也来玩“踢瓶盖挑战”了,你动他就动,靠脑电控制,路人也能玩丨MIT出品...
  3. usb协议规范_你想了解的USB知识,都在这里了!
  4. Debian 和Ubuntu Mono 3.0 部署包
  5. JSP、EL和JSTL-学习笔记01【JSP基础语法】
  6. python定义一个整数变量_python循环定义多个变量的实例分析
  7. python解释器把python代码一次性翻译成目标代码_Python语言程序设计----【第1周 Python基本语法元素】之1.1 程序设计基本方法...
  8. 进击的程序媛:毕业于斯坦福,Google 元老级员工,曾任雅虎 CEO | 人物志
  9. Spring Boot 2.x 把 Guava 干掉了,拥抱本地缓存之王 Caffeine!
  10. HTML iframe标签下 子页面调用父页面js 容易产生的跨域调用问题 Uncaught DOMException
  11. 王道训练营3月27日
  12. 数字信号处理期末总复习
  13. Java计算卡方值和P值
  14. 误删除恢复 (extundelete)
  15. MATLAB多元线性拟合——03
  16. 双显示器LOL加载游戏提示error无法初始化图形设备解决方法
  17. jdbc连接oracle11g
  18. 熔断机制什么意思_熔断机制是什么意思(图文)
  19. 继电保护matlab程序,自适应微机继电保护的matlab仿真实现 程序与算法
  20. oracle的权限授予,Oracle赋予用户sysdba权限

热门文章

  1. MIT 18.06 线性代数公开课笔记 Lecture02 矩阵消元
  2. 吉林大学计算机系2019录取分数线,吉林大学2019年录取分数线
  3. jmeter定时器的使用_jmeter定时器
  4. 休息对于工作的重要性
  5. 【科研论文】基于DSP的激光跟踪仪数据通信及处理模块设计
  6. Android 开启手电筒功能(完美适配4.x, 5.x, 6.x )
  7. 后农耕时代,DeFi何去何从?
  8. 财务自由之路 笔记 第十四章 播种金钱
  9. WanaCry病毒简单分析
  10. boost 处理压缩解压缩