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. MySQL几个特别语法示例
  2. 【Python】Python3中的str和bytes
  3. mfcc中的fft操作_简化音频数据:FFT,STFT和MFCC
  4. JavaScript与JSP区别
  5. oracle数据库基础知识总结,oracle数据库基础知识学习笔记
  6. Linux内存映射实现框架
  7. ImportError:cannot import name 'distribute_covar_matrix_to_match_covariance_type'
  8. Fedora 30 将默认启用 DNF-best 模式
  9. VSCode猜测字符编码
  10. java中级程序员全面学习路线教程
  11. 前端开发3年计划,前端应届生如何做一个职业规划
  12. 第十二天内容《基础交换十二》
  13. 嵌入式linux/鸿蒙开发板(IMX6ULL)开发(二十四)具体单板的GPIO操作方法
  14. Contest 20140914 Mushroom写情书 字符串雙hash 後綴數組
  15. Win10 计算机扩展显示器闪黑屏
  16. 爬虫常见的加密解密算法
  17. 肌电信号的包络matlab程序_基于matlab的肌电信号处理程序:
  18. 国产“芯”时代 盘点国内十大IC卡制卡企业
  19. 智创云享知识付费V2 v2.0.9
  20. 服务器意外终止连接,错误号:0X800CCCOF 如何解决

热门文章

  1. iOS 开源项目介绍之UI篇
  2. 接口500什么原因_各种视频接口介绍?可能很多人不知道它们的传输距离是多少...
  3. 二进制除法转乘法原理
  4. 在matlab中以图像中心为旋转轴逆时针旋转30度自编程序,MATLAB数学建模习题
  5. 【python数据预处理笔记】——整齐数据(Tidy Data)
  6. 为什么心机重的人,却比你过得好?
  7. Android Studio 3.5 打Jar包
  8. Balsamiq Mockups安装使用
  9. 大学时光仅四年,疫情反反复复占几年
  10. [2023] NAND闪存及控制器的市场趋势