opencv学习:图像拼接及完整代码实现

概念

        图像拼接是计算机视觉领域中的一项技术,它涉及将多个图像合并成一个连续的、无缝的全景图像。在OpenCV中,图像拼接通常包括以下几个关键步骤:

1. 编写代码
  • 导入必要的库:导入syscv2numpy库。
  • 定义显示图像的函数:编写cv_show函数,用于在窗口中显示图像。
    import sys
    import cv2
    import numpy as np
    # 显示图像的函数
    def cv_show(name,img):cv2.imshow(name,img)cv2.waitKey(0)
    
  • 定义检测关键点和计算描述符的函数:编写detectAndDescribe函数,使用SIFT算法检测图像中的关键点并计算描述符。
    # 检测关键点并计算描述符的函数
    def detectAndDescribe(image):gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)desciiptor=cv2.SIFT_create()#创建SIFT描述#检测关键点并计算描述符(kps,des)=desciiptor.detectAndCompute(gray,None)#kps 是检测到的关键点的列表,des 是关键点的描述符矩阵。kps_float=np.float32([kp.pt for kp in kps])#转换关键点坐标为浮点数:return (kps,kps_float,des)
    
2. 读取图像
  • 使用cv2.imread函数读取left.jpgright.jpg图像。
    imageA=cv2.imread('left.jpg')
    imageB=cv2.imread('right.jpg')
3. 检测关键点和计算描述符
  • 对两幅图像分别调用detectAndDescribe函数,获取关键点和描述符。
    #检测关键点并计算描述符
    (kpsA,kps_floatA,desA)=detectAndDescribe(imageA)
    (kpsB,kps_floatB,desB)=detectAndDescribe(imageB)
4. 特征匹配
  • 创建匹配器:使用cv2.BFMatcher创建暴力匹配器。
  • 进行K近邻匹配:对两幅图像的描述符进行K近邻匹配,获取匹配点对。
  • 筛选好的匹配点:使用Lowe's ratio test筛选出好的匹配点。
    #创建匹配器
    matcher=cv2.BFMatcher()
    #进行K近邻匹配
    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))
5. 计算单应性矩阵
  • 检查匹配点数量:如果匹配点数量大于4,则继续;否则,程序退出。
  • 计算单应性矩阵:使用cv2.findHomography函数和RANSAC算法计算匹配点之间的单应性矩
    #左侧连接
    # 如果匹配点足够多,则进行下一步
    if len(matches)>4:ptsA=np.float32([kps_floatA[i] for (i,_) in matches])ptsB=np.float32([kps_floatB[i] for (_,i) in matches])# 使用RANSAC算法计算单应性矩阵(H,mask)=cv2.findHomography(ptsB,ptsA,cv2.RANSAC,10)
    else:sys.exit()
    阵。
6. 图像变换和拼接
  • 应用单应性矩阵:使用cv2.warpPerspective函数对右图进行透视变换。
  • 显示变换后的图像:调用cv_show函数显示变换后的图像。
  • 拼接图像:将左图拼接到变换后的右图上。
  • 显示最终结果:调用cv_show函数显示最终的拼接结果。
    # 应用单应性矩阵进行透视变换
    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)
7. 可视化匹配的关键点
# 使用drawMatchesKnn函数绘制匹配的关键点
vis=cv2.drawMatchesKnn(imageB,kpsB,imageA,kpsA,good,None,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv_show('keypoint',vis)

运行结果

完整代码

# 图像拼接
import sys
import cv2
import numpy as np
# 显示图像的函数
def cv_show(name,img):cv2.imshow(name,img)cv2.waitKey(0)# 检测关键点并计算描述符的函数
def detectAndDescribe(image):gray=cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)desciiptor=cv2.SIFT_create()#创建SIFT描述#检测关键点并计算描述符(kps,des)=desciiptor.detectAndCompute(gray,None)#kps 是检测到的关键点的列表,des 是关键点的描述符矩阵。kps_float=np.float32([kp.pt for kp in kps])#转换关键点坐标为浮点数:return (kps,kps_float,des)imageA=cv2.imread('left.jpg')
imageB=cv2.imread('right.jpg')
#检测关键点并计算描述符
(kpsA,kps_floatA,desA)=detectAndDescribe(imageA)
(kpsB,kps_floatB,desB)=detectAndDescribe(imageB)
#创建匹配器
matcher=cv2.BFMatcher()
#进行K近邻匹配
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)
# 使用drawMatchesKnn函数绘制匹配的关键点
vis=cv2.drawMatchesKnn(imageB,kpsB,imageA,kpsA,good,None,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv_show('keypoint',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])# 使用RANSAC算法计算单应性矩阵(H,mask)=cv2.findHomography(ptsB,ptsA,cv2.RANSAC,10)
else: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.xdnf.cn/news/1557998.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

