图像全景拼接

news2024/11/15 4:27:43

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()函数进行透视变换

Homography(透视变换):透视变换就是将图像投影到一个新的视平面。上面提到了一个叫做透视矩阵的东西,其实就是单应性矩阵,用来表示两幅图的对应点的变换关系。在全景图拼接时,很多图像会由于拍摄角度等问题出现一些方向上的不同步

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)
        # ![将图片右进行视角变换](https://img-blog.csdnimg.cn/511e139a7bfe4f0494cbd7a9adbb9466.png)
,result是变换后图片
        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检测:
在这里插入图片描述
在这里插入图片描述
视角转换
在这里插入图片描述
图像拼接
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/732280.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

目标跟踪基础:距离度量

本文来自公众号“AI大道理” —————— 距离度量在CV 、NLP以及数据分析等领域都有众多的应用。 距离度量可以当做某种相似度&#xff0c;距离越近&#xff0c;越相似。 在目标跟踪领域中&#xff0c;需要判断目标之间的距离或相似度&#xff0c;从而判断前后帧的目标是否…

Redis实战案例13-集群下的并发安全问题

在解决一人一单的问题上面&#xff0c;采用了悲观锁的方案&#xff0c;但是这种方案只适合单机情况&#xff0c;在集群的模式下就不适用了&#xff1b; 覆盖yaml文件中的端口号 修改nginx中conf&#xff0c;这样就可以反向代理到两个节点上去&#xff0c;轮询的负载均衡规则&am…

git bash---打开当前路径所在文件夹

0 Preface/Foreword 在Windows操作系统中使用git bash时&#xff0c;可以通过命令直接打开当前路径下的文件夹&#xff0c;命令如下 explorer .

MS17-010漏洞复现

官方描述&#xff1a;Microsoft Security Bulletin MS17-010 - Critical | Microsoft Learn漏洞描述&#xff1a; Microsoft Windows SMB Server远程代码执行漏洞&#xff0c;Microsoft Server Message Block 1.0 (SMBv1)服务器处理某些请求时&#xff0c;在实现上存在远程代码…

Mockplus Cloud - June 2023crack

Mockplus Cloud - June 2023crack 添加便签以澄清情节提要上的任何设计概念。 新的流程图工具直接在情节提要上可视化任何设计流程和过程。 添加了在发布到Mockplus Cloud时删除RP页面的功能。 添加设计注释时包括图像和链接。 添加了一个新的提示&#xff0c;用于在断开互联网…

MySQL练习题(1)

1,创建如下学生表 mysql> create table student( -> id int, -> name varchar(20), -> gender varchar(20), -> chinese int, -> math int, -> english int -> ); 插入如图数据 1-- 查询表中所有学生的信息 select *from student;2-- 查询表中所有学…

mysql语句练习题,创建表,枚举中文字符集设置,修改(update)

作业&#xff1a; 1.创建表&#xff1a; 创建员工表employee&#xff0c;字段如下&#xff1a; id&#xff08;员工编号&#xff09;&#xff0c;name&#xff08;员工名字&#xff09;&#xff0c;gender&#xff08;员工性别&#xff09;&#xff0c;salary&#xff08;员工薪…

厄尔尼诺,“烤热”新能源汽车市场?

在高温极端天气中&#xff0c;买新能源汽车的人变多了还是变少了&#xff1f; 7月4日&#xff0c;世界气象组织宣布&#xff0c;热带太平洋七年来首次形成厄尔尼诺条件&#xff0c;这可能导致全球气温飙升、破坏性天气和气候模式的出现。 注&#xff1a;1月底至6月初&#xff…

【离散数学】实践二 Floyd– Warshall算法

文章目录 目标原理设计与实现&#xff08;代码快照以及代码&#xff09;运行界面和结果截图结语 目标 给定一个距离矩阵&#xff0c;利用 Floyd– Warshall 算法编程&#xff08;C语言&#xff09;求任意两点之间的最短距离。 原理 求取多源最短路径常用Floyd算法&#xff0c…

支持向量机SVM代码详解——多分类/降维可视化/参数优化【python】

