图像特征点提取(SIFT,SURF,ORB)

1.SIFT

SIFT的全称是Scale Invariant Feature Transform,尺度不变特征变换,由加拿大教授David G.Lowe提出的。SIFT特征对旋转、尺度缩放、亮度变化等保持不变性,是一种非常稳定的局部特征。

1.SIFT算法具的特点

图像的局部特征,对旋转、尺度缩放、亮度变化保持不变,对视角变化、仿射变换、噪声也保持一定程度的稳定性。

2.SIFT特征检测的步骤

1.在DOG尺度空间中获取极值点,即关键点。

关于LOG(高斯拉普拉斯金字塔) DOG(高斯差分金字塔)参考 https://blog.csdn.net/dcrmg/article/details/52561656

寻找DoG极值点时,每一个像素点和它所有的相邻点比较,当其大于(或小于)它的图像域和尺度域的所有相邻点时,即为极值点。如下图所示,比较的范围是个3×3的立方体:中间的检测点和它同尺度的8个相邻点,以及和上下相邻尺度对应的9×2个点——共26个点比较,以确保在尺度空间和二维图像空间都检测到极值点。
图像特征点提取(SIFT,SURF,ORB)_第1张图片
2.特征点方向估计
计算以特征点为中心、以3×1.5σ为半径的区域图像的幅角和幅值,每个点L(x,y)的梯度的模m(x,y)以及方向θ(x,y)可通过下面公司求得
图像特征点提取(SIFT,SURF,ORB)_第2张图片
计算得到梯度方向后,就要使用直方图统计特征点邻域内像素对应的梯度方向和幅值。梯度方向的直方图的横轴是梯度方向的角度(梯度方向的范围是0到360度,直方图每36度一个柱共10个柱,或者没45度一个柱共8个柱),纵轴是梯度方向对应梯度幅值的累加,在直方图的峰值就是特征点的主方向。在梯度直方图中,当存在一个相当于主峰值80%能量的柱值时,则可以将这个方向认为是该特征点辅助方向。所以,一个特征点可能检测到多个方向(也可以理解为,一个特征点可能产生多个坐标、尺度相同,但是方向不同的特征点)。

3.生成特征描述
为了保证特征矢量的旋转不变性,要以特征点为中心,在附近邻域内将坐标轴旋转θ(特征点的主方向)角度,即将坐标轴旋转为特征点的主方向。
图像特征点提取(SIFT,SURF,ORB)_第3张图片
将旋转后区域划分为d×d(d为2或者4,通常取4)个子区域(每个区域间隔为mσ像元),在子区域内计算8个方向的梯度直方图,绘制每个方向梯度方向的累加值,形成一个种子点。
与求主方向不同的是,此时,每个子区域梯度方向直方图将0°~360°划分为8个方向区间,每个区间为45°。即每个种子点有8个方向区间的梯度强度信息。由于存在d×d,即4×4个子区域,所以最终共有4×4×8=128个数据,形成128维SIFT特征矢量。
图像特征点提取(SIFT,SURF,ORB)_第4张图片
参考blog:
https://www.cnblogs.com/wangguchangqing/p/4853263.html
https://blog.csdn.net/Darlingqiang/article/details/79511137

代码实现:

import numpy as np
import cv2 as cv
img = cv.imread('./data/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.imshow("SIFT", img)
cv.imwrite('sift_keypoints.jpg',img)
cv.waitKey(0)
cv.destroyAllWindows()

图像特征点提取(SIFT,SURF,ORB)_第5张图片
图像特征点匹配


img1_gray = cv2.imread("./data/000029.jpg")
img2_gray = cv2.imread("./data/000087.jpg")

# sift = cv2.xfeatures2d.SIFT_create()
sift = cv2.xfeatures2d.SURF_create()

kp1, des1 = sift.detectAndCompute(img1_gray, None)
kp2, des2 = sift.detectAndCompute(img2_gray, None)

# BFmatcher with default parms
bf = cv2.BFMatcher(cv2.NORM_L2)
matches = bf.knnMatch(des1, des2, k=2)

goodMatch = []
for m, n in matches:
    if m.distance < 0.50 * n.distance:
        goodMatch.append(m)

goodMatch = np.expand_dims(goodMatch, 1)
# print(goodMatch[:20])

# drawMatchesKnn_cv2(img1_gray, kp1, img2_gray, kp2, goodMatch[:20])
res = cv2.drawMatchesKnn(img1_gray, kp1, img2_gray, kp2, goodMatch[:100], None, flags=2)

cv2.namedWindow('res', cv2.WINDOW_NORMAL)
cv2.resizeWindow('res', 1080, 720)
cv2.imshow('res', res)

cv2.waitKey(0)
cv2.destroyAllWindows()

结果:(显示了前100个匹配点)
图像特征点提取(SIFT,SURF,ORB)_第6张图片

2.SURF

1.SURF的介绍

SURF(Speeded Up Robust Features)改进了特征的提取和描述方式,用一种更为高效的方式完成特征的提取和描述。Sift算法的优点是特征稳定,对旋转、尺度变换、亮度保持不变性,对视角变换、噪声也有一定程度的稳定性;缺点是实时性不高,并且对于边缘光滑目标的特征点提取能力较弱。 SURF是对SIFT的改进,可将速度提高3倍。SURF主要是把SIFT中的某些运算做了简化。

2.SURF算法步骤

  1. 尺度空间的极值检测:搜索所有尺度空间上的图像,通过Hessian来识别潜在的对尺度和选择不变的兴趣点。
  2. 特征点过滤并进行精确定位。
  3. 特征方向赋值:统计特征点圆形邻域内的Harr小波特征。即在60度扇形内,每次将60度扇形区域旋转0.2弧度进行统计,将值最大的那个扇形的方向作为该特征点的主方向。
  4. 特征点描述:沿着特征点主方向周围的邻域内,取4×4个矩形小区域,统计每个小区域的Haar特征,然后每个区域得到一个4维的特征向量。一个特征点共有64维的特征向量作为SURF特征的描述子。
    具体可以参考,写得很好 https://www.cnblogs.com/zyly/p/9531907.html

3.与SIFT的比较

1. 方法比较
(1)在生成尺度空间方面,SIFT算法利用的是差分高斯金字塔与不同层级的空间图像相互卷积生成。SURF算法采用的是不同尺度的box filters与原图像卷积

(2)在特征点检验时,SIFT算子是先对图像进行非极大值抑制,再去除对比度较低的点。然后通过Hessian矩阵去除边缘的点。
而SURF算法是先通过Hessian矩阵来检测候选特征点,然后再对非极大值的点进行抑制

(3)在特征向量的方向确定上,SIFT算法是在正方形区域内统计梯度的幅值的直方图,找到最大梯度幅值所对应的方向。SIFT算子确定的特征点可以有一个或一个以上方向,其中包括一个主方向与多个辅方向。
SURF算法则是在圆形邻域内,检测各个扇形范围内水平、垂直方向上的Haar小波响应,找到模值最大的扇形指向,且该算法的方向只有一个。

(4)SIFT算法生成描述子时,是将的采样点划分为的区域,从而计算每个分区种子点的幅值并确定其方向,共计128维。
SURF算法在生成特征描述子时将的正方形分割成的小方格,每个子区域25个采样点,计算小波haar响应,一共64维。

综上,SURF算法在各个步骤上都简化了一些繁琐的工作,仅仅计算了特征点的一个主方向,生成的特征描述子也与前者相比降低了维数。

2. 效果比较

  • 加速3倍
  • 亮度变化下效果好
  • 模糊方面优于SIFT
  • 尺度不变性不及SIFT
  • 旋转不变上差很多

代码实现:

mport numpy as np
import cv2 as cv
img = cv.imread('./data/000029.jpg',0)

surf = cv.xfeatures2d.SURF_create(2000)

kp, des = surf.detectAndCompute(img,None)
img1 = cv.drawKeypoints(img,kp,None,(0,0,255),4)
cv.imshow('surf', img1)
cv.waitKey(0)
cv.destroyAllWindows()


surf.setHessianThreshold(20000)

kp, des = surf.detectAndCompute(img,None)

img2 = cv.drawKeypoints(img,kp,None,(0,0,255),4)
cv.imshow('surf',img2)
cv.waitKey(0)
cv.destroyAllWindows()

Hessian矩阵阈值越高,能识别的特征就越少。以下是阈值在2k和2w的图像:
图像特征点提取(SIFT,SURF,ORB)_第7张图片
图像特征点提取(SIFT,SURF,ORB)_第8张图片

3.ORB

先上代码,回头再写

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
img1 = cv.imread('./data/box.png',0)          # queryImage
img2 = cv.imread('./data/box_in_scene.png',0) # trainImage
# Initiate ORB detector
orb = cv.ORB_create()
# find the keypoints and descriptors with ORB
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)

# create BFMatcher object
bf = cv.BFMatcher(cv.NORM_HAMMING, crossCheck=True)
# Match descriptors.
matches = bf.match(des1,des2)
# Sort them in the order of their distance.
matches = sorted(matches, key = lambda x:x.distance)
# Draw first 10 matches.
img3 = cv.drawMatches(img1,kp1,img2,kp2,matches[:20],None, flags=2)
plt.imshow(img3),plt.show()

你可能感兴趣的:(图像处理)