《深度学习》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)

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

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

相关文章

【深度学习】05-Rnn循环神经网络-01- 自然语言处理概述/词嵌入层/循环网络/文本生成案例精讲

循环神经网络&#xff08;RNN&#xff09;主要用于自然语言处理的。 循环神经网络&#xff08;RNN&#xff09;、卷积神经网络&#xff08;CNN&#xff09;和全连接神经网络&#xff08;FCN&#xff09;是三种常见的神经网络类型&#xff0c;各自擅长处理不同类型的数据。下面…

【数据库差异研究】update与delete使用表别名的研究

目录 ⚛️总结 ☪️1 Update ♋1.1 测试用例UPDATE users as a SET a.age 111 WHERE a.name Alice; ♏1.2 测试用例UPDATE users as a SET a.age 111 WHERE name Alice; ♐1.3 测试用例UPDATE users as a SET age 111 WHERE a.name Alice; ♑1.4 测试用例UPDATE us…

ubuntu 安装k8s

#关闭 Swap 内存&#xff0c;配置完成建议重启一下 nano /etc/fstab #注释下面相似的一行 #/swapfile none swap sw 0 0 #重启 reboot#部属k8s apt update && apt install -y apt-transport-https 下载 gpg 密钥 curl https://mi…

Python安装流程(Windows + MAC)

目录 Windows 版 1.下载Python 2.开始安装 3.配置环境变量 4.测试python是否成功安装 MAC版 1.下载Python 2.开始安装 Windows 版 1.下载Python 进入Python官网下载&#xff1a;&#xff08;Python更新频繁&#xff0c;下载最新版即可&#xff0c;安装流程一致&#x…

【Bug】STM32F1的PB3和PB4无法正常输出

Bug 使用标准库配置STM32F103C8T6的PB3和PB4引脚输出控制LED灯时&#xff0c;发现引脚电平没有变化无法正常输出高低电平&#xff0c;配置代码如下&#xff1a; GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOB, ENABLE ); GPIO_InitStruc…

C语言+单片机

今天内容有点水哈哈&#xff08;忙着练焊铁技术了嘻嘻&#xff09; C语言 简单学习了while语言以及其与for语言的区别和适用方法 .循环结构&#xff1a; 初始化语句条件判断句条件控制句 for语句 for(int1;i<100;i){执行条件} for (int i 1; i < 100; i) {printf(&quo…

stm32四足机器人(标准库)

项目技术要求 PWM波形的学习 参考文章stm32 TIM输出比较(PWM驱动LED呼吸灯&&PWM驱动舵机&&PWM驱动直流电机)_ttl pwm 驱动激光头区别-CSDN博客 舵机的学习 参考文章 stm32 TIM输出比较(PWM驱动LED呼吸灯&&PWM驱动舵机&&PWM驱动直流电机)…

发布:ultralytics-yolo-webui :Detect 目标检测 工具-先行版本 >> DataBall

通过webui 方式对ultralytics 的 detect 检测任务 进行&#xff1a; 1&#xff09;数据预处理&#xff0c;2&#xff09;模型训练&#xff0c;3&#xff09;模型推理。 本项目提供了 示例数据集&#xff0c;用 labelImage标注&#xff0c;标注文件为 xml 文件。 项目地址&…

css的背景background属性

CSS的background属性是一个简写属性&#xff0c;它允许你同时设置元素的多个背景相关的子属性。使用这个属性可以简化代码&#xff0c;使其更加清晰和易于维护。background属性可以设置不同的子属性。 background子属性 定义背景颜色 使用background-color属性 格式&#x…

【AI绘画】Midjourney进阶:景别详解

博客主页&#xff1a; [小ᶻZ࿆] 本文专栏: AI绘画 | Midjourney 文章目录 &#x1f4af;前言&#x1f4af;为什么要学习景别景别的作用景别在Midjourney中的应用实例 &#x1f4af;大景别&#x1f4af;远景特点提示词书写技巧测试 &#x1f4af;全景特点提示词书写技巧测试…

三、数据链路层(下)

