opencv-python特征匹配

发布时间 2023-08-08 22:41:52作者: 寒水浮云

本章节介绍暴力特征匹配,FLANN特征匹配等。

根据前面章节获取的图像特征点和描述子之后,可以将两幅图像进行特征匹配。

1 暴力特征匹配

通过枚举的方式进行特征匹配,使用第一幅图像中一个特征的描述子,并使用一些距离计算将其与第二幅图像中的所有其他特征匹配,返回最近的一个。

opencv中提供的函数是:BFMatcher(normType,crossCheck) 

normType表示计算距离的方式(L1距离,即绝对值;L2距离,即平方;汉明距离,ORB使用)

crossCheck:是否进行交叉匹配,默认false


然后使用match函数进行特征点匹配,返回的对象是DMatch对象,该对象具有以下属性:
DMatch.distance 描述符之间的距离,越小越好。
DMatch.trainIdx 训练描述符(第二幅图的)中描述符的索引。
DMatch.queryIdx 查询描述符(第一幅图的)中描述符的索引。

DMatch.imgIdx 训练图像的索引。

最后用 drawMatches 绘制匹配的特征点。( drawMatches(img1, keypoints1, img2, keypoints2, matches1to2, outImg) )

使用暴力特征匹配对下面两幅图像的特征进行匹配:

   

import cv2
import numpy as np 

img1 = cv2.imread('./crop.png')
img2 = cv2.imread('./contours.png')

img_gray1 = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
img_gray2 = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)

#创建特征检测对象
sift = cv2.xfeatures2d.SIFT_create()

#检测关键点和计算描述子
kp1,des1 = sift.detectAndCompute(img1,None)
kp2,des2 = sift.detectAndCompute(img2,None)

#进行暴力匹配
bf = cv2.BFMatcher(cv2.NORM_L2)

#进行匹配
match = bf.match(des1,des2)  #match(queryDescriptors,trainDescriptors)

print(len(match))
print(type(match))
print(match[2].distance) #match[2]的描述符之间的距离
print('queryIdx:',match[2].queryIdx) #第一幅图的匹配的第三个特征点的索引
print('zuobiao1:',kp1[match[2].queryIdx].pt) ##第一幅图的匹配的第三个特征点的坐标

print('trainIdx:',match[2].trainIdx)  #第二幅图的匹配的第三个特征点的索引
print('zuobiao2:',kp2[match[2].trainIdx].pt) ##第二幅图的匹配的第三个特征点的坐标

#绘制特征匹配
res = cv2.drawMatches(img1,kp1,img2,kp2,match,None)

cv2.imshow('res',res)
cv2.waitKey(0)
cv2.destroyAllWindows()

 匹配结果如下:

匹配的时候除了使用match函数进行匹配,也可以用knnmatch进行匹配(knn:最近邻算法)。

import cv2
import numpy as np   #用knnmatch进行匹配

img1 = cv2.imread('./crop.png')
img2 = cv2.imread('./contours.png')

img_gray1 = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
img_gray2 = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)

#创建特征检测对象
sift = cv2.xfeatures2d.SIFT_create()

#检测关键点和计算描述子
kp1,des1 = sift.detectAndCompute(img1,None)
kp2,des2 = sift.detectAndCompute(img2,None)

#进行暴力匹配
bf = cv2.BFMatcher(cv2.NORM_L2)

#进行匹配
#match = bf.match(des1,des2)  #match(queryDescriptors,trainDescriptors)
match = bf.knnMatch(des1,des2,k=2) #处理match进行匹配,还可以用knnmatch进行匹配,一般k=2

good = [] #选择两个匹配对象中好一些的保存下来
for m,n in match:
    if m.distance < n.distance*0.7: #设定阈值,距离小于对方的0.7倍,认为是好的匹配点
        good.append(m)

print('match:',len(match))
print('good match:',len(good))
print(type(match))
print(match)


#绘制特征匹配
#res = cv2.drawMatches(img1,kp1,img2,kp2,match,None)
res = cv2.drawMatchesKnn(img1,kp1,img2,kp2,[good],None)  #knn绘制特征匹配

cv2.imshow('res',res)
cv2.waitKey(0)
cv2.destroyAllWindows()

2 FLANN 特征匹配

FLANN 是快速最近邻搜索包,特征匹配记录下目标图像和待匹配图像的特征点(keypoint),并根据特征点集合构造特征量(descriptor),对这个特征量进行比较,筛选,最终得到一个匹配点的映射集合,可以根据这个集合的大小来衡量两幅图像的匹配程度。在面对大数据集的时候效果要好于BFmatch算法。
FLANN特征匹配的函数是:FlannBasedMatcher(index_params, search_params) 

import cv2
import numpy as np 

img1 = cv2.imread('./crop.png')
img2 = cv2.imread('./contours.png')

img_gray1 = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
img_gray2 = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)

#创建特征检测对象
sift = cv2.xfeatures2d.SIFT_create()

#检测关键点和计算描述子
kp1,des1 = sift.detectAndCompute(img1,None)
kp2,des2 = sift.detectAndCompute(img2,None)

#创建FLANN特征匹配对象
index_params = dict(algorithm=1,tree=5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params,search_params)

#进行特征匹配
matches = flann.match(des1,des2)

print(len(matches))

#绘制特征匹配
res = cv2.drawMatches(img1,kp1,img2,kp2,matches,None)

cv2.imshow('res',res)
cv2.waitKey(0)
cv2.destroyAllWindows()

FLANN 特征匹配结果如下:

用knnmatch来进行匹配:

import cv2
import numpy as np 

img1 = cv2.imread('./crop.png')
img2 = cv2.imread('./contours.png')

img_gray1 = cv2.cvtColor(img1,cv2.COLOR_BGR2GRAY)
img_gray2 = cv2.cvtColor(img2,cv2.COLOR_BGR2GRAY)

#创建特征检测对象
sift = cv2.xfeatures2d.SIFT_create()

#检测关键点和计算描述子
kp1,des1 = sift.detectAndCompute(img1,None)
kp2,des2 = sift.detectAndCompute(img2,None)

#创建FLANN特征匹配对象
index_params = dict(algorithm=1,tree=5)
search_params = dict(checks=50)
flann = cv2.FlannBasedMatcher(index_params,search_params)

#进行特征匹配
# matches = flann.match(des1,des2)

match = bf.knnMatch(des1,des2,k=2) #处理match进行匹配,还可以用knnmatch进行匹配,一般k=2

good = [] #选择两个匹配对象中好一些的保存下来
for m,n in match:
    if m.distance < n.distance*0.7: #设定阈值,距离小于对方的0.7倍,认为是好的匹配点
        good.append(m)

# print(len(matches))


res = cv2.drawMatchesKnn(img1,kp1,img2,kp2,[good],None)  #knn绘制特征匹配

cv2.imshow('res',res)
cv2.waitKey(0)
cv2.destroyAllWindows()