数字图像处理学习笔记(三):ORB算法(尺度不变特征变换)Oriented FAST and Rotated BRIEF

数字图像处理学习笔记(三):ORB算法(尺度不变特征变换)Oriented FAST and Rotated BRIEF

一、概述

参考:特征点匹配+特征检测方法汇总
在这里插入图片描述
ORB的全称是Oriented FAST and Rotated BRIEF,是目前来说非常好的能够进行的实时的图像特征提取和描述的算法,它改进了FAST特征提取算法,并使用速度极快的二进制描述子BRIEF。
针对FAST特征提取的算法的一些确定,ORB也做了相应的改进。

  • 使用非最大值抑制,在一定区域内仅仅保留响应极大值的角点,避免FAST提取到的角点过于集中。
  • FAST提取到的角点数量过多且不是很稳定,ORB中可以指定需要提取到的角点的数量N,然后对FAST提取到的角点分别计算Harris响应值,选择前N个具有最大响应值的角点作为最终提取到的特征点集合。
  • FAST提取到的角点不具有尺度信息,在ORB中使用图像金字塔,并且在每一层金字塔上检测角点,以此来保持尺度的不变性。
  • FAST提取到的角点不具有方向信息,在ORB中使用灰度质心法(Intensity Centroid)来保持特征的旋转不变性。

FAST-12算法:

添加预测试操作,于每个像素,直接检测在邻域圆上的第1,5,9,13个像素的亮度,只有当这四个像素当中有三个同时大于IP+T或者小于IP-T的时候,当前像素才有可能是是角点。

  • 问题1:FAST特征点的数量很多,并且不是确定,而大多数情况下,我们希望能够固定特征点的数量。

解决方法:在ORB当中,我们可以指定要提取的特征点数量。对原始的FAST角点分别计算Harris的响应值,然后选取前N个点具有最大相应值的角点,作为最终角点的集合。

  • 问题2:FAST角点不具有方向信息和尺度问题。

解决方法:尺度不变性构建的图像的金字塔,并且从每一层上面来检测角点。旋转性是由灰度质心法实现。

灰度质心法:质心是指以图像块灰度值作为权重的中心。(目标是为了找到方向)

1)在一个小的图像块B中,定义图像块的矩为:
在这里插入图片描述
2)通过矩找到图像块的质心

在这里插入图片描述

3)连接图像块的几何中心o与质心C,得到一个oc的向量,把这个向量的方向定义特征点的方向
在这里插入图片描述

OpenCV提供了两种Matching方式:

• Brute-force matcher (cv::BFMatcher)    

1)暴力方法找到点集1中每个descriptor在点集2中距离最近的descriptor;找寻到的距离最小就认为匹配
2)浮点描述子-欧氏距离;二进制描述符-汉明距离。
3)详细描述:在第一幅图像中选取一个关键点然后依次与第二幅图像的每个关键点进行(描述符)距离测试,最后返回距离最近的关键点

• Flann-based matcher (cv::FlannBasedMatcher)    

1)快速最近邻搜索算法寻找(用快速的第三方库近似最近邻搜索算法)
2)是一个对大数据集和高维特征进行最近邻搜索的算法的集合,在面对大数据集时它的效果要好于BFMatcher。
3)使用FLANN匹配需要传入两个字典参数:

  • 一个参数是IndexParams,对于SIFT和SURF,可以传入参数index_params=dict(algorithm=FLANN_INDEX_KDTREE, trees=5)。
    对于ORB,可以传入参数
    index_params=dict(algorithm=FLANN_INDEX_LSH, table_number=6, key_size=12, multi_probe_level=1)。

  • 第二个参数是SearchParams,可以传入参数search_params=dict(checks=100),它来指定递归遍历的次数,值越高结果越准确,但是消耗的时间也越多。

cv::BFMatcher(int normType=NORM_L2, bool crossCheck=false)

