⚠️这篇是按4.1.0翻译的,你懂得。
⚠️除了版本之外,其他还是照旧,Feature Matching + Homography to find Objects,附原文。
在这一章
在上一期里我们做了什么?我们使用一个搜索图像,找到了一些它里面的特征点,然后我们取另外一张训练图像,也找出其中的特征点,然后在找出两者之间最佳的匹配。简单的说,我们在另一张杂乱的图像中找到了一个物体的某些部分的位置。而这篇介绍的信息足以准确地在训练图像上找到目标对象。
为此,我们可以使用calib3d模块中的函数。比如 cv.findHomography()。如果我们从两张图像传入点的集合,它会算出那个物体的透视变换。然后我们可以使用 cv.perspectiveTransform() 来找到这个物体。它需要至少四个正确的点来计算变换。
我们已经看到,在匹配过程中可能会出现一些可能影响结果的错误。为了解决这个问题,算法使用RANSAC或LEAST_MEDIAN(可以由标志决定)。因此,提供正确估算结果的良好匹配称为inliers(内点、样本点),其余的称为outliers(外点、极端点、异常点、离群点)。cv.findHomography() 返回一个遮罩层,该遮罩层区分了内点和外点。
开搞!
首先,和往常一样,让我们在图像中找出SIFT特征,然后应用比率检定找出最佳匹配。
import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
MIN_MATCH_COUNT = 10
img1 = cv.imread('box.png',0) # queryImage
img2 = cv.imread('box_in_scene.png',0) # trainImage
# Initiate SIFT detector
sift = cv.xfeatures2d.SIFT_create()
# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks = 50)
flann = cv.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(des1,des2,k=2)
# store all the good matches as per Lowe's ratio test.
good = []
for m,n in matches:
if m.distance < 0.7*n.distance:
good.append(m)
现在我们设置了一个条件,即至少需要有有10个匹配项(由MIN_MATCH_COUNT定义)在其中用于查找对象。否则,只显示一条消息,说明没有足够的匹配项。
如果我们找到了足够的匹配项,我们提取了两个图像中匹配关键点的位置。它们被传入用于算出透视变换。一旦我们得到这个3x3变换矩阵,我们使用它转换查询图像中的角点,然后画出它来。
if len(good)>MIN_MATCH_COUNT:
src_pts = np.float32([ kp1[m.queryIdx].pt for m in good ]).reshape(-1,1,2)
dst_pts = np.float32([ kp2[m.trainIdx].pt for m in good ]).reshape(-1,1,2)
M, mask = cv.findHomography(src_pts, dst_pts, cv.RANSAC,5.0)
matchesMask = mask.ravel().tolist()
h,w,d = img1.shape
pts = np.float32([ [0,0],[0,h-1],[w-1,h-1],[w-1,0] ]).reshape(-1,1,2)
dst = cv.perspectiveTransform(pts,M)
img2 = cv.polylines(img2,[np.int32(dst)],True,255,3, cv.LINE_AA)
else:
print( "Not enough matches are found - {}/{}".format(len(good), MIN_MATCH_COUNT) )
matchesMask = None
最终我们画出了我们的内点(如果成功的找到了对象的话)或者匹配的关键点(如果没有找到对象的话)。
draw_params = dict(matchColor = (0,255,0), # draw matches in green color
singlePointColor = None,
matchesMask = matchesMask, # draw only inliers
flags = 2)
img3 = cv.drawMatches(img1,kp1,img2,kp2,good,None,**draw_params)
plt.imshow(img3, 'gray'),plt.show()
参见下面的结果。对象在杂乱的图像中以白色标记。
上篇:【翻译:OpenCV-Python教程】特征匹配
下篇:【翻译:OpenCV-Python教程】均值漂移和连续自适应均值漂移