OpenCV学习笔记-单应性查找对象

我们使用一个查询图像,在其中找到一些特征点(关键点),我们又在另一幅图像中也找到了一些特征点,最后对这两幅图像之间的特征点进行匹配。简单来说就是:我们在一张杂乱的图像中找到了一个对象(的某些部分)的位置。这些信息足以帮助我们在目标图像中准确的找到(查询图像)对象。

为了达到这个目的我们可以使用calib3d模块中的cv.findHomography()函数。如果将这两幅图像中的特征点集传给这个函数,它就会找到这个对象的透视图变换。然后我们就可以使用函数cv.perspectiveTransform()找个对象了。至少要4个正确的点才能找到这种变换。

我们已经知道在匹配过程可能会有一些错误,而这些错误会影响最终结果。为了解决这个问题,算法使用RANSAC和LEAST_MEDIAN(可以通过参数来设定)。所有好的匹配提供的正确的估计被称为inliers,剩下的被称为outliers。cv.findHomography()会返回一个掩模,这个掩模确定了inlier和outlier点。

具体代码:
import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt

img1 = cv.imread('img/box.png', 0)
img2 = cv.imread('img/box_in_scene.png', 0)

MIN_MATCH_COUNT = 10

sift = cv.xfeatures2d.SIFT_create()
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)

FLANN_INDEX_KDTREE = 0
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)

good = []
for m,n in matches:
    if m.distance < 0.7 * n.distance:
        good.append(m)
'''
现在我们设置只有存在10个以上匹匹配时才去查找目标( MIN_MATCH_COUNT=10),否则显示警告消息:“现在匹配不足”  

如果找到了足够的匹配,我们提取两幅图像中匹配点的坐标。把它们传入到函数中计算透视变换。一旦我们找到 3x3 的变换矩阵,
就可以使用它将查询图像的四个顶点( 四个角)变换到目标图像中去了。然后再绘制出来。
'''
if len(good) > MIN_MATCH_COUNT:
    #获取关键点的坐标
    src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2) # queryIdx
    dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2) # trainIdx

    #第三个参数 Method used to computed a homography matrix. The following methods are possible:
    #0 - a regular method using all the points
    #CV_RANSAC - RANSAC-based robust method
    #CV_LMEDS - Least-Median robust method
    #第四个参数取值范围在1-10,拒绝一个点对的阈值。原图像的点经过变换后点与目标图像上对应点的误差
    #超过误差就认为是outlier
    #返回值中 M 是变换矩阵
    M, mask = cv.findHomography(src_pts, dst_pts, cv.RANSAC, 5.0)
    matchesMask = mask.ravel().tolist()
    #获得原图像的高和宽
    h, w = 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 - %d/%d' % (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)


cv.namedWindow('img',cv.WINDOW_AUTOSIZE)
cv.imshow('img',img3)
cv.waitKey(0)
cv.destroyAllWindows()

OpenCV学习笔记-单应性查找对象