在上一篇文章中,您学习了 OpenCV 中的一些基本特征提取算法。特征以像素分类的形式提取。这些确实从图像中抽象出特征,因为您不需要考虑每个像素的不同颜色通道,而是考虑单个值。在本文中,您将学习一些其他特征提取算法,它们可以更简洁地告诉您图像的信息。
完成本教程后,您将了解:
- 图像中的关键点是什么?
- OpenCV 中有哪些常用的算法可以提取关键点?
通过我的书《OpenCV 机器学习》启动您的项目。它提供了带有可用代码的自学教程。
让我们开始吧。

OpenCV 中的图像特征提取:关键点和描述向量
图片由 Silas Köhler 拍摄,部分权利保留。
概述
这篇文章分为两部分:
- 使用 OpenCV 中的 SIFT 和 SURF 进行关键点检测
- 使用 OpenCV 中的 ORB 进行关键点检测
先决条件
本教程假设您已熟悉以下内容:
使用 OpenCV 中的 SIFT 和 SURF 进行关键点检测
尺度不变特征变换(SIFT)和加速鲁棒特征(SURF)是用于检测和描述图像中局部特征的强大算法。它们之所以被称为尺度不变和鲁棒,是因为与例如 Harris 角点检测相比,即使图像发生了一些变化,其结果也是可预期的。
SIFT 算法对图像应用高斯模糊,并计算多个尺度的差值。直观地,如果整个图像是单一的平面颜色,则这种差值将为零。因此,该算法被称为关键点检测,它识别图像中像素值变化最显著的位置,例如角点。
SIFT 算法为每个关键点派生出某些“方向”值,并输出一个表示方向值直方图的向量。
SIFT 算法运行起来相当慢。因此,有一个加速版本,即 SURF。详细描述 SIFT 和 SURF 算法会很冗长,但幸运的是,您不需要了解太多就可以在 OpenCV 中使用它们。
让我们看一个使用以下图像的示例:
与上一篇文章类似,SIFT 和 SURF 算法假定图像是灰度图像。这次,您需要首先创建一个检测器并将其应用于图像:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import cv2 # 加载图像并转换为灰度图 img = cv2.imread('image.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 初始化 SIFT 和 SURF 检测器 sift = cv2.SIFT_create() surf = cv2.xfeatures2d.SURF_create() # 检测关键点并计算描述符 keypoints_sift, descriptors_sift = sift.detectAndCompute(img, None) keypoints_surf, descriptors_surf = surf.detectAndCompute(img, None) |
注意:您可能在您的 OpenCV 安装中运行上述代码时遇到困难。为了使其运行,您可能需要从头开始编译自己的 OpenCV 模块。这是因为 SIFT 和 SURF 获得了专利,因此 OpenCV 将它们视为“非免费”。由于 SIFT 专利已经过期(SURF 仍在有效期内),如果您下载较新版本的 OpenCV,您可能会发现 SIFT 运行良好。
SIFT 或 SURF 算法的输出是关键点列表和描述符的 numpy 数组。描述符数组是 Nx128,表示 N 个关键点,每个关键点由一个长度为 128 的向量表示。每个关键点都是一个具有多个属性的对象,例如方向角。
默认情况下可以检测到很多关键点,因为这有助于检测到的关键点最好的用途之一——在失真图像之间找到关联。
为了减少输出中检测到的关键点数量,您可以在 SIFT 中设置更高的“对比度阈值”和更低的“边缘阈值”(默认为 0.03 和 10),或者在 SURF 中增加“Hessian 阈值”(默认为 100)。这些可以在检测器对象上分别使用 sift.setContrastThreshold(0.03)
、sift.setEdgeThreshold(10)
和 surf.setHessianThreshold(100)
进行调整。
要在图像上绘制关键点,可以使用 cv2.drawKeypoints()
函数并将所有关键点列表应用于它。完整的代码(仅使用 SIFT 算法并设置非常高的阈值以仅保留少量关键点)如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import cv2 # 加载图像并转换为灰度图 img = cv2.imread('image.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 初始化 SIFT 检测器 sift = cv2.SIFT_create() sift.setContrastThreshold(0.25) sift.setEdgeThreshold(5) # 检测关键点并计算描述符 keypoints, descriptors = sift.detectAndCompute(img, None) for x in keypoints: print("({:.2f},{:.2f}) = size {:.2f} angle {:.2f}".format(x.pt[0], x.pt[1], x.size, x.angle)) img_kp = cv2.drawKeypoints(img, keypoints, None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) cv2.imshow("Keypoints", img_kp) cv2.waitKey(0) cv2.destroyAllWindows() |
创建的图像如下所示:

