本文主要参考:1.https://blog.csdn.net/yang843061497/article/details/38553765
2.https://eason.blog.csdn.net/article/details/51764971
3.https://blog.csdn.net/Chenyukuai6625/article/details/75123380
4.https://blog.csdn.net/hujingshuang/article/details/46910259
5.https://blog.csdn.net/Chenyukuai6625/article/details/75195935
6.https://www.cnblogs.com/ronny/p/3985810.html
特征描述子是图像的简化表示,仅包含图像的最重要信息。本博客将介绍几种常用的特征描述子,包括HOG、SIFT、SURF、ORB.一般认为:性能上SIFT>SURF>ORB,速度上完全相反。
目录
4.ORB(Oriented FAST and Rotated BRIEF)
4.ORB(Oriented FAST and Rotated BRIEF)
从它的名字中可以看出它是对FAST特征点与BREIF特征描述子的一种结合与改进,使用FAST来检测特征点,使用BRIEF来对特征点进行描述。FAST 没有方向,ORB增加了方向;BRIEF没有旋转不变性,ORB增加了旋转不变性。
4.1适用领域
ORB是除了SIFT与SURF外一个很好的选择,而且它有很高的效率,最重要的一点是它是免费的,SIFT与SURF都是有专利的,你如果在商业软件中使用,需要购买许可。
4.2 ORB特征提取和匹配过程
1.ORB特征提取
ORB采用FAST(features from accelerated segment test)算法来检测特征点。FAST核心思想就是拿一个点跟它周围的点比较,如果它和其中大部分的点都不一样就可以认为它是一个特征点。
FAST特征点检测的过程:
(1)在图像中任选一点p, 假定其像素(亮度)值为 Ip。
(2)以p点为中心,以3为半径画圆,圆上有16个像素,如下图所示(下图来源于链接3,便于理解放于此处,如有侵权,联系笔者删除):
(3)(4)(5)通过三轮的阈值筛选选定特征点,(6)又使用非极大值抑制对选中的特征点进行帅选。
具体方法如下:
(3)定义一个阈值。计算p1、p9与中心p的像素差,若它们绝对值都小于阈值,则p点不可能是特征点,直接丢弃;否则,当做候选点,进行下一步判断;
(4)若p是候选点,则计算p1、p5、p9、p13与中心p的像素差,若它们的绝对值有至少3个超过阈值,则当做候选点,进行下一步判断;否则,直接丢弃;
(5)若p是候选点,则计算p1到p16这16个点与中心p的像素差,若它们有至少9个超过阈值,则是特征点;否则,直接丢弃。
(6)对图像进行非极大值抑制:判断以特征点p为中心的一个邻域(如3x3或5x5)内是否有多个特征点,如果有多个特征点,则分别计算各个特征点的FAST得分值(即s值,为16个点与中心差值的绝对值总和),如果p是领域所有特征点中s值最大的,则保留这个特征点,否则丢弃掉。如果领域内只有一个特征点,则将这个特征点进行保留,不参与别的计算。
ORB对特征点指定方向:
指定方向的方法称为灰度质心法,灰度质心法假设角点的灰度与质心之间存在一个偏移,这个向量可以用于表示一个方向。
涉及到一个基本知识,矩的概念,先说一下矩:
1.矩是概率与统计中的一个概念,是随机变量的一种数字特征。设X为随机变量,c为常数,k为正整数。则量 ,也就是 称为X关于c点的k阶矩。比较重要的情况有两种:(1)c=0,这时称为X的k阶原点矩。
一阶原点矩:
(2)c=E(X),这时称为X的k阶中心距。一阶原点矩就是期望。一阶中心矩μ1=0,二阶中心矩μ2就是X的方差Var(X)。在统计学上,高于4阶的矩极少使用。μ3可以去衡量分布是否有偏。μ4可以去衡量分布(密度)在均值附近的陡峭程度如何。
2.针对于一幅图像,我们把像素的坐标看成是一个二维随机变量(X,Y),那么一幅灰度图像可以用二维灰度密度函数来表示,因此可以用矩来描述灰度图像的特征。
3.一幅M×N的数字图像f(i,j),其p+q阶几何矩和中心矩为:
其中f(i,j)为图像在坐标点(i,j)处的灰度值。
1=;j1=
若将看作是图像的灰度质量,则(i1,j1)为图像的质心坐标,那么中心矩反映的是图像灰度相对于其灰度质心的分布情况。带入下标可以计算出,,;代表了图像像素在x方向上的偏重,代表了图像像素在y方向上的偏重。
根据上边质心来生成旋转方向(即利用块中所有像素y方向上的差值之和与x方向上的差值之和的比值,可以理解成tan(theta) = delta y / delta x)):
如下图(该图来源于链接1,便于理解放于此处,如有侵权,联系笔者删除),下图中Q为质心:
2.ORB特征描述
ORB采用BRIEF算法来计算一个特征点的描述子。BRIEF算法的核心思想是在关键点P的周围以一定模式选取N个点对,把这N个点对的比较结果组合起来作为描述子。
BRIEF特征描述子:
(1)为减少噪声干扰,先对图像进行高斯滤波(方差为2,高斯窗口为9x9)。
(2)以特征点为中心,取SxS的邻域窗口。在窗口内随机选取一对(两个)点,比较二者像素的大小,进行如下二进制赋值。
其中,p(x),p(y)分别是随机点x=(u1,v1),y=(u2,v2)的像素值。
(3)在窗口中随机选取N对随机点,重复步骤2的二进制赋值,形成一个二进制编码,这个编码就是对特征点的描述,即特征描述子。(一般N=256)
关于一对随机点的选择方法,原作者测试了5种方法。具体可查阅链接4,5。
ORB对描述子添加旋转不变性:
因为BRIEF当我们选取点对的时候,是以当前关键点为原点,以水平方向为X轴,以垂直方向为Y轴建立坐标系。当图片发生旋转时,坐标系不变,同样的取点模式取出来的点却不一样,计算得到的描述子也不一样,这是不符合我们要求的。ORB在计算BRIEF描述子时建立的坐标系是以关键点为圆心,以关键点和取点区域的质心的连线为X轴。如下图(该图来源于链接1,便于理解放于此处,如有侵权,联系笔者删除):
这就解决了旋转一致性的问题。
3.ORB特征点匹配
ORB算法最大的特点就是计算速度快 。 这首先得益于使用FAST检测特征点,FAST的检测速度正如它的名字一样是出了名的快。再次是使用BRIEF算法计算描述子,该描述子特有的2进制串的表现形式不仅节约了存储空间,而且大大缩短了匹配的时间。
BRIEF中对特征点进行匹配,这时计算两特征点描述子的Hamming距离。判断是否匹配的依据:经过大量实验数据测试,不匹配特征点的描述子的Hamming距离在128左右,匹配点对描述子的Hamming距离则远小于128。注:Hamming距离:表示两个(相同长度)字对应位不同的数量。具体来说,就是对两个字符串进行异或运算,并统计结果为1的个数,那么这个数就是汉明距离。总的来说,BRIEF特征配对就是利用汉明距离来进行相关判断:(1)两个特征编码对应bit位上相同元素的个数小于128的,一定不是配对的。(2)一幅图上特征点与另一幅图上特征编码对应bit位上相同元素的个数最多的特征点配成一对。(3)设定阈值,当两个描述子的相似度大于阈值时,认为匹配成功。
4.3 opencv ORB描述子的调用及计算
在上面的讲解中,没有提到尺度不变性,但是在Opencv ORB 的实现中通过增加金字塔的方式来改善这方面的性能。
opencv2及opencv3都可以直接调用,调用方式有所不同。下面代码是opencv2中的;
代码测试:
#include "highgui/highgui.hpp"
#include "opencv2/nonfree/nonfree.hpp"
#include "opencv2/legacy/legacy.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
Mat image01 = imread("image1.jpg", 1);
Mat image02 = imread("image2.jpg", 1);
//灰度图转换
Mat image1, image2;
cvtColor(image01, image1, CV_RGB2GRAY);
cvtColor(image02, image2, CV_RGB2GRAY);
//提取特征点
OrbFeatureDetector orb_detector;
vector<KeyPoint> keyPoint1, keyPoint2;
//检测特征点
orb_detector.detect(image1, keyPoint1);
orb_detector.detect(image2, keyPoint2);
//特征点描述
OrbDescriptorExtractor orb_descriptor;
Mat imageDesc1, imageDesc2;
//分别计算特征点对应的描述子
orb_descriptor.compute(image1, keyPoint1, imageDesc1);
orb_descriptor.compute(image2, keyPoint2, imageDesc2);
BFMatcher matcher(NORM_HAMMING);
vector<DMatch> matches_all;
matcher.match(imageDesc1, imageDesc2, matches_all);
//按最小距离的两倍进行筛选
double max_dist = matches_all[0].distance, min_dist = matches_all[0].distance;
for (int i = 1; i<imageDesc1.rows; i++)
{
if (matches_all.at(i).distance > max_dist)
max_dist = matches_all[i].distance;
if (matches_all.at(i).distance < min_dist)
min_dist = matches_all[i].distance;
}
cout << "min_distance=" << min_dist << endl;
cout << "max_distance=" << max_dist << endl;
//匹配结果删选
vector<DMatch>good_matches_less_twomindis;
for (int i = 0; i<matches_all.size(); i++)
{
if (matches_all[i].distance < 2 * min_dist)
good_matches_less_twomindis.push_back(matches_all[i]);
}
Mat ORB_match_less_twomindis;
drawMatches(image01, keyPoint1, image02, keyPoint2, good_matches_less_twomindis, ORB_match_less_twomindis, Scalar(0, 255, 0), Scalar::all(-1));//匹配特征点绿色,单一特征点颜色随机
imshow("ORB_match_less_twomindis ", ORB_match_less_twomindis);
waitKey();
return 0;
}
运行结果:
文中若有不妥及错误之处,还望指出!