如下所示:

  • normType:它是用来指定要使用的距离测试类型,默认值为cv2.Norm_L2,这很适合SIFT和SURF等(c2.NORM_L1也可)。对于使用二进制描述符的ORB、BRIEF和BRISK算法等,要使用cv2.NORM_HAMMING,
    这样就会返回两个测试对象之间的汉明距离。如果ORB算法的参数设置为WTA_K==3或4,normType就应该设置成cv2.NORM_HAMMING2。

  • crossCheck:默认值为False。如果设置为True,匹配条件就会更加严格,只有到A中的第i个特征点与B中的第j个特征点距离最近,并且B中的第j个特征点到A中的第i个特征点也是最近时才会返回最佳匹配(i,j),
    即这两个特征点要互相匹配才行。

BFMatcher对象有两个方法BFMatcher.match()和BFMatcher.knnMatch()。第一个方法会返回最佳匹配。第二个方法为每个关键点返回k个最佳匹配,其中k是由用户设定的。
cv2.drawMatches()来绘制匹配的点,它会将两幅图像先水平排列,然后在最佳匹配的点之间绘制直线。
如果前面使用的是BFMatcher.knnMatch(),现在可以使用函数cv2.drawMatchsKnn为每个关键点和它的个最佳匹配点绘制匹配线,如果要选择性绘制就要给函数传入一个掩模。

特征点的匹配后的优化

特征的匹配是针对特征描述子进行的,上面提到特征描述子通常是一个向量,两个特征描述子的之间的距离可以反应出其相似的程度,也就是这两个特征点是不是同一个。

根据描述子的不同,可以选择不同的距离度量。如果是浮点类型的描述子,可以使用其欧式距离;对于二进制的描述子(BRIEF)可以使用其汉明距离(两个不同二进制之间的汉明距离指的是两个二进制串不同位的个数)。

有了计算描述子相似度的方法,那么在特征点的集合中如何寻找和其最相似的特征点,这就是特征点的匹配了。最简单直观的方法就是上面使用的:暴力匹配方法(Brute-Froce Matcher),计算某一个特征点描述子与其他所有特征点描述子之间的距离,然后将得到的距离进行排序,取距离最近的一个作为匹配点。这种方法简单粗暴,其结果也是显而易见的,通过上面的匹配结果,也可以看出有大量的错误匹配,这就需要使用一些机制来过滤掉错误的匹配。

  • 交叉匹配
    针对暴力匹配,可以使用交叉匹配的方法来过滤错误的匹配。交叉过滤的思想很简单,再进行一次匹配,反过来使用被匹配到的点进行匹配,如果匹配到的仍然是第一次匹配的点的话,就认为这是一个正确的匹配。举例来说就是,假如第一次特征点A使用暴力匹配的方法,匹配到的特征点是特征点B;反过来,使用特征点B进行匹配,如果匹配到的仍然是特征点A,则就认为这是一个正确的匹配,否则就是一个错误的匹配。OpenCV中BFMatcher已经封装了该方法,创建BFMatcher的实例时,第二个参数传入true即可,BFMatcher bfMatcher(NORM_HAMMING,true)。

  • KNN匹配
    K近邻匹配,在匹配的时候选择K个和特征点最相似的点,如果这K个点之间的区别足够大,则选择最相似的那个点作为匹配点,通常选择K = 2,也就是最近邻匹配。对每个匹配返回两个最近邻的匹配,如果第一匹配和第二匹配距离比率足够大(向量距离足够远),则认为这是一个正确的匹配,比率的阈值通常在2左右。

  • RANSAC
    随机采样一致性(RANSAC)可过滤掉错误的匹配,该方法利用匹配点计算两个图像之间单应矩阵,并分解得到位姿R,t,通过三角测量来得到两个关联特征对应的3D点,将3D点按照当前估计的位姿进行投影,也就是重投影,然后利用重投影误差(观测到得投影位置(像素坐标)与3D点进行重投影的位置之差)来判定某一个匹配是不是正确的匹配。
    OpenCV中封装了求解单应矩阵的方法findHomography,可以为该方法设定一个重投影误差的阈值,可以得到一个向量mask来指定那些是符合该重投影误差的匹配点对(Inliers),以此来剔除错误的匹配,

二、示例

