OpenCV-Python——第27章:SURF特征点提取算法 - Go语言中文社区

OpenCV-Python——第27章:SURF特征点提取算法


注意:

本章使用的是opencv-contrib-python的3.4.2.16版本,安装过程如下:

pip uninstall opencv-python

pip install opencv-contrib-python==3.4.2.16

目录

0 原理        1 OpenCV 中的 SURF        2 举例


0 原理

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

基本步骤:

  1. 构建Hessian矩阵构造高斯金字塔尺度空间 
  2. 利用非极大值抑制初步确定特征点 
  3. 精确定位极值点 
  4. 选取特征点的主方向
  5. 构造surf特征点描述算子

在SIFT中,Lowe在构建尺度空间时使用DoG对LoG进行近似。SURF使用盒子滤波器(box_filter)对 LoG 进行近似。下图显示了这种近似。在进 行卷积计算时可以利用积分图像(积分图像的一大特点是:计算图像中某个窗 口内所有像素和时,计算量的大小与窗口大小无关),是盒子滤波器的一大优点。而且这种计算可以在不同尺度空间同时进行。同样 SURF 算法计算关键点 的尺度和位置是也是依赖与 Hessian 矩阵行列式的。

为了保证特征矢量具有选装不变形,需要对于每一个特征点分配一个主要方向。需要以特征点为中心,以 6s(s 为特征点的尺度)为半径的圆形区域 内,对图像进行 Harr 小波相应运算。这样做实际就是对图像进行梯度运算, 但是利用积分图像,可以提高计算图像梯度的效率,为了求取主方向值,需要设计一个以方向为中心,张角为 60 度的扇形滑动窗口,以步长为 0.2 弧度 左右旋转这个滑动窗口,并对窗口内的图像 Haar 小波的响应值进行累加。主 方向为最大的 Haar 响应累加值对应的方向。在很多应用中根本就不需要旋转 不变性,所以没有必要确定它们的方向,如果不计算方向的话,又可以使算法 提速。SURF 提供了成为 U-SURF 的功能,它具有更快的速度,同时保持了 对 +/-15 度旋转的稳定性。OpenCV 对这两种模式同样支持,只需要对参数upright 进行设置,当 upright 为 0 时计算方向,为 1 时不计算方向,同时速度更快。

生成特征点的特征矢量需要计算图像的 Haar 小波响应。在一个矩形的区域内,以特征点为中心,沿主方向将 20s*20s 的图像划分成 4*4 个子块,每 个子块利用尺寸 2s 的 Haar 小波模版进行响应计算,然后对响应值进行统计, 组成向量 v = (
∑ dx, ∑ dy, ∑ |dx|, ∑ |dy|)。这个描述符的长度为 64。降低的维度可以加速计算和匹配,但又能提供更容易区分的特征。

为了增加特征点的独特性,SURF 还提供了一个加强版 128 维的特征描述符。当 dy 大于 0 和小于 0 时分别对 dx 和 |dx| 的和进行计算,计算 dy 和 |dy| 时也进行区分,这样获得特征就会加倍,但又不会增加计算的复杂度。 OpenCV 同样提供了这种功能,当参数 extended 设置为 1 时为 128 维,当 参数为 0 时为 64 维,默认情况为 128 维。

在检测特征点的过程中计算了 Hessian 矩阵的行列式,与此同时,计算得到了 Hessian 矩阵的迹,矩阵的迹为对角元素之和。

按照亮度的不同,可以将特征点分为两种,第一种为特征点迹其周围小邻域的亮度比背景区域要亮,Hessian 矩阵的迹为正;另外一种为特征点迹其周 围小邻域的亮度比背景区域要暗,Hessian 矩阵为负值。根据这个特性,首先 对两个特征点的 Hessian 的迹进行比较。如果同号,说明两个特征点具有相同 的对比度;如果异号的话,说明两个特征点的对比度不同,放弃特征点之间的 后续的相似性度量。

对于两个特征点描述子的相似性度量,我们采用欧式距离进行计算。

简单来说 SURF 算法采用了很多方法来对每一步进行优化从而提高速度。分析显示在结果效果相当的情况下 SURF 的速度是 SIFT 的 3 倍。SURF 善 于处理具有模糊和旋转的图像,但是不善于处理视角变化和关照变化。

