《计算机视觉》——图像拼接

图像拼接

  • 图像拼接是将多幅有重叠区域的图像合并成一幅全景或更大视角图像的技术,以下为你详细介绍:
    • 原理:图像拼接的核心原理是基于图像之间的特征匹配。首先,从每幅图像中提取独特的特征点,如角点、边缘点等,这些特征点具有在不同图像中能被准确识别的特点。然后,通过计算特征点之间的相似度,找到不同图像中相匹配的特征点对。一旦确定了匹配点,就可以根据这些点来计算图像之间的变换关系,如平移、旋转、缩放等,从而将图像对齐到同一坐标系中。最后,将对齐后的图像进行融合,消除拼接缝隙,生成一幅无缝的拼接图像。

主要步骤

  • 特征提取:常用的特征提取算法有 SIFT(尺度不变特征变换)、SURF(加速稳健特征)和 ORB(加速的具有旋转不变性的 FAST 特征点和 BRIEF 描述子)等。这些算法可以在不同光照、尺度和旋转条件下,稳定地提取图像中的特征点。
  • 特征匹配:通过计算特征点的描述子之间的距离(如欧氏距离),找到不同图像中相似的特征点对。为了提高匹配的准确性,通常会使用一些匹配策略,如最近邻匹配、比率测试等。
  • 图像变换:根据匹配点计算出图像之间的变换矩阵,然后将其中一幅图像进行变换,使其与另一幅图像对齐。常见的变换模型有仿射变换、透视变换等。
  • 图像融合:将对齐后的图像进行融合,以消除拼接缝隙。常用的融合方法有加权平均融合、多分辨率融合等。

应用领域

  • 全景摄影:通过拍摄多张不同角度的照片,然后拼接成一幅全景图像,为用户提供更广阔的视野。
  • 医学图像:在医学领域,将多幅显微镜图像或 X 光图像拼接成一幅完整的图像,以便医生更全面地观察病变区域。
  • 计算机视觉:在机器人导航、自动驾驶等领域,图像拼接技术可以帮助系统获取更广阔的环境信息,提高系统的感知能力。
  • 文物保护与修复:对破损的文物图像进行拼接和修复,恢复文物的原貌。

实例

对两张图片进行拼接:图片1在这里插入图片描述
图片2
在这里插入图片描述

代码

  • 导入模块
# 导入OpenCV库,用于计算机视觉任务,如图像读取、处理和显示等
import cv2
# 导入NumPy库,用于处理多维数组和矩阵运算
import numpy as np
# 导入sys模块,用于与Python解释器进行交互,这里主要用于退出程序
import sys
  • 定义显示图像
# 定义一个函数用于显示图像
def cv_show(name, img):# 在名为name的窗口中显示图像imgcv2.imshow(name, img)# 等待用户按键,按任意键后关闭窗口cv2.waitKey(0)
  • 定义检测关键点
# 定义一个函数用于检测图像中的关键点并提取特征描述符
def detectAndDescribe(image):# 将输入的彩色图像转换为灰度图像,因为SIFT算法通常在灰度图像上进行处理gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)# 创建一个SIFT(尺度不变特征变换)特征检测器和描述符对象descriptor = cv2.SIFT_create()# 使用SIFT对象检测图像中的关键点并计算其特征描述符# kps是关键点对象列表,des是对应的特征描述符矩阵(kps, des) = descriptor.detectAndCompute(gray, None)# 将关键点的坐标从关键点对象中提取出来,并转换为NumPy的浮点型数组kps_float = np.float32([kp.pt for kp in kps])# 返回关键点对象列表、关键点坐标数组和特征描述符矩阵return (kps, kps_float, des)
  • 读取图像显示图像
# 读取第一张图像,图像文件名为'1.jpg'
imageA = cv2.imread('1.jpg')
# 读取第二张图像,图像文件名为'2.jpg'
imageB = cv2.imread('2.jpg')
# 显示第一张图像,窗口名为'imageA'
cv_show('imageA', imageA)
# 显示第二张图像,窗口名为'imageB'
cv_show('imageB', imageB)

在这里插入图片描述
在这里插入图片描述

  • 进行关键点检测和特征描述符提取
# 对第一张图像进行关键点检测和特征描述符提取
(kpsA, kps_floatA, desA) = detectAndDescribe(imageA)
# 对第二张图像进行关键点检测和特征描述符提取
(kpsB, kps_floatB, desB) = detectAndDescribe(imageB)
  • 创建暴力匹配器对象
# 创建一个暴力匹配器对象,用于匹配特征描述符
matcher = cv2.BFMatcher()
  • 特征匹配
# 使用K近邻匹配算法对第二张图像和第一张图像的特征描述符进行匹配
# 这里的2表示每个查询描述符返回两个最近邻的匹配结果
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列表中good.append(m)# 将匹配点的索引对添加到matches列表中matches.append((m[0].queryIdx, m[0].trainIdx))
  • 绘制匹配关键点
