OpenCV Python 特征匹配
【目标】
- 特征匹配
- Brute-Force Matcher 和 FLANN Matcher
【理论】
Brute-Force Matcher字面意思是蛮力匹配器,所以它的过程也很简单,从一个集合里取出一个特征描述子,然后与第二个集合里的特征逐个的进行匹配比较。返回最近的一个。
对于BF matcher,首先我们必须使用cv.BFMatcher()创建BFMatcher对象。它接受两个可选参数。第一个是normType。它指定了要使用的距离测量。默认为cv.NORM_L2。对于 SIFT 和 SURF 来说很好。对于基于二进制字符串的描述符,如ORB, BRIEF, BRISK等等,应该使用NORM_HAMMING,它使用汉明距离作为度量。如果ORB使用WTA_K == 3或4,
第二个参数是布尔变量,crossCheck默认为false。如果为真,Matcher只返回值为(i,j)的匹配,这样集合A中的第i个描述符与集合B中的第j个描述符是最佳匹配,反之亦然。也就是说,两个集合中的两个特征应该相互匹配。该方法可较好地替代D.Lowe在SIFT论文中提出的比值检验方法。
创建后,有两个重要的方法是BFMatcher.match()和BFMatcher.knnMatch()。第一个返回最佳匹配。第二个方法返回k个用户指定的最佳匹配项。当我们需要做额外的工作时,它可能会有用。
就像我们使用 cv2.drawKeypoints 绘制关键点一样,cv2.drawMatches 绘制匹配点。它将两张图像水平堆叠,并从第一张图像连接到第二张图像,以显示最佳匹配。
【代码】
- ORB 特征及 bf matcher
# ORB 特征及 bf matcher
import numpy as np
import cv2
import matplotlib.pyplot as plt
img1 = cv2.imread("assets/box.png", 0)
img2 = cv2.imread("assets/box_in_scene.png", 0)
# 创建 ORB 对象
orb = cv2.ORB_create()
# 检测关键点并计算特征
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)
# 创建匹配器
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
# 匹配
matchs = bf.match(des1, des2)
# 排序
matchs = sorted(matchs, key=lambda x: x.distance)
# 绘制匹配结果
img_res = cv2.drawMatches(img1, kp1, img2, kp2, matchs[:15], None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
cv2.imshow("orb-bfmatches", img_res)
cv2.waitKey(0)
cv2.destroyAllWindows()
- SIFT 和 bf knn matcher
# SIFT 和 bf knn matcher
import numpy as np
import cv2
img1 = cv2.imread("assets/box.png", 0)
img2 = cv2.imread("assets/box_in_scene.png", 0)
sift = cv2.SIFT_create()
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1, des2, k=2)
good = []
for m, n in matches:
if m.distance < 0.5*n.distance:
good.append([m])
img_res = cv2.drawMatchesKnn(img1, kp1, img2, kp2, good,
None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
cv2.imshow("sift-bfknnmatches", img_res)
cv2.waitKey(0)
cv2.destroyAllWindows()
- sift FLANN matcher
# sift FLANN matcher
import numpy as np
import cv2
img1 = cv2.imread("assets/box.png", 0)
img2 = cv2.imread("assets/box_in_scene.png", 0)
# 初始化创建
sift = cv2.SIFT_create()
# 关键点检测和特征计算
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)
# FLANN parameters
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
search_params = dict(checks=50) # or pass empty dictionary
flann = cv2.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(des1, des2, k=2)
# Need to draw only good matches, so create a mask
matchesMask = [[0, 0] for i in range(len(matches))]
# ratio test as per Lowe's paper
for i, (m, n) in enumerate(matches):
if m.distance < 0.5*n.distance:
matchesMask[i] = [1, 0]
draw_params = dict(matchColor=(0, 255, 0),
singlePointColor=(255, 0, 0),
matchesMask=matchesMask,
flags=cv2.DrawMatchesFlags_DEFAULT)
img3 = cv2.drawMatchesKnn(img1, kp1, img2, kp2, matches, None, **draw_params)
cv2.imshow("sift-flannmatches", img3)
cv2.waitKey(0)
cv2.destroyAllWindows()
【接口】
- BFMatcher
cv2.BFMatcher( [, normType[, crossCheck]] ) -> <BFMatcher object>
- normType: NORM_L1, NORM_L2, NORM_HAMMING, NORM_HAMMING2; L1和L2是SIFT和SURF描述符使用,ORB,BRISK和BRIEF使用,NORM_HAMMING2 是 ORB 中 WTA_K==3或4时使用。
- crossCheck: 如果为 false, 默认的 BFMatcher 返回 k 最近邻的匹配描述符,如果为真,并且 k=1时,返回的匹配对
cv2.drawMatches( img1, keypoints1, img2, keypoints2, matches1to2, outImg[, matchColor[, singlePointColor[, matchesMask[, flags]]]] ) -> outImg
cv2.drawMatches( img1, keypoints1, img2, keypoints2, matches1to2, outImg, matchesThickness[, matchColor[, singlePointColor[, matchesMask[, flags]]]] ) -> outImg
cv2.drawMatchesKnn( img1, keypoints1, img2, keypoints2, matches1to2, outImg[, matchColor[, singlePointColor[, matchesMask[, flags]]]] ) -> outImg
绘制两幅图像中的匹配的点。
- img1: 第一幅图像
- keypoints1: 第一幅图像中的关键点
- img2: 第二幅图像
- keypoints2: 第二幅图像中的关键点
- matches1to2: 第一幅图像和第二幅图像中匹配的描述符
- outImg: 绘制结果的图像
- matchColor: 绘制匹配点的颜色,如果 matchColor==Scalar::all(-1) 则颜色随机生成
- singlePointColor: 绘制单个匹配点的颜色,如果 singlePointColor==Scalar::all(-1) 则颜色随机生成
- matchesMask: 如果为空,绘制所有;
- flags: 绘制特征的标识符 DrawMatchesFlags.
- DrawMatchesFlags
【参考】
- OpenCV: Feature Matching