【笔记】基于Open CV使用SIFT提取特征,并使用FLANN完成单应性匹配

本文转载于:https://blog.csdn.net/qq_44491709/article/details/130401645

一,关于单应性

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

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

二,实现

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

三,效果

在这里插入图片描述

————————————————
版权声明:本文为CSDN博主「NBA首席形象大使阿坤」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/qq_44491709/article/details/130401645

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值