算法灰度膨胀腐蚀算子优化方法

第1章 当前灰度膨胀腐蚀算子 图像最大值最小值滤波。效果如下: 1.1. 常规实现 1.1.1. 半径范围遍历 对于一个像素,其膨胀腐蚀结果,查看周围半径范围内的所有像素,取最大最小值。 uint8_t nMax = 0; for (int j = -nRY; j <= nRY; j++) {for (int i = -nRX; i <= …

《重生到现代之从零开始的C语言生活》—— 联合体和枚举

联合体 像结构体一样&#xff0c;联合体也是由一个或多个成员构成 但是只会给最大的成员分配内存&#xff0c;联合体的特点就是所有成员共用一块内存空间&#xff0c;所以也叫共同体 由于所有的成员共用一块内存空间&#xff0c;所以如果给其中的一个成员赋值的话&#xff0…

Ubuntu修改IP方法

方法一&#xff1a;通过图形化界面修改IP 打开网络设置&#xff1a; 点击桌面右上角的网络图标&#xff0c;然后选择“设置”或“网络设置”。 选择网络接口&#xff1a; 在网络设置窗口中&#xff0c;选择你正在使用的网络接口&#xff08;有线或无线网络&#xff09;。 进…

避雷!Google Adsense联盟营销七大投放误区

你是否在使用Google AdSense进行广告投放&#xff1f;你是否想进一步优化你的投放策略&#xff1f;那么这篇文章你不可错过啦&#xff01; Google AdSense为跨境商家提供了一个平台&#xff0c;我们可以通过展示相关广告来赚取收入。然而&#xff0c;即使是最有经验的商家也可…

ReentrantLock相关知识

加锁流程 公平锁加锁流程&#xff1a; public final void acquire(int arg) {if (!tryAcquire(arg) &&acquireQueued(addWaiter(Node.EXCLUSIVE), arg))selfInterrupt(); } 加锁流程主要分三大步&#xff1a; tryAcquire尝试获取锁 protected final boolean tryAc…

C++nullptr

其实理解nullptr很简单&#xff0c;它其实就是将一个指针置为空 int* arrnullptr; 但是为什么C语言明明有NULL可以将指针置为空&#xff0c;C还要引入nullptr呢 其实简单理解C语言的NULL它其实是一个宏 #ifndef NULL #ifdef __cplusplus #define NULL 0 #else #define NUL…

【Agent】Cognitive Architectures for Language Agents

arxiv: https://arxiv.org/abs/2309.02427 背景 现有的Agent框架&#xff0c;大部分是基于强化学习提出的框架。本文结合生产系统和认知科学&#xff0c;提出了一个结构化和模块化的Agent架构。 2、记忆 记忆可分为两类&#xff1a; 工作记忆&#xff08;短期记忆&#xf…

多线程股吧(东方财富)用户信息爬取

多线程东方财富&#xff08;股吧&#xff09;用户信息爬取 在上一篇博客股吧信息爬取的基础上加入了多线程&#xff0c;使得速度提升了十几倍&#xff0c;爬取内容如下&#xff1a; 最终爬取结果如下&#xff1a; 完整代码如下&#xff08;准备好环境&#xff0c;比如pytho…

近年来自动驾驶行业就业与企业需求情况

自动驾驶行业在近年来持续发展&#xff0c;就业情况和企业需求呈现出多样化和复杂化的趋势。 以下是基于我搜索到的资料对自动驾驶行业最新就业情况和企业需求的详细分析&#xff1a; 自动驾驶行业对高端技术人才的需求非常旺盛&#xff0c;尤其是架构工程师、算法工程师等岗…

Qt(10.8)

作业&#xff1a;完善登录界面 源文件 #include "widget.h" #include "ui_widget.h" #include<QDebug> #include<QLabel> #include<QMessageBox> Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setu…

【C++篇】继承之韵:解构编程奥义,领略面向对象的至高法则

文章目录 C 继承详解&#xff1a;初阶理解与实战应用前言第一章&#xff1a;继承的基本概念与定义1.1 继承的概念1.2 继承的定义 第二章&#xff1a;继承中的访问权限2.1 基类成员在派生类中的访问权限2.2 基类与派生类对象的赋值转换2.2.1 派生类对象赋值给基类对象2.2.2 基类…

leetcode68:文本左右对齐

给定一个单词数组 words 和一个长度 maxWidth &#xff0c;重新排版单词&#xff0c;使其成为每行恰好有 maxWidth 个字符&#xff0c;且左右两端对齐的文本。 你应该使用 “贪心算法” 来放置给定的单词&#xff1b;也就是说&#xff0c;尽可能多地往每行中放置单词。必要时可…

Ubuntu 22.04 安装 KVM

首先检查是否支持 CPU 虚拟化&#xff0c;现在的 CPU 都应该支持&#xff0c;运行下面的命令&#xff0c;大于0 就是支持。 egrep -c (vmx|svm) /proc/cpuinfo安装 Libvirt apt install -y qemu-kvm virt-manager libvirt-daemon-system virtinst libvirt-clients bridge-uti…

DAMA数据管理知识体系(第11章 数据仓库和商务智能)

课本内容 11.1 引言 概要 数据仓库被公认为企业数据管理的核心语境关系图 图11-1 语境关系图&#xff1a;数据仓库和商务智能业务驱动因素 运营支持职能合规需求商务智能活动目标和原则 目标 一个组织建设数据仓库的目标通常有&#xff1a; 1&#xff09;支持商务智能活动。 2&…

易图讯军用VR三维电子沙盘系统

深圳易图讯军用VR三维电子沙盘系统是一种集成了虚拟现实&#xff08;VR&#xff09;技术、三维建模技术、大数据分析、实时动态更新以及高度安全可靠的综合性军事指挥平台。该系统通过高精度三维模型真实再现战场环境&#xff0c;为指挥员提供沉浸式体验和交互操作的可能性&…

数据结构与算法——Java实现 31.阻塞队列

—— 24.10.8 一、问题提出 目前队列存在的问题 1.很多场景要求分离生产者、消费者两个角色、它们需要由不同的线程来担当&#xff0c;而之前的实现根本没有考虑线程安全问题 2.poll方法&#xff0c;队列为空&#xff0c;那么在之前的实现里会返回null&#xff0c;如果就是硬…

构建MySQL健康检查Web应用

构建MySQL健康检查Web应用 在这里将探讨如何将MySQL健康检查功能转换为一个功能完整的Web应用。这个应用允许用户通过简单的Web界面执行MySQL健康检查&#xff0c;并查看详细的结果。我们将逐步介绍代码实现、改进过程以及如何设置和运行这个应用。 1. MySQL健康检查类 首先…

codetop标签双指针题目大全解析(二),双指针刷穿地心!!!!!

复习比学习更重要&#xff0c;如果忘了就跟没学是一样的 1.和为k的子数组2.统计[优美子数组]3.区间列表的交集4.将x减到0的最小操作5.替换子串得到平衡字符串6.划分字母区间7.分隔链表8.通过删除字母匹配到字典里最长单词9.寻找目标值-二维数组10.至多包含两个不同字符的最长子…

麒麟系统串口配置篇

麒麟系统串口配置篇 1.配置串口驱动&#xff08;编译/动态加载串口&#xff09; 解压文件夹,然后在解压后的文件夹所在目录&#xff0c;右键选择打开终端&#xff0c;依次执行以下命令&#xff1a; 以麒麟系统下的CH341串口驱动为例&#xff0c;解压CH341SER_LINUX.zip sudo…

2024_10_8 系统进展

改进位置 发现是label_api里藏了我需要改进的东西 settings.py 数据库 我这边电脑上使用的是windows 192 vue.config.js 陈家强是这样设置的 module.exports {publicPath: process.env.NODE_ENV production? /: /,assetsDir: static,// css: {// extract: false// },…