opencv图像特征之尺寸不变特性+算法对比总结

1.引入SIFT

在前面我们学习了一些角点检测技术,比如Harris 等。它们具有旋转不变特性,即使图片发生了旋转,我们也能找到同样的角点。很明显即使图像发生旋转之后角点还是角点。那如果我们对图像进行缩放呢?角点可能就不再是角点了。以下图为例,在一副小图中使用一个小的窗口可以检测到一个角点,但是如果图像被放大,再使用同样的窗口就检测不到角点了。
在这里插入图片描述
所以在2004 年,D.Lowe 提出了一个新的算法:尺度不变特征变换(SIFT),这个算法可以帮助我们提取图像中的关键点并计算它们的描述符。

2.opencv中的SIFT

代码速记:

  • cv2.xfeatures2d.SIFT_create()
  • sift.detect()
  • sift.compute()
  • sift.detectAndCompute()
  • cv2.drawKeypoints()

实战:

def sift(self):
	#【1】读取图像,转为灰度图像
    img=self.img
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
   	#【2】创建sift对象,检测关键点,计算描述符
    sift = cv2.xfeatures2d.SIFT_create()
    
    #方法一:分别计算
    kp = sift.detect(gray, None)#在图像中找到关键点。
    #如果想在图像中的一个区域搜索的话,可以创建一个掩模图像作为参数使用。
    #返回的关键点是一个带有很多不同属性的特殊结构体,这些属性中包含它的坐标(x,y),有意义的邻域大小,确定其方向的角度等。
    kp, des = sift.compute(gray, kp)
    
    #方法二:一步到位
    kp, des = sift.detectAndCompute(gray, None)#kp 是一个关键点列表。des 是一个Numpy 数组,其大小是关键点数目乘以128。
    
    #【3】绘制关键点
    img = cv2.drawKeypoints(gray, kp, img)#在关键点的部位绘制一个小圆圈
    #img=cv2.drawKeypoints(gray,kp,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
    #绘制代表关键点大小的圆圈甚至可以绘制除关键点的方向
    
    #展示结果
    plt.subplot(121), plt.imshow(gray,'gray'), plt.title('raw'), plt.xticks([]), plt.yticks([])
    plt.subplot(122), plt.imshow(img,'gray'), plt.title('keypoints'), plt.xticks([]), plt.yticks([])
    plt.show()

在这里插入图片描述

3.引入SURF

SIFT 算法可以进行关键点检测和描述。但是这种算法的执行速度比较慢,人们需要速度更快的算法。在2006 年Bay,H.,Tuytelaars,T. 和Van Gool,L 共同提出了SURF(加速稳健特征)算法。跟它的名字一样,这是个算法是加速版的SIFT。

4.opencv中的SURF

代码速记:

  • cv2.xfeatures2d.SURF_create()
  • surf.detectAndCompute()
  • surf.getHessianThreshold()
  • surf.setHessianThreshold()
  • cv2.drawKeypoints()

实战:

def surf(self):
    img = cv2.imread('../images/white_point.jpg',0)#读入灰度图像
    surf = cv2.xfeatures2d.SURF_create(400)#创建surf对象
    print(surf.getHessianThreshold())
    #【1】当HessianThreshold为400时
    kp, des = surf.detectAndCompute(img, None)
    img2 = cv2.drawKeypoints(img, kp, None, (255, 0, 0), 4)
    print(len(kp))#285个关键点
    #【2】增大HessianThreshold
    surf.setHessianThreshold(20000)
    kp, des = surf.detectAndCompute(img, None)
    img3 = cv2.drawKeypoints(img, kp, None, (255, 0, 0), 4)
    print(len(kp))#151
    #【3】u-surf:所有的关键点的朝向都是一致的。它比前面的快很多
    print(surf.getUpright())#Check upright flag, if it False, set it to True
    surf.setUpright(True)
    kp = surf.detect(img, None)
    img4 = cv2.drawKeypoints(img, kp, None, (255, 0, 0), 4)
    #【4】改描述符64维为128维
    print(surf.descriptorSize())#64
    print(surf.getExtended())#如果结果是64维,就代表这个bool值为false
    surf.setExtended(True)
    kp, des = surf.detectAndCompute(img, None)
    print(surf.descriptorSize())
    #展示结果
    plt.subplot(221), plt.imshow(img,'gray'), plt.title('raw'), plt.xticks([]), plt.yticks([])
    plt.subplot(222), plt.imshow(img2,'gray'), plt.title('keypoints1'), plt.xticks([]), plt.yticks([])
    plt.subplot(223), plt.imshow(img3, 'gray'), plt.title('keypoints2'), plt.xticks([]), plt.yticks([])
    plt.subplot(224), plt.imshow(img4, 'gray'), plt.title('keypoints3'), plt.xticks([]), plt.yticks([])
    plt.show()

在这里插入图片描述

5.引入FAST算法

我们前面学习了几个特征检测器,它们大多数效果都很好。但是从实时处理的角度来看,这些算法都不够快。一个最好例子就是SLAM(同步定位与地
图构建),移动机器人,它们的计算资源非常有限。为了解决这个问题,Edward_Rosten 和Tom_Drummond 在2006 年提出里FAST 算法。

6.opencv中的FAST算法

代码速记:

  • cv2.FastFeatureDetector_create()
  • fast.detect()
  • cv2.drawKeypoints()
  • fast.setNonmaxSuppression(0)

实战:

def fast(self):
    img = cv2.imread('../images/blox.jpg', 0)
    #【1】用默认值初始化fast对象
    fast = cv2.FastFeatureDetector_create()
    #【2】检测并绘制关键点
    kp = fast.detect(img, None)
    img2 = cv2.drawKeypoints(img, kp, None, color=(255, 0, 0))
    #【3】打印所有默认参数
    print("Threshold: ", fast.getThreshold())
    print("nonmaxSuppression: ", fast.getNonmaxSuppression())
    print("neighborhood: ", fast.getType())
    print("Total Keypoints with nonmaxSuppression: ", len(kp))
    #【4】不使用非最大值抑制
    #使用极大值抑制的方法可以解决检测到的特征点相连的问题
    fast.setNonmaxSuppression(0)
    kp = fast.detect(img, None)
    print("Total Keypoints without nonmaxSuppression: ", len(kp))
    img3 = cv2.drawKeypoints(img, kp, None, color=(255, 0, 0))
    #展示结果
    plt.subplot(131), plt.imshow(img, 'gray'), plt.title('raw'), plt.xticks([]), plt.yticks([])
    plt.subplot(132), plt.imshow(img3,'gray'), plt.title('more'), plt.xticks([]), plt.yticks([])
    plt.subplot(133), plt.imshow(img2,'gray'), plt.title('less'), plt.xticks([]), plt.yticks([])
    plt.show()

在这里插入图片描述

Threshold: 10
nonmaxSuppression: True
neighborhood: 2
Total Keypoints with nonmaxSuppression: 431
Total Keypoints without nonmaxSuppression: 1575

7.引入BRIEF

  • 我们知道SIFT 算法使用的是128 维的描述符。由于它是使用的浮点数,所以要使用512 个字节。同样SURF 算法最少使用256 个字节(64 为维描述符)。创建一个包含上千个特征的向量需要消耗大量的内存,在嵌入式等资源有限的设备上这样是合适的。匹配时还会消耗更多的内存和时间。
  • 但是在实际的匹配过程中如此多的维度是没有必要的。我们可以使用PCA,LDA 等方法来进行降维。甚至可以使用LSH(局部敏感哈希)将SIFT 浮点数的描述符转换成二进制字符串。对这些字符串再使用汉明距离进行匹配。汉明距离的计算只需要进行XOR 位运算以及位计数,这种计算很适合在现代的CPU 上进行。但我们还是要先找到描述符才能使用哈希,这不能解决最初的内存消耗问题。
  • BRIEF 应运而生。它不去计算描述符而是直接找到一个二进制字符串。BRIEF 是一种特征描述符,它不提供查找特征的方法。所以我们不得不使用其他特征检测器,比如SIFT 和SURF 等。原始文献推荐使用CenSurE 特征检测器,这种算法很快。而且BRIEF 算法对CenSurE关键点的描述效果要比SURF 关键点的描述更好。
  • 简单来说BRIEF 是一种对特征点描述符计算和匹配的快速方法。这种算法可以实现很高的识别率,除非出现平面内的大旋转。

8.opencv中的BRIEF

代码速记:

  • cv2.xfeatures2d.StarDetector_create()
  • cv2.xfeatures2d.BriefDescriptorExtractor_create()
  • star.detect()
  • brief.compute()

实战:
下面的代码使用了CenSurE 特征检测器和BRIEF 描述符。(在OpenCV中CenSurE 检测器被叫做STAR 检测器)。

def brief(self):
    img = cv2.imread('../data/blox.jpg', 0)
    #【1】初始化FAST检测器
    star = cv2.xfeatures2d.StarDetector_create()
    #【2】初始化BRIEF提取器
    brief = cv2.xfeatures2d.BriefDescriptorExtractor_create()
    #【3】用star找到关键点
    kp = star.detect(img, None)
    #【4】用BRIEF计算描述符
    kp, des = brief.compute(img, kp)
    #函数brief:getInt(′bytes′) 会以字节格式给出nd 的大小,默认值为32。
    print("brief.descriptorSize: ",brief.descriptorSize())

brief.descriptorSize: 32

9.引入ORB算法

  • 计算开支,匹配效率以及更主要的是专利问题方面ORB 算法是是SIFT 和SURF 算法的一个很好的替代品。SIFT 和SURF 算法是有专利保护的,如果你要使用它们,就可能要花钱。但是ORB 不需要。
  • ORB 基本是FAST 关键点检测和BRIEF 关键点描述器的结合体,并通过很多修改增强了性能。

10.opencv中的ORB算法

代码速记:

  • cv2.ORB_create()
  • orb.detect()
  • orb.compute()
  • cv2.drawKeypoints()

实战:

def orb(self):
    img = cv2.imread('../images/blox.jpg', 0)
    #【1】初始化ORB 特征检测器
    orb = cv2.ORB_create()
    #【2】用ORB找到关键点
    kp = orb.detect(img, None)
    #【3】用ORB计算描述符
    kp, des = orb.compute(img, kp)
    #【4】只画出关键点位置。不考虑大小、方向。
    img2 = cv2.drawKeypoints(img, kp, None, color=(0, 255, 0), flags=0)
    #展示结果
    plt.subplot(121), plt.imshow(img, 'gray'), plt.title('raw'), plt.xticks([]), plt.yticks([])
    plt.subplot(122), plt.imshow(img2,'gray'), plt.title('ret'), plt.xticks([]), plt.yticks([])
    plt.show()

在这里插入图片描述

11.特征检测+特征描述算法总结

算法 特征检测 计算描述符 特点
Harris × 旋转不变
Shi-Tomasi × 对Harris的修改,更适合跟踪
SubPix √× × 需要以Harris角点为基础。精度更高,适用几何测量
ChessboardCorners × 找到棋盘角点。找全的话会有连线。适用摄像机标定。
SIFT 尺度不变
SURF 比SIFT更快
FAST × 检测关键点更快,适用实时处理。
BRIEF × 描述符数据更小。
ORB 不要钱。FAST和BRIEF结合。
发布了195 篇原创文章 · 获赞 59 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/qq_36622009/article/details/104922686