当前位置: 首页 > news >正文

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.图像配准&#xff08;1&#xff09;.特征点检测&#xff08;2&#xff09;.特征匹配 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 数据库中的异常和游标管理

异常和游标管理 游标&#xff1a; 用来查询数据库&#xff0c;获取记录集合&#xff08;结果集&#xff09;的指针&#xff0c;可以让开发者一次访问一行结果集&#xff0c;在每条结果集上作操作。 分类&#xff1a; 静态游标&#xff1a; 分为显式游标和隐式游标。 REF游标&…...

关于python 日志设定为INFO 但是DEBUG仍旧写入的问题

问题&#xff1a;将logging设定为了INFO级别&#xff0c;但是在打印的时候发现jieba包中的DEBUG级别的信息还是出现了。 原因&#xff1a;在我引用的包中&#xff0c;一些python文件也使用了logging&#xff0c;我设定的INFO级别只能设定我当前使用的文件&#xff0c;而调用的包…...

TypeScript 语法基础 第一部分 类型

【视频链接】尚硅谷TypeScript教程&#xff08;李立超老师TS新课&#xff09; TypeScript TypeScript 语法基础 第二部分 类、接口、泛型1. 类型1.1 | 联合类型1.2 字面量类型1.3 any 任意类型1.4 unkown 类型1.5 as 类型断言1.6 object 对象类型1.7 { } 对象类型1.8 &#xff…...

GO Serial 学习与使用

文章目录 主要特性安装基本用法配置选项错误处理其他功能 github.com/goburrow/serial 是一个 Go 包&#xff0c;提供了一种简单的方式来与串口进行交互。以下是该包的主要特性和用法的简要概述&#xff1a; 主要特性 跨平台支持&#xff1a;支持 Windows、macOS 和 Linux。简…...

安卓app开发系列之-常用工具与库

✨ 关于我 ✨ &#x1f468;‍&#x1f4bb; Hi there! 我是 [Jamson]&#xff0c;一名热爱编程与技术的狂热者&#xff0c;致力于前后端的全栈独立软件系统开发。通过不断学习和实践&#xff0c;我希望将知识分享给更多的朋友们&#xff0c;和大家一起成长。 &#x1f4a1; &…...

视频汇聚EasyCVR视频监控平台调取接口提示“认证过期”是什么原因?

视频汇聚EasyCVR视频监控平台&#xff0c;作为一款智能视频监控综合管理平台&#xff0c;凭借其强大的视频融合汇聚能力和灵活的视频能力&#xff0c;在各行各业的应用中发挥着越来越重要的作用。EasyCVR平台具备强大的拓展性和灵活性&#xff0c;支持多种视频流的外部分发&…...

uniapp视频禁止用户推拽进度条并保留进度条显示的解决方法——方案二

在uniapp项目中&#xff0c;使用<video>组件播放视频非常方便。默认情况下&#xff0c;视频组件会显示进度条&#xff0c;用户可以随意拖动进度条来控制视频播放进度。然而&#xff0c;在某些特定场景&#xff0c;如在线教育、广告宣传等&#xff0c;我们希望禁止用户拖动…...

mysql复合查询 -- 多表查询(介绍,笛卡尔积,使用),自连接(介绍,使用)

目录 多表查询 介绍 使用 表数据 显示雇员名,雇员工资,以及所在部门名 显示部门号为10的部门名,员工名,工资 自连接 介绍 场景 表数据 题目 子查询 自连接 多表查询 介绍 实际开发中往往数据来自不同的表&#xff0c;所以需要多表查询 语法: from 表1,表2 (笛卡…...

【个人笔记】数据一致性的解决方案

保证数据一致性&#xff1a;指保证redis里的数据和mysql的数据是一致的&#xff0c;不能说mysql更新了&#xff0c;但redis里面的还是旧的数据&#xff0c;反之亦然 先说结论&#xff1a;增删改的时候&#xff0c;把Redis中的缓存删了 为什么不先更新数据库&#xff0c;再更新…...

【WPF】多屏幕展示

使用环境为.Net Framework&#xff0c;如果有.Net 6的解决方案&#xff0c;欢迎交流。 话不多说&#xff0c;先上代码&#xff01; /// <summary>/// Window窗口展示设置/// </summary>/// <param name"monitor"></param>/// <param nam…...

vue admin 若依框架 解决无权限时进入死循环的问题 auths

核心原因&#xff1a; if (auths && auths.length > 0) { // like12 find bug,数组为空[]时依然会进入死循环 原来为&#xff1a;if (auths) // 获取用户信息getInfo({ commit, state }) {return new Promise((resolve, reject) > {getInfo(state.token).then(…...

kubernetes存储入门(kubernetes)

实验环境依旧是三个节点拉取镜像&#xff0c;然后在master节点拉取资源清单&#xff1a; 然后同步会话&#xff0c;导入镜像&#xff1b; 存储入门 ConfigMap volume卷--》volumemount&#xff08;挂载卷&#xff09; Glusterfs NFS ISCSI HostPath ConfigMap Secret E…...

局部代理有什么好处?为什么不使用全局代理?

