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

《深度学习》OpenCV 图像拼接 原理、参数解析、案例实现

目录

一、图像拼接

1、直接看案例

图1与图2展示:

合并完结果:

2、什么是图像拼接

3、图像拼接步骤

1)加载图像

2)特征点检测与描述

3)特征点匹配

4)图像配准

5)图像变换和拼接

6)图像调整

二、案例实现

1、定义函数返回图像的关键点和描述符

2、定义展示图像函数

3、计算读入图像的特征点和描述符

调试模式状态下:

kps对应值:

des对应值:

4、建立暴力匹配器和K近邻算法

1)关于BFMatcher暴力匹配

2)暴力匹配的K近邻

用法:

参数解析:

返回值:

3)续接上文代码

运行结果:

调试模式rawMatches内容:

5、绘制匹配结果

运行结果:

6、计算视角变换矩阵

调试模式下

kps_floatA与kps_floatB状态

matches状态

7、透视变换后拼接

运行结果:

8、完整代码:


一、图像拼接

1、直接看案例

        图1与图2展示:

        合并完结果:

2、什么是图像拼接

        图像拼接是指将多个图像拼接成一个大图像。在计算机视觉和图像处理领域,图像拼接常用于创建全景图像、创建大幅面照片、图像拼接等应用。

3、图像拼接步骤

        1)加载图像

                使用OpenCV的cv::imread函数加载需要拼接的多个图像。

        2)特征点检测与描述

                使用特征提取算法(如SIFTORB等)检测图像中的特征点,并计算每个特征点的描述符。

        3)特征点匹配

                使用特征匹配算法(如KNN匹配)来找到两个图像间的对应关系。常见的方法有基于距离的匹配(如欧氏距离、汉明距离等)和基于相似性度量的匹配(如比率测试)。

        4)图像配准

                根据特征点的匹配结果,使用配准算法(如RANSAC)估计两个图像间的变换矩阵。常见的变换矩阵包括仿射变换、透视变换等。

        5)图像变换和拼接

                使用估计得到的变换矩阵,将需要拼接的图像进行变换,并将它们拼接在一起。可以使用OpenCV的cv::warpPerspective函数或cv::warpAffine函数来实现变换和拼接。

        6)图像调整

                对拼接后的图像进行调整,使得拼接边缘平滑过渡,消除拼接处的不连续性。常见的方法包括图像融合图像平滑等。

二、案例实现

1、定义函数返回图像的关键点和描述符

import cv2
import numpy as np
import sysdef detectAndDescribe(image):   # 函数用于gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)   # 将影色园片转换成死没图descriptor = cv2.SIFT_create()   # 建立SIFT生成器(kps,des) = descriptor.detectAndCompute(gray,None)   # 读入参数为灰度图和可选参数掩膜,检测关键点及描述符,返回关键点列表和关键点对应的描述符列表,每个描述符都是一个向量,描述关键点周围图像内容# 此处kps是元组类型,des是ndarry矩阵类型# 将关键点列表的结果转换战NumPy数组kps_float = np.float32([kp.pt for kp in kps])# kp.pt 包含两个值,分别是关键点在图像中的 x 和 y 坐标。这些坐标通常是浮点数,可以精确的捕述关键点在图像中的位置return (kps,kps_float,des)   # 返回特征点集,及对应的描述特征

2、定义展示图像函数

def cv_show(name,img):   # 函数用于展示图片cv2.imshow(name,img)cv2.waitKey(0)

3、计算读入图像的特征点和描述符

"""读取拼接图片"""
imageA = cv2.imread("1.jpg")
cv_show('imageA',imageA)
imageB = cv2.imread("2.jpg")
cv_show("imageB",imageB)"""计算图片特征点及描述符"""
(kpsA,kps_floatA,desA) = detectAndDescribe(imageA)
(kpsB,kps_floatB,desB) = detectAndDescribe(imageB)
        调试模式状态下:
                kps对应值:

                des对应值:

4、建立暴力匹配器和K近邻算法

        1)关于BFMatcher暴力匹配

                在图像处理中,特征点匹配是指在不同图像中找到对应的特征点。BFMatcher可用于在两个特征向量集合中计算最佳匹配。它通过计算两个特征向量的相似度(如欧氏距离、汉明距离等),并选择最近邻的特征点作为匹配点。

        

        2)暴力匹配的K近邻
                用法:
使用KNN检测来自A、B图的SIFT特征匹配对
# knnMatch(gueryDescriptors, trainDescriptors, k, mask=None, compactResult=None)
                参数解析:

                        queryDescriptors:匹配图像A的描述符

                        trainDescriptors:匹配图像B的描述符

                        K:最佳匹配的描述符个数,一般K=2

                        mask 可选参数:一个掩码数组,用于过滤不需要匹配的特征点。默认为None,表示不使用掩码。

                        compactResult 可选参数:一个布尔值,指定是否返回紧凑的匹配结果。默认为None,表示根据特征描述符的类型自动选择。

        

                返回值:

                        distance:匹配的特征点描述符的欧式距离,数值越小也就说明俩个特征点越相近

                        queryIdx:测试图像特征点描述符的下标(第几个特征点描述符),同时也是描述符对应特征点的下标。

                        trainIdx:样本图像的特征点描述符下标,同时也是描述符对应特征点的下标。

        3)续接上文代码
matcher = cv2.BFMatcher()
rawMatches = matcher.knnMatch(desB,desA,2)   # 对desB中的每个描述符在desA中查找两个最近邻
good = []   # 设置空列表用于存放匹配成功的特征点
matches =[]   # 用于存放匹配成功的两个点的索引值
for m in rawMatches:# 当最近距离跟次近距离的比值小于0.65值时,保留此匹配对if len(m) == 2 and m[0].distance < 0.65 * m[1].distance:  # len(m) == 2 表示检查是否有两个匹配项# m[0].distance < 0.65 * m[1].distance表示判断匹配的两个点最近邻和次近邻的比值是否小于0.65good.append(m)# 存储两个点在featuresA,featuresB中的索引值matches.append((m[0].trainIdx, m[0].queryIdx))
print(len(good))  # 返回匹配成功的特征点个数
print(matches)   # 打印匹配成功点的索引
                运行结果:

                调试模式rawMatches内容:

5、绘制匹配结果

# 绘制两组关键点的匹配结果,输入参数为B图原图,B图的关键点列表,A图原图,A图的关键点列表,匹配成功的点的坐标,掩码图像默认为None
# flag 表示绘制的标志,cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS表示在关键点周围绘制圆圈,圆圈大小与关键点尺度成比例
vis = cv2.drawMatchesKnn(imageB,kpsB,imageA,kpsA,good,None,flags = cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv_show('keypoint matches',vis)
        运行结果:

6、计算视角变换矩阵

"""透视变换"""
if len(matches) > 4 :  # 当前筛选后的匹配对大于4.计算视角变换矩阵# 分别获取匹配成功的A图中点的坐标与B图中点的坐标ptsA = np.float32([kps_floatA[i] for (i,_) in matches])   # kps_floatA是匹配成功点的坐标,matches是通过阈值筛选之后的特征点对象,其中存放匹配成功点的索引,ptsB = np.float32([kps_floatB[i] for (_,i) in matches])   # kps_floatB是图片B中的全就特征点坐标(H, mask) = cv2.findHomography(ptsB, ptsA, cv2.RANSAC,  10)
else:print('图片未找到4个以上的匹配点')sys.exit()
        调试模式下
                kps_floatA与kps_floatB状态

                matches状态

7、透视变换后拼接

# 根据视角变换矩阵H将原图B进行透视变换,然后将变换后的图片与A进行拼接
result = cv2.warpPerspective(imageB,H,(imageB.shape[1] + imageA.shape[1],imageB.shape[0]))
cv_show('resultB',result)
# 将图片A传入result图片最左端
result[0:imageA.shape[0],0:imageA.shape[1]] = imageA
cv_show('result',result)
        运行结果:

8、完整代码:

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)   return (kps,kps_float,des)   imageA = cv2.imread("1.jpg")
cv_show('imageA',imageA)
imageB = cv2.imread("2.jpg")
cv_show("imageB",imageB)(kpsA,kps_floatA,desA) = detectAndDescribe(imageA)
(kpsB,kps_floatB,desB) = detectAndDescribe(imageB)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:  good.append(m)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 matches',vis)if len(matches) > 4 :  ptsA = np.float32([kps_floatA[i] for (i,_) in matches])   ptsB = np.float32([kps_floatB[i] for (_,i) in matches])   (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)
result[0:imageA.shape[0],0:imageA.shape[1]] = imageA
cv_show('result',result)

