全景图像(Panorama Image)向透视图像(Perspective Image)的跨视图转化(Cross-view)

一、概念讲解

        全景图像到透视图像的转化是一个复杂的图像处理过程,它涉及到将一个360度的全景图像转换为一个具有透视效果的图像,这种图像更接近于人眼观察世界的方式。全景图像通常是一个矩形图像,它通过将球面图像映射到平面上得到,而透视图像则模拟了相机的视角,具有近大远小的特性。在进行转换时,我们首先需要理解全景图像和透视图像的几何关系。全景图像可以看作是一个球面上的图像,而透视图像则是从球面上的某一点向外投影到一个平面上的结果。这个投影过程可以通过数学上的几何变换来实现,涉及到球面坐标和笛卡尔坐标之间的转换。

1.理解全景图像和透视图像

  • 全景图像:通常是指能够捕捉360度环境视角的图像,上下边缘对应天空和地面,左右边缘连续,形成一个完整的视角。
  • 透视图像:更接近于传统相机视角的图像,它模拟了人眼观察世界的方式,具有近大远小的特性。

2. 转换原理

  • 转换过程基于球面和平面之间的几何映射。全景图像可以看作是投影到一个虚拟球面上,然后从球的某一点(虚拟相机的位置)向外投影到一个平面上,从而获得透视图像。

3. 数学模型和算法

  • 球面到平面的投影:通过数学上的几何变换,将全景图像上的点映射到透视图像上。这涉及到球面坐标和笛卡尔坐标之间的转换。
  • 旋转矩阵:在三维空间中,使用旋转矩阵来实现全景图像到透视图像的转换。这包括绕X、Y、Z轴的旋转,以模拟相机的视角变化。

4. Python实现

  • 库的使用:使用OpenCV和NumPy库来处理图像和进行数值计算。
  • 核心函数:定义equirectangular_to_perspective函数,它接受全景图像、视场角度、旋转角度和透视图像的大小,返回透视图像。
  • 旋转函数:定义rotate_3D函数,基于旋转矩阵实现三维空间中的点旋转。

5. 使用OpenCV进行透视变换

  • 获取透视变换矩阵:可以通过求解透视变换公式或使用预先计算的矩阵获得。
  • 设置输出图像大小:根据需要设置输出图像的大小。
  • 调用cv2.warpPerspective()函数:使用提供的参数执行透视变换。

二、现有工作

        在PanFusion这篇论文中,全景分支(Panorama Branch)和透视分支(Perspective Branch)之间的信息传递是通过一个称为Equirectangular-Perspective Projection Attention (EPPA) 模块来实现的。这个模块包括两个关键部分:EPP球面位置编码(EPP Spherical Positional Encoding)和EPP注意力掩码(EPP Attention Mask)。

1. EPP球面位置编码(EPP Spherical Positional Encoding)

        EPP球面位置编码的目的是将全景特征图的极坐标映射到高维空间,以便在全景和透视视图之间学习对应关系。球面位置编码(SPE)函数如下:

SPE(θ,ϕ)=(γ(θ),γ(ϕ))

        其中,θ和ϕ分别是极坐标的纬度和经度,γ是一个将极坐标映射到更高维空间的函数,具体定义为:

γ(θ)=[sin(2πθ),cos(2πθ),…,sin((2L−1)πθ),cos((2L−1)πθ)]

        这里,L 是编码的维度,通常设置为通道数 c 的四分之一,即L=c/4。

2. 投影函数P(.)

        投影函数P(⋅)用于将全景特征图的球面位置编码投影到每个透视特征图上,使得不同格式中的对应像素共享相同的SPE向量。具体过程如下:

        首先计算全景特征图的SPE映射,然后将其投影到每个透视特征图上。将SPE映射添加到相应的特征图上,然后通过一个线性层得到查询Q和键K。

        计算查询Q和键K的矩阵乘积,得到亲和力矩阵A。

        以全景到透视方向为例,亲和力矩阵A的计算如下:

A=Q⋅KT

        其中,Q∈Rc×h×w 和 K∈RN×c×h/2×h/2,N是透视分支中的相机数量,ℎ和w 分别是全景特征图的高度和宽度。

