OpenCV系列之特征匹配+单应性查找对象 | 四十五

目标在本章节中,
我们将把calib3d模块中的特征匹配和findhomography混合在一起,以在复杂图像中找到已知对象
基础
那么我们在上一环节上做了什么?我们使用了queryimage,找到了其中的一些特征点,我们使用了另一个trainimage,也找到了该图像中的特征,并且找到了其中的最佳匹配。简而言之,我们在另一个混乱的图像中找到了对象某些部分的位置。此信息足以在trainimage上准确找到对象。
为此,我们可以使用calib3d模块中的函数,即cv.findhomography()。如果我们从两个图像中传递点集,它将找到该对象的透视变换。然后,我们可以使用cv.perspectivetransform()查找对象。找到转换至少需要四个正确的点。
我们已经看到,匹配时可能会出现一些可能影响结果的错误。为了解决这个问题,算法使用ransac或least_median(可以由标志决定)。因此,提供正确估计的良好匹配称为“内部点”,其余的称为“外部点”。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)          # 索引图像
img2 = cv.imread('box_in_scene.png',0) # 训练图像
# 初始化sift检测器
sift = cv.xfeatures2d.sift_create()
# 用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)
# #根据lowe的比率测试存储所有符合条件的匹配项。
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), # 用绿色绘制匹配
                  singlepointcolor = none,
                  matchesmask = matchesmask, # 只绘制内部点
                  flags = 2)
img3 = cv.drawmatches(img1,kp1,img2,kp2,good,none,**draw_params)
plt.imshow(img3, 'gray'),plt.show()
请参阅下面的结果。对象在混乱的图像中标记为白色:
☆☆☆为方便大家查阅,小编已将opencv-python专栏文章统一整理到公众号底部菜单栏,同步更新中,关注公众号,点击左下方“文章”,如图:或点击下方“阅读原文”,进入opencv-python专栏,即可查看系列文章。
   不断更新资源
   获取更多精彩
长按二维码扫码关注