篇1&#xff1a;SVM原理及多分类python代码实例讲解&#xff08;鸢尾花数据&#xff09; SVM原理 支持向量机&#xff08;Support Vector Machine,SVM&#xff09;&#xff0c;主要用于小样本下的二分类、多分类以及回归分析&#xff0c;是一种有监督学习的算法。基本思想是寻…

腾讯云对象存储的创建和S3 Browser的使用

简述 想想第一次接触对象存储的时候还是很兴奋的&#xff0c;同时也是一脸懵逼&#xff1b;然后开始网上疯狂的找资料&#xff0c;但因为客户当时给的文档写的是关于Amazon S3之类的&#xff0c;所以自以为的就只有Amazon S3这一家&#xff0c;接着开始查资料&#xff0c;经过一…

Spark学习---2、SparkCore(RDD概述、RDD编程(创建、分区规则、转换算子、Action算子))

1、RDD概述 1.1 什么是RDD RDD(Resilient Distributed Dataset)叫弹性分布式数据集&#xff0c;是Spark中对于分布式数据集的抽象。代码中是一个抽象类&#xff0c;它代表一个弹性的、不可变、可分区、里面的元素可并行计算的集合。 1.2 RDD五大特性 1、一组分区&#xff0…

Pyecharts 绘制各种统计图的案例

Pyecharts 绘制各种统计图的案例 基础使用 from pyecharts import options as opts from pyecharts.charts import Bar, Line, Pie, Scatter from pyecharts.faker import Faker# 柱状图示例 def bar_chart():x_data Faker.choose()y_data Faker.values()bar (Bar().add_xa…

simulink实战 建模 简单车辆动力学模型

Gmg Discrete-TimeIntegrator 离散时间积分器

CentOS 7 搭建 Impala 4.1.2 + Kudu 1.15.0 测试环境

安装依赖 这部分不过于详细介绍&#xff0c;如果有现成环境也可以直接拿来使用。 Java 下载 java 安装包&#xff0c;需要登录 oracle&#xff0c;请自行下载。 cd /mnt tar zxvf jdk-8u202-linux-x64.tar.gz配置环境变量到 /etc/bashrc&#xff0c;并执行 source /etc/bas…

关于深度学习图像数据增广

数据增广方法在广义上可以按照产生新数据的方式分为数据变形和数据过采样。由于操作简单&#xff0c;同时数据量上的需求远比现在要低得多&#xff0c;早期对数据增广的应用多是数据变形类方法。对于图像数据&#xff0c;基本的图像变换操作都属于数据变形类增广方法&#xff0…

Jvm参数设置-JVM(八)

上篇文章说了逃逸分析和标量&#xff0c;代码实例解析了内存分配先从eden区域开始&#xff0c;当内存不足的时候&#xff0c;才会进入s0和s1&#xff0c;发生yangGC&#xff0c;之后大内存会放入old&#xff0c;因为我们昨天程序运行了一个45M的对象&#xff0c;于是小对象在ed…

详解------>数组笔试题(必备知识)

目录 本章将通过列题进一步了解sizeof 与strlen的区别&#xff0c;加强对数组的理解。 1&#xff1a;一维数组列题 2&#xff1a;字符数组列题 3&#xff1a;二维数组列题 首先在进行这些习题讲解之前我们需要知道的知识点 sizeof&#xff1a;是一个关键字&#xff0c;可以…

KMP--高效字符串匹配算法(Java)

KMP算法 KMP算法算法介绍代码演示: KMP算法 KMP算法是为了解决这一类问题,给定一个字符串str1,和一个字符串str2,如果str2属于str1d的字串,则返回字串第一个出现位置的下标,不存在返回-1. 注意: 子串是连续的. 举个例子 str1 “abc123abs” str1 长度假设m str2 “123”; str2…

pycharm汉化

安装pycharm 不多说了&#xff0c;直接下载安装即可 汉化 file -setting plugins 输入chinese进行搜索 点击 进行安装&#xff0c;等待安装完成 安装完成需要重启&#xff0c;点击重启&#xff0c;等待重启完成即可 出现上图&#xff0c;说明汉化成功了