SIFT 算法检测到的关键点(放大)
原始照片由 Gleren Meneghin 拍摄,部分权利保留。
函数 cv2.drawKeypoints()
不会修改您的原始图像,而是返回一个新图像。在上图中,您可以看到关键点被绘制成与其“大小”成比例的圆圈,并带有一条表示方向的笔画。门上的数字“17”和邮件槽上都有关键点。但确实还有更多。从上面的 for 循环中,您可以看到一些关键点是重叠的,因为找到了多个方向角。
在图像上显示关键点时,您使用了返回的关键点对象。但是,如果您想进一步处理关键点,例如运行聚类算法,您可能会发现存储在 descriptors
中的特征向量很有用。但请注意,您仍然需要关键点列表的信息,例如坐标,以匹配特征向量。
使用 OpenCV 中的 ORB 进行关键点检测
由于 SIFT 和 SURF 算法已获得专利,因此有动力开发一种无需许可的免费替代方案。它是 OpenCV 开发人员自己的产品。
ORB 代表 Oriented FAST and Rotated BRIEF。它是另外两种算法 FAST 和 BRIEF 的组合,并进行了修改以匹配 SIFT 和 SURF 的性能。您无需了解算法细节即可使用它,其输出也是关键点对象列表,如下所示:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
import cv2 # 加载图像并转换为灰度图 img = cv2.imread('image.jpg') gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 初始化 ORB 检测器 orb = cv2.ORB_create(30) # 检测关键点并计算描述符 keypoints, descriptors = orb.detectAndCompute(img, None) for x in keypoints: print("({:.2f},{:.2f}) = size {:.2f} angle {:.2f}".format( x.pt[0], x.pt[1], x.size, x.angle)) img_kp = cv2.drawKeypoints(img, keypoints, None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) cv2.imshow("Keypoints", img_kp) cv2.waitKey(0) cv2.destroyAllWindows() |
在上面,您在创建检测器时将 ORB 设置为生成前 30 个关键点。默认情况下,此数字将为 500。
检测器返回关键点列表和描述符的 numpy 数组(每个关键点的特征向量),与之前完全相同。然而,每个关键点的描述符现在长度为 32,而不是 128。
生成的关键点如下所示:

ORB 算法检测到的关键点
原始照片由 Gleren Meneghin 拍摄,部分权利保留。
您可以看到,关键点大致在相同位置生成。结果并非完全相同,因为存在重叠的关键点(或偏移非常小的距离),并且 ORB 算法很容易达到最大计数 30。此外,不同算法之间的大小不可比较。
想开始学习 OpenCV 机器学习吗?
立即参加我的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
书籍
- 使用 Python 精通 OpenCV 4, 2019.
网站
- OpenCV,https://opencv.ac.cn/
- OpenCV 特征检测和描述,https://docs.opencv.ac.cn/4.x/db/d27/tutorial_py_table_of_contents_feature2d.html
总结
在本教程中,您学习了如何应用 OpenCV 的关键点检测算法:SIFT、SURF 和 ORB。
具体来说,你学到了:
- 图像中的关键点是什么?
- 如何使用 OpenCV 函数查找关键点和相关的描述符向量。
如果您有任何问题,请在下面留言。
暂无评论。