目录 3.6以太网 以太网的分类 Mac地址 以太网数据格式 3.7互联网 数据是如何传输的&#xff1f; 3.8以太网、局域网、互联网的区别 总结&#xff1a; 3.9 vlan基本概念与基本原理 Vlan实现 划分 VLAN 例题 3.10广域网及相关协议 ppp协议 PPP协议所满足的要求 P…

防sql注入的网站登录系统设计与实现

课程名称 网络安全 大作业名称 防sql注入的网站登录系统设计与实现 姓名 学号 班级 大 作 业 要 求 结合mysql数据库设计一个web登录页面密码需密文存放&#xff08;可以采用hash方式&#xff0c;建议用sha1或md5加盐&#xff09;采用服务器端的验证码&#…

C(十)for循环 --- 黑神话情景

前言&#xff1a; "踏过三界宝刹&#xff0c;阅过四洲繁华。笑过五蕴痴缠&#xff0c;舍过六根牵挂。怕什么欲念不休&#xff0c;怕什么浪迹天涯。步履不停&#xff0c;便是得救之法。" 国际惯例&#xff0c;开篇先喝碗鸡汤。 今天&#xff0c;杰哥写的 for 循环相…

笔记整理—linux进程部分(6)进程间通信、alarm和pause

两个进程间通信可能是任何两个进程间的通信&#xff08;IPC&#xff09;。同一个进程是在同一块地址空间中的&#xff0c;在不同的函数与文件以变量进程传递&#xff0c;也可通过形参传递。2个不同进程处于不同的地址空间&#xff0c;要互相通信有难度&#xff08;内存隔离的原…

【H2O2|全栈】关于CSS(9)CSS3扩充了哪些新鲜的东西?(二)

目录 CSS3入门 前言 准备工作 伪元素补充 :before :after 文本溢出属性 转换效果 预告和回顾 后话 CSS3入门 前言 本系列博客主要介绍CSS相关的知识点。 这一期主要介绍以下几个CSS3的知识点&#xff1a; 伪元素补充文本溢出属性转换 没有基础的朋友&#xff…

怎样过好国庆节

今天是2024年10月1号&#xff0c;国庆节&#xff0c;七天小长假&#xff0c;估计每个人都有自己的小计划。有想出去浪的&#xff0c;有想闭关修炼的&#xff0c;有想约会恋爱的&#xff0c;也有想回家看父母的&#xff0c;只要有事干&#xff0c;有想法&#xff0c;有行动&…

ArcGIS共享数据的最佳方法(不丢可视化、标注等各类显示信息一样带)

今天我们介绍一下ArcGIS数据共享的几个小妙招 我们时常要把数据发给对方&#xff0c;特别是很多新手朋友要将shp发给对方时只是发送了shp后缀的文件&#xff0c;却把shp的必要组成文件dbf、shx等等给落下了。 还有很多朋友给图层做好了符号化标注&#xff0c;但是数据一发给别…

源2.0全面适配百度PaddleNLP,大模型开发开箱即用

近日&#xff0c;源2.0开源大模型与百度PaddleNLP完成全面适配。用户通过PaddleNLP&#xff0c;可快速调用源2.0预训练大模型&#xff0c;使用源2.0在语义、数学、推理、代码、知识等方面的推理能力&#xff0c;也可以使用特定领域的数据集对源2.0 进行微调&#xff0c;训练出适…

【设计模式-中介者模式】

定义 中介者模式&#xff08;Mediator Pattern&#xff09;是一种行为设计模式&#xff0c;通过引入一个中介者对象&#xff0c;来降低多个对象之间的直接交互&#xff0c;从而减少它们之间的耦合度。中介者充当不同对象之间的协调者&#xff0c;使得对象之间的通信变得简单且…

IT新秀系列:Go语言的兴起

Go语言&#xff08;Golang&#xff09;由谷歌于2007年发起&#xff0c;并于2009年正式开源。它的诞生背景可以追溯到互联网技术的高速发展时期。那时&#xff0c;软件开发面临着多核计算、大规模并发处理、部署和维护效率低下等挑战。作为一种新型的编程语言&#xff0c;Go主要…