OpenCV-图像拼接
文章目录
- 一、基本原理
- 二、步骤
- 三、代码实现
- 1.定义函数
- 2.读取图像
- 3.图像配准
- (1).特征点检测
- (2).特征匹配
 
- 4.透视变换
- 5.图像拼接
 
- 四、图像拼接的注意事项
图像拼接是一种将多张有重叠部分的图像合并成一张无缝的全景图或高分辨率图像的技术。它在许多领域都有广泛的应用,如摄影、虚拟现实、医学成像等。
一、基本原理
图像拼接的基本原理是通过找到不同图像之间的相似性或重叠区域,利用这些区域将图像无缝地融合在一起,形成一幅更大的图像。这个过程通常包括图像预处理、图像配准、建立变换模型、统一坐标变换以及融合重构等步骤。
二、步骤
- 图像预处理 - 去噪:去除图像中的噪声,提高图像质量。
- 边缘提取:提取图像的边缘信息,有助于后续的配准和融合。
- 直方图处理:调整图像的亮度、对比度等,使不同图像在视觉上更加一致。
 
- 图像配准 - 特征点检测:使用算法(如SIFT、SURF、ORB等)检测图像中的特征点。
- 特征匹配:根据特征点的描述符进行匹配,找到不同图像之间的对应点。
- 变换关系计算:根据匹配点计算图像之间的变换关系,如单应性矩阵或仿射变换矩阵。
 
- 建立变换模型 - 根据匹配点之间的对应关系,建立数学模型,描述图像之间的变换关系。
 
- 统一坐标变换 - 将待拼接图像根据变换模型转换到同一坐标系中,使图像在空间位置上对齐。
 
- 图像融合 - 在图像的重叠区域进行融合处理,消除拼接痕迹,使拼接后的图像看起来自然无缝。
- 融合方法包括多带混合、泊松图像编辑等。
 
三、代码实现
在OpenCV中,图像拼接通常涉及到特征检测、特征匹配、计算变换矩阵(如单应性矩阵或仿射变换矩阵)以及使用这些矩阵将图像变换到统一坐标系下,最后进行图像拼接的过程。
1.定义函数
import cv2
import numpy as np
import sys
def cv_show(name, img):cv2.imshow(name, img)cv2.waitKey(0)def detectAndDescribe(image):gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)descriptor = cv2.SIFT_create()(kps, des) = descriptor.detectAndCompute(gray, None)kps_float = np.float32([kp.pt for kp in kps])return (kps, kps_float, des)
- 首先我们定义了两个函数,cv_show用来展示图像,detectAndDescribe使用了 OpenCV 的
 SIFT(尺度不变特征变换)算法来检测图像中的关键点和计算这些关键点的描述符。
2.读取图像
"""读取图片"""
imageA = cv2.imread('xiangjiA.jpg')
cv_show('A', imageA)
imageB = cv2.imread('xiangjiB.jpg')
# imageB = cv2.resize(imageB,(662, 604))
cv_show('B', imageB)
- 使用cv2.imread()读取图片。
- 使用cv_show()函数显示图片。
  
3.图像配准
(1).特征点检测
"""计算图片特征点及描述符"""
(kpsA, kps_floatA, desA) = detectAndDescribe(imageA)
(kpsB, kps_floatB, desB) = detectAndDescribe(imageB)
- 调用定义的函数detectAndDescribe
- 将图片转换为灰度图。
- 使用SIFT算法(cv2.SIFT_create())检测特征点和计算描述符。
(2).特征匹配
"""建立暴力匹配器BFMatcher,在匹配大型训练集合时使用FlannBaesdMatcher速度快"""
matcher = cv2.BFMatcher()
rawMatches = matcher.knnMatch(desB, desA, 2)
good = []
matches = []
for m in rawMatches:if len(m) == 2 and m[0].distance < 0.65 * m[1].distance:goodB.append(m)matchesB.append((m[0].trainIdx, m[0].queryIdx))
rawMatchesA = matcher.knnMatch(desA, desB, 2)
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 Maxtchs', vis)
- 使用BFMatcher(暴力匹配器)进行特征点匹配,并应用Lowe’s ratio test来筛选好的匹配点。
- 分别计算从imageB到imageA的匹配点。

4.透视变换
"""透视变换"""
if len(matches) > 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]))
- 如果匹配点数量超过4个,则使用cv2.findHomography()计算单应性矩阵。
- 使用单应性矩阵和cv2.warpPerspective()进行透视变换。
5.图像拼接
cv_show('result', result)
result[0:imageA.shape[0], 0:imageA.shape[1]] = imageA
cv_show('resultB', result)
- 将变换后的图片与另一张图片合并,并显示结果。这里我们是从图像左上角位置开始合并。
  
  
 以上是一个基本的图像拼接流程。在实际应用中,可能需要调整特征检测器的参数、匹配阈值以及RANSAC的阈值,以获得最佳结果。此外,对于复杂场景或大规模数据集,可能还需要考虑并行处理和优化内存使用等问题。
