在OpenCV里使用ORB

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/caimouse/article/details/102676703

SIFT和SURF都是比较好的特征检测算法,但是你是否想每年都为这两个算法花一些钱去买它们的使用权呢?这两个算法都是受版本保护的,如果要使用必须付费购买。那么有没有不付费,也有与之相比美的算法呢?OpenCV的爱好者开发了一个新的免费算法来替代SIFT和SURF,这个算法就是ORB。

 

理论:

作为一个OpenCV粉丝,莫过于看到ORB算法的出处,居然是OpenCV Labs出品,这个算法在2011年由Ethan Rublee, Vincent Rabaud, Kurt Konolige and Gary R. Bradski发表在论文《ORB: An efficient alternative to SIFT or SURF》里。顾名思义,它在计算成本、匹配性能以及主要专利等方面是SIFT和SURF的一个很好的替代品。因为SIFT和SURF算法,你需要付钱才能使用它,但是ORB不用付费。

ORB算法整合了FAST关键点检测和BRIEF描述,同时在性能方面做了很多增强。首先它使用FAST去寻找关键点,接着使用Harris角方法找最优的N个点,然后用金字塔产生多尺度特征。但是FAST算法有一个问题,就是它不会计算角点的方向,所以怎么样才能加入旋转不变性呢?ORB开发人员接着下来作了如下修改。采用灰度质心法(Intensity Centriod)为每个特征点计算了主方向,这个向量方向是从角点位置指向这一块区域的质心方向。为了提高旋转不变性,用x和y计算矩,x和y应该在半径r的圆形区域内,其中r是区域的大小。

现在到修改ORB的描述符BRIEF了,从前面学习可以知道BRIEF没有旋转描述。把这种方法称为"Steer BRIEF"。对于任何一个特征点来说,它的BRIEF描述子是一个长度为n的二值码串,这个二值码串是由特征点邻域n个点对生成的,我们现在讲这2n个点(xi,yi),i=1,2,.....,2n组成一个矩阵S:

Calonder建议为每个块的旋转和投影集合分别计算BRIEF描述子,但代价昂贵。ORB中采用了一个更有效的方法:使用邻域方向θ和对应的旋转矩阵Rθ,构建S的一个校正版本Sθ:

而θ即我们为特征点求得的主方向。实际上,我们可以把角度离散化,即把360度分为12份,每一份是30度,然后我们对这个12个角度分别求得一个Sθ,这样我们就创建了一个查找表,对于每一个θ,我们只需要查表即可快速得到它的点的集合Sθ。

BRIEF令人惊喜的特性之一是:对于n维的二值串的每个特征位,所有特征点在该位上的值都满足一个均值接近于0.5,而方差很大的高斯分布。方差越大,说明区分性越强,那么不同特征点的描述子就表现出来越大差异性,对匹配来说不容易误配。但是当我们把BRIEF沿着特征点的方向调整为Steered BRIEF时,均值就漂移到一个更加分散式的模式。可以理解为有方向性的角点关键点对二值串则展现了一个更加均衡的表现。而且论文中提到经过PCA对各个特征向量进行分析,得知Steered BRIEF的方差很小,判别性小,各个成分之间相关性较大。

 

为了减少Steered BRIEF方差的亏损,并减少二进制码串之间的相关性,ORB使用了一种学习的方法来选择一个较小的点对集合。方法如下:

 

首先建立一个大约300k关键点的测试集,这些关键点来自于PASCAL2006集中的图像。进行贪婪搜索,从T中把排在第一的那个列放到R中,T中就没有这个点对的测试结果了,然后把T中的排在下一个的列与R中的所有元素比较,计算它们的相关性,如果相关超过了某一事先设定好的阈值,就扔了它,否则就把它方到R里面。重复上面的步骤,直到R中有256个列向量位置。如果把T全部找完也没有找到256个,那么我们可以把相关的阈值调高一些,再尝试一遍。这样,我们就得到了256个点对。上面这个过程我们称它为rBRIEF。

 

ORB中有很多参数可以设置,在OpenCV中它可以通过ORB来创建一个ORB检测器。

cv2.ORB_create([,nfeatues[,scaleFactor[,nlevels[,edgeThreshold[,firstLevel[,WTA_K[,[scoreType,[patchSize,fastThreshold]]]]]]]]])

参数说明:

 

nfeatures :最多提取的特征点的数量;

scaleFactor : 金字塔图像之间的尺度参数,类似于SIFT中的k;

nlevels: 高斯金字塔的层数;

edgeThreshold :边缘阈值,这个值主要是根据后面的patchSize来定的,靠近边缘edgeThreshold以内的像素是不检测特征点的。

firstLevel-:看过SIFT都知道,我们可以指定第一层的索引值,这里默认为0。

WET_K : 用于产生BIREF描述子的点对的个数,一般为2个,也可以设置为3个或4个,那么这时候描述子之间的距离计算就不能用汉明距离了,而是应该用一个变种。OpenCV中,如果设置WET_K = 2,则选用点对就只有2个点,匹配的时候距离参数选择NORM_HAMMING,如果WET_K设置为3或4,则BIREF描述子会选择3个或4个点,那么后面匹配的时候应该选择的距离参数为NORM_HAMMING2。

scoreType :用于对特征点进行排序的算法,你可以选择HARRIS_SCORE,也可以选择FAST_SCORE,但是它也只是比前者快一点点而已。

patchSize :用于计算BIREF描述子的特征点邻域大小。

 

演示例子:

#python 3.7.4,opencv4.1
#蔡军生 https://blog.csdn.net/caimouse/article/details/51749579
#
import numpy as np
import cv2
from matplotlib import pyplot as plt

#读取文件
img = cv2.imread('szcen1.png')

#初始化ORB检测器
orb = cv2.ORB_create()

#用ORB查找关键点
kp = orb.detect(img,None)

#用ORB计算关键点描述
kp, des = orb.compute(img, kp)

#显示关键点
img2 = cv2.drawKeypoints(img, kp, None, color=(0,255,0), flags=0)

#显示图片
cv2.imshow('img',img2)
           
cv2.waitKey(0)
cv2.destroyAllWindows()

结果输出如下:

https://blog.csdn.net/caimouse/article/details/51749579

猜你喜欢

转载自blog.csdn.net/caimouse/article/details/102676703