【OpenCV】第二十三章: 图像特征检测之SURF、FAST、BRIEF、OBR算法

第二十三章: 图像特征检测之SURF、FAST、BRIEF、OBR算法

本章是二十二章的延续,继续讲图像特征的提取,主要讲SURF、FAST、BRIEF、OBR四种算法提取特征,然后在第二十四章讲用这些特征点去做特征匹配,并给出一个图像查找的小案例,给大家呈现一套完整的特征提取、特征匹配、图像查找的全流程。

  • 图像特征点有哪些应用场景?比如:
    1、图像搜索,以图搜图,很多搜索引擎都有以图搜图的功能。如果我们用一整张图去搜索,那运算量就非常大,一张图像小则几K,多则几兆,一一对比每个像素点,计算量非常大,我们通常的做法是把图片的特征点提取出来,然后再做匹配。比如谷歌的做法就是,谷歌数据库里的大量图片,它都是先提取这些图片的特征点,提取出的特征点存储到数据库中,当用户以图搜图的时候,谷歌先对用户提交的图像进行特征点提取,提取后再和它数据库里的图片的特征点进行匹配搜索,返回匹配值最大的图片。这样以图搜图就块得很多了。
    2、图像拼接,将两张有关联的图片拼接到一起。因为镜头的范围比人眼看到的范围要小,我们可以用摄像机连续拍多个角度范围的图片,然后这些图片之间是有重复的景象,我们将重复的景象的特征点提取出来,按照特征点拼接到一起,这样就可以得到一个全景照片,这个全景照片甚至可以超过人眼的范围。
    3、模板匹配,模板匹配的应用场景就非常多了。
    。。。。。
    总之,图像的特征点是非常有用的,是一张图像的表示和标识,所以,提取一些好的、稳定的、有代表性的特征点非常重要。二十二章讲的SIFT检测,实在是繁琐至极,所以本章只讲api。

1、SURF特征检测
SURF,全称是Speeded-Up Robust Features,加速的鲁棒性特征点检测。
SIFT最大的优点就是特征点检测的非常准确,并且描述子也描述得非常详细,但是缺点是速度慢。如果我们想对一个视频(就是一系列图片)进行特征检测,并获得它的描述子的话,SIFT会慢到无法忍受,因此才出现了SURF,SURF诞生的目的就是加速SIFT的处理速度,所以SURF提取图像的特征点和描述子稍逊于SIFT,但是优点是速度快,但也只是相对于SIFT快,也没有快到可以实时检测视频的效果。

  • API:cv2.xfeatures2d.SURF_create()
    这个类在cv2.xfeatures2d下面,这个类也有版权问题,所以也放在opencv的扩展库中。有版权问题或者还处于实验阶段的算法,opencv都把它们放在扩展包中。
    (1)实例化一个SURF类:surf = cv2.xfeatures2d.SURF_create()
    (2)进行检测,获取关键点和描述子:kp, des = surf.detectAndCompute(img, mask)
    (3)绘制kp:cv2.drawKeypoints(gray, kp, img)
#例23.1 调用SURF算法检测图像的特征点  
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread(r'C:\Users\25584\Desktop\building.jpg')  #原图  (600, 868, 3)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)    #转灰度图   (600, 868)

surf = cv2.xfeatures2d.SURF_create()    #创建surf对象
kp, des = surf.detectAndCompute(img_gray, None)        #进行检测

img1 = img.copy()                       #绘制keypoint
cv2.drawKeypoints(img_gray, kp, img1)
print(des)  

#---------------可视化----------------------------------
plt.figure(figsize=(10,8), dpi=100)
ret = np.hstack((img[:,:,::-1], img1[:,:,::-1]))
plt.imshow(ret), plt.title('SIFT detect'), plt.xticks([]), plt.yticks([])
plt.show()

 

说明:SURF和SIFT检测结果还是有区别的:SURF检测的点比SIFT要密集,要多,所以有些点其实很近,是重复的点,可以或略掉,不然会能加匹配操作中的计算量;此外SRUF在平坦区域检测的点比SIFT要少。

2、FAST特征点检测