四、图像拼接的注意事项
- 确保图像有重叠部分:图像拼接依赖于图像之间的重叠区域,因此确保待拼接图像有足够的重叠是非常重要的。
- 选择合适的拼接方法:不同的拼接方法适用于不同的场景和需求,选择合适的拼接方法可以获得更好的效果。
- 调整参数:在拼接过程中,可能需要调整一些参数(如特征点检测器的阈值、匹配阈值等),以获得最佳的拼接效果。
- 检查拼接效果:拼接完成后,仔细检查拼接效果,确保没有明显的拼接痕迹或失真现象。
通过以上步骤和注意事项,可以实现高质量的图像拼接,满足各种应用需求。
相关文章:
 
OpenCV-图像拼接
文章目录 一、基本原理二、步骤三、代码实现1.定义函数2.读取图像3.图像配准(1).特征点检测(2).特征匹配 4.透视变换5.图像拼接 四、图像拼接的注意事项 图像拼接是一种将多张有重叠部分的图像合并成一张无缝的全景图或高分辨率图…...
 
C++【类和对象】(取地址运算符重载与实现Date类)
文章目录 取地址运算符重载const成员函数取地址运算符重载 Date类的实现Date.hDate.cpp1.检查日期合法性2. 构造函数/赋值运算符重载3.得到某月的天数4. Date类 - 天数的操作4.1 日期 天数4.2 日期 天数4.3 日期 - 天数4.4 日期 - 天数 5. Date的前后置/--5.1 前置5.2 后置5.…...
oracle 数据库中的异常和游标管理
异常和游标管理 游标: 用来查询数据库,获取记录集合(结果集)的指针,可以让开发者一次访问一行结果集,在每条结果集上作操作。 分类: 静态游标: 分为显式游标和隐式游标。 REF游标&…...
关于python 日志设定为INFO 但是DEBUG仍旧写入的问题
问题:将logging设定为了INFO级别,但是在打印的时候发现jieba包中的DEBUG级别的信息还是出现了。 原因:在我引用的包中,一些python文件也使用了logging,我设定的INFO级别只能设定我当前使用的文件,而调用的包…...
TypeScript 语法基础 第一部分 类型
【视频链接】尚硅谷TypeScript教程(李立超老师TS新课) TypeScript TypeScript 语法基础 第二部分 类、接口、泛型1. 类型1.1 | 联合类型1.2 字面量类型1.3 any 任意类型1.4 unkown 类型1.5 as 类型断言1.6 object 对象类型1.7 { } 对象类型1.8 ÿ…...
GO Serial 学习与使用
文章目录 主要特性安装基本用法配置选项错误处理其他功能 github.com/goburrow/serial 是一个 Go 包,提供了一种简单的方式来与串口进行交互。以下是该包的主要特性和用法的简要概述: 主要特性 跨平台支持:支持 Windows、macOS 和 Linux。简…...
安卓app开发系列之-常用工具与库
✨ 关于我 ✨ 👨💻 Hi there! 我是 [Jamson],一名热爱编程与技术的狂热者,致力于前后端的全栈独立软件系统开发。通过不断学习和实践,我希望将知识分享给更多的朋友们,和大家一起成长。 💡 &…...
 
视频汇聚EasyCVR视频监控平台调取接口提示“认证过期”是什么原因?
视频汇聚EasyCVR视频监控平台,作为一款智能视频监控综合管理平台,凭借其强大的视频融合汇聚能力和灵活的视频能力,在各行各业的应用中发挥着越来越重要的作用。EasyCVR平台具备强大的拓展性和灵活性,支持多种视频流的外部分发&…...
uniapp视频禁止用户推拽进度条并保留进度条显示的解决方法——方案二
在uniapp项目中,使用<video>组件播放视频非常方便。默认情况下,视频组件会显示进度条,用户可以随意拖动进度条来控制视频播放进度。然而,在某些特定场景,如在线教育、广告宣传等,我们希望禁止用户拖动…...
 
