【进阶OpenCV】 (4)--图像拼接

news2024/11/26 9:34:06

文章目录

  • 图像拼接
    • 1. 读取图片
    • 2. 计算图片特征点及描述符
    • 3. 建立暴力匹配器
    • 4. 特征匹配
    • 5. 透视变换
    • 6. 图像拼接
  • 总结

图像拼接

图像拼接是一项将多张有重叠部分的图像(这些图像可能是不同时间、不同视角或者不同传感器获得的)拼成一幅无缝的全景图或高分辨率图像的技术。

主要过程:找到特征匹配点,然后进行透视变换操作,模拟了人眼或相机镜头观看三维空间物体时的透视效果,从而能够改变图像的视角和形状,使得两个图片可以完全拼接在一起。

1. 读取图片

在这里插入图片描述

在这里插入图片描述

def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)
"""-----读取拼接图片-----"""
imageA = cv2.imread("t1.jpg")
cv_show('imageA',imageA)
imageB = cv2.imread("t2.jpg")
cv_show('imageB',imageB)

2. 计算图片特征点及描述符

def detectAndDescribe(image):
    gray = cv2.cvtColor(image,cv2.COLOR_RGB2GRAY) # 将彩色图片转化为灰度图
    descriptor = cv2.SIFT_create() # 建立SIFT生成器
    # 检测SIFT特征点,并计算描述符,第二个参数为掩膜
    (kps,des) = descriptor.detectAndCompute(gray,None)
    # 将结果转化成Numoy数组
    kps_float = np.float32([kp.pt for kp in kps])
    # kp.pt包含两个值,分别是关键点在图像中的x和y坐标,这些坐标通常时浮点数,可以精确地描述关键点在图像中的位置
    return (kps,kps_float,des) # 返回特征点集,及对应的描述特征

"""-----计算图片特征点及描述符-----"""
(kpsA,kps_floatA,desA) = detectAndDescribe(imageA)
(kpsB,kps_floatB,desB) = detectAndDescribe(imageB)

3. 建立暴力匹配器

"""-----建立暴力匹配器BFMatcher,在匹配大型训练集合时使用FlannBasedMatcher速度更快-----"""
matcher = cv2.BFMatcher()

4. 特征匹配

方法:关键点A与找到的两个关键点 X、Y的欧氏距离分别 d1、d2,且d1<d2。

欧氏距离(关键点A,关键点X)=d1。欧氏距离(关键点A,关键点Y)=d2。

(1)d1<d2,比值较大:可能不是匹配点,通常是由噪声引起的。

(2)d1<d2,比值较小:是匹配点。

在这里插入图片描述

  • 函数
--knnMatch(queryDescriptors,trainDescriptors,k,mask=None,compactResult = None)
使用KNN检测来自A、B图的SIFT特征匹配对,参数说明:
queryDescriptors:匹配图像A的描述符
trainDescriptors:匹配图像B的描述符
k:最佳匹配的描述符个数,一般k=2
  • 返回值
--返回的数据结构描述:
distance:匹配的特征点描述符的欧氏距离,数值越小也就说明两个特征点越相近。
queryIdx:测试图像的特征点描述符的下标(第几个特征点描述符),同时也是描述符对应特征点的下表
trainIdx:样本图像的特征点描述符下标,同时也是描述符对应特征点的下标。
  • 代码应用:
rawMatches = matcher.knnMatch(desB,desA,2)
good = []
matches = []
for m in rawMatches:
    # 当最近距离跟次近距离的比值小于0.65时,保留此对匹配
    if len(m) == 2 and m[0].distance < 0.65 * m[1].distance:
        good.append(m)
        # 存储两个点在featureA,featureB中的索引值
        matches.append((m[0].trainIdx,m[0].queryIdx))
print(len(good))
print(matches)

