opencv-python特征匹配
本章节介绍暴力特征匹配,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 = flann.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()