Python OpenCV特征检测之特征匹配方式详解

 更新时间:2021年12月31日 15:21:21   作者:机器视觉小学徒  
OpenCV中提供了两种技术用于特征匹配,分别为Brute-Force匹配器和基于FLANN的匹配器。本文将为大家详细介绍一下这两种匹配方式,需要的可以参考一下

前言 

获得图像的关键点后,可通过计算得到关键点的描述符。关键点描述符可用于图像的特征匹配。通常,在计算图A是否包含图B的特征区域时,将图A称做训练图像,将图B称为查询图像。图A的关键点描述符称为训练描述符,图B的关键点描述符称为查询描述符。

一、暴力匹配器

暴力匹配器使用描述符进行特征比较。在比较时,暴力匹配器首先在查询描述符中取一个关键点的描述符,将其与训练描述符中的所有关键点描述符进行比较,每次比较后会给出一个距离值,距离最小的值对应最佳匹配结果。所有描述符比较完后,匹配器返回匹配结果列表。

OpenCV的cv2.BFMatcher_create()函数用于创建暴力匹配器,其基本格式如下:

bf = cv2.BFMatcher_create([normType[, crossCheck]])

bf为返回的暴力匹配器对象

normType为距离测量类型, 默认为cv2.NORM_L2, 通常, SIFT描述符使用cv2.NORM_L1或cv2.NORM_L2, ORB描述符使用cv2.NORM_HAMMING

crossCheck默认为False, 匹配器为每个查询描述符找到k个距离最近的匹配描述符, 为True时, 只返回满足交叉验证条件的匹配结果

暴力匹配器对象的match()方法返回每个关键点的最佳匹配结果,其基本格式如下:

ms = bf.match(des1, des2)

ms为返回的结果, 它是一个DMatch对象列表, 每个DMatch对象表示关键点的一个匹配结果, 其dintance属性表示距离, 距离值越小匹配度越高

des1为查询描述符

des2为训练描述符

获得匹配结果后,可调用cv2.drawMatches()函数或cv2.drawMatchesKnn()函数绘制匹配结果图像,其基本格式如下:

outImg = cv2.drawMatches(img1, keypoints1, img2, keypoints2, matches1to2[, matchColor[, singlePointColor[, matchesMask[, flags]]]])

outImg为返回的绘制结果图像, 图像中查询图像与训练图像中匹配的关键点个两点之间的连线为彩色

img1为查询图像

keypoints1为img1的关键点

img2为训练图像

keypoints2为img2的关键点

matches1to2为img1与img2的匹配结果

matchColor为关键点和链接线的颜色, 默认使用随机颜色

singlePointColor为单个关键点的颜色, 默认使用随机颜色

matchesMask为掩膜, 用于决定绘制哪些匹配结果, 默认为空, 表示绘制所有匹配结果

flags为标志, 可设置为下列参数值:

cv2.DrawMatchesFlags_DEFAUL:默认方式, 绘制两个源图像、匹配项和单个关键点, 没有围绕关键点的圆以及关键点的大小和方向

cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS:不会绘制单个关键点

cv2.DrawMatchesFlags_DRAW_RICH_KEYPOINTS:在关键点周围绘制具有关键点大小和方向的圆圈

# 暴力匹配器、ORB描述符和match()方法
import cv2

img1 = cv2.imread("xhu1.jpg", cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread("xhu2.jpg", cv2.IMREAD_GRAYSCALE)

orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)

bf = cv2.BFMatcher_create(cv2.NORM_HAMMING, crossCheck = False)
ms = bf.match(des1, des2)
ms = sorted(ms, key = lambda x:x.distance)
img3 = cv2.drawMatches(img1, kp1, img2, kp2, ms[:20], None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)

cv2.imshow("Xhu1", img1)
cv2.imshow("Xhu2", img2)
cv2.imshow("Matches", img3)

cv2.waitKey(0)
cv2.destroyAllWindows()

# 暴力匹配器、SIFT描述符和match()方法
import cv2

img1 = cv2.imread("xhu1.jpg", cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread("xhu2.jpg", cv2.IMREAD_GRAYSCALE)

sift=cv2.SIFT_create()
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)

bf = cv2.BFMatcher_create(cv2.NORM_L1, crossCheck = False)
ms = bf.match(des1, des2)
ms = sorted(ms, key = lambda x:x.distance)
img3 = cv2.drawMatches(img1, kp1, img2, kp2, ms[:20], None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)

# ms = np.expand_dims(ms,1)
# img3 = cv2.drawMatchesKnn(img1, kp1, img2, kp2, ms[:20], None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)

cv2.imshow("Xhu1", img1)
cv2.imshow("Xhu2", img2)
cv2.imshow("Matches", img3)

cv2.waitKey(0)
cv2.destroyAllWindows()

暴力匹配器对象的knnMatch()方法可返回指定数量的最佳匹配结果,其基本格式如下:

ms = knnMatch(des1, des2, k=n)

ms为返回的匹配结果, 每个列表元素是一个子列表, 它包含了由参数k指定个数的DMatch对象

des1为查询描述符

des2为训练描述符

k为返回的最佳匹配个数

# 暴力匹配器、ORB描述符和knnMatch()方法
import cv2

img1 = cv2.imread("xhu1.jpg", cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread("xhu2.jpg", cv2.IMREAD_GRAYSCALE)

orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)

bf = cv2.BFMatcher_create(cv2.NORM_HAMMING, crossCheck = False)
ms = bf.knnMatch(des1, des2, k=2)