openCV处理流程:
1)读取图像
2)获取检测器的实例
3)在OpenCV3中重新的封装了特征提取的接口,可统一的使用Ptr detector = FeatureDetector::create()来得到特征提取器的一个实例,所有的参数都提供了默认值,也可以根据具体的需要传入相应的参数。
4)在得到特征检测器的实例后,可调用的detect方法检测图像中的特征点的具体位置,检测的结果保存在vector向量中。
5)有了特征点的位置后,调用compute方法来计算特征点的描述子,描述子通常是一个向量,保存在Mat中。
6)得到了描述子后,可调用匹配算法进行特征点的匹配。上面代码中,使用了opencv中封装后的暴力匹配算法BFMatcher,该算法在向量空间中,将特征点的描述子一一比较,选择距离(上面代码中使用的是Hamming距离)较小的一对作为匹配点。
7)绘制结果

  • 汉明距离小于最小距离的两倍
    选择已经匹配的点对的汉明距离不大于最小距离的两倍作为判断依据,如果不大于该值则认为是一个正确的匹配,过滤掉;大于该值则认为是一个错误的匹配。

DMatch类存放匹配结果

struct DMatch
{       int queryIdx;  		//此匹配对应的查询图像的特征描述子索引int trainIdx;   		//此匹配对应的训练(模板)图像的特征描述子索引int imgIdx;    		//训练图像的索引(若有多个)float distance;  		//两个特征向量之间的欧氏距离,越小表明匹配度越高。bool operator < (const DMatch &m) const;
};
#include <opencv2/opencv.hpp>using namespace cv;
using namespace std;int main()
{// 0 读取图像Mat img1 = imread("F:/C++/2. OPENCV 3.1.0/TEST/w.jpg",1);Mat img2 = imread("F:/C++/2. OPENCV 3.1.0/TEST/e.jpg",1);// 1 初始化特征点和描述子,ORBstd::vector<KeyPoint> keypoints1, keypoints2;    // 定义关键点(特征点)Mat descriptors1, descriptors2;                            // 定义描述子Ptr<ORB> orb = ORB::create();// 2 、提取 Oriented FAST 特征点orb->detect(img1, keypoints1);orb->detect(img2, keypoints2);// 3 、根据角点位置计算 BRIEF 描述子orb->compute(img1, keypoints1, descriptors1);orb->compute(img2, keypoints2, descriptors2);//    // 4、绘制特征关键点.
//    Mat img_keypoints_1;
//    Mat img_keypoints_2;
//    drawKeypoints( img1, keypoints1, img_keypoints_1, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
//    drawKeypoints( img2, keypoints2, img_keypoints_2, Scalar::all(-1), DrawMatchesFlags::DEFAULT );
//    // 5、显示效果图
//    imshow("特征点检测效果图1", img_keypoints_1 );
//    imshow("特征点检测效果图2", img_keypoints_2 );// 6、对两幅图像中的BRIEF描述子进行匹配,使用 Hamming 距离// DMatch类存放匹配结果:matches中保存着匹配关系vector<DMatch> matches;// 暴力匹配算法:找到点集1中每个descriptor在点集2中距离(hamming distance)最近的descriptor;找寻到的距离最小就认为匹配BFMatcher bfmatcher(NORM_HAMMING,true);// 匹配函数bfmatcher.match(descriptors1, descriptors2, matches);// 7、匹配对筛选:选择 hamming距离小于最小距离的两倍的特征点double min_dist = 1000, max_dist = 0;// 找出所有匹配之间的最大值和最小值for (int i = 0; i < descriptors1.rows; i++){double dist = matches[i].distance;//汉明距离在matches中if (dist < min_dist)min_dist = dist;if (dist > max_dist)max_dist = dist;}// 当描述子之间的匹配大于2倍的最小距离时,即认为该匹配是一个错误的匹配。// 但有时描述子之间的最小距离非常小,可以设置一个经验值作为下限vector<DMatch> good_matches;for (int i = 0; i < descriptors1.rows; i++){if (matches[i].distance <= max(2 * min_dist, 30.0))good_matches.push_back(matches[i]);}// 8、绘制匹配结果Mat img_match;drawMatches(img1, keypoints1, img2, keypoints2, good_matches, img_match);imshow("所有匹配点对", img_match);

结果:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/491074.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

华为:对部分顶尖学生实行年薪制 最高200万元

来源&#xff1a;EETOP7月23日上午消息&#xff0c;据华为总裁办签发的电子邮件&#xff0c;华为对部分2019届顶尖学生实行年薪制管理。华为以电邮通知【2019】068号文发布了8名天才少年的年薪方案&#xff0c;这8名人员全部为2019届应届顶尖学生&#xff0c;其年薪的最低限为8…

matplotlib使用GridSpec自定义子图位置 (非对称的子图)

上图的结构可以用一下两种方式画&#xff1a; import matplotlib.pyplot as plt from matplotlib.gridspec import GridSpecfig plt.figure(1) gs GridSpec(3, 3)ax1 plt.subplot(gs[0, :]) ax2 plt.subplot(gs[1, :2]) ax3 plt.subplot(gs[1:, 2]) ax4 plt.subplot(gs[…

大脑简史(1)-历史上的大事件

来源&#xff1a;人机与认知实验室能够上天入地&#xff0c;却不知道自己的大脑&#xff0c;笔者认为这是很多人的疑惑。随着科技的发展&#xff0c;我们能够延伸到的地方越来越多&#xff0c;无论是伸手不见五指的海底&#xff0c;还是扶摇直上九万里的浩渺星空&#xff0c;都…

作业3词频统计

(1). 实现一个控制台程序&#xff0c;给定一段英文字符串&#xff0c;统计其中各个英文单词&#xff08;4字符以上含4字符&#xff09;的出现频率。 答&#xff1a; 从文件读取遍历字符串大写转小写将句子分隔成一个个单词判断是否为单词计算单词出现的频率预估时间10minutes10…

MATLAB报错Invalid ADAPTORNAME specified. Type 'imaqhwinfo' for a list of available ADAPTORNAMEs. Image

MATLAB报错Invalid ADAPTORNAME specified. Type imaqhwinfo for a list of available ADAPTORNAMEs. Image acquisition adaptors may be available as downloadable support packages. Open Support Package Installer to install additional vendors. 这时需要安装两个安装…

陈天奇:十年机器学习科研之路(附链接)

来源&#xff1a;深度学习自然语言处理链接&#xff1a;https://zhuanlan.zhihu.com/p/74249758导读十年前&#xff0c;MSRA的夏天&#xff0c;刚开始尝试机器学习研究的我面对科研巨大的不确定性&#xff0c;感到最多的是困惑和迷茫。十年之后&#xff0c;即将跨出下一步的时候…

QT示例:基于TCP 点对多Socket通讯(server,clients)

QT示例&#xff1a;基于TCP 点对多通讯&#xff08;server,clients&#xff09;一、服务器server二、客户端Client下载&#xff1a;基于TCP 点对多Socket通讯 一、服务器server 因为对于客户端来说&#xff0c;只能连接一个服务器。而对于服务器来说&#xff0c;它是面向多连…

MATLAB GUI的CreateFcn如何创建

看MATLAB关于GUI代码的时候发现有一些function _CreateFcn(hObject, eventdata, handles)函数&#xff0c;那么这类函数是如何创建出出来的呢&#xff1f; 首先在MATLAB中输入guide&#xff0c;打开其中一个GUI文件&#xff0c;现在随便打开一个我之前创建好的GUI&#xff1a;…

文小刚:量子革命是最不可思议的物理革命

来源&#xff1a;科学网人类生活在一个怎样的世界里&#xff1f;凝聚态理论物理学家、美国麻省理工学院终身教授、美国科学院院士文小刚的答案是&#xff1a;“我们生活在量子计算机里面。量子信息是真实的&#xff0c;而所看到的各种物质、人&#xff0c;都是量子信息的虚拟反…

QT+Halcon综合示例:clip回形针2D位姿检测

QTHalcon综合示例&#xff08;一&#xff09;&#xff1a;clip回形针2D位姿检测0、halcon源码&#xff1a;1、Qt代码&#xff1a;2、运行结果&#xff1a;下载&#xff1a;clip回形针2D位姿检测 0、halcon源码&#xff1a; * clip.hdev: Orientation of clips * dev_close_w…

MATLAB GUI如何创建Callback函数

本文以创建按钮的Callback函数为例介绍了在MATLAB如何在GUI中创建Callback函数 首先在MATLAB中输入guide&#xff0c;打开GUI文件&#xff0c;这里我随机打开一个我之前创建的GUI文件&#xff1a; 假设现在要创建start按钮的Callback函数&#xff0c;则双击该按钮&#xff0c;…

互联网50年:从信息高速公路到超级智能的进化

来源&#xff1a;战略前沿技术编者按&#xff1a;2019年&#xff0c;迎来互联网诞生50周年。本文根据中信出版社7月出版的《崛起的超级智能&#xff1a;互联网大脑如何影响科技未来》一书的内容和观点&#xff0c;重点阐述了互联网是如何在50年中发生重大变化&#xff0c;如何促…

MATLAB摄像头可以运行但是打不开视频

今天在学习一个MATLAB关于摄像头操作的代码&#xff0c;运行之后摄像头会一闪一闪&#xff0c;但是就是打不开视频的画面&#xff0c;查看了半天代码发现代码也没有错&#xff0c;最后尝试着将代码中的下面这句中的320x240改为640x480就可以打开视频了 vid videoinput(winvid…

大脑简史(2)-研究大脑的手段

来源&#xff1a;人机与认知实验室上篇文章笔者和大家分享了认知神经科学历史上的大事件&#xff0c;这些大事件有的极大程度的改变了人们的思维&#xff0c;有的直接推动了神经科学的发展&#xff0c;可以这么说&#xff0c;没有这些前人的努力&#xff0c;就没有我们现在取得…

stm32_DMA采集一个AD数据_并通过DMA向串口发送

这是以前学32的时候写的&#xff0c;那时候学了32之后感觉32真是太强大了&#xff0c;比51强的没影。关于dma网上有许多的资料&#xff0c;关于dma采集ad网上也有很多。亲们搜搜&#xff0c;这里只贴代码了&#xff0c;其实我也想详详细细地叙述一番&#xff0c;但是自己本身打…

QT综合示例:QT串口通信

QT综合示例&#xff1a;QT串口通信0、界面&#xff1a;1、代码&#xff1a;如果用qt写程序作为上位机&#xff0c;然后通过和usb和下位机通信的时候&#xff0c;就需要用到qt中的串口通信了。 0、界面&#xff1a; 1、代码&#xff1a; 1&#xff09;.pro 添加&#xff1a; …

MATLAB GUI如何制作下拉列表

MATLAB在GUI中可以实现下图所示的下拉列表&#xff1a; 方法&#xff1a; 在MATLAB中输入guide打开一个现有的GUI或者新建一个GUI放置一个弹出式菜单&#xff0c;如图所示双击新建的弹出式菜单&#xff0c;打开检查器&#xff0c;点击检查器的“string”菜单栏右侧的按钮&…

如果每个人都是一个粒子…… | 从物理学中寻找社会规律

来源&#xff1a;环球科学人类的许多社会行为似乎是难以捉摸的&#xff0c;包括经济、交通、个人选择。不少科学家尝试从物理的角度解释人类社会&#xff0c;他们将人比作粒子&#xff0c;每个个体之间的行为、选择都会互相影响。就像物理粒子会受到不同类型的力的控制&#xf…

猎豹MFC--文件对话框CFileDialog

如下叫做打开文件对话框&#xff1a;CFileDialog类在对话框上添加文本框&#xff0c;接收回车键设置&#xff0c;多行&#xff0c;编辑修改ID&#xff0c;垂直滚动条 水平滚动条 属性设置。添加菜单资源&#xff1a;这个菜单是给主窗口使用的&#xff0c;所以在主窗口对话框属…

MATLAB的GUI界面不显示XY坐标轴

在GUI中创建一个坐标轴&#xff0c;默认会显示XY坐标&#xff0c;如下图&#xff1a; 如何关闭XY坐标轴呢&#xff1f; 首先在打开GUI界面&#xff0c;双击该坐标轴&#xff0c;在Xcolor和Ycolor中选择白色&#xff0c;将坐标轴设置为白色&#xff1a; 然后在xticklabel和ytic…