与SIFT比较:

  SIFT SURF
尺度空间 DOG与不同尺度的图片卷积 不同尺度的box filters与原图片卷积
特征点检测 先进行非极大抑制,再去除低对比度 点。再通过Hessian矩阵去除边缘的点 先利用Hessian矩阵确定候选点,然 后进行非极大抑制
方向 在正方形区域内统计梯度的幅值的直方图,找max对应的方向。可以有多个方向。 在圆形区域内,计算各个扇形范围内 X、y方向的haar小波响应,找模最大的扇形方向
特征描述子 16x16的采样点划分为4x4的区域, 计算每个区域的采样点的梯度方向和 幅值,统计成8bin直方图,一共 4x4x8=128维 20x20s的区域划分为4x4的子区域, 每个子区域找5x5个采样点,计算采样 点的haar小波响应,记录Σdx, Σdy,Σ|dx|,Σ|dy|, —共 4x4x4=64

 

1 OpenCV 中的 SURF

与 SIFT 相同 OpenCV 也提供了 SURF 的相关函数。首先我们要初始化一个 SURF 对象,同时设置好可选参数:64/128 维描述符,Upright/ Normal 模式等。所有的细节都已经在文档中解释的很明白了。就像我们在 SIFT 中一样,我们可以使用函数 SURF.detect(),SURF.compute() 等 来进行关键点搀着和描述。

创建一个SURF对象:

cv2.xfeatures2d.SURF_create(, hessianThreshold, nOctaves, nOctaveLayers, extended, upright)

  • hessianThreshold:默认100关键点检测的阈值,越高监测的点越少
  • nOctaves:默认4,金字塔组数
  • nOctaveLayers:默认3,每组金子塔的层数
  • extended:默认False,扩展描述符标志,True表示使用扩展的128个元素描述符,False表示使用64个元素描述符。
  • upright:默认False,垂直向上或旋转的特征标志,True表示不计算特征的方向,False-计算方向。

之后也可以通过类似getHessianThreshold(),setHessianThreshold()等函数来获取或修改上述参数值,例如

surf.setHessianThreshold(True)表示将HessianThreshold参数修改为True。

绘制特征点:

cv2.drawKeypoint(image, keypoints, outImage, color, flags)

或:outImage = cv2.drawKeypoint(image, keypoints, None, color, flags)

  • image:输入图像
  • keypoints:上面获取的特征点
  • outImage:输出图像
  • color:颜色,默认为随机颜色
  • flags:绘制点的模式,有以下四种模式

cv2.DRAW_MATCHES_FLAGS_DEFAULT

默认值,只绘制特征点的坐标点,显示在图像上就是一个个小圆点,每个小圆点的圆心坐标都是特征点的坐标。

cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS

绘制特征点的时候绘制的是带有方向的圆,这种方法同时显示图像的坐标,size,和方向,是最能显示特征的一种绘制方式。

cv2.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG

只绘制特征点的坐标点,显示在图像上就是一个个小圆点,每个小圆点的圆心坐标都是特征点的坐标。

cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINT

 单点的特征点不被绘制 

2 举例

程序如下:

import numpy as np
import cv2
import matplotlib.pyplot as plt

img = cv2.imread('test32.jpg', 0)

surf = cv2.xfeatures2d.SURF_create(30000)

kp = surf.detect(img, None)

img2 = cv2.drawKeypoints(img, kp, None, (255, 0, 0), 4)

# 不检查关键点的方向
surf.setUpright(True)
# 修改阈值
surf.setHessianThreshold(40000)
kp = surf.detect(img, None)
img3 = cv2.drawKeypoints(img, kp, None, (255, 0, 0), 4)

plt.subplot(121), plt.imshow(img2),
plt.title('Dstination'), plt.axis('off')
plt.subplot(122), plt.imshow(img3),
plt.title('Dstination'), plt.axis('off')
plt.show()

结果如下:

 

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/yukinoai/article/details/88914269
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。
  • 发表于 2020-03-01 23:11:50
  • 阅读 ( 853 )
  • 分类:算法

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