# 应用比例测试选择要使用的匹配结果
good = []
for m, n in ms:
    if m.distance < 0.75 * n.distance:
		good.append(m)

img3 = cv2.drawMatches(img1, kp1, img2, kp2, good[:20], None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
# good = np.expand_dims(good,1)
#img3 = cv2.drawMatchesKnn(img1, kp1, img2, kp2, good[:20], None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)

cv2.imshow("Xhu1", img1)
cv2.imshow("Xhu2", img2)
cv2.imshow("Matches", img3)


cv2.waitKey(0)
cv2.destroyAllWindows()

二、FLANN匹配器

FLANN(Fast Library for Approximate Nearest Neignbors)为近似最近邻的快速库,FLANN特征匹配算法比其它的最近邻算法更快。

在创建FLANN匹配器时,需要传递两参数:index_params和search_params。

index_params用来指定索引树的算法类型和数量。SIFT算法可以使用下面的代码来设置。

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(check = 50)
# FLANN匹配器、ORB描述符
import cv2

img1 = cv2.imread("xhu1.jpg", cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread("xhu2.jpg", cv2.IMREAD_GRAYSCALE)

orb = cv2.ORB_create()
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(check = 50)

flann = cv2.FlannBasedMatcher(index_params, search_params)
matches = flann.match(des1, des2)
draw_params = dict(matchColor = (0,255,0),
                   singlePointColor = (255,0,0),
                   matchesMask = None,
                   flags = cv2.DrawMatchesFlags_DEFAULT)

img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:20], None, **draw_params)

cv2.imshow("Xhu1", img1)
cv2.imshow("Xhu2", img2)
cv2.imshow("Matches", img3)


cv2.waitKey(0)
cv2.destroyAllWindows()

# FLANN匹配器、SIFT描述符
import cv2

img1 = cv2.imread("xhu1.jpg", cv2.IMREAD_GRAYSCALE)
img2 = cv2.imread("xhu2.jpg", cv2.IMREAD_GRAYSCALE)

sift = cv2.SIFT_create()
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(check = 50)

flann = cv2.FlannBasedMatcher(index_params, search_params)
matches = flann.match(des1, des2)
draw_params = dict(matchColor = (0,255,0),
                   singlePointColor = (255,0,0),
                   matchesMask = None,
                   flags = cv2.DrawMatchesFlags_DEFAULT)

img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:20], None, **draw_params)

cv2.imshow("Xhu1", img1)
cv2.imshow("Xhu2", img2)
cv2.imshow("Matches", img3)


cv2.waitKey(0)
cv2.destroyAllWindows()

到此这篇关于Python OpenCV特征检测之特征匹配方式详解的文章就介绍到这了,更多相关Python OpenCV特征匹配内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • python 利用百度API识别图片文字(多线程版)

    python 利用百度API识别图片文字(多线程版)

    这篇文章主要介绍了python 利用百度API识别图片文字(多线程版),帮助大家更好的利用python进行机器识别,感兴趣的朋友可以了解下
    2020-12-12
  • PyTorch中torch.manual_seed()的用法实例详解

    PyTorch中torch.manual_seed()的用法实例详解

    在Pytorch中可以通过相关随机数来生成张量,并且可以指定生成随机数的分布函数等,下面这篇文章主要给大家介绍了关于PyTorch中torch.manual_seed()用法的相关资料,需要的朋友可以参考下
    2022-06-06
  • tensorflow实现KNN识别MNIST

    tensorflow实现KNN识别MNIST

    这篇文章主要为大家详细介绍了tensorflow实现KNN识别MNIST,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-03-03
  • python requests post多层字典的方法

    python requests post多层字典的方法

    今天小编就为大家分享一篇python requests post多层字典的方法,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2018-12-12
  • Python中Jupyter notebook快捷键总结

    Python中Jupyter notebook快捷键总结

    在本篇文章里小编给大家整理的是一篇关于Python中Jupyter notebook快捷键总结内容,有兴趣的朋友们可以学习下。
    2021-04-04
  • python FTP编程基础入门

    python FTP编程基础入门

    这篇文章主要介绍了python FTP编程基础入门的的相关资料,帮助大家更好的理解和学习使用python,感兴趣的朋友可以了解下
    2021-02-02
  • Pandas DataFrame replace替换后无效的解决

    Pandas DataFrame replace替换后无效的解决

    这篇文章主要介绍了Pandas DataFrame replace替换后无效的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2023-08-08
  • python进阶教程之动态类型详解

    python进阶教程之动态类型详解

    这篇文章主要介绍了python进阶教程之动态类型详解,动态类型是动态语言的特性,本文对多种动态类型应用做了讲解,需要的朋友可以参考下
    2014-08-08
  • 基于Python实现简单的学生点名系统

    基于Python实现简单的学生点名系统

    现在的学生大部分都很积极,会主动举手回答问题。但是,也会遇到一些不好的情况,比如年级越高主动举手的人越少,所以本文做了一个随机的学生点名系统可以帮老师解决这些问题
    2022-09-09
  • 打包Python代码的常用方法小结

    打包Python代码的常用方法小结

    Python是一门强大的编程语言,但在将Python代码分享给其他人时,让他们安装Python解释器并运行脚本可能有点繁琐,这时,将Python代码打包成可执行的应用程序(.exe)可以大大简化这个过程,本文将介绍几种常用的方法,轻松地将Python代码变成独立的可执行文件
    2023-11-11

最新评论