openCV:SIFT特征提取

2019-09-29  本文已影响0人  SwiftBirds

SIFT特征提取算法

定义

SIFT的全称是Scale Invariant Feature Transform,尺度不变特征变换。是在不同的尺度空间上查找关键点(特征点),并计算出关键点的方向。SIFT所查找到的关键点是一些十分突出、不会因光照、仿射变换和噪音等因素而变化的点,如角点、边缘点、暗区的亮点及亮区的暗点等。SIFT特征对旋转、尺度缩放、亮度变化等保持不变性,是一种非常稳定的局部特征。

步骤

  1. 构建DOG尺度空间
  2. 关键点搜索和定位
  3. 方向赋值和特征描述的生成

构建DOG尺度空间

模拟图像数据的多尺度特征,大尺度轮廓特征,小尺度细节特征。通过构建高斯金字塔(每一层用不同的参数σ做高斯模糊(加权)),保证图像在任何尺度都能有对应的特征点,即保证尺度不变性。

图像尺度空间

在一定的范围内,无论物体是大还是小,人眼都可以分辨出来,然而计算机要有相同的能力却很难,所以要让机器能够对物体在不同尺度下有一个统一的认知,就需要考虑图像在不同的尺度下都存在的特点。

尺度空间的获取通常使用高斯模糊来实现,不同σ的高斯函数决定了对图像的平滑程度,越大的σ值对应的图像越模糊。

sift_3.png sift_2.png

多分辨率金字塔

图像金字塔是同一图像在不同的分辨率下得到的一组结果,一个传统的金字塔中,每一层的图像是其上一层图像长、高的各一半。

多分辨率的图像金字塔虽然生成简单,但其本质是降采样,图像的局部特征则难以保持,也就是无法保持特征的尺度不变性。

通过图像的模糊程度来模拟人在距离物体由远到近时物体在视网膜上成像过程,距离物体越近其尺寸越大图像也越模糊,这就是高斯尺度空间。通过结合高斯尺度空间和多分辨率金字塔可以检测出在不同的尺度下都存在的特征点。

sift_4.png

高斯差分金字塔(DOG)

将相邻的两个高斯空间的图像相减就得到了DoG的响应图像。

sift_5.png sift_6.png

关键点搜索和定位

关键点搜索

为了寻找尺度空间的极值点,每个像素点要和其图像域(同一尺度空间)和尺度域(相邻的尺度空间)的所有相邻点进行比较,当其大于(或者小于)所有相邻点时,该点就是极值点。如下图所示,中间的检测点要和其所在图像的3×3邻域8个像素点,以及其相邻的上下两层的3×3领域18个像素点,共26个像素点进行比较。

sift_7.png

关键点的精确定位

这些候选关键点是DOG空间的局部极值点,而且这些极值点均为离散的点,精确定位极值点的一种方法是,对尺度空间DoG函数进行曲线拟合,计算其极值点,从而实现关键点的精确定位。

sift_8.png sift_9.png

消除边界响应

sift_10.png

方向赋值

特征点的主方向

每个特征点可以得到三个信息(x,y,σ,θ),即位置、尺度和方向。具有多个方向的关键点可以被复制成多份,然后将方向值分别赋给复制后的特征点,一个特征点就产生了多个坐标、尺度相等,但是方向不同的特征点。

sift_11.png

生成特征描述

在完成关键点的梯度计算后,使用直方图统计邻域内像素的梯度和方向。

sift_12.png

为了保证特征矢量的旋转不变性,要以特征点为中心,在附近邻域内将坐标轴旋转θ角度,即将坐标轴旋转为特征点的主方向。

sift_14.png

旋转之后的主方向为中心取8x8的窗口,求每个像素的梯度幅值和方向,箭头方向代表梯度方向,长度代表梯度幅值,然后利用高斯窗口对其进行加权运算,最后在每个4x4的小块上绘制8个方向的梯度直方图,计算每个梯度方向的累加值,即可形成一个种子点,即每个特征的由4个种子点组成,每个种子点有8个方向的向量信息。

sift_16.png

论文中建议对每个关键点使用4x4共16个种子点来描述,这样一个关键点就会产生128维的SIFT特征向量。

sift_17.png
import cv2
import numpy as np

img = cv2.imread('test_1.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 得到特征点
sift = cv2.xfeatures2d.SIFT_create()
kp = sift.detect(gray, None)

img = cv2.drawKeypoints(gray, kp, img)

cv2.imshow('drawKeypoints', img)
cv2.waitKey(0)
cv2.destroyAllWindows()
得到特征点.PNG
# 计算特征
kp, des = sift.compute(gray, kp)
print (np.array(kp).shape)
(6807,)
des.shape
(6807, 128)
des[0]
array([  0.,   0.,   0.,   0.,   0.,   0.,   0.,   0.,  21.,   8.,   0.,
         0.,   0.,   0.,   0.,   0., 157.,  31.,   3.,   1.,   0.,   0.,
         2.,  63.,  75.,   7.,  20.,  35.,  32.,  74.,  23.,  66.,   0.,
         0.,   1.,   3.,   4.,   1.,   0.,   0.,  76.,  15.,  13.,  27.,
         8.,   1.,   0.,   2., 157., 112.,  50.,  31.,   2.,   0.,   0.,
         9.,  49.,  42., 157., 157.,  12.,   4.,   1.,   5.,   1.,  13.,
         7.,  12.,  41.,   5.,   0.,   0., 104.,   8.,   5.,  19.,  53.,
         5.,   1.,  21., 157.,  55.,  35.,  90.,  22.,   0.,   0.,  17.,
         3.,   6.,  69., 157.,  52.,   0.,   0.,   0.,   7.,  33.,  10.,
        10.,  11.,   0.,   1.,   6.,  44.,   9.,   3.,   7.,  19.,   5.,
        14.,  26.,  38.,  28.,  32.,  92.,  16.,   2.,   3.,   4.,   0.,
         0.,   7.,  92.,  23.,   0.,   0.,   0.], dtype=float32)
上一篇下一篇

猜你喜欢

热点阅读