【OpenCV-Python】教程:4-10 特征匹配和单应性查找对象

OpenCV Python 特征匹配和单应性查找对象

【目标】

  • 结合特征匹配和单应性查找目标

【理论】

前面几节我们做了什么?我们使用queryImage,在其中找到一些特征点,我们使用另一个trainImage,也在该图像中找到特征,并在其中找到最佳匹配。简而言之,我们在另一张杂乱的图像中找到了物体的某些部分的位置。这些信息足以准确地在trainImage上找到对象。

为此,我们可以使用calib3d模块中的函数,即cv2.findHomography()。如果我们从两个图像中传递点的集合,它会找到那个物体的透视变换。然后我们可以使用cv2.perspectiveTransform()来查找对象。它需要至少四个正确的点来找到变换。

我们已经看到,在匹配时可能会有一些错误,这可能会影响结果。为了解决这个问题,算法使用RANSAC或LEAST_MEDIAN(可以由标志来决定)。因此,提供正确估计的良好匹配被称为内值,其余的被称为异常值。cv2.findHomography()返回一个掩码,该掩码指定了靠近点和离群点。

【代码】

【OpenCV-Python】教程:4-10 特征匹配和单应性查找对象_第1张图片

import numpy as np 
import cv2 
from matplotlib import pyplot as plt

# 读入图像
img1 = cv2.imread("assets/box.png", 0)
img2 = cv2.imread("assets/box_in_scene.png", 0)

# 创建SIFT
sift = cv2.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)
seach_params = dict(checks = 50)

good = []
flann = cv2.FlannBasedMatcher(index_params, seach_params)
matches = flann.knnMatch(des1, des2, k=2)
for m, n in matches:
    if m.distance < 0.7*n.distance:
        good.append(m)


# 找到映射关系
MIN_MATCH_COUNT = 10
pts__ = None 
dst__ = None 
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 = cv2.findHomography(src_pts, dst_pts, cv2.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__ = cv2.perspectiveTransform(pts__, M)
    # img2 = cv2.polylines(img2, [np.int32(dst__)], True, 255, 3, cv2.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 = cv2.drawMatches(img1, kp1, img2, kp2, good, None, **draw_params)

# 对应的点发生了偏移
shift_x = np.float32([[w-1, 0], [w-1, 0], [w-1, 0], [w-1, 0]]).reshape(-1, 1, 2)
dst2__ = np.int32(dst__ + shift_x)

# 绘制原始图像图像的位置和查找目标的位置
img3 = cv2.polylines(img3, [np.int32(pts__)], True, 
                    (0, 0, 255), 2, cv2.LINE_AA)
img3 = cv2.polylines(img3, [np.int32(dst2__)], True,
                    (0, 0, 255), 2, cv2.LINE_AA)

cv2.imshow("result", img3)
cv2.waitKey(0)
cv2.destroyAllWindows()

【接口】

  • findHomography
cv2.findHomography(	srcPoints, dstPoints[, method[, ransacReprojThreshold[, mask[, maxIters[, confidence]]]]]	) ->	retval, mask
cv2.findHomography(	srcPoints, dstPoints, params[, mask]	) ->	retval, mask

查找平面间的透视变换

  • srcPoints: 原始平面里的点,type CV_32FC2 or vector
  • dstPoints: 查找目标平面里的点,type CV_32FC2 or vector
  • method: 查找方法,可选值为:
    • 0: 常规的方法用所有的点,最小二乘法;
    • RANSAC: 基于RANSAC的鲁棒方法;
    • LMEDS: 最小中值稳健方法;
    • RHO: 基于PROSAC鲁棒方法;
  • ransacReprojThreshold: 将点对作为内线处理时允许的最大重投影误差(仅用于RANSAC和RHO方法)。如果 ∣ ∣ d s t P o i n t s i − c o n v e r t P o i n t s H o m o g e n e o u s ( H ∗ s r c P o i n t s i ) ∣ ∣ 2 > r a n s a c R e p r o j T h r e s h o l d ||dstPoints_i−convertPointsHomogeneous(H∗srcPoints_i)||_2>ransacReprojThreshold dstPointsiconvertPointsHomogeneous(HsrcPointsi)2>ransacReprojThreshold , 则点 i i i 为离群点。一般设置为1~10
  • mask: 通过鲁棒方法(RANSAC或lmed)设置的可选输出掩码。注意,输入掩码值将被忽略。
  • maxIters: RANSAC 最大迭代次数
  • confidence: 置信度层级,0~1
  • perspectiveTransform 参考如下

【OpenCV-Python】教程:3-2 几何变换(仿射变换,透视变换)_黄金旺铺的博客-CSDN博客_python根据三个点仿射变换

【参考】

  1. OpenCV: Feature Matching + Homography to find Objects

你可能感兴趣的:(#,OpenCV-Python,教程,opencv,python,计算机视觉,单应性)