- 1. 学习如何在你的电脑上配置OpenCV-Python环境!
- 1.1 开始了解OpenCV-Python
- 1.2 在 Windows 下安装 OpenCV-Python
- 1.3 在 Fedora 环境下安装 OpenCV-Python
- 1.4 在 Debian(Ubuntu)中配置 OpenCV-Python
- 1.5 在Docker中安装OpenCV-Python
- 1.6 在树莓派配置OpenCV-Python
- 2. OpenCV中的GUI功能
- 2.1 开始使用图像
- 2.2 开始使用视频
- 2.3 OpenCV 中的绘图函数
- 2.4 以鼠标为画笔
- 2.5 用滑块控制条做调色板
- 3. OpenCV中的GUI功能
- 3.1 图片基本操作
- 3.2 图像算术操作
- 3.3 性能评估与改进技巧
- 4. OpenCV中的图像处理
- 4.1 更换颜色空间
- 4.2 对图像进行几何变换
- 4.3 图像二值化处理
- 4.4 平滑图像
- 4.5 形态学转换
- 4.6 图像梯度
- 4.7 Canny边缘检测
- 4.8 图像金字塔
- 4.9.1 直方图:查找,绘制,分析
- 4.9.2 直方图均衡化
- 4.9.3 二维直方图
- 4.9.4 直方图反投影
- 4.10 OpenCV中的图像变换
- 4.10.1 傅立叶变换
- 4.11 模板匹配
- 4.12 霍夫直线变换
- 4.13 霍夫圆变换
- 4.14 基于分水岭算法的图像分割
- 4.14 使用 GrabCut 算法交互式前景提取
- 5. 特征检测和描述符
- 5.1 理解特征
- 5.2 Harris 角点检测
- 5.3 Shi-Tomasi 角点检测 & 适合用来跟踪的特征
- 5.4 介绍SIFT(尺度不变特征转换)
- 5.5 介绍SURF(加速稳健特征)
- 5.6 角点检测的FAST算法
- 5.7 BRIEF特征点描述算法
- 5.8 ORB 特征描述符(Oriented FAST and Rotated BRIEF)
- 5.9 特征匹配
- 5.10 特征匹配和使用单应性匹配来搜索物体
- 6. 视频分析
- 6.1 Meanshift和Camshift
- 6.2 光流
- 6.3 背景分割
- 7. 相机校准和3D重建
- 7.1 相机校准
- 7.2 姿势估计
- 7.3 极线几何
- 7.4 来自立体图像的深度图
- 8. 机器学习
- 8.1 K-最近邻算法
- 8.1.1 了解k-最近邻算法
- 8.1.2 使用kNN进行手写字符的OCR
- 8.2 支持向量机(SVM)
- 8.2.1 理解SVM
- 8.2.2 使用SVM的手写数据的OCR
- 8.3 K-Means聚类
- 8.3.1 理解 K-Means 聚类
- 8.3.2 OpenCV中的K-Means聚类
- 9. 计算摄影学
- 9.1 图像去噪
- 9.2 图像修复
- 9.3 高动态范围(HDR)
- 10. 目标检测
- 10.1 使用 Haar Cascades 的面部识别
- 11. OpenCV-Python 绑定
- 11.1 OpenCV-Python绑定如何工作?
5.9 特征匹配
目标
在这一章中,
- 我们将看到如何将一个图片上的特征和其他图片上的特征匹配起来。
- 我们将使用 OpenCV 中的蛮力匹配器和 FLANN 匹配器。
蛮力匹配器基础
蛮力匹配器很简单。 它采用第一组中的一个特征的描述符并且使用一些距离计算与第二组中的所有其他特征匹配。 返回最接近的一个。
对于BF匹配器,首先我们必须使用 cv2.BFMatcher()
来创建 BFMatcher
对象。 它需要两个可选的参数。 首先是 normType
。 它指定要使用的距离测量方法。 默认情况下,它是 cv2.NORM_L2
。 对于SIFT,SURF等(cv2.NORM_L1
也在这些之中)。 对于像 ORB,BRIEF,BRISK 等基于二进制字符串的描述符,应该使用 cv2.NORM_HAMMING
,它使用汉明距离作为度量。 如果ORB使用 WTA_K == 3
或 4,则应使用 cv2.NORM_HAMMING2
。
第二个参数是布尔变量 crossCheck
,其默认为 false。 如果它为 true,Matcher 只返回值为 $(i,j)$ 的那些匹配,使得集合A中的第i个描述符在集合B中具有第j个描述符作为最佳匹配,反之亦然。 也就是说,两组中的两个特征应该相互匹配。 它提供了一致的结果,这是 D.Lowe 在SIFT论文中提出的比率测试的一个很好的替代品。
一旦一个 BFMatcher
对象被创建,两个重要的方法是 BFMatcher.match()
和 BFMatcher.knnMatch()
。 第一个返回最佳匹配。 第二个返回k个最佳匹配,其中k由用户指定。当我们需要做额外的工作时,这可能是有用的。
就像我们使用cv2.drawKeypoints()
来绘制关键点那样,cv2.drawMatches()
帮助我们绘制匹配。 它将两个图像水平堆叠,并从第一个图像绘制到第二个图像,显示最佳匹配。 也有cv2.drawMatchesKnn()
函数来绘制所有k个最好的匹配。 如果$k=2$,则会为每个关键点绘制两条匹配线。 所以如果我们要选择性地绘制它,我们必须传入一个mask。
让我们来看看SURF和ORB(使用不同的距离测量)的示例。
用 ORB 描述符进行蛮力匹配
在这里,我们将看到一个关于如何匹配两个图像之间的特征的简单例子。 在这种情况下,我有一个 queryImage 和 trainImage。 我们将尝试使用特征匹配来在queryImage中查找trainImage。 (图片是 /samples/c/box.png 和 /samples/c/box_in_scene.png)
我们使用ORB描述符来匹配特征。
让我们开始加载图像,找到描述符等。
import numpy as np
import cv2
import matplotlib.pyplot as plt
img1 = cv2.imread('box.png',0) # queryImage
img2 = cv2.imread('box_in_scene.png',0) # trainImage
# 初始化ORB检测器
orb = cv2.ORB_create()
# 用ORB寻找关键点和描述符
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)
接下来我们创建一个距离测量方法为cv2.NORM_HAMMING
的BFMatcher对象(因为我们使用的是ORB),为了获得更好的结果,我们将打开crossCheck
。 然后我们使用Matcher.match()
方法获得两幅图像中的最佳匹配。 我们按照距离升序对它们进行排序,以便最佳匹配(低距离)出现在前面。 然后我们只画出前10个匹配(只是为了可见性考虑。你可以随意增加这个值)。
# 创建BFMatcher对象
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
# 匹配描述符
matches = bf.match(des1,des2)
# 按照距离排序
matches = sorted(matches, key = lambda x:x.distance)
# 画出前10个匹配
img3 = cv2.drawMatches(img1,kp1,img2,kp2,matches[:10], flags=2)
plt.imshow(img3)
plt.show()
Matcher 对象是什么?
matches = bf.match(des1,des2)
这行的结果是DMatch对象的列表。 DMatch对象具有以下属性:
DMatch.distance
- 描述符之间的距离。 越低表示匹配地越好。DMatch.trainIdx
- 训练集中描述符的索引。DMatch.queryIdx
- 查询集中描述符的索引。DMatch.imgIdx
- 训练图片的索引。
用 SIFT 描述符进行蛮力匹配和比率测试
这一次,我们将使用BFMatcher.knnMatch()
来获得k个最佳匹配。 在这个例子中,我们将采取k = 2,以便我们可以应用在D.Lowe的论文中提到的比率测试。
import numpy as np
import cv2
from matplotlib import pyplot as plt
img1 = cv2.imread('box.png',0) # queryImage
img2 = cv2.imread('box_in_scene.png',0) # trainImage
# 初始化SIFT检测器
sift = cv2.SIFT()
# 用SIFT搜索关键点和描述子
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)
# 用默认的BFMatcher进行匹配
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1,des2, k=2)
# 进行比率测试
good = []
for m,n in matches:
if m.distance < 0.75*n.distance:
good.append([m])
# 用cv2.drawMatchesKnn绘制一个列表的匹配对象
img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,flags=2)
plt.imshow(img3)
plt.show()
基于 FLANN 的 Matcher
FLANN,即快速近似最邻近库。 它包含一组经过优化的算法,用于大数据集以及高维特征数据集中的快速最近邻搜索。 对于大数据集,它的工作速度比BFMatcher快。 我们将看到基于FLANN的匹配器的第二个例子。
对于基于FLANN的匹配器,我们需要传递两个字典,指定要使用的算法,相关的参数等。首先是IndexParams
。 对于各种算法,要传递的信息在FLANN文档中进行了解释。 总而言之,对于像SIFT,SURF等算法,您可以传入以下这些东西:
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
在使用ORB的时候,你可以传入下面这些值。 这些值都是文档推荐的值,但在某些情况下这些值不会提供所需的结果。 而其他值却工作正常。
FLANN_INDEX_LSH = 6
index_params= dict(algorithm = FLANN_INDEX_LSH,
table_number = 6, # 12
key_size = 12, # 20
multi_probe_level = 1) #2
第二个字典是 SearchParams
。 它指定了索引中的树应递归遍历的次数。 更高的值会提高精度,但也需要更多的时间。 如果你想改变这个值,传入 search_params = dict(checks = 100)
。
有了这些信息,我们就准备好了。
import numpy as np
import cv2
from matplotlib import pyplot as plt
img1 = cv2.imread('box.png',0) # queryImage
img2 = cv2.imread('box_in_scene.png',0) # trainImage
# 初始化SIFT检测器
sift = cv2.SIFT()
# 用SIFT找到关键点和描述符
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)
# FLANN参数
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50) # 或者传入空的字典
flann = cv2.FlannBasedMatcher(index_params,search_params)
matches = flann.knnMatch(des1,des2,k=2)
# 只需要画出好的匹配,所以创建一个mask
matchesMask = [[0,0] for i in xrange(len(matches))]
# 比率测试
for i,(m,n) in enumerate(matches):
if m.distance < 0.7*n.distance:
matchesMask[i]=[1,0]
draw_params = dict(matchColor = (0,255,0),
singlePointColor = (255,0,0),
matchesMask = matchesMask,
flags = 0)
img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,**draw_params)
plt.imshow(img3,)
plt.show()
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论