1、sift介绍
SIFT全称Scale-Invariant Feature Transform(尺度不变特征转换)。它用来侦测与描述影像中的局部性特征,它在空间尺度中寻找极值点,并提取出其位置、尺度、旋转不变量,此算法由 David Lowe在1999年所发表,2004年完善总结。
SIFT算法分解为如下四步:
(1)构建尺度空间
搜索所有尺度上的图像位置,通过高斯微分函数来识别潜在的对于尺度和旋转不变的兴趣点,具体的过程如下。
A、采用高斯函数对图像进行模糊以及降采样处理得到高斯金字塔
B、采用DOG(Difference of Gaussian)即在高斯金子塔中的每组中相邻两层相减(“下一层减上一层”)生成高斯差分金字塔
(2)关键点定位
A、找到局部极值点
B、剔除极值点
通过Taylor展开式(插值函数)精确定位关键点,通过Hessian矩阵消除边缘响应点。
(3)方向确定
对关键点进行梯度计算生成梯度直方图统计领域内像素的梯度和方向,从而确定方向。
(4)关键点特征描述子
取特征点周围44个区域块,统计每小块内8个梯度方向,用这448=128维向量作为Sift特征的描述子。
2、surf介绍
SURF全称Speeded Up Robust Features,为SIFT的加速版本。它改进了特征的提取和描述方式,用一种更为高效的方式完成特征的提取和描述。
SURF跟SIFT一样分四步走:
(1)构建尺度空间
A、使用box filter滤波,然后使用Hessian矩阵获取二阶梯度特征(相当于LoG算子或SIFT里的DOG)
从左到右分别表示在y方向LoG算子(),xy方向的LoG算子,y方向近似的LoG算子,xy方向近似的LoG算子
(2)构建Hessian矩阵塔
surf在建塔的时候每层图像大小不变,只是对模板的尺度不断增大,相当于一个上采样的过程。
第一塔中size分别为,而以后每塔中size边长差距逐塔翻倍。
(2)关键点定位
A、找到局部极值点
这里和LoG,DoG相同,都是在生成尺度空间后,在三维上找极值点。
B、剔除极值点
这里和DoG不同的是不用剔除边缘导致的极值点了,因为Hessian矩阵的行列式就已经考虑到边缘的问题了,而DoG计算只是把不同方向变化趋势给出来,后续还需要使用Hessian矩阵的特征值剔除边缘产生的影响。
通过Taylor展开式(插值函数)精确定位关键点。
(3)方向确定
统计特征点圆形邻域内的harr小波特征,按每60度划分一个扇区进行计算,最后得到值最大的那个扇区的方向做为主方向。
(4)关键点特征描述子
在特征点周围取一个44的矩形区域块,但是所取得矩形区域方向是沿着特征点的主方向。每个子区域统计25个像素的水平方向和垂直方向的haar小波特征,这里的水平和垂直方向都是相对主方向而言的。该haar小波特征为水平方向值之后、垂直方向值之后、水平方向绝对值之后以及垂直方向绝对值之和4个方向。
把这4个值作为每个子块区域的特征向量,所以一共有4^4=64维向量作为Surf特征的描述子。
3、sift与surf对比
(1)SURF不同点
A、在尺度空间中,使用box filtes与原图像卷积,而不是使用DoG算子。
B、确定关键点方向时,Surf是利用不同方向bin中的haar小波响应的最大值最为方向,而Sift是统计周围区域像素点的方向直方图,找出最大方向bin作为主方向,而且还可以有多个方向。
C、特征描述子,Surf在关键点周围取区域分成44块小区域,在每个小区域计算采样点的haar响应,统计对应的四个特征,共64维特征,而Sift在周围1616的区域划分成4*4的子区域,每一个子区域提取长度为8的方向直方图特征,排列起来形成128维特征向量。
(2)SURF速度更快
A、使用box filters相对于高斯滤波,再辅助以积分图速度肯定提升不少。
B、Hessian矩阵的计算一般而言还是挺麻烦的,但这里可以使用积分图计算,无论尺度是多少都可以使用几个数的加减完成,速度很快。
C、确定关键点方向时使用haar特征同样可以利用积分图,简单快速。
D、特征描述子使用64维取代128维特征降低了后续处理的数据规模。
4、sift示例
#sift特征匹配
def siftFeature(queryPhoto,trainPhoto):
img1 = cv.imread(queryPhoto,3) # queryImage
img2 = cv.imread(trainPhoto,3) # trainImage
# Initiate SIFT detector初始化SIFT检测器
# ref:https://docs.opencv.org/3.4.2/d5/d3c/classcv_1_1xfeatures2d_1_1SIFT.html
sift = cv.xfeatures2d.SIFT_create()
# find the keypoints and descriptors with SIFT获取关键点与特征描述子
# ref:https://docs.opencv.org/3.4.2/d0/d13/classcv_1_1Feature2D.html#a8be0d1c20b08eb867184b8d74c15a677
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)
# print(len(kp1))#输出关键点的长度
# Brute-force descriptor matcher蛮力描述子匹配
# ref:https://docs.opencv.org/3.4.2/d3/da1/classcv_1_1BFMatcher.html
bf = cv.BFMatcher()
#从查询集中查找每个描述符的k个最佳匹配。
#ref:https://docs.opencv.org/3.4.2/db/d39/classcv_1_1DescriptorMatcher.html#aa880f9353cdf185ccf3013e08210483a
matches = bf.knnMatch(des1,des2, k=2)
# Apply ratio test
good = []
for m,n in matches:
if m.distance < 0.75*n.distance:#剔除两个匹配具体相差太远的项
good.append([m])
#从两个图像中绘制找到的关键点匹配项,flags指定画出匹配关键点的方式
#ref:https://docs.opencv.org/3.4.2/d4/d5d/group__features2d__draw.html
img3 = cv.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2)
return img3
5、surf示例
#surf特征匹配
def surfFeature(queryPhoto,trainPhoto):
img1 = cv.imread(queryPhoto,3) # queryImage
img2 = cv.imread(trainPhoto,3) # trainImage
# Initiate SURF detector初始化SURF检测器
#ref:https://docs.opencv.org/3.4.2/d5/df7/classcv_1_1xfeatures2d_1_1SURF.html
surf=cv.xfeatures2d.SURF_create(400)#初始Hessian矩阵的阈值
# find the keypoints and descriptors with SURF
kp1, des1 = surf.detectAndCompute(img1,None)
kp2, des2 = surf.detectAndCompute(img2,None)
# print(len(kp1))
# surf.setHessianThreshold(5000) #指定Hessian矩阵的阈值
# print(surf.getHessianThreshold())
# BFMatcher with default params
bf = cv.BFMatcher()
matches = bf.knnMatch(des1,des2, k=2)
# Apply ratio test
good = []
for m,n in matches:
if m.distance < 0.75*n.distance:
good.append([m])
print(type(good[0][0]))# cv2.DMatch
img3 = cv.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2)
return img3
参考:
Introduction to SIFT (Scale-Invariant Feature Transform)
https://docs.opencv.org/3.3.0/da/df5/tutorial_py_sift_intro.html
图像相似度算法--SIFT算法详解
SIFT特征点提取
DoG (Difference of Gaussian)角点检测
Surf特征提取分析
SURF算法