Python如何实现SIFT特征提取?本文带你了解如何使用 Python 中的 OpenCV 库计算和检测 SIFT 特征以进行特征匹配等。
SIFT 代表Scale Invariant Feature Transform,它是一种特征提取方法(其中包括HOG 特征提取),其中将图像内容转换为对平移、尺度和其他图像变换不变的局部特征坐标。
在这个Python OpenCV实现SIFT特征提取教程中,你将学习 SIFT 背后的理论以及如何使用 OpenCV 库在 Python 中实现它,包括Python SIFT特征提取示例。
以下是 SIFT 的优点:
- 地方性:特色是地方性的;对遮挡和杂波具有鲁棒性。
- 独特性:提取的单个特征可以与大型对象数据集相匹配。
- 数量:使用 SIFT,我们可以从小对象中提取许多特征。
- 效率:SIFT 接近实时性能。
这些是 SIFT 的高级细节:
- 尺度空间极值检测:识别可以在同一场景或对象的不同视图下重复分配的位置和尺度。
- 关键点定位:拟合模型以确定特征的位置和尺度,根据稳定性度量选择关键点。
- 方向分配:计算每个关键点区域的最佳方向。
- 关键点描述:使用选定比例和旋转的局部图像梯度来描述每个关键点区域。
尺度空间极值检测
Python如何实现SIFT特征提取?在第一步中,我们确定可以在同一对象或场景的不同视图下重复分配的位置和比例。为了识别,我们将使用高斯函数使用尺度的连续函数在多个尺度上搜索稳定特征。
图像的尺度空间是一个函数 L(x, y, a),它是由高斯核(在不同尺度下)与输入图像的卷积产生的。
在每个八度音阶中,初始图像与高斯函数反复卷积以产生一组尺度空间图像。在每个级别,图像都会被平滑并缩小尺寸。在每个八度音阶之后,高斯图像按 2 倍进行下采样,以生成大小为 1/4 的图像以开始下一个级别。减去相邻的高斯以产生DoG(高斯差)。
为了创建第一个八度音程,高斯滤波器应用于具有不同 sigma 值的输入图像,然后对于第二个和即将到来的八度音程,图像首先按因子 2 进行下采样,然后应用具有不同值的高斯滤波器。
西格玛值如下。
- Octave 1 使用 σ 的音阶。
- Octave 2 使用 2σ 的音阶。
- 等等。
下图显示了四个八度,每个八度包含六个图像:
一个问题是关于每八度音阶有多少个音阶?研究表明,每个八度应该有 4 个音阶:
然后将八度音阶中的两个连续图像相减以获得高斯的差值。
关键点定位
Python OpenCV实现SIFT特征提取:取高斯差后,我们需要通过将一个像素(x)与当前和相邻尺度中的26个像素进行比较来检测尺度空间中的极大值和极小值。每个点与当前图像中的 8 个相邻点和上下尺度中的 9 个相邻点进行比较。
以下是在我们的示例图像中找到的极值点:
方向分配
完成方向分配以实现旋转不变性。对高斯模糊图像中关键点周围相邻区域中的每个像素进行梯度幅度和方向计算。
幅度代表像素的强度,方向给出了相同的方向。
用于梯度幅度的公式为:
方向计算公式为:
现在我们需要查看每个点的方向。权重也与方向一起分配。下面蓝色方块中的箭头大约是 90 度角,它的长度显示了它的重要性。
直方图是通过将方向量化为 36 个区间形成的,每个区间覆盖 10 度。直方图将告诉我们有多少像素具有某个角度。例如,有多少像素有 36 度角?
关键点描述
此时,每个关键点都有一个位置、尺度和方向。现在 我们需要计算一个描述符,我们需要使用关键点周围的标准化区域。我们将首先在关键点周围取一个 16×16 的邻域。这个 16×16 块被进一步划分为 4×4 子块,对于这些子块中的每一个,我们使用幅度和方向生成直方图。
将 16 个直方图连接到一个 128 维的长向量中。4x4 乘以 8 个方向给出一个包含 128 个值的向量。
另请阅读: 如何在 Python 中应用 HOG 特征提取。
Python 实现
Python如何实现SIFT特征提取?现在你希望了解 SIFT 背后的理论,让我们深入研究使用 OpenCV 的 Python 代码。首先,让我们安装一个实现 SIFT 的特定版本的 OpenCV:
pip3 install numpy opencv-python==3.4.2.16 opencv-contrib-python==3.4.2.16
打开一个新的 Python 文件并继续,我将在这张包含特定书籍的表上进行操作(在此处获取):
import cv2
# reading the image
img = cv2.imread('table.jpg')
# convert to greyscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
Python SIFT特征提取示例代码介绍 - 上面的代码加载图像并将其转换为灰度,让我们创建 SIFT 特征提取器对象:
# create SIFT feature extractor
sift = cv2.xfeatures2d.SIFT_create()
为了检测关键点和描述符,我们只需将图像传递给detectAndCompute()
方法:
# detect features from the image
keypoints, descriptors = sift.detectAndCompute(img, None)
最后,让我们绘制关键点,显示并保存图像:
# draw the detected key points
sift_image = cv2.drawKeypoints(gray, keypoints, img)
# show the image
cv2.imshow('image', sift_image)
# save the image
cv2.imwrite("table-sift.jpg", sift_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
Python OpenCV实现SIFT特征提取示例 - 这是生成的图像:
这些 SIFT 特征点对许多用例都很有用,这里有一些:
Python如何实现SIFT特征提取?为了在本演示中实际使用,我们选择了特征匹配,让我们使用 OpenCV 从不同角度匹配同一对象的 2 张图像(你可以在此 Github 存储库中获取图像):
import cv2
# read the images
img1 = cv2.imread('book.jpg')
img2 = cv2.imread('table.jpg')
# convert images to grayscale
img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)
# create SIFT object
sift = cv2.xfeatures2d.SIFT_create()
# detect SIFT features in both images
keypoints_1, descriptors_1 = sift.detectAndCompute(img1,None)
keypoints_2, descriptors_2 = sift.detectAndCompute(img2,None)
Python SIFT特征提取示例代码介绍 - 现在我们有了两个图像的关键点和描述符,让我们创建一个匹配器来匹配描述符:
# create feature matcher
bf = cv2.BFMatcher(cv2.NORM_L1, crossCheck=True)
# match descriptors of both images
matches = bf.match(descriptors_1,descriptors_2)
让我们按距离对匹配项进行排序并绘制前 50 个匹配项:
# sort matches by distance
matches = sorted(matches, key = lambda x:x.distance)
# draw first 50 matches
matched_img = cv2.drawMatches(img1, keypoints_1, img2, keypoints_2, matches[:50], img2, flags=2)
最后,显示并保存图像:
# show the image
cv2.imshow('image', matched_img)
# save the image
cv2.imwrite("matched_images.jpg", matched_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
输出:
结论
好的,在这个Python OpenCV实现SIFT特征提取教程中,我们已经介绍了 SIFT 的基础知识,我建议你阅读原始论文以获取更多详细信息。
此外,OpenCV 在cv2.xfeatures2d.SIFT_create()
方法中使用 SIFT 的默认参数,你可以更改要保留的特征数量 ( nfeatures
) nOctaveLayers
、sigma
等。键入help(cv2.xfeatures2d.SIFT_create)
以获取更多信息。