Opencv之特征匹配

Brute-Force 蛮力匹配

1、导入需要的库

import cv2 
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

2、定义绘图函数

def cv_show(name,img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

3、读入需要进行匹配的两张图片

img1 = cv2.imread('box.png', 0)
img2 = cv2.imread('box_in_scene.png', 0)
cv_show('img1',img1)
cv_show('img2',img2)

展示图片:
在这里插入图片描述在这里插入图片描述

4、实例化SIFT函数

sift = cv2.xfeatures2d.SIFT_create()

5、检测特征点并计算特征

kp1, des1 = sift.detectAndCompute(img1, None)
print(np.array(kp1).shape)
print(np.array(des1).shape)
kp2, des2 = sift.detectAndCompute(img2, None)
print(np.array(kp2).shape)
print(np.array(des2).shape)

可以得到结果:img1中有603个特征点,img2中有969个特征点,因为从img1和img2本身的图像来看,img2中是包含img1的,所以进行特征匹配的时候只会匹配img1和img2共有的603个特征点。
ps:当然,这里也可以分开来做,即先检测特征点再计算特征。即:

kp1 = sift.detect(img1, None)
kp2 = sift.detect(img2, None)
kp1, des1 = sift.compute(img1, kp1)
kp2, des2 = sift.compute(img2, kp2)

6、进行BF匹配

此时,情况应分成进行1对1的匹配还是k对最佳匹配。

1对1匹配

创建BF匹配器对象

函数介绍:
cv2.BFMatcher(normType=cv2.NORM_L2, crossCheck=True)

传入参数:

  • normType:指定要使用的距离量度。默认是cv2.NORM_L2。适用于SIFT和SURF特征。对于二进制字符串的描述子,比如ORB,BRIEF,BRISK等,应该用cv2.NORM_HAMMING。使用Hamming距离度量,如果ORB使用VTA_K == 3或者4,应该用cv2.NORM_HAMMING2。
  • crossCheck:表示两个特征点要互相匹配,例如A中的第i个特征点与B中的第j个特征点最近的,并且B中的第j个特征点到A中的第i个特征点也是。当BF匹配器对象创建以后,两个重要的方法是BFMatcher.match()和BFMatcher.knnMatch()。第一个返回最匹配的,crossCheck=True,第二个方法返回k个最匹配的,k由用户指定,此时crossCheck=False。
bf = cv2.BFMatcher(normType=cv2.NORM_L2, crossCheck=True)
进行匹配操作

函数介绍:
bf.match(des1, des2)

输出:
DMatch类型的数据结构。

那么这个这个DMatch数据结构究竟是什么呢?
它包含三个非常重要的数据分别是queryIdx,trainIdx,distance。

  • queryIdx:此匹配对应的测试图像的特征描述子索引(第几个特征点描述符)。即DMatch.queryIdx表示一个测试图像中的特征点。对于一个特征点来说,它本身也具有以下属性:.pt:关键点坐标,.angle:表示关键点方向,.response表示响应强度,.size:表示该点的直径大小。
  • trainIdx:此匹配对应的训练(模板)图像的特征描述子索引(第几个特征点描述符)。即DMatch.trainIdx表示一个训练(模板)图像中的特征点。同样地,对于一个特征点来说,它本身也具有以下属性:.pt:关键点坐标,.angle:表示关键点方向,.response表示响应强度,.size:表示该点的直径大小。
  • distance:代表这对匹配的特征点描述符的欧式距离,数值越小也就说明俩个特征点越相近。即DMatch.distance表示一个距离。
matches = bf.match(des1, des2)
找出最匹配的十个特征点并将它们用线连起来

函数介绍:
cv2.drawMatches(imageA, kpsA, imageB, kpsB, matches[:10], None, flags=2)

传入参数:

  • imageA和imageB表示图片。
  • kpsA和kpsB表示关键点。
  • matches表示进过cv2.BFMatcher获得的匹配的索引值,也有距离。
  • flags表示有几个图像。
matches = sorted(matches, key=lambda x: x.distance)
img3 = cv2.drawMatches(img1, kp1, img2, kp2, matches[:10], None,flags=2)
cv_show('img3',img3)

得到结果:
在这里插入图片描述

k对最佳匹配

k对最佳匹配是指,每一个特征点在另一张图片上都会有k个最匹配的点存在,例如k=2,它会给每个特征点画两根匹配线。
实现方法与1对1匹配大同小异。

创建BF匹配器对象

注意,此时,crossCheck=False(默认)

bf = cv2.BFMatcher()
进行匹配操作

函数介绍:
bf.knnMatch(des1, des2, k=2)

输出:
Knnmatch与match的返回值类型一样,都是DMatch类型的数据结构,只不过一组返回的k(此处=2)个DMatch类型。

matches = bf.knnMatch(des1, des2, k=2)
找出匹配的特征点并将它们用线连起来

在这里,每一个特征点(设为A)都有最匹配的另外两个特征点在另一张图上,设为B和C。其中AB的距离最短,AC的距离次短。
那么规定,如果AB间的距离小于AC间距离的0.75倍,则认为AB的匹配度远远大于A与其他任何点的匹配度,则将AB两点连起来。

good = []
for m, n in matches:
    if m.distance < 0.75 * n.distance:
        good.append([m])
img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2)
cv_show('img3',img3)

得到结果:
在这里插入图片描述

  • 4
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

cofisher

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值