OpenCV 的 turtorial 相当好:链接
这个网上例子也太多,总的来说,就是三部曲:
- 提取图像中的关键点,关键点就是特征点在图像中的位置,可能还有方向等其他信息
- 计算关键点的描述子,描述子通常是一个向量,人为设计来描述关键点周围像素的信息
- 根据描述子进行匹配,两张图片得到许多描述子,需要筛选出合格的匹配对
得到匹配对,就可以进行相关应用了,如图像配准里面,就可以用匹配的点计算变换矩阵(1.4节)。
特征提取和特征描述的方法实在太多太多了,Opencv features2d 和 xfeatures2d 模块。
不多做说明,如上所述,OpenCV turtorial 已经写的非常好,直接参考即可。这里不写各个参数的细节了,可以参考官方代码,然后自行调整。
简单的角点有 Harris(cornerHarris
), Shi-Tomasi Corner(goodFeatureToTrack
), 复杂专业的有 FAST, SIFT, SURF, ORB, KAZE, AKAZE, BRISK, AGAST... 具体对应函数去官方文档上查吧,其中前面两个在 2.2.md 上有详细介绍。
- 各个方法的返回值类型可能有差异,这个打印下类,然后查手册就行,这里也有一个转为二维数组的简单示例
# 各个方法转为二维点(纵坐标在前)
# 返回值: 图片大小,每个像素是否是角点
result = cv2.cornerHarris(src_gray, 2, 3, 0.04)
points = np.argwhere(result > 0.05*result.max())
points[..., [0, 1]] = points[..., [1, 0]]
# 返回值: 一堆点 (n, 1, 2)
points = cv2.goodFeaturesToTrack(src_gray, 25, 0.01, 10).astype(int)
points = points[:, 0, :]
# 返回值: (keypoints, descriptors), keypoints 每个元素是 KeyPoint
sift = cv2.SIFT_create()
keypoints = sift.detect(src_gray, None)
points = np.array([x.pt for x in keypoints])
# SIFT, SURF, ORB, FAST, BRIEF 返回类型基本一样
-
各个方法的评价
- Harris, Shi-Tomasi 只是简单的角点检测(具体看 Note 2.2)
- 如果需要较高的鲁棒性和不变性,可以选择SIFT或SURF算法
- 如果需要速度较快且对旋转和尺度变化有一定鲁棒性,可以选择ORB算法
- 如果速度是最关键的因素,并且只需要简单的关键点检测,可以选择FAST算法
其实上面如 SIFT、ORB 等不仅仅只是特征提取方法,其也包含了后续的特征描述。所以有许多示例代码中通常直接用如 sift.detectAndCompute
来代替 sift.detect
+sift.compute
的组合。
单独的特征描述方法在 OpenCV Turotial 中只有一个 BRIEF 算法:
sift = cv2.SIFT_create()
brief = cv2.BRIEF_create()
# 特征点检测
rawpoints = sift.detect(src_gray,None)
# 不同的特征点描述
keypoints1, descriptors1 = sift.compute(src_gray, rawpoints)
keypoints2, descriptors2 = brief.compute(src_gray, rawpoints)
# SIFT 这种特征提取、描述都有的方法其实可以合成一句
keypoints3, descriptors3 = sift.detectAndCompute(src_gray, None)
直接看 官方文档 即可。有两类 BFMatcher 和 FLANNMatcher,这两个类都继承自 DescriptorMatcher 类,他们的方法基本是一致的。
-
匹配方法都有 match、knnMatch、radiusMatch,返回值有点差别,官方文档中有使用示例。
-
还有当时比较犯迷糊的 train 方法,我觉得 DescriptorMatcher 那个文档写的很好,每次执行 match 都会执行 train,而 BruteForceMatcher 不需要 train,所以在这个类的实现中 train 方法是空的:
Trains a descriptor matcher (for example, the flann index). In all methods to match, the method train() is run every time before matching. Some descriptor matchers (for example, BruteForceMatcher) have an empty implementation of this method. Other matchers really train their inner structures (for example, FlannBasedMatcher trains flann::Index ).
- 还有一个 add 方法,就是把特征描述加入到“训练集”中,用于 train;这里反正要明确,这个 train 其实不是神经网络的那种训练,它就是一个聚类方法。
匹配之后,可以用 drawMatches
进行绘图。
补充:在 contrib xfeatures2d 又新增了两个方法 GMS 和 LOGOS,具体用法查文档。关于 GMS 多说几句:
- 这个方法不同其他特征匹配方法,是用于匹配更一步的细筛。即先执行普通的 match 函数,然后再执行它。其中需要输入的参数 matches1to2 就是执行初步 match 时候得到的结果。
- GMS 在特征数量较多时效果良好,OpenCV 建议使用 ORB 特性并将 FastThreshold 设置为 0(因为 ORB 得出的特征数量较多)。
- 如果图片有很大的旋转和比例变化,请将参数 withRotation 或 withScale 设置为 true。