继SIFT和SURF后,大家在特征点检测的速度上又进行了很多的改进尝试,但速度的提升效果都不是非常明显,直到FAST算法诞生,特征点检测的速度才有了一个质的飞跃。FAST是可以做到特征点的实时检测,但FAST不计算描述子,只检测特征点。
FAST,全称Feature from accelerated segment test, 是Edward Rosten和Tom Drummond在2006年提出的,并在2010年对其进行了修正。FAST算法检测的是角点,而且检测原理和harris不同,FAST算法的原理是:提取图像中的点,判断以该点为圆心的周围邻域内像素点和该点有多不同,来判断该点是否是角点。或者说,若一个像素周围有一定数量的像素与该点像素值不同,则认为其为角点。

  • FAST算法的基本流程
    1、在图像中选取一个像素点p,来判断它是不是关键点。Ip表示像素点p的灰度值。
    2、以r为半径画圆,覆盖p点周围的M个像素,通常情况下,设置r=3,则M=16,如下图所示:

    3、设置一个阈值t,如果在这16个像素点中存在n个连续像素点的灰度值都高于Ip+t,或者低于Ip-t,那么像素点p就被认为是一个角点。如上图中的虚线所示,n一般取值为12。
    4、由于在检测特征点时是需要对图像中所有的像素点进行检测,然而图像中的绝大多数点都不是特征点,如果对每个像素点都进行上述的检测过程,那显然是种浪费,所以FAST采用一种进行非特征点判别的方法:首先对候选点的周围90度的点(1,9,5,13)四个点进行测试,而且是先测试1和9,如果它们两个符合阈值要求再测试5和13。如果p是角点,那么这四个点中至少有3个要符合阈值要求,否则直接剔除,然后对保留下来的点再继续进行测试,测试是否有12个点符合阈值要求。

  • FAST检测器的缺点:
    1、获取的获选点比较多
    2、特征点的选取不是最优的,因为它的效果取决于要解决的问题和角点的分布情况。
    3、进行非特征点判别时大量的点被丢弃。
    4、检测到的很多特征点都是相邻的。
    前3个问题可以通过机器学习的方法解决,最后一个问题可以通过使用非极大值抑制的方法解决。

  • 机器学习的角点检测器
    1、选择一组训练图片,最好是跟最后应用相关的图片
    2、使用FAST算法找到每幅图像的特征点,对图像中的每一个特征点,将其周围的16个像素存储构成一个向量P。

    3、每一个特征点的16像素点都属于下列三类中的一种

    4、根据这些像素点的分类,特征向量p也被分为3个子集:Pd,Ps,Pb
    5、定义一个新的布尔变量Kp,如果P是角点就设置为True,如果不是就设置为False.
    6、利用特征值向量p,目标值是𝐾𝑝��,训练ID3树,训练完毕就是我们的机器学习角点分类器。
  • 非极大值抑制
    在筛选出来的候选角点中有很多是紧挨在一起的,需要通过非极大值抑制来消除这种影响。
    为所有的候选角点都确定一个打分函数V,V的值可以这样计算:先分别计算Ip与圆上16个点的像素值差值,取绝对值,再将这16个绝对值相加,就得到了V的值:

    最后比较毗邻候选角点的V值,把V值较小的候选角点pass掉。

FAST算法的思想与我们对角点的直观认识非常接近,化繁为简。FAST算法比其他角点检测算法要快得多,但在噪声较高时不够稳定,这需要设置合适的阈值。

  • API:
    1、实例化一个fast类:fast = cv2.FastFeatureDetector_create(threshold, nonmaxSuppression)
    threshold:阈值t,默认值是10
    nonmaxSuppression:是否进行非极大值抑制,默认是True,进行抑制
    2、检测关键点:kp = fast.detect(Img, None)
    Img:进行关键点检测的图像,这里可以是灰度图像也可以是原图
    kp:关键点信息,包括位置、方向、尺度信息。
    3、绘制kp:cv2.drawKeypoints(img, kp, outputimage, color, flags)

说明:opencv中的FAST算法并没有加入机器学习分类器。

#例23.2 调用FAST算法检测图像的特征点  
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread(r'C:\Users\25584\Desktop\building.jpg')  #原图  (600, 868, 3),不用转灰度图就可以

fast1 = cv2.FastFeatureDetector_create(threshold=30)    #创建fast对象,进行极大值抑制
kp1 = fast1.detect(img, None)        #进行检测
img1 = img.copy()                       #绘制keypoint
img1 = cv2.drawKeypoints(img1, kp1, None, color=(0,0,255))

