sitf+LK+pnp 识别、跟踪图片,并求三维旋转角度(一) -----特征匹配

前一段时间做了个项目,就此记录下遇到的坑。网上查了很多资料,求图片在三维中的旋转角度,要么vip才能看或者收费,要么文章就是写的乱七八糟的,要么根本没写角度怎么计算的。索性我自己写吧。

转载请注明出处https://blog.csdn.net/qq_38284951/article/details/113335656

通常大佬们的增强现实使用的是slam技术,但是本人是个slam小白不懂那一套,于是通过各种渠道、资料,先去了解如何实现以图识图,以图识图很好做,有传统方法和深度学习方法。

但是为了省去以后添加一张新的识别图而重新训练的尴尬,采用了传统的opencv中自带的提取特征方法,并通过这些特征点去匹配,匹配方法有暴力匹配有flann方法,并通过匹配点

找到待识别图和原图之间的单应性矩阵的关系。具体就不详细介绍了,网上关于这些方法的介绍和详细代码一大堆,包括性能等等,我就直接上相关代码。我这里使用过orb、sift、brisk以及akaze。

sift,orb和brisk相关代码 返回单应性矩阵和匹配点,brisk, akaze是什么匹配方法我记不清了,读者可以分别进行测试下。我用了网上的一张图片进行了旋转后和原图做测试,可以看到sift的匹配效果。

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

def sift(img1,img2):
    sift = cv2.xfeatures2d.SIFT_create(nfeatures=100)#特征点数可以自行查阅opencv
    # brisk = cv2.BRISK_create()
    kp1, des1 = sift.detectAndCompute(img1, None)
    kp2, des2 = sift.detectAndCompute(img2, None)
    FLANN_INDEX_KDTREE = 1
    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)
    #筛选好的特征点
    good = []
    for m, n in matches:
        if m.distance < 0.7 * n.distance:
            good.append(m)
    #   只有好的匹配点多于  10  个才查找目标,否则显示匹配不足
    if len(good) > 10:
        #   获取匹配点在原图像和目标图像中的的位置
        # kp1  :原图像的特征点
        # m.queryIdx  :匹配点在原图像特征点中的索引
        # .pt  :特征点的坐标
        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)
        #   获取变换矩阵,采用  RANSAC  算法
        M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 4.0)
        print("mask", len(mask))
        matchesMask = mask.ravel().tolist()
    else:
        print("Not enough matches are found ",len(matches))
        matchesMask = None
    draw_params = dict(matchColor=(0, 0, 255),  # 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)
    plt.imshow(img3), plt.title('Test3'),
    plt.axis('off')
    plt.show()
    return src_pts,M

if __name__ == '__main__':
    img_1 = r"E:\workspace\yolo5\yoloV5-arcface_forlearn-master\yoloV5_arcface\inference\images\02.jpg"
    img_2 = r"E:\workspace\yolo5\yoloV5-arcface_forlearn-master\yoloV5_arcface\inference\images\03.jpg"
    img1 = cv2.imread(img_1,0)
    img2 = cv2.imread(img_2,0)
    sift(img1,img2)

orb相关代码,注释是可以看到特征点的匹配情况

def ORB(img1,img2):

    orb= cv2.ORB_create()
    kp1, des1 = orb.detectAndCompute(img1, None)
    kp2, des2 = orb.detectAndCompute(img2, None)
    bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
    matches = bf.match(des1, des2)
    # img_out = cv2.drawKeypoints(img2, kp2, img2, flags=2)
    # plt.imshow(img_out), plt.title('Test3'),
    # plt.axis('off')
    # plt.show()
    # plt.imshow(img_out)
    # matches = bf.knnMatch(des1, des2, k=1)
    #   获得匹配结果

    min_distance = matches[0].distance
    max_distance = matches[0].distance
    for x in matches:
        if x.distance < min_distance:
            min_distance = x.distance
        if x.distance > max_distance:
            max_distance = x.distance

    '''
        当描述子之间的距离大于两倍的最小距离时,认为匹配有误。
        但有时候最小距离会非常小,所以设置一个经验值30作为下限。
    '''
    matches = sorted(matches, key=lambda matches: matches.distance)
    # 准备空的掩膜 画好的匹配项
    good = []
    good_match = []
    for x in matches:
        if x.distance <= max(2 * min_distance, 20):
            good.append(x)
    if len(good) > 10:
        # Construct the two sets of points
        if isinstance(kp1[0], cv2.KeyPoint):
            src_points = np.float32([kp1[good[idx].queryIdx].pt for idx in range(len(good))])
            dst_points = np.float32([kp2[good[idx].trainIdx].pt for idx in range(len(good))])
        else:
            src_points = np.float32([kp1[good[idx].queryIdx] for idx in good])
            dst_points = np.float32([kp2[good[idx].trainIdx] for idx in good])
    #         # Compute the homography between the two sets of points and compute the ratio of matched points
            H, status = cv2.findHomography(src_points, dst_points, cv2.RANSAC, int(len(good) / 2))
    #     #matchesMask = status.ravel().tolist()
    #     src_points = np.array(src_points).reshape(-1,1,2)
    # else:
    #     print("Not enough matches are found ",len(matches), 10))
    #     matchesMask = None
    # draw_params = dict(matchColor=(0, 0, 255),  # 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)
    # plt.imshow(img3), plt.title('Test3'),
    # plt.axis('off')
    # plt.show()
    src_points = np.array(src_points).reshape(-1,1,2)
    return src_points,H

如果运行上面代码放两张图片可以看到这样的效果:

注:你会遇到sift错误,那是因为opencv对sift有版权限制,你可以pip install opencv 4.4版本。

下篇文章:sitf+LK+pnp 识别、跟踪图片,并求三维旋转角度(二) -----单应性矩阵分解,求解角度

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值