PythonOpenCV-特征检测-特征匹配
0. 简介
获得图像的关键点后,可通过计算得到关键点的描述符。
关键点描述符可用于图像的特征匹配通常,在计算图A 是否包含图 B 的特征区域时,将图A 称为训练图像,将图 B 称为查询图像。
图A的关键点描述符称为训练描述符,图 B的关键点描述符称为查询描述符。
1. 暴力匹配器
暴力匹配器使用描述符进行特征比较。在比较时,暴力匹配器首先在查询描述符中取一个关键点的描述符,将其与训练描述符中的所有关键点描述符进行比较,每次比较后会给出一个距离值,距离最小的值对应最佳匹配结果。
所有描述符比较完后,匹配器返回匹配结果列表。
OpenCV的 cv2.BFMatcher_create()函数用于创建暴力匹配器,其基本格式如下:
bf = cv2,BFMatcher_create([normType[, crossCheck]])
参数说明 :
bf:返回的暴力匹配器对象
normType:距离测量类型,默认为 CV2.NORM_L2。通常,SIFT、SURF 等描述符使用 CV2.NORM_L1 或 CV2.NORM_L2,ORB、BRISK 或 BRIEF 等描述符使用CV2.NORM_HAMMING。
crossCheck:默认为 False,匹配器为每个查询描述符找到 k 个距离最近的匹配描述符;crossCheck 为 True 时,只返回满足交叉验证条件的匹配结果。
暴力匹配器对象的 match()方法返回每个关键点的最佳匹配结果,其基本格式如下:
ms = bf.match(des1, des2)
参数说明:
ms:返回的匹配结果,它是一个 DMatch 对象列表。每个 DMatch 对象表示关键点的-个匹配结果,其 distance 属性表示距离,值越小匹配度越高
des1:查询描述符
des2:训练描述符
获得匹配结果后,可调用 cv2.drawMatches()或 cv2.drawMatchesKnn()函数绘制匹配结果图像,其基本格式如下:
outImg = cv2.drawMatches(img1, keypoints1, img2, keypoints2, matches1to2, outImg[, matchColor[,singlePointColor[, matchesMask[, flags]]]])
outImg = cv2.drawMatchesKnn(img1, keypoints1, img2, keypoints2, matches1to2, outImg[,matchColor[,singlePointColor[,matchesMask[, flags]]]])
参数说明 :
outlmg:返回的绘制结果图像,图像中查询图像与训练图像中匹配的关键点和两点之间的连线为彩色
img1:查询图像
keypoints1: img1的关键点
img2:训练图像
keypoints2: img2 的关键点
matches1to2:img1 与 img2 的匹配结果
matchColor:关键点和连接线的颜色,默认使用随机颜色
singlePointColor:单个关键点的颜色,默认使用随机颜色
matchesMask :掩模,用于决定绘制哪些匹配结果,默认为空,表示绘制所有匹配结果
flags:标志,可设置为下列参数值:
- cv2.DrawMatchesFlags_DEFAULT:默认方式,绘制两个源图像、匹配项和单个关键点,没有围绕关键点的圆以及关键点的大小和方向
- cv2.DrawMatchesFlags_DRAW_OVER_OUTIMG:根据输出图像的现有内容进行绘制
- CV2.DrawMatchesFlags NOT_DRAW_SINGLE_POINTS:不会绘制单个关键点
- CV2.DrawMatchesFlags DRAW_RICH_KEYPOINTS:在关键点周围绘制具有关键点大小和方向的圆圈
代码示例:
import cv2 as cv import matplotlib.pyplot as plt img1 = cv.imread('xhu1.jpg', cv.IMREAD_GRAYSCALE) # 打开灰度图像 img2 = cv.imread('xhu2.jpg', cv.IMREAD_GRAYSCALE) # 打开灰度图像 orb = cv.ORB_create() # 创建ORB检测器 kp1, des1 = orb.detectAndCompute(img1, None) # 检测关键点和计算描述符 kp2, des2 = orb.detectAndCompute(img2, None) # 检测关键点和计算描述符 bf = cv.BFMatcher_create(cv.NORM_HAMMING, crossCheck=True) # 创建匹配器 ms = bf.match(des1, des2) # 执行特征匹配 ms = sorted(ms, key=lambda x: x.distance) # 按距离排序 img3 = cv.drawMatches(img1, kp1, img2, kp2, ms[:20], None, flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS) # 绘制前20个匹配结果 plt.imshow(img3) plt.axis('off') plt.show()
暴力匹配器对象的 knnMatch0方法可返回指定数量的最佳匹配结果,其基本格式如下:
ms = bf.knnMatch(des1, des2, k=n)
参数说明:
ms:返回的匹配结果列表,每个列表元素是一个子列表,它包含了由参数 k 指定个数的DMatch 对象
des1:查询描述符
des2:训练描述符
k:返回的最佳匹配个数
代码示例:
import cv2 as cv import matplotlib.pyplot as plt img1 = cv.imread('xhu1.jpg', cv.IMREAD_GRAYSCALE) # 打开灰度图像 img2 = cv.imread('xhu2.jpg', cv.IMREAD_GRAYSCALE) # 打开灰度图像 orb = cv.ORB_create() # 创建ORB检测器 kp1, des1 = orb.detectAndCompute(img1, None) # 检测关键点和计算描述符 kp2, des2 = orb.detectAndCompute(img2, None) # 检测关键点和计算描述符 bf = cv.BFMatcher_create(cv.NORM_HAMMING, crossCheck=False) # 创建匹配器 ms = bf.knnMatch(des1, des2, k=2) # 执行特征匹配 # 应用比例测试选择要使用的匹配结果 good = [] for m, n in ms: if m.distance < 0.75 * n.distance: # 因为k=2,所以这里比较两个匹配结果的距离 good.append(m) img3 = cv.drawMatches(img1, kp1, img2, kp2, good[:20], None, flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS) # 绘制前20个匹配结果 plt.imshow(img3) plt.axis('off') plt.show()
3. FLANN 匹配器
FLANN为近似最近邻的快速库,FLANN 特征匹配算法比其他的最近邻算法更快
在创建 FLANN 匹配器时,需要传递两个字典参数: index_params 和search_params
index_params 用于指定索引树的算法类型和数量。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, key_size = 12, multi_probe_level = 1)
search_params 用于指定索引树的遍历次数,遍历次数越多,匹配结果越精确,通常设置为50即可:
search_params = dict(checks=50)
代码示例:
import cv2 as cv import matplotlib.pyplot as plt img1 = cv.imread('xhu1.jpg', cv.IMREAD_GRAYSCALE) # 打开灰度图像 img2 = cv.imread('xhu2.jpg', cv.IMREAD_GRAYSCALE) # 打开灰度图像 orb = cv.ORB_create() # 创建SIFT检测器 kp1, des1 = orb.detectAndCompute(img1, None) # 检测关键点和计算描述符 kp2, des2 = orb.detectAndCompute(img2, None) # 检测关键点和计算描述符 # 定义FLANN参数 FLANN_INDEX_LSH = 6 index_params = dict(algorithm=FLANN_INDEX_LSH, table_number=6, key_size=12, multi_probe_level=1) search_params = dict(checks=50) flann = cv.FlannBasedMatcher(index_params, search_params) # 创建FLANN匹配器 matches = flann.match(des1, des2) # 执行匹配操作 draw_params = dict(matchColor=(0, 255, 0), # 关键点和连接线为绿色 singlePointColor=(255, 0, 0), # 单个点为红色 matchesMask=None, flags=cv.DrawMatchesFlags_DEFAULT) # 绘制匹配结果 img3 = cv.drawMatches(img1, kp1, img2, kp2, matches[:20], None, **draw_params) plt.imshow(img3) plt.axis('off') plt.show() # 显示结果
/*-------------------------------------------------------------------------------------------------------
笔者说明:
该笔记来源于本人学习Python + OpenCv时的资料,
分享出来只是为了供大家学习,并且为了自己以后想要用的时候方便寻找。
时间:2023年9月3日
------------------------------------------------------------------------------------------------------------*/