fast2 = cv2.FastFeatureDetector_create(threshold=30, nonmaxSuppression=False)    #不进行极大值抑制
kp2 = fast2.detect(img, None)        #进行检测
img2 = img.copy()                       #绘制keypoint
img2 = cv2.drawKeypoints(img2, kp2, None, color=(0,0,255))

#---------------可视化-------------------
plt.figure(figsize=(10,8), dpi=100)
ret = np.hstack((img[:,:,::-1], img1[:,:,::-1], img2[:,:,::-1]))
plt.imshow(ret), plt.title('FAST detect'), plt.xticks([]), plt.yticks([])
plt.show()

3、BRIEF特征描述

BRIEF,Binary Robust Independent Elementary Features。
BRIEF算法是对已检测到的特征点进行描述,仅仅是生成特征描述子,所以还需要配合特征点检测算法一起使用,如FAST算法、Harris算法等。原始文献推荐使用CenSurE特征检测器,这种算法很快。而且BRIEF算法对CenSurE关键点的描述效果要比SURF关键点的描述更好。

BRIEF算法加快了特征描述符建立的速度,所以也极大的降低了特征匹配的时间。或者说,BRIEF是一种对特征点描述符计算和匹配的快速方法。这种算法可以实现很高的识别率,除非出现平面内的大旋转。

优点:BRIEF抛弃了传统的用梯度直方图描述区域的方法,改用检测随机响应,大大加快了描述子建立速度;生成的二进制描述子便于高速匹配(计算汉明距离只需通过异或操作加上统计二进制编码中“1”的个数的操作,这些通过底层的运算即可实现),且便于在硬件上实现。
缺点:不具备旋转不变性,不具备尺度不变性,容易受噪声影响。

  • API:
    1、创建CenSurE特征检测器(在OpenCV中称为STAR检测器):
    star = cv2.xfeatures2d.StarDetector_create(maxSize, responseThreshold, lineThresholdProjected, lineThresholdBinarized, suppressNonmaxSize)
    maxSize:最大尺寸,默认45
    responseThreshold:响应阈值,默认30
    lineThresholdProjected:线性投影阈值,默认10
    lineThresholdBinarized:线性二值化阈值,默认8
    suppressNonmaxSize:非极大抑制参数,默认5

2、创建BRIEF描述符: brief = cv2.xfeatures2d.BriefDescriptorExtractor_create(bytes, use_orientation)
bytes:描述符中n{{d}}的值,用字节表示可取16, 32 (default) or 64,代表n{{d}}的值为 128,256,512
use_orientation:使用特征点方向的示例模式,默认情况下禁用。

3、计算在图像中检测到的一组特征点的描述符:
kp, des = brief.compute(img, kp)
image:输入图像
kp:输入特征点集合。无法计算描述符的特征点将被删除。有时可以添加新的特征点,例如:SIFT具有多个主导方向的重复特征点(对于每个方向)。
des:输出计算后的描述符,是一个矩阵。

#例23.3 调用BRIEF算法计算特征点描述符    
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread(r'C:\Users\25584\Desktop\building.jpg')  #原图  (600, 868, 3),不用转灰度图就可以
star = cv2.xfeatures2d.StarDetector_create()  #全部使用默认值  
brief = cv2.xfeatures2d.BriefDescriptorExtractor_create() #全部使用默认值  
kp = star.detect(img, None)   #通过star检测器检测特征点
kp, des = brief.compute(img, kp)  #通过BRIEF计算描述子
print(brief.descriptorSize())  
print(des.shape)  

img1 = img.copy()
img1 = cv2.drawKeypoints(img1, kp, None, color=(0, 0, 255), flags=cv2.DRAW_MATCHES_FLAGS_DEFAULT) 
img2 = img.copy()
img2 = cv2.drawKeypoints(img2, kp, None, color=(0, 0, 255), flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) 

#---------------可视化-------------------
fig, axes = plt.subplots(1,3, figsize=(16,8), dpi=100)
axes[0].imshow(img[:,:,::-1]), axes[0].xaxis.set_ticks([]), axes[0].yaxis.set_ticks([])  #原图
axes[1].imshow(img1[:,:,::-1]), axes[1].xaxis.set_ticks([]), axes[1].yaxis.set_ticks([])
axes[2].imshow(img2[:,:,::-1]), axes[2].xaxis.set_ticks([]), axes[2].yaxis.set_ticks([]) 
plt.show()
32
(872, 32)