1. 什么是局部代理与全局代理&#xff1f; 局部代理&#xff1a;局部代理只会对特定应用程序或特定的网络流量进行代理&#xff0c;而不会影响其他网络流量。例如&#xff0c;你可以设置浏览器使用代理&#xff0c;而其他应用程序如邮件客户端或游戏仍然使用本地网络连接。 全…...

ssm模糊知识点整合

一、参数绑定常用注解 RequestParam&#xff1a;用于将请求参数绑定到你的方法参数上。 PathVariable&#xff1a;用于将路径变量绑定到你的方法参数上。 RequestBody&#xff1a;用于将请求主体绑定到你的方法参数上&#xff0c;通常用于绑定POST请求的JSON或XML数据。 Req…...

2、Spring Boot 3.x 集成 Feign

一、前言 本篇主要是围绕着两个点&#xff0c;1、集成 Feign&#xff0c;2、分离feign接口层&#xff0c;独立服务&#xff1b; 还有一点就是上篇文章的服务 iot-channel、system-server 服务名称调整成为了 chain-iot-channel、chain-system二、搭建 chain-common 服务 pom.…...

深度学习-图像处理篇-5ResNet和ResNeXt

解决问题&#xff1a; 梯度消失或梯度爆炸 退化问题(degradation problem) 迁移学习 ResNeXt...

类的关联、依赖、聚合和组合关系的思考(一)

最近在看《设计模式》这本书&#xff0c;发现对类之间的关系还没搞的很明白&#xff0c;而类之间的关系对读书、阅读代码和代码设计都非常重要&#xff0c;因此边看书边查阅了一些资料&#xff0c;感觉有些理解了。下面是我的一些思考&#xff0c;分享一下。 查阅了很多博客&a…...

云舟观测:集成开源Grafana Faro构建前端页面性能监控平台

在当今互联网时代&#xff0c;面对纷乱繁杂的网上资源&#xff0c;用户的耐心和注意力是极为宝贵的资源&#xff0c;当用户访问一个网站或应用时&#xff0c;他们期望的是快速且无缝的体验&#xff0c;任何加载延迟或功能故障都可能导致用户流失&#xff0c;影响品牌体验。因此…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

MongoDB学习和应用(高效的非关系型数据库)

一丶 MongoDB简介 对于社交类软件的功能&#xff0c;我们需要对它的功能特点进行分析&#xff1a; 数据量会随着用户数增大而增大读多写少价值较低非好友看不到其动态信息地理位置的查询… 针对以上特点进行分析各大存储工具&#xff1a; mysql&#xff1a;关系型数据库&am…...

线程同步:确保多线程程序的安全与高效!

全文目录&#xff1a; 开篇语前序前言第一部分&#xff1a;线程同步的概念与问题1.1 线程同步的概念1.2 线程同步的问题1.3 线程同步的解决方案 第二部分&#xff1a;synchronized关键字的使用2.1 使用 synchronized修饰方法2.2 使用 synchronized修饰代码块 第三部分&#xff…...

Linux简单的操作

ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...

反射获取方法和属性

Java反射获取方法 在Java中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时访问和操作类的内部属性和方法。通过反射&#xff0c;可以动态地创建对象、调用方法、改变属性值&#xff0c;这在很多Java框架中如Spring和Hiberna…...

鸿蒙中用HarmonyOS SDK应用服务 HarmonyOS5开发一个生活电费的缴纳和查询小程序

一、项目初始化与配置 1. 创建项目 ohpm init harmony/utility-payment-app 2. 配置权限 // module.json5 {"requestPermissions": [{"name": "ohos.permission.INTERNET"},{"name": "ohos.permission.GET_NETWORK_INFO"…...

LLM基础1_语言模型如何处理文本

基于GitHub项目&#xff1a;https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken&#xff1a;OpenAI开发的专业"分词器" torch&#xff1a;Facebook开发的强力计算引擎&#xff0c;相当于超级计算器 理解词嵌入&#xff1a;给词语画"…...

C++八股 —— 单例模式

文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全&#xff08;Thread Safety&#xff09; 线程安全是指在多线程环境下&#xff0c;某个函数、类或代码片段能够被多个线程同时调用时&#xff0c;仍能保证数据的一致性和逻辑的正确性&#xf…...

使用Spring AI和MCP协议构建图片搜索服务

目录 使用Spring AI和MCP协议构建图片搜索服务 引言 技术栈概览 项目架构设计 架构图 服务端开发 1. 创建Spring Boot项目 2. 实现图片搜索工具 3. 配置传输模式 Stdio模式&#xff08;本地调用&#xff09; SSE模式&#xff08;远程调用&#xff09; 4. 注册工具提…...

RabbitMQ入门4.1.0版本(基于java、SpringBoot操作)

RabbitMQ 一、RabbitMQ概述 RabbitMQ RabbitMQ最初由LShift和CohesiveFT于2007年开发&#xff0c;后来由Pivotal Software Inc.&#xff08;现为VMware子公司&#xff09;接管。RabbitMQ 是一个开源的消息代理和队列服务器&#xff0c;用 Erlang 语言编写。广泛应用于各种分布…...