[特征提取与匹配]基于Open CV使用SIFT提取特征,并使用FLANN完成单应性匹配

关于单应性

单应性:当一张图是另一张图的一个透视畸变时,在两张图中寻找彼此的一种情况

实现步骤

  1. 导入需要的库;
  2. 读取两张灰度图像作为匹配对象;
  3. 创建SIFT对象,用于检测SIFT特征点并计算描述子;
  4. 在两张图像中分别检测SIFT特征点,并计算每个特征点的描述子,即将其转换为若干长度固定的向量;
  5. 自定义参数执行基于FLANN的匹配。FLANN是一种快速最近邻搜索算法,可以在高维空间中快速搜索最相似的数据点。这里指定使用FLANN索引类型为KDTREE,并指定树的数量为5;
  6. 指定搜索参数,其中checks表示执行检查或者遍历的次数。checks越大,可以提供的精度也就越高,但是计算成本也就更高;
  7. 使用FlannBasedMatcher对象对两组SIFT描述子之间进行k近邻匹配,返回值为列表的列表,每个内部列表至少包含一个匹配项,且不超过k个匹配项,各匹配项从最佳(最短距离)到最差依次排序;
  8. 应用乘数为0.7的劳氏比率检验,剔除不稳定的匹配对。这是一种基于距离比值来剔除不稳定匹配对的方法,可以排除掉一些明显不合理的匹配对;
  9. 至少需要10个好的匹配点才能进行透视变换;
  10. 将good_matches中的特征点转换为numpy数组形式,并重塑为三维形式;
  11. 寻找单应性,计算变换矩阵M和掩模mask。cv2.findHomography方法可以将源图像中的四边形映射到目标图像中的四边形,从而计算出变换矩阵。其中RANSAC算法是一种随机抽样一致性算法,用于估计基础矩阵或单应性矩阵等模型参数;
  12. 在图像img1中绘制所有与img0匹配的线段。通过透视变换,可以将img0的四个角映射到img1中,并计算出新的四个角坐标dst_corners;
  13. 在图像img1中绘制由两个点(x0, y0)和(x1, y1)组成的线段,颜色为白色,粗细为3。这里使用cv2.line方法绘制线段;
  14. 显示绘制结果。

Code

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

MIN_NUM_GOOD_MATCHES = 10

img0 = cv2.imread('other/B11643_6_15.png',
                  cv2.IMREAD_GRAYSCALE)
img1 = cv2.imread('other/B11643_6_16.png',
                  cv2.IMREAD_GRAYSCALE)

cv2.imshow("result", img0)
cv2.waitKey()

# Perform SIFT feature detection and description.
sift = cv2.xfeatures2d.SIFT_create()
kp0, des0 = sift.detectAndCompute(img0, None)
kp1, des1 = sift.detectAndCompute(img1, None)

# Define FLANN-based matching parameters.
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5)
search_params = dict(checks=50)

# Perform FLANN-based matching.
flann = cv2.FlannBasedMatcher(index_params, search_params)
matches = flann.knnMatch(des0, des1, k=2)

# Find all the good matches as per Lowe's ratio test.
good_matches = []
for m, n in matches:
    if m.distance < 0.7 * n.distance:
        good_matches.append(m)

if len(good_matches) >= MIN_NUM_GOOD_MATCHES:
    src_pts = np.float32(
        [kp0[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)
    dst_pts = np.float32(
        [kp1[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)

    M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
    mask_matches = mask.ravel().tolist()

    h, w = img0.shape
    src_corners = np.float32(
        [[0, 0], [0, h-1], [w-1, h-1], [w-1, 0]]).reshape(-1, 1, 2)
    dst_corners = cv2.perspectiveTransform(src_corners, M)
    dst_corners = dst_corners.astype(np.int32)

    # Draw the bounds of the matched region based on the homography.
    num_corners = len(dst_corners)
    for i in range(num_corners):
        x0, y0 = dst_corners[i][0]
        if i == num_corners - 1:
            next_i = 0
        else:
            next_i = i + 1
        x1, y1 = dst_corners[next_i][0]
        cv2.line(img1, (x0, y0), (x1, y1), 255, 3, cv2.LINE_AA)

    # Draw the matches that passed the ratio test.
    img_matches = cv2.drawMatches(
        img0, kp0, img1, kp1, good_matches, None,
        matchColor=(0, 255, 0), singlePointColor=None,
        matchesMask=mask_matches, flags=2)

    # Show the homography and good matches.
    plt.imshow(img_matches)
    plt.show()
else:
    print("Not enough matches good were found - %d/%d" % \
          (len(good_matches), MIN_NUM_GOOD_MATCHES))

输出

[特征提取与匹配]基于Open CV使用SIFT提取特征,并使用FLANN完成单应性匹配_第1张图片

你可能感兴趣的:(机器学习,计算机视觉,python,机器学习,计算机视觉)