相关文章:

《深度学习》OpenCV 图像拼接 原理、参数解析、案例实现

目录 一、图像拼接 1、直接看案例 图1与图2展示&#xff1a; 合并完结果&#xff1a; 2、什么是图像拼接 3、图像拼接步骤 1&#xff09;加载图像 2&#xff09;特征点检测与描述 3&#xff09;特征点匹配 4&#xff09;图像配准 5&#xff09;图像变换和拼接 6&am…...

Hive数仓操作(三)

一、Hive 数据库操作 1. 创建数据库 基本创建数据库命令&#xff1a; CREATE DATABASE bigdata;说明&#xff1a; 数据库会在 HDFS 中以目录的形式创建和保存&#xff0c;数据库名称会存储在 Hive 的元数据中。如果不指定目录&#xff0c;数据库将在 /user/hive/warehouse 下…...

TDSQL-C电商可视化,重塑电商决策新纪元

前言&#xff1a; 在数字化浪潮席卷全球的今天&#xff0c;电子商务行业以其独特的魅力和无限潜力&#xff0c;成为了推动全球经济增长的重要引擎。然而&#xff0c;随着业务规模的急剧扩张&#xff0c;海量数据的涌现给电商企业带来了前所未有的挑战与机遇。如何高效地处理、…...

翔云 OCR:发票识别与验真

在数字化时代&#xff0c;高效处理大量文档和数据成为企业和个人的迫切需求。翔云 OCR 作为一款强大的光学字符识别工具&#xff0c;在发票识别及验真方面表现出色&#xff0c;为我们带来了极大的便利。 一、翔云 OCR 简介 翔云 OCR 是一款基于先进的人工智能技术开发的文字识别…...

HTML ASCII:Web 开发中的字符编码基础

HTML ASCII&#xff1a;Web 开发中的字符编码基础 ASCII&#xff0c;全称为美国信息交换标准代码&#xff08;American Standard Code for Information Interchange&#xff09;&#xff0c;是一种用于电子通信的字符编码标准。它最初于1963年提出&#xff0c;用于在不同的计算…...

Meta 首个多模态大模型一键启动!首个多针刺绣数据集上线,含超 30k 张图片

小扎在 Meta Connect 2024 主题演讲中宣布推出首个多模态大模型 Llama 3.2 vision&#xff01;该模型有 11B 和 90B 两个版本&#xff0c;成为首批支持多模态任务的 Llama 系列模型&#xff0c;根据官方数据&#xff0c;这两个开原模型的性能已超越闭源模型。 小编已经迫不及待…...

阿里云ECS服务器仿真

1.首先使用qemu-img对RAW镜像进行转换&#xff0c;qemu-img convert -O vmdk 1.raw 2.vmdk 2.使用WinHex对镜像的root密码进行删除 3.由于这次阿里云ECS使用了CONFIG_SYSTEM_TRUSTED_KEYS验证&#xff0c;无法直接仿真&#xff0c;需使用live系统对内核进行修改。分为以下几步&…...

如何为树莓派安装操作系统,以及远程操控树莓派的两种方法,无线操控和插网线操控

文章目录 一、下载树莓派的系统二、将文件下载到SD卡中1.使用官方软件2.其他选择 三、远程连接电脑安装vnc-viewer1.无线操作&#xff08;配置树莓派&#xff0c;开启VNC&#xff09;电脑远程配置2.有线连接&#xff08;需要一根网线&#xff09; 总结 一、下载树莓派的系统 下…...

【最新华为OD机试E卷-支持在线评测】简单的自动曝光(100分)多语言题解-(Python/C/JavaScript/Java/Cpp)

