《深度学习》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/438649.html

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

相关文章

【若依】postman调试出现认证失败,无法访问系统资源

如果前后端都已经连接通了&#xff0c;但是调试出现错误代码&#xff0c;可能是因为没有授权的问题&#xff0c;需要获得授权。 授权内容在cookie中 把cookie中的token内容粘贴到postman里面 这个时候再在postman里测试接口&#xff0c;发现可以拿到数据了

pytorch之梯度累加

1.什么是梯度&#xff1f; 梯度可以理解为一个多变量函数的变化率&#xff0c;它告诉我们在某一点上&#xff0c;函数的输出如何随输入的变化而变化。更直观地说&#xff0c;梯度指示了最优化方向。 在机器学习中的作用&#xff1a;在训练模型时&#xff0c;我们的目标是最小…

TransFormer 视频笔记

TransFormer BasicsAttention单头注意力 single head attentionQ&#xff1a; query 查寻矩阵 128*12288K key matrix 128*12288SoftMax 归一 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/19e3cf1ea28442eca60d5fc1303921f4.png)Value matrix 12288*12288 MLP Bas…

【Linux】进程地址空间、环境变量:从理论到实践(三)

&#x1f308; 个人主页&#xff1a;Zfox_ &#x1f525; 系列专栏&#xff1a;Linux 目录 &#x1f680; 前言一&#xff1a;&#x1f525; 环境变量 &#x1f95d; 基本概念&#x1f95d; 常见环境变量&#x1f95d; 查看环境变量方法 二&#xff1a;&#x1f525; 测试 &…

前端算法合集-1(含面试题)

(这是我面试一家中厂公司的二面算法题) 数组去重并按出现次数排序 题目描述: 给定一个包含重复元素的数组&#xff0c;请你编写一个函数对数组进行去重&#xff0c;并按元素出现的次数从高到低排序。如果次数相同&#xff0c;则按元素值从小到大排序。 let arr [2, 11,10, 1…

GPTQ vs AWQ vs GGUF(GGML) 速览和 GGUF 文件命名规范

简单介绍一下四者的区别。 参考链接&#xff1a;GPTQ - 2210.17323 | AWQ - 2306.00978 | GGML | GGUF - docs | What is GGUF and GGML? 文章目录 GPTQ vs AWQ vs GGUF&#xff08;GGML&#xff09; 速览GGUF 文件命名GGUF 文件结构文件名解析答案 附录GGUF 文件命名GGUF 文件…

15分钟学 Python 第35天 :Python 爬虫入门(一)

Day 35 : Python 爬虫简介 1.1 什么是爬虫&#xff1f; 网页爬虫&#xff08;Web Crawler&#xff09;是自动访问互联网并提取所需信息的程序。爬虫的主要功能是模拟用户通过浏览器访问网页的操作&#xff0c;从而实现对网页内容的批量访问与信息提取。它们广泛应用于数据收集…

JAVA并发编程系列(13)Future、FutureTask异步小王子

美团本地生活面试&#xff1a;模拟外卖订单处理&#xff0c;客户支付提交订单后&#xff0c;查询订单详情&#xff0c;后台需要查询店铺备餐进度、以及外卖员目前位置信息后再返回。 时间好快&#xff0c;一转眼不到一个月时间&#xff0c;已经完成分享synchronized、volatile、…

【VUE】案例:商场会员管理系统

编写vuedfr实现对会员进行基本增删改查 1. drf项目初始化 请求&#xff1a; POST http://127/0.0.0.1:8000/api/auth/ {"username":"cqn", "password":"123"}返回&#xff1a; {"username":"cqn", "token&q…

读论文、学习时 零碎知识点记录01

1.入侵检测技术 2.深度学习、机器学习相关的概念 ❶注意力机制 ❷池化 ❸全连接层 ❹Dropout层 ❺全局平均池化 3.神经网络中常见的层

.NET Core 集成 MiniProfiler性能分析工具

前言&#xff1a; 在日常开发中&#xff0c;应用程序的性能是我们需要关注的一个重点问题。当然我们有很多工具来分析程序性能&#xff1a;如&#xff1a;Zipkin等&#xff1b;但这些过于复杂&#xff0c;需要单独搭建。 MiniProfiler就是一款简单&#xff0c;但功能强大的应用…