BRIEF虽然免费,但由于其本身并不具有特征检测的功能,并且BRIEF的描述符在旋转的图像下表现很差劲,所以下面我们介绍更加强大的同时速度更快的算法ORB。

4、ORB特征检测
ORB, Oriented FAST and Rotated BRIEF
ORB = Oriented FAST + Rotated BRIEF
FAST检测只检测特征点不计算描述子,所以特征点也不带方向,Oriented FAST是在FAST的基础上加上了特征点的方向。
BRIEF特征描述的缺点是对图像旋转处理得不太好,改进后的Rotated BRIEF对旋转具有鲁棒性。
ORB是对FAST和BRIEF进行改进后再结合到一起的技术。

ORB最大的优势是可以做到实时检测,它将FAST和BRIEF两种技术融合到一起,才真正将速度大大提升,做到实时检测。它从两方面进行改进,一方面从特征点检测上进行改进,也就是改进FAST算法,另一方面从描述子计算上进行改进,也就是改进BRIEF算法,将两种改进算法结合到一起才形成ORB,才真正做到了实时检测。
ORB能做到实时性,主要就是对数据量进行了缩减。找特征点的时候,区域的划分时,抛弃一些没有必要的点;计算描述子的时候也是抛弃了大量的数据。所以缩减了的特征点和描述子肯定不如全部检测的SIFT和SURF效果好。这是ORB的缺点。所以在大规模的图像特征点检测场景下,ORB就显示出其优势了,如果只有几张图,我们追求检测的准确性,就最好用SIFT了。

ORB整个算法是放在opencv的主库中,都是开源的,免费的,我们使用的时候不会牵扯到版权问题。

  • API:cv2.ORB_create()
    (1)实例化一个ORB对象:orb = cv2.ORB_create()
    (2)调用detectAndCompute方法来进行特征点的检测和描述子的计算:kp, des = orb.detectAndCompute(img, mask),参数img是灰度化的图像,参数mask=None是对整张图进行检测
    (3)绘制kp:cv2.drawKeypoints(gray, kp, img),sift算法中对这个函数的参数有详细介绍。
#例23.3 调用ORB算法检测图像的特征点  
import cv2
import numpy as np
import matplotlib.pyplot as plt

img = cv2.imread(r'C:\Users\25584\Desktop\building.jpg')  #原图  (600, 868, 3)

orb = cv2.ORB_create()    #创建orb对象
kp, des = orb.detectAndCompute(img, None)        #进行检测

img1 = img.copy()                       #绘制keypoint
img1 = cv2.drawKeypoints(img1, kp, None, color=(0, 0, 255)) 
img2 = img.copy() 
img2 = cv2.drawKeypoints(img2, kp, None, color=(0, 0, 255), flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) 
print(len(kp))  

#---------------可视化----------------------------------
plt.figure(figsize=(14,4), dpi=100)
ret = np.hstack((img[:,:,::-1], img1[:,:,::-1], img2[:,:,::-1]))
plt.imshow(ret), plt.title('ORB detect'), plt.xticks([]), plt.yticks([])
plt.show()
500

说明:len(kp),len(des),都返回:500,就是只找到了500个特征点,计算了500个描述子,这还不然SIFT的零头多呢。
des[0].shape返回(32,),说明描述子是一个长32的向量,SIFT描述子是128。
从结果上看,检测到的这些特征点基本都在角点区域,而且这些特征点都是集中在一起。
所以ORB提取的特征点是非常少的,那它在匹配的时候计算量就会非常少,速度就会快了。
由此可见,在特征点检测和描述子计算的时候,真正影响速度的就是数据量,要想速度实时性提升上来,就必须减少数据量,将大部分用处不大的数据都抛弃掉。

小结:SIFT是准确率最高的特征检测算法,但速度最慢。
SURF速度比SIFT快,但准确率要比SIFT差一些。
ORB最大的特点就是可以达到实时性的检测要求,相对SIFT和SURF速度要快得多得多。但最大缺点是特征点检测的准确性没有SIFT和SURF好。

  • 11
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值