mysql复合查询 -- 多表查询(介绍,笛卡尔积,使用),自连接(介绍,使用)
目录 多表查询 介绍 使用 表数据 显示雇员名,雇员工资,以及所在部门名 显示部门号为10的部门名,员工名,工资 自连接 介绍 场景 表数据 题目 子查询 自连接 多表查询 介绍 实际开发中往往数据来自不同的表,所以需要多表查询 语法: from 表1,表2 (笛卡…...
【个人笔记】数据一致性的解决方案
保证数据一致性:指保证redis里的数据和mysql的数据是一致的,不能说mysql更新了,但redis里面的还是旧的数据,反之亦然 先说结论:增删改的时候,把Redis中的缓存删了 为什么不先更新数据库,再更新…...
【WPF】多屏幕展示
使用环境为.Net Framework,如果有.Net 6的解决方案,欢迎交流。 话不多说,先上代码! /// <summary>/// Window窗口展示设置/// </summary>/// <param name"monitor"></param>/// <param nam…...
vue admin 若依框架 解决无权限时进入死循环的问题 auths
核心原因: if (auths && auths.length > 0) { // like12 find bug,数组为空[]时依然会进入死循环 原来为:if (auths) // 获取用户信息getInfo({ commit, state }) {return new Promise((resolve, reject) > {getInfo(state.token).then(…...
 
kubernetes存储入门(kubernetes)
实验环境依旧是三个节点拉取镜像,然后在master节点拉取资源清单: 然后同步会话,导入镜像; 存储入门 ConfigMap volume卷--》volumemount(挂载卷) Glusterfs NFS ISCSI HostPath ConfigMap Secret E…...
局部代理有什么好处?为什么不使用全局代理?
1. 什么是局部代理与全局代理? 局部代理:局部代理只会对特定应用程序或特定的网络流量进行代理,而不会影响其他网络流量。例如,你可以设置浏览器使用代理,而其他应用程序如邮件客户端或游戏仍然使用本地网络连接。 全…...
ssm模糊知识点整合
一、参数绑定常用注解 RequestParam:用于将请求参数绑定到你的方法参数上。 PathVariable:用于将路径变量绑定到你的方法参数上。 RequestBody:用于将请求主体绑定到你的方法参数上,通常用于绑定POST请求的JSON或XML数据。 Req…...
 
2、Spring Boot 3.x 集成 Feign
一、前言 本篇主要是围绕着两个点,1、集成 Feign,2、分离feign接口层,独立服务; 还有一点就是上篇文章的服务 iot-channel、system-server 服务名称调整成为了 chain-iot-channel、chain-system二、搭建 chain-common 服务 pom.…...
 
深度学习-图像处理篇-5ResNet和ResNeXt
解决问题: 梯度消失或梯度爆炸 退化问题(degradation problem) 迁移学习 ResNeXt...
类的关联、依赖、聚合和组合关系的思考(一)
最近在看《设计模式》这本书,发现对类之间的关系还没搞的很明白,而类之间的关系对读书、阅读代码和代码设计都非常重要,因此边看书边查阅了一些资料,感觉有些理解了。下面是我的一些思考,分享一下。 查阅了很多博客&a…...
 
云舟观测:集成开源Grafana Faro构建前端页面性能监控平台
在当今互联网时代,面对纷乱繁杂的网上资源,用户的耐心和注意力是极为宝贵的资源,当用户访问一个网站或应用时,他们期望的是快速且无缝的体验,任何加载延迟或功能故障都可能导致用户流失,影响品牌体验。因此…...
[特殊字符] 智能合约中的数据是如何在区块链中保持一致的?
🧠 智能合约中的数据是如何在区块链中保持一致的? 为什么所有区块链节点都能得出相同结果?合约调用这么复杂,状态真能保持一致吗?本篇带你从底层视角理解“状态一致性”的真相。 一、智能合约的数据存储在哪里…...
 
Docker 离线安装指南
参考文章 1、确认操作系统类型及内核版本 Docker依赖于Linux内核的一些特性,不同版本的Docker对内核版本有不同要求。例如,Docker 17.06及之后的版本通常需要Linux内核3.10及以上版本,Docker17.09及更高版本对应Linux内核4.9.x及更高版本。…...
 
MFC内存泄露
1、泄露代码示例 void X::SetApplicationBtn() {CMFCRibbonApplicationButton* pBtn GetApplicationButton();// 获取 Ribbon Bar 指针// 创建自定义按钮CCustomRibbonAppButton* pCustomButton new CCustomRibbonAppButton();pCustomButton->SetImage(IDB_BITMAP_Jdp26)…...
 
循环冗余码校验CRC码 算法步骤+详细实例计算
通信过程:(白话解释) 我们将原始待发送的消息称为 M M M,依据发送接收消息双方约定的生成多项式 G ( x ) G(x) G(x)(意思就是 G ( x ) G(x) G(x) 是已知的)࿰…...
【SpringBoot】100、SpringBoot中使用自定义注解+AOP实现参数自动解密
在实际项目中,用户注册、登录、修改密码等操作,都涉及到参数传输安全问题。所以我们需要在前端对账户、密码等敏感信息加密传输,在后端接收到数据后能自动解密。 1、引入依赖 <dependency><groupId>org.springframework.boot</groupId><artifactId...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
 
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
 
智能仓储的未来:自动化、AI与数据分析如何重塑物流中心
当仓库学会“思考”,物流的终极形态正在诞生 想象这样的场景: 凌晨3点,某物流中心灯火通明却空无一人。AGV机器人集群根据实时订单动态规划路径;AI视觉系统在0.1秒内扫描包裹信息;数字孪生平台正模拟次日峰值流量压力…...
 
初探Service服务发现机制
1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能:服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源…...
QT3D学习笔记——圆台、圆锥
类名作用Qt3DWindow3D渲染窗口容器QEntity场景中的实体(对象或容器)QCamera控制观察视角QPointLight点光源QConeMesh圆锥几何网格QTransform控制实体的位置/旋转/缩放QPhongMaterialPhong光照材质(定义颜色、反光等)QFirstPersonC…...