Unraid的cache使用btrfs或zfs?

Unraid的cache使用btrfs或zfs&#xff1f; 背景&#xff1a;由于在unraid中添加了多个docker和虚拟机&#xff0c;因此会一直访问硬盘。然而&#xff0c;单个硬盘实在难以让人放心。在阵列盘中&#xff0c;可以通过添加校验盘进行数据保护&#xff0c;在cache中无法使用xfs格式…

深入挖掘C++中的特性之一 — 继承

目录 1.继承的概念 2.举个继承的例子 3.继承基类成员访问方式的变化 1.父类成员的访问限定符对在子类中访问父类成员的影响 2.父类成员的访问限定符子类的继承方式对在两个类外访问子类中父类成员的影响 4.继承类模版&#xff08;注意事项&#xff09; 5.父类与子类间的转…

数据结构——计数、桶、基数排序

目录 引言 计数排序 1.算法思想 2.算法步骤 3.代码实现 4.复杂度分析 桶排序 1.算法思想 2.算法步骤 3.代码实现 4.复杂度分析 基数排序 1.算法思想 2.算法步骤 3.代码实现 4.复杂度分析 排序算法的稳定性 1.稳定性的概念 2.各个排序算法的稳定性 结束语 引…

C++(string类的实现)

1. 迭代器、返回capacity、返回size、判空、c_str、重载[]和clear的实现 string类的迭代器的功能就类似于一个指针&#xff0c;所以我们可以直接使用一个指针来实现迭代器&#xff0c;但如下图可见迭代器有两个&#xff0c;一个是指向的内容可以被修改&#xff0c;另一个则是指…

Pytorch最最适合研究生的入门教程,Q3 开始训练

文章目录 Pytorch最最适合研究生的入门教程Q3 开始训练3.1 训练的见解3.2 Pytorch基本训练框架work Pytorch最最适合研究生的入门教程 Q3 开始训练 3.1 训练的见解 如何理解深度学习能够完成任务&#xff1f; 考虑如下回归问题 由函数 y f ( x ) yf(x) yf(x)采样得到的100个…

【安当产品应用案例100集】018-Vmware Horizon如何通过安当ASP身份认证系统增强登录安全性

启用Radius认证是提高VMware Horizon环境安全性的有效方法&#xff0c;特别是在需要满足复杂安全要求的场景中。 启用Radius认证对于VMware Horizon具有以下几个关键优势&#xff1a; 增强安全性&#xff1a;Radius认证支持多种认证方法&#xff0c;包括PAP、CHAP、MS-CHAPv1…

web前端面试中拍摄的真实js面试题(真图)

web前端面试中拍摄的真实js面试题&#xff08;真图&#xff09; WechatIMG258.jpeg WechatIMG406.jpeg WechatIMG407.jpeg WechatIMG922.jpeg WechatIMG1063.jpeg © 著作权归作者所有,转载或内容合作请联系作者 喜欢的朋友记得点赞、收藏、关注哦&#xff01;&#xff01;…

TypeScript 算法手册 - 【冒泡排序】

文章目录 TypeScript 算法手册 - 冒泡排序1. 冒泡排序简介1.1 冒泡排序定义1.2 冒泡排序特点 2. 冒泡排序步骤过程拆解2.1 比较相邻元素2.2 交换元素2.3 重复过程 3. 冒泡排序的优化3.1 提前退出3.2 记录最后交换位置案例代码和动态图 4. 冒泡排序的优点5. 冒泡排序的缺点总结 …

【SpringBoot详细教程】-09-Redis详细教程以及SpringBoot整合Redis【持续更新】

🌲 Redis 简介 🌾 什么是Redis Redis 是C语言开发的一个开源高性能键值对的内存数据库,可以用来做数据库、缓存、消息中间件等场景,是一种NoSQL(not-only sql,非关系型数据库)的数据库 Redis是互联网技术领域使用最为广泛的存储中间件,它是「Remote DictionaryServic…