Harris角点检测具有旋转不变特性,也就是图像发生了旋转之后角点还是角点,然而,如果我们对图像进行放缩,再使用相同的窗口,可能角点就不再是角点了,例如:
所以在 2004 年,D.Lowe 提出了一个新的算法:尺度不变特征变换(SIFT),这个算法可以帮助我们提取图像中的关键点并计算它们的描述符。
SIFT算法主要以下几步构成:
1. 尺度空间极值检测
2. 关键点(极值点)定位
3. 为关键点(极值点)指定方向参数
4. 关键点描述符
5.关键点匹配
OpenCV 中的 SIFT
用函数 cv2.xfeatures2d.SIFT_create() 初始化SIFT检测器对象,提取关键点,函数sift.detect() 可以在图像中找到关键点,如果只想在图像中的一个区域搜索的话,也可以创建一个掩模图像作为参数使用。返回的关键点是一个带有很多不同属性的特殊结构体,这些属性中包含它的坐标(x,y),有意义的邻域大小,确定其方向的角度等。
OpenCV 也提供了绘制关键点的函数:cv2.drawKeyPoints(),它可以在关键点的部位绘制一个小圆圈。如果你设置参cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS,
就会绘制代表关键点大小的圆圈甚至可以绘制除关键点的方向。
import cv2
import numpy as np
# 读入图像
img = cv2.imread('C:/Users/www12/Desktop/Photo/test_1.jpg')
# 灰度化
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 初始化SIFT检测器对象
sift = cv2.xfeatures2d.SIFT_create()
# 在灰度图上调用SIFT算法进行角点检测,找到关键点
kp = sift.detect(gray, None)
# 在关键点的部位画一个小圆圈
img = cv2.drawKeypoints(gray, kp, img)
# 画出只有圆圈的的图像
cv2.imshow('img',cv2.resize(img, (800, 600)))
cv2.waitKey(0)
cv2.destroyAllWindows()
img=cv2.drawKeypoints(gray,kp,img,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
# 画出带有关键点方向的图像
cv2.imshow('img',cv2.resize(img, (800, 600)))
cv2.waitKey(0)
cv2.destroyAllWindows()
原图:
关键点
关键点带方向
找出了并且标记出了关键点之后我们可以来计算关键点描述符,OpenCV提供了两种方法。
- 由于我们已经找到了关键点,我们可以使用函数 sift.compute() 来计算这些关键点的描述符。
kp, des = sift.compute(gray, kp)
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)
这里 kp 是一个关键点列表。des 是一个 Numpy 数组,其大小是关键点数目乘以 128。
- 如果还没有找到关键点,可以使用函数 sift.detectAndCompute()一步到位直接找到关键点并计算出其描描述。
这里第二种方法有兴趣可以自行尝试。