🍭 大家好这里是春秋招笔试突围 ,一枚热爱算法的程序员 💻 ACM金牌🏅️团队 | 大厂实习经历 | 多年算法竞赛经历 ✨ 本系列打算持续跟新华为OD-E/D卷的多语言AC题解 🧩 大部分包含 Python / C / Javascript / Java / Cpp 多语言代码 👏 感谢大家的订阅➕ 和 喜欢�…...

每日一练:等差数列划分

413. 等差数列划分 - 力扣&#xff08;LeetCode&#xff09; 题目要求&#xff1a; 如果一个数列 至少有三个元素 &#xff0c;并且任意两个相邻元素之差相同&#xff0c;则称该数列为等差数列。 例如&#xff0c;[1,3,5,7,9]、[7,7,7,7] 和 [3,-1,-5,-9] 都是等差数列。 给…...

Kotlin真·全平台——Kotlin Compose Multiplatform Mobile(kotlin跨平台方案、KMP、KMM)

前言 随着kotlin代码跨平台方案的推出&#xff0c;kotlin跨平台一度引起不少波澜。但波澜终归没有掀起太大的风浪&#xff0c;作为一个敏捷型开发的公司&#xff0c;依然少不了Android和iOS的同步开发&#xff0c;实际成本和效益并没有太多变化。所以对于大多数公司来说依然风平…...

unity 默认渲染管线材质球的材质通道,材质球的材质通道

标准渲染管线——材质球的材质通道 文档&#xff0c;与内容无关&#xff0c;是介绍材质球的属性的。 https://docs.unity3d.com/2022.1/Documentation/Manual/StandardShaderMaterialParameters.html游戏资源中常见的贴图类型 https://zhuanlan.zhihu.com/p/260973533 十大贴图…...

PostgreSQL升级:使用pg_upgrade进行大版本(16.3)升级(17.0)

1.pg_upgrade工具介绍 pg_upgrade 会创建新的系统表&#xff0c;并以重用旧的数据文件的方式进行升级。 pg_upgrade 的参数选项如下&#xff1a; -b bindir&#xff0c;--old-bindirbindir&#xff1a;旧的 PostgreSQL 可执行文件目录&#xff1b; -B bindir&#xff0c;--new-…...

userdel命令:删除指定Linux用户

一、命令简介 ​userdel​ 命令用于删除 Linux 系统中的用户账号。当您不再需要某个用户账号时&#xff0c;可以使用 userdel​ 命令将其从系统中删除。 ‍ 二、命令参数 userdel [选项] 用户名一些常用的选项包括&#xff1a; -r, --remove: 删除用户的家目录及邮件目录。…...

QT系统学习篇(1)

一、什么是Qt、Qt的优势 QT是一个跨平台的C图形用户界面库&#xff0c;目前包括Qt Creator、Qt Designer等等快速开发工具。支持所有Linux/Unix系统&#xff0c;还支持windows平台。Qt很容易扩展&#xff0c;并且允许真正的组件编程。&#xff08;军工企业项目开发基本离不开Q…...

每日一刷——9.26——ACM训练题——Fibonacci Again

题目描述&#xff1a; There are another kind of Fibonacci numbers: F(0) 7, F(1) 11, F(n) F(n-1) F(n-2) (n>2). Input Input consists of a sequence of lines, each containing an integer n. (n < 1,000,000). Output Print the word "yes" if 3 d…...

代码随想录 | Day28 | 回溯算法:组合组合总和III

代码随想录 | Day28 | 回溯算法&#xff1a;组合&&组合总和III 关于这个章节&#xff0c;大家最好是对递归函数的理解要比较到位&#xff0c;听着b站视频课可能呢才舒服点&#xff0c;可以先去搜一搜关于递归函数的讲解&#xff0c;理解&#xff0c;再开始这个章节会比…...

【重学 MySQL】四十五、数据库的创建、修改与删除

【重学 MySQL】四十五、数据库的创建、修改与删除 一条数据存储的过程数据输入数据验证数据处理数据存储数据持久化反馈与日志注意事项 标识符命名规则基本规则长度限制保留字与特殊字符命名建议示例 MySQL 中的数据类型创建数据库创建数据库时指定字符集和排序规则 查看数据库…...

STM32驱动直流电机

