使用Python的 SIFT 兴趣点检测器 – OpenCV
SIFT(尺度不变傅立叶变换)检测器用于检测输入图像上的兴趣点。它允许识别图像中的局部特征,这在以下应用中是必不可少的:
- 图像中的物体识别
- 路径检测和避障算法
- 手势识别、马赛克生成等
与依赖于图像属性(如视点、深度和尺度)的Harris Detector不同,SIFT 可以独立于图像的这些属性执行特征检测。这是通过将图像数据转换为尺度不变坐标来实现的。据说 SIFT 检测器是灵长类视觉系统中使用的系统的近似。
提取兴趣点的步骤
第一阶段:尺度空间峰选择
尺度空间的概念涉及将连续范围的高斯滤波器应用于目标图像,以便所选的高斯滤波器具有不同的 sigma 参数值。这样得到的图称为尺度空间。尺度空间峰值选择取决于空间重合假设。据此,如果在多个尺度(由尺度空间中的零交叉表示)在同一位置检测到边缘,那么我们将其归类为实际边缘。
在二维图像中,我们可以使用高斯拉普拉斯算子尺度空间中的局部最大值/最小值来检测兴趣点。对于给定的 sigma 值,潜在的 SIFT 兴趣点是通过选择潜在的兴趣点并考虑上层(具有较高 sigma)、相同水平和下层(sigma 低于当前 sigma 水平)中的像素来确定的。如果该点是所有这 26 个相邻点的最大值/最小值,则它是一个潜在的 SIFT 兴趣点 - 它充当兴趣点检测的起点。
第二阶段:关键点定位
关键点定位涉及对前一阶段选择的关键点进行细化。低对比度关键点、不稳定关键点和位于边缘的关键点被消除。这是通过计算在前一阶段找到的关键点的拉普拉斯算子来实现的。极值计算如下:
上式中,D代表高斯差。为了去除不稳定的关键点,计算z的值,如果 z 处的函数值低于阈值,则排除该点。
第三阶段:为关键点分配方向
为了实现相对于图像旋转不变的检测,需要计算关键点的方向。这是通过考虑关键点的邻域并计算邻域梯度的大小和方向来完成的。根据获得的值,构建一个包含 36 个 bin 的直方图来表示 360 度的方向(每个 bin 10 度)。因此,如果某个点的梯度方向是 67.8 度,则与该点的梯度幅度成正比的值被添加到表示 60-70 度的 bin。 80% 以上的直方图峰值被转换为新的关键点,用于决定原始关键点的方向。
第四阶段:关键点描述符
最后,对于每个关键点,使用关键点邻域创建一个描述符。这些描述符用于匹配图像中的关键点。关键点的 16×16 邻域用于定义该关键点的描述符。这个 16×16 的邻域被划分为子块。每个这样的子块都是一个不重叠的、连续的、4×4 的邻域。随后,对于每个子块,与方向分配中讨论的类似,创建 8 个 bin 方向。这 128 个 bin 值(16 个子块 * 每块 8 个 bin)表示为向量以生成关键点描述符。
示例: Python中的 SIFT 检测器
在同一目录中使用名为“geeks.jpg”的文件运行以下脚本会生成“image-with-keypoints.jpg”,其中包含使用 OpenCV 中的 SIFT 模块检测到的兴趣点,并使用圆形叠加进行标记。
下面是实现:
Python3
# Important NOTE: Use opencv <= 3.4.2.16 as
# SIFT is no longer available in
# opencv > 3.4.2.16
import cv2
# Loading the image
img = cv2.imread('geeks.jpg')
# Converting image to grayscale
gray= cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
# Applying SIFT detector
sift = cv2.xfeatures2d.SIFT_create()
kp = sift.detect(gray, None)
# Marking the keypoint on the image using circles
img=cv2.drawKeypoints(gray ,
kp ,
img ,
flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imwrite('image-with-keypoints.jpg', img)
输出: