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()