stm32通过PWM控制直流电机的方向和速度。 小直流电机需要几百毫安的电流&#xff0c;单片机只能提供几毫安的电流。电机内线圈转动时切割磁感线以及电机内转子线圈的电感效应都会产生反电动势&#xff0c;损坏芯片。 电机驱动芯片能够作为STM32驱动电机的帮手。 SLEEP暂停工作…...

【C++】二叉搜索树+变身 = AVL树

&#x1f680;个人主页&#xff1a;小羊 &#x1f680;所属专栏&#xff1a;C 很荣幸您能阅读我的文章&#xff0c;诚请评论指点&#xff0c;欢迎欢迎 ~ 目录 前言一、AVL树二、AVL树的实现2.1 平衡因子2.2 旋转处理2.2.1 左单旋&#xff1a;插入新节点后单纯的右边高2.2.2 …...

在HarmonyOS ArkTS ArkUI-X 5.0及以上版本中,手势开发全攻略:

在 HarmonyOS 应用开发中&#xff0c;手势交互是连接用户与设备的核心纽带。ArkTS 框架提供了丰富的手势处理能力&#xff0c;既支持点击、长按、拖拽等基础单一手势的精细控制&#xff0c;也能通过多种绑定策略解决父子组件的手势竞争问题。本文将结合官方开发文档&#xff0c…...

DAY 47

三、通道注意力 3.1 通道注意力的定义 # 新增&#xff1a;通道注意力模块&#xff08;SE模块&#xff09; class ChannelAttention(nn.Module):"""通道注意力模块(Squeeze-and-Excitation)"""def __init__(self, in_channels, reduction_rat…...

2021-03-15 iview一些问题

1.iview 在使用tree组件时&#xff0c;发现没有set类的方法&#xff0c;只有get&#xff0c;那么要改变tree值&#xff0c;只能遍历treeData&#xff0c;递归修改treeData的checked&#xff0c;发现无法更改&#xff0c;原因在于check模式下&#xff0c;子元素的勾选状态跟父节…...

【HTTP三个基础问题】

面试官您好&#xff01;HTTP是超文本传输协议&#xff0c;是互联网上客户端和服务器之间传输超文本数据&#xff08;比如文字、图片、音频、视频等&#xff09;的核心协议&#xff0c;当前互联网应用最广泛的版本是HTTP1.1&#xff0c;它基于经典的C/S模型&#xff0c;也就是客…...

vue3+vite项目中使用.env文件环境变量方法

vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量&#xff0c;这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

Unity | AmplifyShaderEditor插件基础(第七集:平面波动shader)

目录 一、&#x1f44b;&#x1f3fb;前言 二、&#x1f608;sinx波动的基本原理 三、&#x1f608;波动起来 1.sinx节点介绍 2.vertexPosition 3.集成Vector3 a.节点Append b.连起来 4.波动起来 a.波动的原理 b.时间节点 c.sinx的处理 四、&#x1f30a;波动优化…...

AGain DB和倍数增益的关系

我在设置一款索尼CMOS芯片时&#xff0c;Again增益0db变化为6DB&#xff0c;画面的变化只有2倍DN的增益&#xff0c;比如10变为20。 这与dB和线性增益的关系以及传感器处理流程有关。以下是具体原因分析&#xff1a; 1. dB与线性增益的换算关系 6dB对应的理论线性增益应为&…...

推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)

推荐 github 项目:GeminiImageApp(图片生成方向&#xff0c;可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...

数据库——redis

一、Redis 介绍 1. 概述 Redis&#xff08;Remote Dictionary Server&#xff09;是一个开源的、高性能的内存键值数据库系统&#xff0c;具有以下核心特点&#xff1a; 内存存储架构&#xff1a;数据主要存储在内存中&#xff0c;提供微秒级的读写响应 多数据结构支持&…...

零基础在实践中学习网络安全-皮卡丘靶场(第十一期-目录遍历模块)

经过前面几期的内容我们学习了很多网络安全的知识&#xff0c;而这期内容就涉及到了前面的第六期-RCE模块&#xff0c;第七期-File inclusion模块&#xff0c;第八期-Unsafe Filedownload模块。 什么是"遍历"呢&#xff1a;对学过一些开发语言的朋友来说应该知道&…...