图像全景拼接

本文介绍了如何使用SIFT关键点检测和KNN匹配方法来实现两幅图像的全景拼接。首先,对图像进行SIFT特征检测和描述符计算,然后通过BFMatcher进行KNN匹配找到最佳匹配点,接着计算视角变换矩阵H,最后利用warpPerspective进行图像变换和拼接。
摘要由CSDN通过智能技术生成

TODO: 实现图片的全景拼接

流程:

(1)检测左右2图片的SIFT关键特征点,并计算特征描述
(2)使用KNN检测来自左右2图的SIFT特征,进行匹配
(3)计算视角变换矩阵H,用变换矩阵H对右图进行变换,左图加入到变换后的图像获得最终图像
(4)使用调用已经编辑好的函数运行程序进行全景拼接

(1)检测左右2图片的SIFT关键特征点,并计算特征描述

def sift_kp(image):
	 """
    将读取进行灰度化转化,并输出图像、关键点,计算描述符
    :param image:
    :return: kp_image, kp, des
    """
    # 灰度值转换
    gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # 创建sift对象
    sift = cv2.xfeatures2d.SIFT_create()
    # 计算特征点
    kp, des = sift.detectAndCompute(image, None)
    # 绘制特征点
    kp_image = cv2.drawKeypoints(gray_image, kp, None)
    return kp_image, kp, des

sift = cv2.xfeatures2d.SIFT_create() 在4.0以后的opencv版本可以直接使用SIFT_create()进行sift对象的创建

(2)使用KNN检测来自左右2图的SIFT特征,进行匹配

BF 匹配,Brute-Force Matcher,暴力匹配. 其原理比较简单,首先从集合A中选择一个特征的描述子,然后与集合B中所有的其他特征计算某种相似度,进行匹配,并返回最接近的项.

OpenCV 中,首先使用 cv2.BFMatcher()创建 BFMatcher 实例,其包含两个可选参数:normTypecrossCheck.

normType:如 NORM_L1, NORM_L2, NORM_HAMMING, NORM_HAMMING2.
NORM_L1 和 NORM_L2 更适用于 SIFT 和 SURF 描述子;
NORM_HAMMING 和 ORB、BRISK、BRIEF 一起使用;
NORM_HAMMING2 用于 WTA_K==3或4 的 ORB 描述子.

crossCheck:默认为 False,其寻找每个查询描述子的 k 个最近邻.
若值为 True,则 knnMatch() 算法 k=1,仅返回(i, j)的匹配结果,
即集合A中的第 i 个描述子在集合B中的第 j 个描述子是最佳匹配.
也就是说,两个集合中的两个描述子特征是互相匹配的.
其提供连续的结果.
当有足够的匹配项时,其往往能够找到最佳的匹配结果.

def get_good_match(des1, des2):
    """
    使用匹配器进行匹配进行匹配返回最佳的匹配值

    :param des1:
    :param des2:
    :return: good
    """
    # 使用**cv.BFMatcher**()创建BFMatcher对象
    # 它使用第一组中一个特征的描述符,并使用一些距离计算将其与第二组中的所有其他特征匹配。并返回最接近的一个。
    bf = cv2.BFMatcher()
    # 利用匹配器 匹配两个描述符的相近成都
    # (knn 匹配可以返回k个最佳的匹配项    bf返回所有的匹配项)
    matches = bf.knnMatch(des1, des2, k=2)  # des1为模板图,des2为匹配图
    # 按照相近程度,进行排序
    matches = sorted(matches, key=lambda x: x[0].distance / x[1].distance)
    good = []
    for m, n in matches:
        print(m.distance, n.distance)
        # 对欧式距离进行筛选
        if m.distance < 0.75 *n.distance:
            good.append(m)
    return good

调用knnMatch方法进行匹配:match = bf.knnMatch(des1, des2, k)
参数des1,des2是描述子,就是通过SIFT\SURF\ORB等特征提取算法计算出来的描述子;参数k表示取欧式距离最近的前k个关键点,就是计算第一组每个描述子和第二组所有描述子之间的欧式距离,然后取距离最小的前k对儿。当k=1就和match方法的结果一样
knnMatch()函数返回的三个值:
queryIdx:测试图像的特征点描述符的下标(第几个特征点描述符),同时也是描述符对应特征点的下标。
trainIdx:样本图像的特征点描述符下标,同时也是描述符对应特征点的下标。
distance:代表这图像匹配的特征点描述符的欧式距离,数值越小也就说明两个特征点越相近。

使用match检测来自左右2图的SIFT特征,进行匹配

match函数返回的也是三个值:
queryIdx:测试图像的特征点描述符的下标(第几个特征点描述符),同时也是描述符对应特征点的下标。
trainIdx:样本图像的特征点描述符下标,同时也是描述符对应特征点的下标。
distance:代表这图像匹配的特征点描述符的欧式距离,数值越小也就说明两个特征点越相近。

代码部分需要修改如下:

def get_good_match(des1, des2):
    bf = cv2.BFMatcher()
    matches = bf.match(des1, des2)  # des1为模板图,des2为匹配图
    good = []
    for m in matches:
        good.append(m)
    return good

