sift+flann(kd-tree)+RANSAC 进行图像匹配

发布时间 2023-10-23 16:42:43作者: 皮五辣子

python 3.7.11

opencv3.4.2.16

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


def img_match_first(src,dst):
    # sift特征提取
    sift = cv2.xfeatures2d.SIFT_create()
    kp1, des1 = sift.detectAndCompute(src, None)
    kp2, des2 = sift.detectAndCompute(dst, None)
    # FLANN最近邻匹配
    flann_index_kdtree = 0
    index_params = dict(algorithm=flann_index_kdtree, trees=5)
    search_params = dict(checks=50)

    flann = cv2.FlannBasedMatcher(index_params, search_params)
    matches = flann.knnMatch(des1, des2, k=2)

    #  Lowe's ratio test 算法
    good = []
    for m, n in matches:
        if m.distance <0.7 * n.distance:
            good.append(m)
    print('第一次,ratioWithNoRansac', len(good) / len(matches))
    inLiner = 0
    if len(good) > 10:
        src_pts = np.float32([kp1[i.queryIdx].pt for i in good]).reshape(-1, 1, 2)  #将所有好的匹配的对应点的坐标存储下来
        dst_pts = np.float32([kp2[i.trainIdx].pt for i in good]).reshape(-1, 1, 2)  #将所有好的匹配的对应点的坐标存储下来
ransacReprojThreshold = 10.0
        M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, ransacReprojThreshold) #计算变化矩阵和mask
        matchesMask = mask.ravel().tolist()

        for i in range(len(matchesMask)):
            if matchesMask[i] == 1:
                inLiner += 1

        ratio = inLiner / len(matchesMask)
        print('第一次,足够好的好点数量:', inLiner, '好点数量:', len(matchesMask), '匹配率:', ratio)
        imgOut = cv2.warpPerspective(dst, M, (src.shape[1],src.shape[0]),flags=cv2.INTER_LINEAR + cv2.WARP_INVERSE_MAP)
        return imgOut
    else:
        return None
def img_match_second(img1,img2):
    # sift特征提取
    sift = cv2.xfeatures2d.SIFT_create()
    kp1, des1 = sift.detectAndCompute(img1, None)
    kp2, des2 = sift.detectAndCompute(img2, None)

    # FLANN最近邻匹配
    flann_index_kdtree = 0
    index_params = dict(algorithm=flann_index_kdtree, trees=5)
    search_params = dict(checks=50)

    flann = cv2.FlannBasedMatcher(index_params, search_params)
    matches = flann.knnMatch(des1, des2, k=2)

    #  Lowe's ratio test 算法
    good = []
    for m, n in matches:
        if m.distance < 0.7 * n.distance:
            good.append(m)

    print('ratioWithNoRansac',len(good)/len(matches))
    # ransac 随机抽样一直过滤
    min_match_count = 10  # ransac阈值,期望匹配的好点最低数目 (根据项目判断)
    inLiner = 0  # 符合ransac算法变换矩阵的好点
    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: 3x3 变换矩阵.
        M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
        matchesMask = mask.ravel().tolist()

        for i in range(len(matchesMask)):
            if matchesMask[i] == 1:
                inLiner += 1

        ratio = inLiner / len(matchesMask)
        print('第二次,足够好的好点数量:', inLiner, '好点数量:', len(matchesMask), '匹配率:', ratio)

        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)
        plt.show()
    else:
        # 没有足够多的好点可以认为直接不匹配
        print("第二次,好点匹配数量不够多 - %d/%d" % (len(good), min_match_count))
        matchesMask = None
if __name__ == "__main__":
    # 图片读取
    img1 = cv2.imread('1.jpg', 0)
    img2 = cv2.imread('2.jpg', 0)
    img_match_second(img1, img_match_first(img1, img2))