vis = cv2.drawMatchesKnn(imageB,kpsB,imageA,kpsA,good,None,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv_show("keypoint Matchs",vis)

在这里插入图片描述

5. 透视变换

透视变换是指利用透视中心、像点、目标点三点共线的条件,按透视旋转定律使承影面(透视面)绕迹线(透视轴)旋转某一角度,破坏原有的投影光线束,但仍能保持承影面上投影几何图形不变的变换。它是中心投影的射影变换,在用非齐次射影坐标表达时是平面的分式线性变换。

  • 函数
-- 计算透视变换矩阵
findHomography(srcPoints,disPoints,method=None,ransacReprojThreshold=None,mask=None,maxIters=None,confidence=None)
计算视角变换矩阵,透视变换函数,与cv2.getPerspectiveTransform()的区别在于可多个数据点变换
参数:
-- srcPoints:图片A的匹配点坐标
-- disPoints:图片B的匹配点坐标
-- method:计算变换矩阵的方法
   0 - 使用所有的点,最小二乘
   RANSAC - 基于随机样本一致性
   LMEDS - 最小中值
   RHO - 基于渐进样本一致性
-- ransacReprojThreshold:最大允许重投影错误阈值,该参数只有在method参数为RANSAC与RHO的时候启用,默认为3
返回值:H为变换矩阵,mask时掩膜标志,指示哪些点对时内点,哪些是外点.内点:指那些与估计的模型非常接近的数据点,通常是正确匹配或真实数据
  • 代码应用
if len(matches) > 4: # 当筛选后的匹配对大于4时,计算视角变换矩阵
    # 获取匹配对的点坐标
    ptsA = np.float32([kps_floatA[i] for (i, _) in matches]) # matches是通过阈值筛选之后的特征点对象
    ptsB = np.float32([kps_floatB[i] for (_, i) in matches]) # kps_floatA是图片A中的全部特征点坐标
    (H,mask) = cv2.findHomography(ptsB,ptsA,cv2.RANSAC,10)
else:
    print("图片未找到4个以上的匹配点")
    sys.exit()
result = cv2.warpPerspective(imageB,H,(imageB.shape[1] + imageA.shape[1],imageB.shape[0]))
cv_show('resultB',result)

在这里插入图片描述

6. 图像拼接

# 将图片A传入result图片最左端
result[0:imageA.shape[0],0:imageA.shape[1]] = imageA
cv_show("result",result)

在这里插入图片描述

总结

本篇介绍了:

如何通过计算关键点以及透视变换的矩阵将两个不同视角的图片进行拼接,使得它们能够完整协和的展示出来。

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

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

相关文章

论文翻译 | Model-tuning Via Prompts Makes NLP Models Adversarially Robust

摘要 近年来&#xff0c;NLP从业者集中于以下实践:(i)导入现成的预训练(掩码)语言模型;(ii)在CLS令牌的隐藏表示(随机初始化权重)上附加多层感知器;(iii)在下游任务(MLP-FT)上微调整个模型。这一过程在标准的NLP基准上产生了巨大的收益&#xff0c;但这些模型仍然很脆弱&#x…

mysql单表查询·3

准备好表 create table product(id int primary key,name varchar(32),price double,category varchar(32) ); # 插入数据 INSERT INTO product(id,name,price,category) VALUES(1,联想,5000,c001); INSERT INTO product(id,name,price,category) VALUES(2,海尔,3000,c001); I…

加密与安全_HOTP一次性密码生成算法

文章目录 HOTP 的基础原理HOTP 的工作流程HOTP 的应用场景HOTP 的安全性安全性增强措施Code生成HOTP可配置项校验HOTP可拓展功能计数器&#xff08;counter&#xff09;计数器在客户端和服务端的作用计数器的同步机制客户端和服务端中的计数器表现服务端如何处理计数器不同步计…

好用的苹果笔推荐!五大高品质王者款!附避坑宝典助你选购无忧!

现在平板和电容笔在一定程度上可以替代传统的笔和纸&#xff0c;很多用户在购置iPad后&#xff0c;急需找到一款好用的电容笔。但由于苹果原装笔的价格太过高昂&#xff0c;让许多人不得不选择平替电容笔&#xff01;下面我就为大家推荐五款高品质的电容笔&#xff0c;并分享几…

单细胞hdWGCNA分析学习和整理

hdWGCNA的分析逻辑是跟bulkRNA数据中的WGCNA基本一样&#xff0c;只是hdWGCNA中多了一步metacell过程&#xff0c;有助于减少无用的信息(单细胞数据有很多零值&#xff0c;会影响分析结果)。 WGCNA的基础信息可见既往推文: https://mp.weixin.qq.com/s/2Q37RcJ1pBy_WO1Es8upIg…

二分查找算法专题(2)

找往期文章包括但不限于本期文章中不懂的知识点&#xff1a; 个人主页&#xff1a;我要学编程(ಥ_ಥ)-CSDN博客 所属专栏&#xff1a; 优选算法专题 对于二分查找算法不是很了解或者只了解一部分的小伙伴一定要去看下面这篇博客&#xff1a;二分查找算法的介绍与另外一种查找方…

【EcoNAS: Finding Proxies for Economical Neural Architecture Search】读后感

鄙人近日阅读了来自 CVPR2020 的一篇论文, 在这里与大家分享一下读后感, 有些东西可能不一定正确, 还望大家指正. Exploration Study 进化算法是 NAS 中一种常用的搜索算法, 使用进化算法时, 如果将每一个候选网络训练到完全收敛来评估性能的话, 需要耗费大量的资源 (时间, G…

现代身份和访问管理 IAM 如何降低风险

您的公司是否仍在使用 1998 年时的身份管理系统&#xff1f;仅凭用户名和密码就能登录本地网络并访问几乎所有资源吗&#xff1f; 虽然大多数企业已经转向现代身份和访问管理(IAM) 平台&#xff0c;但成千上万的企业和其他组织仍然依赖过时的用户名/密码系统。 如果你看一下传…

Ubuntu18.04配置OpenPCDet并运行demo过程记录

一、概述 因为最近需要配置OpenPCDet&#xff0c;发现在配置过程中存在诸多的问题需要解决&#xff0c;将过程中所遇到的问题进行记录保存。 二、具体配置过程 &#xff08;一&#xff09;参考链接 因为中间遇到了很多问题&#xff0c;参考了很多不少相应的博客进行问题解决。…

【Unity】unity安卓打包参数(个人复习向/有不足之处欢迎指出/侵删)

1.Texture Compression 纹理压缩 设置发布后的纹理压缩格式 Use Player Settings:使用在播放器设置中设置的纹理压缩格式 ETC&#xff1a;使用ETC格式&#xff08;兼容&#xff09; ETC2&#xff1a;使用ETC2格式&#xff08;很多设备不支持&#xff09; ASTC&#xff1a;使用…

使用JavaScript写一个网页端的四则运算器

目录 style(内联样式表部分) body部分 html script 总的代码 网页演示 style(内联样式表部分) <style>body {font-family: Arial, sans-serif;display: flex;justify-content: center;align-items: center;height: 100vh;background-color: #f0f0f0;}.calculator {…

c++ 指针传参

// // Created by 徐昌真 on 2024/10/4. // #include <iostream>//函数的值传递 void swap(int a, int b){ //只是单纯的改变了函数内部a b的值 在main函数内值并不会改变 因为值存在地址里面 而地址里面的值要通过指针来改变int temp;temp a;a b;b temp; }//函数的址…

Oracle架构之表空间详解

文章目录 1 表空间介绍1.1 简介1.2 表空间分类1.2.1 SYSTEM 表空间1.2.2 SYSAUX 表空间1.2.3 UNDO 表空间1.2.4 USERS 表空间 1.3 表空间字典与本地管理1.3.1 字典管理表空间&#xff08;Dictionary Management Tablespace&#xff0c;DMT&#xff09;1.3.2 本地管理方式的表空…

8647 实现图的存储结构

### 思路 1. 读取输入的顶点个数n和边的条数m。 2. 初始化一个n*n的邻接矩阵&#xff0c;所有元素初始为0。 3. 读取每条边的信息&#xff0c;更新邻接矩阵对应位置为1。 4. 输出邻接矩阵。 ### 伪代码 1. 读取n和m。 2. 初始化n*n的邻接矩阵matrix&#xff0c;所有元素为0。 …

CSS列表和超链接的使用(8个案例+代码+效果图+素材)

目录 1.无序列表ul 案例:定义不同type的li 1.代码 2.效果 2.有序列表ol type 取值 start属性 value 案例:定义不同类型的有序列表 1.代码 2.效果 3.定义列表dl 1.代码 2.效果 4.list-style-type属性 list-style-type的取值 案例:list-type的使用 1.代码 2.效果 5.list-style-im…

关于OJ平台的一个代码小问题 ——

目录 一、关于OJ平台的一个代码小问题 1、将OJ代码复制粘贴到vs上 2、创建测试方法&#xff0c;调用本次要调试的目标方法 3、利用vs调试工具排查代码问题 一、关于OJ平台的一个代码小问题 思考&#xff1a;OJ代码有bug怎么办&#xff1f; 答&#xff1a;VS调试技能用起来 …

G. Gears (2022 ICPC Southeastern Europe Regional Contest. )

G. Gears 思路&#xff1a; 本身这个题并不难&#xff0c;奈何卡了很久后看了题解才做出来&#xff0c;感觉自己好笨。 很容易想到的是&#xff0c;只要确定了一个齿轮的位置&#xff0c;其他齿轮的位置都可以直接推出来。所以当前目标是如何确定第一个齿轮的位置。 令 x [ i …

第2篇:Windows权限维持----应急响应之权限维持篇

关键词&#xff1a;Windows系统后门、权限维持 在获取服务器权限后&#xff0c;通常会用一些后门技术来维持服务器权限&#xff0c;服务器一旦被植入后门&#xff0c;攻击者便如入无人之境。本文将对常见的window服务端自启动后门技术进行解析&#xff0c;知己知彼方能杜绝后门…

系统规划与管理——1信息系统综合知识(4)

文章目录 1.3 信息系统1.3.4 信息系统总体规划 1.3 信息系统 1.3.4 信息系统总体规划 信息系统总体规划的概念和作用 一个组织或一个区域的信息系统建设&#xff0c;都要经历由初始到成熟的发展过程。诺兰总结了信息系统发展的规律&#xff0c;在1973年提出了信息系统发展的阶…

《Linux从小白到高手》理论篇:Linux的系统服务管理

值此国庆佳节&#xff0c;深宅家中&#xff0c;闲来无事&#xff0c;就多写几篇博文。本篇详细深入介绍Linux的系统服务管理。 系统服务通常在系统启动时自动启动&#xff0c;并在后台持续运行&#xff0c;为系统和用户提供特定的功能。例如&#xff0c;网络服务、打印服务、数…