(3)计算视角变换矩阵H,用变换矩阵H对右图进行变换,左图加入到变换后的图像获得最终图像

在Python中可以使用findHomography()计算多个二维点对之间的最优单映射变换矩阵H(3行3列)

函数功能:该函数能够找到并返回源平面和目标平面之间的转换矩阵H,以便于反向投影错误率达到最小。

使用warpPerspective()进行透视变换

函数功能:对图像进行透视变换。简单来说,就是有这么一副图像,它的拍摄视角不是从正面拍摄的,而是带有一定的角度,我们希望能得到从正面观察的视角。

def siftimg_rightleftment(img_right, img_left):
	"""
    用变换矩阵H对右图进行变换,左图加入到变换后
    :param img_right:
    :param img_left:
    :return:result
    """
    _, kp1, des1 = sift_kp(img_right)
    _, kp2, des2 = sift_kp(img_left)
    goodMatch = get_good_match(des1, des2)
    if len(goodMatch) > 4:
        # 获取匹配对的点坐标
        ptsA = np.float32([kp1[m.queryIdx].pt for m in goodMatch]).reshape(-1, 1, 2)
        ptsB = np.float32([kp2[m.trainIdx].pt for m in goodMatch]).reshape(-1, 1, 2)
        ransacReprojThreshold = 4
        H, status = cv2.findHomography(ptsA, ptsB, cv2.RANSAC, ransacReprojThreshold)
        result = cv2.warpPerspective(img_right, H, (img_right.shape[1] + img_left.shape[1], img_right.shape[0]))
        # 展示图片
        cvshow('result_medium', result)
        result[0:img_left.shape[0], 0:img_left.shape[1]] = img_left
        cvshow('result',result)

4、使用调用已经编辑好的函数运行程序进行全景拼接

# 特征匹配+全景拼接
import numpy as np
import cv2

# 读取拼接图片(注意图片左右的放置)
# 是对右边的图形做变换
img_right = cv2.imread(r'pin4.png')
img_left = cv2.imread(r'pin3.png')

img_right = cv2.resize(img_right,(800,400))
# 保证两张图一样大
img_left = cv2.resize(img_left, (img_right.shape[1], img_right.shape[0]))

kpimg_right, kp1, des1 = sift_kp(img_right)
kpimg_left, kp2, des2 = sift_kp(img_left)

# 同时显示原图和关键点检测后的图
cvshow('img_left', np.hstack((img_left, kpimg_left)))
cvshow('img_right', np.hstack((img_right, kpimg_right)))
goodMatch = get_good_match(des1, des2)

all_goodmatch_img = cv2.drawMatches(img_right, kp1, img_left, kp2, goodMatch, None, flags=2)

# goodmatch_img自己设置前多少个goodMatch[:10]
goodmatch_img = cv2.drawMatches(img_right, kp1, img_left, kp2, goodMatch[:10], None, flags=2)

cvshow('Keypoint Matches1', all_goodmatch_img)
cvshow('Keypoint Matches2', goodmatch_img)

# 把图片拼接成全景图
result = siftimg_rightlignment(img_right, img_left)
cvshow('result', result)

match方法检测:

在这里插入图片描述
将图片右进行视角变换
在这里插入图片描述
全景拼接
在这里插入图片描述
knnmatch检测:
在这里插入图片描述
在这里插入图片描述
视角转换
在这里插入图片描述
图像拼接
在这里插入图片描述

压缩包中包含的具体内容: 对给定数据中的6个不同场景图像,进行全景拼接操作,具体要求如下: (1) 寻找关键点,获取关键点的位置和尺度信息(DoG检测子已由KeypointDetect文件夹中的detect_features_DoG.m文件实现;请参照该算子,自行编写程序实现Harris-Laplacian检测子)。 (2) 在每一幅图像中,对每个关键点提取待拼接图像的SIFT描述子(编辑SIFTDescriptor.m文件实现该操作,运行EvaluateSIFTDescriptor.m文件检查实现结果)。 (3) 比较来自两幅不同图像的SIFT描述子,寻找匹配关键点(编辑SIFTSimpleMatcher.m文件计算两幅图像SIFT描述子间的Euclidean距离,实现该操作,运行EvaluateSIFTMatcher.m文件检查实现结果)。 (4) 基于图像中的匹配关键点,对两幅图像进行配准。请分别采用最小二乘方法(编辑ComputeAffineMatrix.m文件实现该操作,运行EvaluateAffineMatrix.m文件检查实现结果)和RANSAC方法估计两幅图像间的变换矩阵(编辑RANSACFit.m 文件中的ComputeError()函数实现该操作,运行TransformationTester.m文件检查实现结果)。 (5) 基于变换矩阵,对其中一幅图像进行变换处理,将其与另一幅图像进行拼接。 (6) 对同一场景的多幅图像进行上述操作,实现场景的全景拼接(编辑MultipleStitch.m文件中的makeTransformToReferenceFrame函数实现该操作)。可以运行StitchTester.m查看拼接结果。 (7) 请比较DoG检测子和Harris-Laplacian检测子的实验结果。图像拼接的效果对实验数据中的几个场景效果不同,请分析原因。 已经实现这些功能,并且编译运行均不报错!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

阿龙的代码在报错

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值