RANSAC+SIFT影像特征匹配(python-opencv)

文章讲述了使用OpenCV中的SIFT特征检测和BFMatcher进行图像匹配,然后通过粗筛和RANSAC算法进行精确匹配,以减少误匹配的过程。
摘要由CSDN通过智能技术生成

首先读入图片

import cv2
import numpy as np

img1=cv2.imread("./picture1/picture1/1/14x00424.JPG")
img2=cv2.imread("./picture1/picture1/1/14x00425.JPG")

然后识别影像特征点及其特征点描述子

sift = cv2.SIFT_create(1000)

kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)

构建匹配器,执行KNN匹配。

bf=cv2.BFMatcher()

matches = bf.knnMatch(des1,des2,k=2)
"""
这里有个大坑,当你想这里直接画出所有的匹配时,
这里面的matches返回的是最近距离和次近距离的两个Dmacther元组。
如下图,直接用drawMatches函数时,matches1 to matches2就会是含有两个值的元组,然后出现BUG。
"""

但是在后续粗匹配时,我们又需要最近邻次距离之比做粗匹配筛选错点。如果不需要,建议直接用matches直接做暴力匹配。

但是,为了同时对比未筛选匹配和粗筛之后的匹配,我这里直接在近次邻中提取了最近距离。

# 画出暴力匹配初步匹配后的所有匹配
matches1=[]
for i in matches:
    matches1.append(i[0])
img_matches=cv2.drawMatches(img1,kp1,img2,kp2,matches1,None,flags=2)

然后根据最近邻次比做粗筛,画出粗筛之后的匹配。

good_matches=[]
for m,n in matches:
    if m.distance < 0.7 * n.distance:
        good_matches.append(m)
img_good_matches=cv2.drawMatches(img1,kp1,img2,kp2,good_matches, None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)

仔细观察依旧存在很多误匹配的点。 

这时,我们采用RANSAC算法进行最后的精匹配。 

MIN_MATCH_COUNT = 10
if len(good_matches)>MIN_MATCH_COUNT:
    src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)
    dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)
    M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 4.0)
    matchesMask = mask.ravel().tolist()
    ransac = []
    for i in range(0,len(matchesMask)):
        if matchesMask[i]==1:
            # print(i)
            ransac.append(good_matches[i])  #单独取出内点
            print(ransac)
"""
这里的cv2.findHomography()返回值有两个.
第一个是变换所需要的单应矩阵M,
第二个返回的是一个掩膜值mask,这个掩模确定了RANSAC算法筛选之后的内点和外点。

"""

可以发现这个掩膜的值为0或者1,掩膜通常是一个与原始图像大小相同的二值或布尔图像,其中,选定的区域被标记为1(或True),而其余区域被标记为0(或False)。也就是值为1所对应的good_matches是筛选之后的内点。

最后输出精匹配的成果图即可。

完整代码如下: 

import cv2
import numpy as np

img1=cv2.imread("./picture1/picture1/1/14x00424.JPG")
img2=cv2.imread("./picture1/picture1/1/14x00425.JPG")


sift = cv2.SIFT_create(1000)

kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)

bf=cv2.BFMatcher()

matches = bf.knnMatch(des1,des2,k=2)
# 画出暴力匹配初步匹配后的所有匹配
matches1=[] # 最近距离
for i in matches:
    matches1.append(i[0])
img_matches=cv2.drawMatches(img1,kp1,img2,kp2,matches1,None,flags=2)

good_matches=[]
for m,n in matches:
    if m.distance < 0.7 * n.distance:
        good_matches.append(m)
img_good_matches=cv2.drawMatches(img1,kp1,img2,kp2,good_matches, None, flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)

MIN_MATCH_COUNT = 10
if len(good_matches)>MIN_MATCH_COUNT:
    src_pts = np.float32([kp1[m.queryIdx].pt for m in good_matches]).reshape(-1, 1, 2)
    dst_pts = np.float32([kp2[m.trainIdx].pt for m in good_matches]).reshape(-1, 1, 2)
    M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 4.0)
    matchesMask = mask.ravel().tolist()
    ransac = []  # 筛选出RANSAC之后的内点
    for i in range(0,len(matchesMask)):
        if matchesMask[i]==1:
            # print(i)
            ransac.append(good_matches[i])
            print(ransac)
    # h,w = img1.shape[:2]
    # 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, 5, cv2.LINE_AA)
img_ransac=cv2.drawMatches(img1, kp1, img2, kp2, good_matches, None)

"未经过筛选的匹配"
cv2.namedWindow("matches1",cv2.WINDOW_NORMAL)
cv2.imshow("matches1",img_matches)
cv2.imwrite("img_matches.jpg",img_matches)


"粗筛之后的匹配"
cv2.namedWindow("good_matches",cv2.WINDOW_NORMAL)
cv2.imshow("good_matches",img_good_matches)
cv2.imwrite("./good_matches.jpg",img_good_matches)

"使用RANSAC算法筛选过后的匹配"
ransac_result=cv2.drawMatches(img1,kp1,img2,kp2,ransac,None,flags=2)
cv2.namedWindow("ransac_result",cv2.WINDOW_NORMAL)
cv2.imshow("ransac_result",ransac_result)
cv2.imwrite("./ransac_result.jpg",ransac_result)
cv2.waitKey(0)
cv2.destroyAllWindows()

  • 12
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值