3. EPP注意力掩码(EPP Attention Mask)

        EPP注意力掩码用于鼓励注意力机制关注对应像素。具体过程如下:

        对于全景特征图中的每个像素,使用投影函数P(⋅)将二进制掩码Mj,k​投影到每个透视视图上。

应用高斯核平滑掩码,并将其归一化到[−1,1]。

        将掩码堆叠并重塑为M,然后将其添加到亲和力矩阵A中,得到增强的亲和力矩阵A′。

A′=A+M

        其中,

4. 注意力权重和输出

        最后,对增强的亲和力矩阵A′应用softmax函数得到注意力权重,并将这些权重与值V相乘得到输出:

Attention(Q,K,V)=softmax(A′)⋅V

        这个输出将被用作目标特征图的更新,从而实现全景分支到透视分支的信息传递。

三、相关代码分析

1.示例代码        

以下是一个简单的代码示例,展示了如何使用Python和OpenCV将全景图像转换为透视图像:

import cv2
import numpy as npdef equirectangular_to_perspective(equi_img, fov, theta, phi, width, height):persp_img = np.zeros((height, width, 3), np.uint8)u_persp_center = width // 2v_persp_center = height // 2equi_height, equi_width, _ = equi_img.shapef = (width / 2) / np.tan(np.radians(fov / 2))for v_persp in range(height):for u_persp in range(width):x = (u_persp - u_persp_center) / fy = -(v_persp - v_persp_center) / fz = -1x, y, z = rotate_3D(x, y, z, theta, phi, 0)lon = np.arctan2(y, x)lat = np.arcsin(z)u_equi = 0.5 * (lon / np.pi + 1) * equi_widthv_equi = 0.5 * (lat / np.pi + 0.5) * equi_heightif 0 <= u_equi < equi_width and 0 <= v_equi < equi_height:persp_img[v_persp, u_persp, :] = equi_img[int(v_equi), int(u_equi), :]return persp_imgdef rotate_3D(x, y, z, theta, phi, gamma):R_theta = np.array([[np.cos(theta), -np.sin(theta), 0],[np.sin(theta), np.cos(theta), 0],[0, 0, 1]])R_phi = np.array([[1, 0, 0],[0, np.cos(phi), -np.sin(phi)],[0, np.sin(phi), np.cos(phi)]])R_gamma = np.array([[np.cos(gamma), 0, np.sin(gamma)],[0, 1, 0],[-np.sin(gamma), 0, np.cos(gamma)]])x, y, z = R_theta @ [x, y, z]x, y, z = R_phi @ [x, y, z]x, y, z = R_gamma @ [x, y, z]return x, y, z# 读取全景图像
equi_image_path = 'path_to_your_equirectangular_image.jpg'
equi_img = cv2.imread(equi_image_path)# 定义参数
fov = 90  # 视场角度
theta = np.radians(0)  # 水平旋转角度
phi = np.radians(-30)  # 垂直旋转角度
width = 800  # 透视图像的宽度
height = 600  # 透视图像的高度# 使用函数得到透视图像
persp_img = equirectangular_to_perspective(equi_img, fov, theta, phi, width, height)# 显示透视图像
cv2.imshow('Perspective Image', persp_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

        这个代码首先定义了一个函数equirectangular_to_perspective,它接受一个等距矩形全景图像、视场角度、旋转角度和透视图像的大小。这个函数可以返回透视图像。内部函数rotate_3D是一个三维空间中点的旋转函数,它基于旋转矩阵来实现三个方向上的旋转。

2.rotate_3D函数

        这个函数负责在三维空间中旋转一个点。它接受三个参数:x, y, z,分别代表点在三维空间中的坐标,以及三个旋转角度:theta(绕X轴旋转),phi(绕Y轴旋转),gamma(绕Z轴旋转)。函数返回旋转后的点的坐标。

旋转矩阵如下所示:

  • R_theta:绕X轴旋转
  • R_phi:绕Y轴旋转
  • R_gamma:绕Z轴旋转

这些矩阵分别对应不同的旋转操作,通过矩阵乘法来实现点的旋转。旋转的顺序是先绕X轴,再绕Y轴,最后绕Z轴。

3.equirectangular_to_perspective函数

这个函数是全景图到透视图转换的核心。它接受以下参数:

  • equi_img:全景图像
  • fov:透视图像的视场角度
  • theta:水平旋转角度
  • phi:垂直旋转角度
  • width和height:输出透视图像的宽度和高度

4.代码中的数学和几何原理

  • 球面到笛卡尔的转换:全景图像的每个点可以用球面坐标(经度和纬度)表示,转换为笛卡尔坐标后,可以通过旋转矩阵进行旋转。

  • 视场角度:视场角度决定了透视图像的宽广程度,影响焦距的计算。

  • 旋转:通过旋转矩阵,我们可以模拟相机围绕三个轴的旋转,从而改变视角。

  • 投影:将旋转后的三维点投影到二维平面上,得到透视图像中的点。

四、相关算法优化

        上文中提及的代码中没有明确实现插值算法,这可能导致图像边缘出现锯齿或不连续。且对于大尺寸图像,这种逐像素处理的方法可能效率较低。对于参数而言,可能需要根据实际情况调整FOV、旋转角度等参数,以获得最佳效果。

        为了完善之前的代码,我们可以添加插值功能来提高图像质量,并优化性能。以下是完善后的代码,它包括了双线性插值和一些性能优化:

import cv2
import numpy as npdef rotate_3D(x, y, z, theta, phi):# 绕X轴旋转x_rot, y_rot = x, y * np.cos(theta) - z * np.sin(theta)z_rot = y * np.sin(theta) + z * np.cos(theta)# 绕Y轴旋转x_rot, z_rot = x_rot * np.cos(phi) + z_rot * np.sin(phi), -x_rot * np.sin(phi) + z_rot * np.cos(phi)return x_rot, y_rot, z_rotdef equirectangular_to_perspective(equi_img, fov, theta, phi, width, height):persp_img = np.zeros((height, width, 3), dtype=np.uint8)equi_height, equi_width, _ = equi_img.shapef = width / (2 * np.tan(np.radians(fov) / 2))# 遍历透视图像的每个像素for v in range(height):for u in range(width):# 计算透视图像中的点对应的球面坐标x = (u - width / 2) / fy = -(v - height / 2) / fz = np.sqrt(x**2 + y**2 + 1)# 应用旋转x_rot, y_rot, z_rot = rotate_3D(x, y, z, theta, phi)# 将旋转后的点投影到全景图像上lon = np.arctan2(y_rot, x_rot)lat = np.arcsin(z_rot)# 计算全景图像中的对应像素位置u_equi = (lon + np.pi) / (2 * np.pi) * equi_widthv_equi = (np.pi - lat) / np.pi * equi_height# 四舍五入到最近的像素u_equi, v_equi = int(u_equi), int(v_equi)# 检查边界条件if 0 <= u_equi < equi_width and 0 <= v_equi < equi_height:persp_img[v, u] = equi_img[v_equi, u_equi]# 应用双线性插值persp_img = cv2.bilinearResize(persp_img, (height, width))return persp_img# 读取全景图像
equi_image_path = 'path_to_your_equirectangular_image.jpg'
equi_img = cv2.imread(equi_image_path)# 定义参数
fov = 90  # 视场角度
theta = np.radians(0)  # 水平旋转角度
phi = np.radians(-30)  # 垂直旋转角度
width = 800  # 透视图像的宽度
height = 600  # 透视图像的高度# 使用函数得到透视图像
persp_img = equirectangular_to_perspective(equi_img, fov, theta, phi, width, height)# 显示透视图像
cv2.imshow('Perspective Image', persp_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

代码改进点:

  1. 双线性插值:使用cv2.bilinearResize函数对透视图像进行双线性插值,以提高图像质量。

  2. 边界检查:在将全景图像的像素值赋给透视图像之前,添加了边界检查,以确保不会访问全景图像数组之外的元素。

  3. 性能优化:通过减少不必要的计算和使用OpenCV的内置函数,提高了代码的执行效率。

        这段代码提供了一个更完整的解决方案,用于将全景图像转换为透视图像,并应用了双线性插值以提高图像质量。

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

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

相关文章

RabbitMQ7:消息转换器

欢迎来到“雪碧聊技术”CSDN博客&#xff01; 在这里&#xff0c;您将踏入一个专注于Java开发技术的知识殿堂。无论您是Java编程的初学者&#xff0c;还是具有一定经验的开发者&#xff0c;相信我的博客都能为您提供宝贵的学习资源和实用技巧。作为您的技术向导&#xff0c;我将…

C#开发合集

用C#轻松搞定m3u8视频下载与合并 嘿&#xff0c;程序员们&#xff01;今天咱们来聊聊如何用C#写个小程序&#xff0c;轻松下载和合并m3u8视频文件。没错&#xff0c;就是那种分段的流媒体视频。准备好了吗&#xff1f;让我们开始吧&#xff01; 准备工作 在动手之前&#xf…

HarmonyOS4+NEXT星河版入门与项目实战(22)------动画(属性动画与显示动画)

文章目录 1、属性动画图解2、案例实现-小鱼移动游戏1、代码实现2、代码解释3、资源图片4、实现效果3、显示动画4、案例修改-显示动画5、总结1、属性动画图解 这里我们用一张完整的图来汇整属性动画的用法格式和使用的主要属性范围,如下所示: 2、案例实现-小鱼移动游戏 1、代…

【rustdesk】客户端和服务端的安装和部署(自建服务器,docker,远程控制开源软件rustdesk)

【rustdesk】客户端和服务端的安装和部署&#xff08;自建服务器&#xff0c;docker&#xff09; 一、官方部署教程 https://rustdesk.com/docs/zh-cn/client/mac/ 官方服务端下载地址 https://github.com/rustdesk/rustdesk-server/releases 我用的docker感觉非常方便&am…

Qt程序发布及打包成exe安装包

参考:Qt之程序发布以及打包成exe安装包 目录 一、简述 Qt 项目开发完成之后,需要打包发布程序,而因为用户电脑上没有 Qt 配置环境,所以需要将 release 生成的 exe 文件和所依赖的 dll 文件复制到一个文件夹中,然后再用 Inno Setup 打包工具打包成一个 exe 安装包,就可以…

python学opencv|读取图像

【1】引言 前序学习了使用matplotlib模块进行画图&#xff0c;今天开始我们逐步尝试探索使用opencv来处理图片。 【2】学习资源 官网的学习链接如下&#xff1a; OpenCV: Getting Started with Images 不过读起来是英文版&#xff0c;可能略有难度&#xff0c;所以另推荐一…

数据结构 ——— 归并排序算法的实现

目录 归并排序的思想 归并排序算法的实现 归并排序的思想 将已经有序的子序列合并&#xff0c;得到完全有序的序列&#xff0c;即先使每个子序列有序后&#xff0c;再使子序列段间有序 若将两个有序表合并成一个有序表&#xff0c;称为二路归并 归并排序步骤示意图&#x…

Springboot项目搭建(6)-前端登录跳转与Pinia实用

1.添加响应错误拦截 文件地址&#xff1a;src\utils\request.js import axios from axios import { ElMessage } from element-plus const baseURL /api const instance axios.create({baseURL}) //添加拦截器 instance.interceptors.response.use(result>{&#x1f447…

多输入多输出 | Matlab实现TCN-LSTM时间卷积神经网络结合长短期记忆神经网络多输入多输出预测

多输入多输出 | Matlab实现TCN-LSTM时间卷积神经网络结合长短期记忆神经网络多输入多输出预测 目录 多输入多输出 | Matlab实现TCN-LSTM时间卷积神经网络结合长短期记忆神经网络多输入多输出预测预测效果基本介绍程序设计参考资料 预测效果 基本介绍 多输入多输出 | Matlab实现…

C++网络编程:select IO多路复用及TCP服务器开发

C网络编程&#xff1a;使用select实现IO多路复用 一、什么是 IO 多路复用&#xff1f;二、IO多路复用器 select三、相关接口3.1、fd_set 结构体3.2、宏和函数 四、select 实现 TCP 服务器五、总结 一、什么是 IO 多路复用&#xff1f; 在网络编程中&#xff0c;最容易想到的并…

HDU Go Running(最小点覆盖 + 网络流优化)

题目大意&#xff1a;有一条无限长跑道&#xff0c;每个人可以规定自己跑步的方向&#xff0c;起点&#xff0c;跑步起止时间。每个人跑步的速度都是1m/s。最后从监控人员哪里得到了n个报告&#xff0c;每个报告给出了某人在某一时候所在的位置&#xff0c;问跑步的最少可能人数…

28.UE5实现对话系统

目录 1.对话结构的设计&#xff08;重点&#xff09; 2.NPC对话接口的实现 2.1创建类型为pawn的蓝图 2.2创建对话接口 3.对话组件的创建 4.对话的UI设计 4.1UI_对话内容 4.2UI_对话选项 4.3UI_对话选项框 5.对话组件的逻辑实现 通过组件蓝图&#xff0c;也就是下图中的…

Reachy 2,专为AI与机器人实验室打造的卓越开源双臂移动操作平台!

近期&#xff0c;花粉机器人&#xff08;POLLEN ROBOTICS&#xff09;隆重推出Reachy 2仿生机器人——下一代开源操作平台&#xff0c;为AI与机器人实验室带来理想的双臂移动操作科研平台&#xff01; Reachy 2的仿生性&#xff1a; 》拥有两个基于Maxon无刷电机的仿生7自由度…

python的openpyxl库设置表格样式:字体/边框/对齐/颜色等

学习目录 1. 安装和使用openpyxl库设置表格样式 2 设置字体font 3 设置边框 4 设置对齐方式 5 设置单元格数据格式 6 设置行高和列宽 7 填充单元格颜色 附录-关于颜色说明 本章节主要介绍如何使用openpyxl库设置表格中的一些样式&#xff0c;比如字体&#xff0c;边框…

Git旧文件覆盖引发思考

一天&#xff0c;我的同事过来找到我&#xff0c;和我讲&#xff1a;张叫兽&#xff0c;大事不好&#xff0c;我的文件被人覆盖了。git是真的不好用啊 git不好用&#xff1f;文件被覆盖&#xff1b;瞬间我似乎知道了什么&#xff0c;让我想到了某位男明星的语法&#xff1a;他…

QSqlTableModel的使用

实例功能 这边使用一个实例显示数据库 demodb 中 employee 数据表的内容&#xff0c;实现编辑、插入、删除的操作&#xff0c;实现数据的排序和记录过滤&#xff0c;还实现 BLOB 类型字段 Photo 中存储照片的显示、导入等操作&#xff0c;运行界面如下图&#xff1a; 在上图中…

什么是代理,nodenginx前端代理详解

一. 什么是代理&#xff1f; 代理就是通过一个特殊的网络服务去访问另一网络服务的一种间接访问方式。像我们不能直接访问国外的网站&#xff0c;只能使用VPN&#xff0c;就是使用了代理 二. 前端为什么要用代理&#xff1f; 首先明确以下两个概念 &#xff08;1&#xff09…

java脚手架系列16-AI大模型集成

之所以想写这一系列&#xff0c;是因为之前工作过程中有几次项目是从零开始搭建的&#xff0c;而且项目涉及的内容还不少。在这过程中&#xff0c;遇到了很多棘手的非业务问题&#xff0c;在不断实践过程中慢慢积累出一些基本的实践经验&#xff0c;认为这些与业务无关的基本的…

网络安全中的数据科学如何重新定义安全实践?

组织每天处理大量数据&#xff0c;这些数据由各个团队和部门管理。这使得全面了解潜在威胁变得非常困难&#xff0c;常常导致疏忽。以前&#xff0c;公司依靠 FUD 方法&#xff08;恐惧、不确定性和怀疑&#xff09;来识别潜在攻击。然而&#xff0c;将数据科学集成到网络安全中…

【算法day1】数组:双指针算法

题目引用 这里以 1、LeetCode704.二分查找 2、LeetCode27.移除元素 3、LeetCode977.有序数组的平方 这三道题举例来说明数组中双指针的妙用。 1、二分查找 给定一个 n 个元素有序的&#xff08;升序&#xff09;整型数组 nums 和一个目标值 target &#xff0c;写一个函数搜…