今天回顾一下SIFT关键点。
一、SIFT算子
在2004年,不列颠哥伦比亚大学的D.Lowe的论文《尺度不变关键点中的独特图像特征》中提出了一种新的尺度不变特征变换(SIFT)算法,该算法提取关键点并计算其描述符。回顾一下SIFT算法的计算步骤,主要包括四个步骤。
1. 尺度空间极值检测
使用尺度空间滤波器可实现不同尺度角度的检测,比如不同σ值的高斯拉普拉斯算子。LoG可以用做blob检测器,通过改变σ值可检测各种大小的blob。但是LoG计算量比较大,因此SIFT算法使用LoG的近似算子即高斯差分算子。高斯差分是两个不同σ值图像高斯模糊结果的差值。此过程是在高斯金字塔中不同层图像中完成的。如下图所示。
当计算出DoG,就要在尺度和空间上搜索图像的局部极值。例如,将图像中一个像素与其相邻的8个像素以及相邻下一个尺度的9个像素和相邻前一个尺度的9个像素,共26个点进行比较(8邻域),判断是否是局部极值,这就确保在尺度和空间都检测到极值点。如下图所示。
2.关键点定位
当找到候选关键点位置后,就要对其进行优化获取更准确的结果。通过尺度空间泰勒级数展开式来获得更精确的极值位置,如果该极值的强度小于固定阈值(论文中为0.03),则丢弃该候选关键点。
DoG会产生较强的边缘响应,需要删除不稳定的边缘响应点。可以使用2x2的Hessian矩阵来计算主曲率。为了剔除边缘响应点,需要让主曲率值小于一定的阈值(论文中为10),如果大于此阈值的关键点就会被丢弃。
消除了低对比度关键点和不稳定的边缘关键点,剩下的就强关键点。
3.关键点方向分配
为了使描述符具有旋转不变性,需要给每个关键点分配一个方向。对于检测出来的关键点,获取其位置附近邻域区域,在该区域中计算梯度大小值和方向。梯度直方图将0~360度的方向范围分为36个柱(bins),其中每柱是10度。保留直方图中的最高峰,且保留超过最高峰值80%的任何峰来计算梯度方向,所以在相同位置和尺度上将会有多个关键点被创建但它们方向是不同的。这有助于匹配的稳定性。
4.关键点描述符
通过以上步骤,对于每一个关键点已经有了三个信息:位置、尺度以及方向。接下来就是为每个关键点建立一个描述符,用一组向量将这个关键点描述出来。将关键点周围16x16邻域分为4x4大小的16个子块,对于每个子块,创建8柱梯度方向直方图,共有生成128个值向量形式来描述关键点。
二、SIFT算子提取关键实现
opencv中已经有现成的SIFT算子,但是受专利保护的。sift.detect()函数用来找图像中的关键点,sift.compute()函数是计算关键点的描述符即特征向量,上述两步可以合成一步计算的函数是sift.detectAndCompute()。
import numpy as np
import cv2 as cv
img = cv.imread('home.jpg')
gray= cv.cvtColor(img,cv.COLOR_BGR2GRAY)
sift = cv.xfeatures2d.SIFT_create()
kp = sift.detect(gray,None)
img=cv.drawKeypoints(gray,kp,img)
cv.imwrite('sift_keypoints.jpg',img)
#method1#
kp, des = sift.compute(gray,kp )
#method2#
kp, des = sift.detectAndCompute(gray,None)
在下一内容中,我会分享如何在医学图像上提取SIFT关键点特征。