# 在两张图像上绘制满足条件的匹配关键点
# flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS表示绘制带有关键点信息的匹配线
vis = cv2.drawMatchesKnn(imageB, kpsB, imageA, kpsA, good, None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
# 显示绘制了匹配关键点的图像,窗口名为'Keypoint Matches'
cv_show('Keypoint Matches', vis)

在这里插入图片描述

  • 透视变换
# 检查匹配点的数量是否大于4
if len(matches) > 4:# 提取第二张图像中匹配点的坐标ptsB = np.float32([kps_floatB[i] for (i, _) in matches])# 提取第一张图像中匹配点的坐标ptsA = np.float32([kps_floatA[i] for (_, i) in matches])# 使用RANSAC算法计算从第二张图像到第一张图像的单应性矩阵H# 10是RANSAC算法的阈值(H, mask) = cv2.findHomography(ptsB, ptsA, cv2.RANSAC, 10)
else:# 如果匹配点数量小于等于4,打印提示信息print('图片未找到四个以上的匹配点')# 退出程序sys.exit()# 使用计算得到的单应性矩阵H对第二张图像进行透视变换
# 变换后的图像宽度为两张图像宽度之和,高度为第二张图像的高度
result = cv2.warpPerspective(imageB, H, (imageB.shape[1] + imageA.shape[1], imageB.shape[0]))
# 显示透视变换后的第二张图像,窗口名为'resultB'
cv_show('resultB', result)

在这里插入图片描述

  • 进行拼接
# 将第一张图像复制到透视变换后的图像的左上角
result[0:imageA.shape[0], 0:imageA.shape[1]] = imageA
# 显示拼接后的最终图像,窗口名为'result'
cv_show('result', result)

在这里插入图片描述

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

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

相关文章

后台管理系统-园区管理

功能演示和模版搭建 <template><div class"building-container"><!-- 搜索区域 --><div class"search-container"><div class"search-label">企业名称&#xff1a;</div><el-input clearable placeholde…

CSS中padding和margin属性的使用

在 HTML 中&#xff0c;padding 和 margin 是用于控制元素布局和间距的重要属性。 一、Padding&#xff08;内边距&#xff09; 定义&#xff1a;Padding 是指元素内容与元素边框之间的距离。它可以在元素内部创造出空白区域&#xff0c;使得内容不会紧贴着边框。 作用 增加元…

git中,如何查看具体单个文件的log

在 Git 中&#xff0c;可以使用多种方式查看单个文件的提交日志&#xff08;Log&#xff09;&#xff0c;以下详细介绍不同场景下的查看方法&#xff1a; 目录 一、基本命令查看文件的完整提交日志 二、查看文件提交日志并显示差异内容 三、限制显示的提交日志数量 四、按…

日常知识点之刷题一

1&#xff1a;流浪地球 0~n-1个发动机&#xff0c;计划启动m次&#xff0c;求最后启动的发动机的个数。 以及发动机的编号。&#xff08;模拟过程&#xff0c;每次手动启动的机器对应时间向两边扩散&#xff09; //输入每个启动的时间和编号 void test_liulang() {int n, m;ci…

C++面向对象编程技术研究

一、引言 面向对象编程&#xff08;OOP&#xff09;是一种程序设计方法&#xff0c;它将现实世界中的实体抽象为“对象”&#xff0c;并通过类和对象来实现程序的设计。OOP的核心思想包括封装、继承和多态&#xff0c;这些特性使得程序更加模块化、易于扩展和维护。C作为一种支…

Day54(补)【AI思考】-SOA,Web服务以及无状态分步解析与示例说明

文章目录 **SOA&#xff0c;Web服务以及无状态**分步解析与示例说明**分步解析与示例说明****1. 核心概念解析****2. 为什么说SOA与Web服务是“正交的”&#xff1f;****3. 架构风格 vs. 实现技术****4. 接口&#xff08;Interface&#xff09;的核心作用****5. Web服务的“被认…

【Deepseek高级使用教程】Deepseek-R1的5种高级进阶玩法,5分钟教会你Deepseek+行业的形式进行工作重构的保姆级教程

AI视频生成&#xff1a;小说文案智能分镜智能识别角色和场景批量Ai绘图自动配音添加音乐一键合成视频https://aitools.jurilu.com/ 最近&#xff0c;有各行各业的小伙伴问我&#xff0c;到底应该怎么将deepseek融入进他们自身的工作流呢&#xff1f;其实这个问题很简单。我就以…

selenium爬取苏宁易购平台某产品的评论

目录 selenium的介绍 1、 selenium是什么&#xff1f; 2、selenium的工作原理 3、如何使用selenium&#xff1f; webdriver浏览器驱动设置 关键步骤 代码 运行结果 注意事项 selenium的介绍 1、 selenium是什么&#xff1f; 用于Web应用程序测试的工具。可以驱动浏览…

[实现Rpc] 客户端 | Requestor | RpcCaller的设计实现

目录 Requestor类的实现 框架 完善 onResponse处理回复 完整代码 RpcCaller类的实现 1. 同步调用 call 2. 异步调用 call 3. 回调调用 call Requestor类的实现 &#xff08;1&#xff09;主要功能&#xff1a; 客户端发送请求的功能&#xff0c;进行请求描述对服务器…

P2889 [USACO07NOV] Milking Time S

题目大意 有 N N N 个小时可以挤奶。其中有 m m m 个时间段可以给 Bessis 奶牛挤奶。第 i i i 个时间段为 s i s_i si​ ~ t i t_i ti​&#xff0c;可以获得 E f f i Eff_i Effi​ 滴奶。每次挤完奶后&#xff0c;人都要休息 R R R 小时。最后问&#xff0c;一共能挤出…

ONNX转RKNN的环境搭建和部署流程

将ONNX模型转换为RKNN模型的过程记录 工具准备 rknn-toolkit:https://github.com/rockchip-linux/rknn-toolkit rknn-toolkit2:https://github.com/airockchip/rknn-toolkit2 rknn_model_zoo:https://github.com/airockchip/rknn_model_zoo ultralytics_yolov8:https://github…

20250221 NLP

1.向量和嵌入 https://zhuanlan.zhihu.com/p/634237861 encoder的输入就是向量&#xff0c;提前嵌入为向量 二.多模态文本嵌入向量过程 1.文本预处理 文本tokenizer之前需要预处理吗&#xff1f; 是的&#xff0c;文本tokenizer之前通常需要对文本进行预处理。预处理步骤可…

C++基础知识学习记录—多态

1、函数覆盖 函数覆盖也被称为函数重写&#xff0c;类似于函数隐藏&#xff0c; 函数覆盖是多态的前提条件之一。 函数覆盖与函数隐藏的区别&#xff1a; ● 基类的被覆盖函数需要使用virtual关键字修饰&#xff0c;表示这个函数是一个虚函数 在Qt Creator中虚函数是斜体 虚…

GoFly框架中集成Bolt 和badfer两个Go语言嵌入式键值数据库

本插件集成了Bolt 和badfer两个纯Go实现的快速的嵌入式K/V数据库&#xff0c;方便开发时本地存储使用。插件集成Bolt 和badfer两个&#xff0c;如果确定使用其中一个&#xff0c;也可以把其中不用的一个删除&#xff0c;不删除也不会有任何影响。 插件使用说明 1.安装插件 到…

AWS - Redshift - 外部表读取 Parquet 文件中 timestamp 类型的数据

问题&#xff1a; 通过 Redshift Spectrum 功能可以读取 S3 中的文件&#xff0c;当读取 Parquet 文件时&#xff0c;如果列格式设置为 timestamp&#xff0c; 通过 psql 客户端读取会出现以下错误&#xff1a; testdb# select * from myspectrum_schema_0219.test_ns; ERROR…

Pretraining Language Models with Text-Attributed Heterogeneous Graphs

Pretraining Language Models with Text-Attributed Heterogeneous Graphs EMNLP 推荐指数&#xff1a;#paper/⭐⭐#​ 贡献&#xff1a; 我们研究了在更复杂的数据结构上预训练LM的问题&#xff0c;即&#xff0c;TAHG。与大多数只能从每个节点的文本描述中学习的PLM不同&…

重新求职刷题DAY18

1.513. 找树左下角的值 给定一个二叉树的 根节点 root&#xff0c;请找出该二叉树的 最底层 最左边 节点的值。 假设二叉树中至少有一个节点。 示例 1: 外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传 输入: root [2,1,3] 输出: 1思路&#xff1a; 这…

B站pwn教程笔记-2

这次是栈溢出基础。 栈基础知识 栈帧结构概览 看上图的高地址和低地址。arguments是子函数的形参。蓝色的是上一个栈的ebp值&#xff0c;用于在子函数执行完毕之后&#xff0c;返回到正确的ebp. heap的占的内存大大的超过stack。 下面看看调用栈的详细过程。 一个函数都是以…

Qt中C++与QML交互从原理、方法与实践陷阱深度解析

在我们使用Qt开发中&#xff0c;现在以及普遍通过 C 与 QML 的交互&#xff0c;将 C 的强大功能与 QML 的界面设计优势相结合&#xff0c;既保证了应用程序的性能和稳定性&#xff0c;又能快速实现美观、易用的用户界面。接下来专门讲下C与QML交互原理、方法与实践中的一些陷阱…

JavaScript获取DOM元素语法总结(getElementsByName()、querySelector()、querySelectorAll())

文章目录 JavaScript DOM 元素获取语法总结关键点简介方法概述详细报告引言DOM 元素获取方法1. getElementById()&#xff08;弃用&#xff09;2. getElementsByClassName()&#xff08;弃用&#xff09;3. getElementsByTagName()&#xff08;弃用&#xff09;4. getElementsB…