OpenCv_04——特征匹配

目录

  • 4.特征匹配
    • 4.1 Brute-Force蛮力匹配
    • 4.2 RANSAC算法
      • 4.2.1 图像拼接

上一篇: OpenCv_03——图像特征
下一篇: OpenCv_05——背景建模

4.特征匹配

测试图片自取

book.jpg book1.jpg zuo.jpg you.jpg

4.1 Brute-Force蛮力匹配

import cv2
import numpy as np
import matplotlib.pyplot as plt
%matplotlib inline

img1=cv2.imread('book.jpg')
img2=cv2.imread('book1.jpg')

def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

cv_show('img1',img1)

OpenCv_04——特征匹配_第1张图片

cv_show('img2',img2)

OpenCv_04——特征匹配_第2张图片

sift=cv2.xfeatures2d.SIFT_create()

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

#crossCheck表示两个特征点要互相匹配,例如A种的第i个特征点最近的,并且B中的第j个特征点也是
#NORM_1.2:归一化数组的(欧几里得距离),如果其它特征计算方法需要考虑不同的匹配计算方式
bf=cv2.BFMatcher(crossCheck=True)

#1队1匹配
matches=bf.match(des1,des2)
matches=sorted(matches,key=lambda x:x.distance)

img3=cv2.drawMatches(img1,kp1,img2,kp2,matches[:10],None,flags=2)#连起来
cv_show('img3',img3)

OpenCv_04——特征匹配_第3张图片

#k对最佳匹配
bf=cv2.BFMatcher()
matches=bf.knnMatch(des1,des2,k=2)

good=[]
for m,n in matches:
    if m.distance<0.75*n.distance:
        good.append([m])
        
img3=cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=2)
cv_show('img3',img3)

OpenCv_04——特征匹配_第4张图片

如果需要更快速完成操作,可以尝试使用cv2.FlannBasedMatcher

4.2 RANSAC算法

随机抽样一致算法(Random sample consensus,RANSAC)

OpenCv_04——特征匹配_第5张图片

OpenCv_04——特征匹配_第6张图片

选择初始样本进行拟合,给定一个容忍,不断进行迭代。

OpenCv_04——特征匹配_第7张图片

每一次拟合后,容差范围内都有对应的数据点数,找出数据点个数最多的情况,就是最终的拟合结果

OpenCv_04——特征匹配_第8张图片

单应性矩阵

OpenCv_04——特征匹配_第9张图片

4.2.1 图像拼接

实现过程

1、用SIFT提取图像中的特征点,并对每个关键点周围的区域计算特征向量。
2、在分别提取好了两张图片的关键点和特征向量以后,可以利用它们进行两张图片的匹配。在拼接图片中,可以使用Knn进行匹配,但是使用FLANN快速匹配库更快,图片拼接,需要用到FLANN的单应性匹配。
3、单应性匹配完之后可以获得透视变换H矩阵,用这个的逆矩阵来对第二幅图片进行透视变换,将其转到和第一张图一样的视角,为下一步拼接做准备。
4、透视变化完后就可以直接拼接图片了,将图片通过numpy直接加到透视变化完成的图像的左边,覆盖掉重合的部分,得到拼接图片,但是这样拼接得图片中间会有一条很明显的缝隙,可以通过加权平均法,界线的两侧各取一定的比例来融合缝隙,速度快,但不自然。或者羽化法,或者拉普拉斯金字塔融合,效果最好。在这里用的是加权平均法,可以把第一张图叠在左边,但是对第一张图和它的重叠区做一些加权处理,重叠部分,离左边图近的,左边图的权重就高一些,离右边近的,右边旋转图的权重就高一些,然后两者相加,使得过渡是平滑地,这样看上去效果好一些,速度就比较慢。

#导入库
import cv2
import numpy as np
import sys
from PIL import Image
#图像显示函数
def show(name,img):
    cv2.imshow(name, img)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
    
#读取输入图片
ima = cv2.imread("you.jpg")
imb = cv2.imread("zuo.jpg")
A = ima.copy()
B = imb.copy()
imageA = cv2.resize(A,(0,0),fx=0.2,fy=0.2)
imageB = cv2.resize(B,(0,0),fx=0.2,fy=0.2)

#检测A、B图片的SIFT关键特征点,并计算特征描述子
def detectAndDescribe(image):
    # 建立SIFT生成器
    sift = cv2.xfeatures2d.SIFT_create()
    # 检测SIFT特征点,并计算描述子
    (kps, features) = sift.detectAndCompute(image, None)
    # 将结果转换成NumPy数组
    kps = np.float32([kp.pt for kp in kps])
    # 返回特征点集,及对应的描述特征
    return (kps, features)
    
#检测A、B图片的SIFT关键特征点,并计算特征描述子
kpsA, featuresA = detectAndDescribe(imageA)
kpsB, featuresB = detectAndDescribe(imageB)
# 建立暴力匹配器
bf = cv2.BFMatcher()
# 使用KNN检测来自A、B图的SIFT特征匹配对,K=2
matches = bf.knnMatch(featuresA, featuresB, 2)
good = []
for m in matches:
    # 当最近距离跟次近距离的比值小于ratio值时,保留此匹配对
    if len(m) == 2 and m[0].distance < m[1].distance * 0.75:
        # 存储两个点在featuresA, featuresB中的索引值
        good.append((m[0].trainIdx, m[0].queryIdx))
        
# 当筛选后的匹配对大于4时,计算视角变换矩阵
if len(good) > 4:
    # 获取匹配对的点坐标
    ptsA = np.float32([kpsA[i] for (_, i) in good])
    ptsB = np.float32([kpsB[i] for (i, _) in good])
    # 计算视角变换矩阵
    H, status = cv2.findHomography(ptsA, ptsB, cv2.RANSAC,4.0)
    
# 匹配两张图片的所有特征点,返回匹配结果
M = (matches, H, status)
# 如果返回结果为空,没有匹配成功的特征点,退出程序
if M is None:
    print("无匹配结果")
    sys.exit()
# 否则,提取匹配结果
# H是3x3视角变换矩阵
(matches, H, status) = M
# 将图片A进行视角变换,result是变换后图片
result = cv2.warpPerspective(imageA, H, (imageA.shape[1] + imageB.shape[1], imageA.shape[0]))
# 将图片B传入result图片最左端
result[0:imageB.shape[0], 0:imageB.shape[1]] = imageB
show('res',result)
print(result.shape)

OpenCv_04——特征匹配_第10张图片

你可能感兴趣的:(#,OpenCv,opencv,计算机视觉,python)