【视点合成】代码解读:生成demo视频
变换工具
def render_3dphoto(src_imgs, # 输入的源图像,维度为 [batch_size, 3, height, width]mpi_all_src, # 输入的所有源图像的MPI,维度为 [batch_size, num_planes, 4, height, width]disparity_all_src, # 所有源图像的视差信息,维度为 [batch_size, num_planes]k_src, # 源相机的内参矩阵,维度为 [batch_size, 3, 3]k_tgt, # 目标相机的内参矩阵,维度为 [batch_size, 3, 3]save_path, # 渲染视频的保存路径
):
disparity 也就是深度。
单应性变换
使用HomographySample变换。utils.mpi.homography_sampler.HomographySample
class HomographySample:"""处理与单应性变换相关的操作,它提供了生成二维网格坐标的功能,计算平面法线,以及将欧拉角转换为旋转矩阵"""def __init__(self, H_tgt, W_tgt, device=None):if device is None:self.device = torch.device("cpu")else:self.device = deviceself.Height_tgt = H_tgtself.Width_tgt = W_tgtself.meshgrid = self.grid_generation(self.Height_tgt, self.Width_tgt, self.device) # 生成目标图像的二维网格坐标self.meshgrid = self.meshgrid.permute(2, 0, 1).contiguous() # 3xHxW 对生成的网格进行维度重排,以匹配 3xHxW 的形状self.n = self.plane_normal_generation(self.device) # 生成平面法线
其中方法:
def euler_to_rotation_matrix(x_angle, y_angle, z_angle, seq='xyz', degrees=False):"""将欧拉角转换为旋转矩阵Note that here we want to return a rotation matrix rot_mtx, which transform the tgt points into src frame,i.e, rot_mtx * p_tgt = p_srcTherefore we need to add negative to x/y/z_angle 由于在欧拉角中,旋转是绕坐标轴的正方向进行的,而我们希望进行的是相反方向的旋转,因此需要对 x/y/z 分量的欧拉角添加负号,以实现从目标点到源坐标系的变换。注意 **这里的欧拉角需要取反,因为我们希望得到的旋转矩阵是将目标点变换到源坐标系的旋转** https://docs.scipy.org/doc/scipy/reference/generated/scipy.spatial.transform.Rotation.html:param roll::param pitch::param yaw::return:"""r = Rotation.from_euler(seq,[-x_angle, -y_angle, -z_angle],degrees=degrees)rot_mtx = r.as_matrix().astype(np.float32)# 用于图像的单应性变换,其中 meshgrid 用于定义原始图像中每个像素的坐标,plane_normal_generation 用于定义平面法线(对于单应性变换而言通常是不必要的,但可能用于其他3D变换),# euler_to_rotation_matrix 则用于根据给定的欧拉角生成对应的旋转矩阵。这些操作都是在准备实施单应性变换或其他相关图像几何变换的数据和参数。return rot_mtx
映射前定义网格
@staticmethoddef grid_generation(H, W, device):""":生成网格坐标,用于后续的映射计算。"""# 使用 numpy 生成x和y方向的线性等分点,并通过 np.meshgrid 生成一个二维网格x = np.linspace(0, W - 1, W)y = np.linspace(0, H - 1, H)xv, yv = np.meshgrid(x, y) # HxWxv = torch.from_numpy(xv.astype(np.float32)).to(dtype=torch.float32, device=device)yv = torch.from_numpy(yv.astype(np.float32)).to(dtype=torch.float32, device=device)# 生成一个全为1的张量,与x和y坐标一起堆叠(通道维度)成3通道的网格坐标张量ones = torch.ones_like(xv)meshgrid = torch.stack((xv, yv, ones), dim=2) # HxWx3return meshgrid@staticmethoddef plane_normal_generation(device):"""创建一个表示垂直于xy平面(即z轴方向)的法线向量的张量"""n = torch.tensor([0, 0, 1], dtype=torch.float32, device=device)return n
使用
在utils.utils.render_novel_view
中:
- 计算深度
- 计算视点变换
- 执行变换
- 帧序列到视频
def render_novel_view(mpi_all_rgb_src,mpi_all_sigma_src,disparity_all_src,G_tgt_src,K_src_inv,K_tgt,homography_sampler,
):"""mpi_all_rgb_src, # 来源视角的RGB图像集合mpi_all_sigma_src, # 来源视角的不透明度(sigma)集合disparity_all_src, # 来源视角的视差图集合G_tgt_src, # 目标视角到来源视角的变换矩阵K_src_inv, # 来源视角的相机内参矩阵的逆矩阵K_tgt, # 目标视角的相机内参矩阵homography_sampler, # 用于生成和采样单应性(Homographies)的工具"""# 从源视角的视差图计算出每个平面上点的3D坐标xyz_src_BS3HW = mpi_rendering.get_src_xyz_from_plane_disparity(homography_sampler.meshgrid,disparity_all_src,K_src_inv)# 使用源视角的3D坐标和从目标视角到源视角的变换矩阵 G_tgt_src 来计算目标视角的3D坐标xyz_tgt_BS3HW = mpi_rendering.get_tgt_xyz_from_plane_disparity(xyz_src_BS3HW,G_tgt_src)# 调用 render_tgt_rgb_depth 函数,将源视角的RGB图像、不透明度、视差图和3D坐标映射到目标视角,生成合成的目标视角图像 tgt_imgs_syntgt_imgs_syn, _, _ = mpi_rendering.render_tgt_rgb_depth(homography_sampler,mpi_all_rgb_src,mpi_all_sigma_src,disparity_all_src,xyz_tgt_BS3HW,G_tgt_src,K_src_inv,K_tgt,use_alpha=False,is_bg_depth_inf=False,)return tgt_imgs_syn
生成
函数入口
def render_3dphoto(src_imgs, # [b,3,h,w]mpi_all_src, # [b,s,4,h,w]disparity_all_src, # [b,s]k_src, # [b,3,3]k_tgt, # [b,3,3]save_path,
):"""src_imgs, # 输入的源图像,维度为 [batch_size, 3, height, width]mpi_all_src, # 输入的所有源图像的MPI,维度为 [batch_size, num_planes, 4, height, width]disparity_all_src, # 所有源图像的视差信息,维度为 [batch_size, num_planes]k_src, # 源相机的内参矩阵,维度为 [batch_size, 3, 3]k_tgt, # 目标相机的内参矩阵,维度为 [batch_size, 3, 3]save_path, # 渲染视频的保存路径"""h, w = mpi_all_src.shape[-2:]device = mpi_all_src.devicehomography_sampler = HomographySample(h, w, device) # 生成单应性变换k_src_inv = torch.inverse(k_src) # 计算源相机内参矩阵的逆矩阵,用于从像素坐标到相机坐标系的转换。# preprocess the predict MPI# 将视差信息转换为3D空间坐标xyz_src_BS3HW = mpi_rendering.get_src_xyz_from_plane_disparity( homography_sampler.meshgrid,disparity_all_src,k_src_inv,)# 分离通道mpi_all_rgb_src = mpi_all_src[:, :, 0:3, :, :] # BxSx3xHxWmpi_all_sigma_src = mpi_all_src[:, :, 3:, :, :] # BxSx1xHxW# 调用一个渲染函数,用于计算从MPI合成图像时使用的混合权重_, _, blend_weights, _ = mpi_rendering.render(mpi_all_rgb_src,mpi_all_sigma_src,xyz_src_BS3HW,use_alpha=False,is_bg_depth_inf=False,)# 混合权重来更新源图像的MPI RGB部分,这里使用的是alpha blending算法mpi_all_rgb_src = blend_weights * src_imgs.unsqueeze(1) + (1 - blend_weights) * mpi_all_rgb_src# render novel views# 定义通过改变相机外参来模拟相机移动的参数。同时初始化一个空列表用于存储渲染出的帧。swing_path_list = gen_swing_path()frames = []# for cam_ext in tqdm(swing_path_list):# 利用render_novel_view函数来渲染从新视角看到的图像。这个函数需要当前的MPI RGB数据、透明度数据、视差数据、目标相机的外参(这里假设cam_ext是外参# ,cam_ext.cuda()将外参移动到GPU上)、源相机的内参矩阵的逆以及目标相机的内参矩阵。homography_sampler可能用于计算在新视角下图像的单应性变换。for cam_ext in swing_path_list:frame = render_novel_view(mpi_all_rgb_src,mpi_all_sigma_src,disparity_all_src,cam_ext.cuda(), # 目标视角到来源视角的变换矩阵k_src_inv,k_tgt, # 目标视角的相机内参矩阵homography_sampler,)# 张量转换为NumPy数组,并进行必要的排列以匹配图像的形状要求。然后它将像素值缩放到0-255范围,并转换为uint8类型frame_np = frame[0].permute(1, 2, 0).contiguous().cpu().numpy() # [b,h,w,3]frame_np = np.clip(np.round(frame_np * 255), a_min=0, a_max=255).astype(np.uint8)frames.append(frame_np)rgb_clip = ImageSequenceClip(frames, fps=30)# moviepy库的ImageSequenceClip类将帧列表转换成视频剪辑,设置每秒帧数为30。然后调用write_videofile方法将视频保存到指定的save_path路径# 使用mpeg4编解码器,不显示详细信息,设置比特率为3000kbps。rgb_clip.write_videofile(save_path, verbose=False, codec='mpeg4', logger=None, bitrate='3000k')
获取移动路径
def gen_swing_path(num_frames=90, r_x=0.14, r_y=0.0, r_z=0.10):"""生成一个摆动路径.生成一系列的4x4变换矩阵,每个矩阵代表了不同时间点的位置num_frames 表示要生成的帧数,默认为90帧;r_x、r_y 在x、y方向上的摆动半径r_z 表示z轴方向上的摆动半径"""# 创建了一个从0到1等间距的一维张量 t。这个张量表示从摆动开始到结束的时间线索引t = torch.arange(num_frames) / (num_frames - 1)# 创建了一个4x4的单位矩阵(identity matrix),然后将其重复 num_frames 次,用来存储最终生成的每一帧的变换矩阵。poses = torch.eye(4).repeat(num_frames, 1, 1)# 计算了在x轴上的摆动,使用正弦函数来生成x轴的平移部分,摆动的幅度由 r_x 确定# 正余弦: 需要一个物体的运动从最大幅度开始并且回到最大幅度poses[:, 0, 3] = r_x * torch.sin(2. * math.pi * t)poses[:, 1, 3] = r_y * (torch.cos(2. * math.pi * t) )poses[:, 2, 3] = r_z * (torch.cos(2. * math.pi * t) - 1.0) # 减去了1,这样摆动的起始点会更低return poses.unbind() # 张量 poses 拆分成一个元组,元组中的每个元素是一个4x4矩阵,代表了每一帧的变换矩阵
相关文章:
【视点合成】代码解读:生成demo视频
变换工具 def render_3dphoto(src_imgs, # 输入的源图像,维度为 [batch_size, 3, height, width]mpi_all_src, # 输入的所有源图像的MPI,维度为 [batch_size, num_planes, 4, height, width]disparity_all_src, # 所有源图像的视差信息&…...

Process On在线绘制流程图
目录 一.ProcessOn 1.1.介绍 1.2.直接网上使用 二.绘制门诊流程图 三.绘制住院流程图 四.绘制药库采购入库流程图 五.绘制OA会议流程图 今天就到这里了哦!!!希望能帮到你哦!!! 一.ProcessOn 1.1.介绍 ProcessOn(流程&#…...
【Hadoop-OBS-Hive】利用华为云存储对象 OBS 作为两个集群的中间栈 load 文件到 Hive
【Hadoop-OBS-Hive】利用华为云存储对象 OBS 作为两个集群的中间栈 load 文件到 Hive 1)压缩文件2)上传文件到 OBS 存储对象3)crontab 定时压缩上传4)从 obs 上拉取下来文件后解压缩5)判断对应文件是否存在6࿰…...
直线检测算子
hough_lines_dir 接口 hough_lines_dir(ImageDir : HoughImage, Lines : DirectionUncertainty, AngleResolution, Smoothing, FilterSize, Threshold, AngleGap, DistGap, GenLines : Angle, Dist) 参数 in: ImageDir :由边缘检测算子sobel_dir、edge_image获取的…...

如何在本地Docker中部署MinIO服务并实现远程访问管理界面
文章目录 前言1. Docker 部署MinIO2. 本地访问MinIO3. Linux安装Cpolar4. 配置MinIO公网地址5. 远程访问MinIO管理界面6. 固定MinIO公网地址 前言 MinIO是一个开源的对象存储服务器,可以在各种环境中运行,例如本地、Docker容器、Kubernetes集群等。它兼…...
逛商场。。。
题目名字 逛商场 题意 见到想买的物品,只要能买得起,就一定会买下来之后才会继续往前走;如果买不起就直接跳过 思路 接着,它读取数组 aa 的值,并存储在数组中。然后,程序读取一个整数 m。初始化计数器 cn…...

RTrPPG
研究背景 心率 (HR) 和脉搏率变异性 (PRV) 是允许分析心脏行为的两个生理参数。心率监测可以通过接触式和非接触式的两种方法进行。通常用于测量 HR 和 PRV 的两种接触式技术是心电图 (ECG) 和光电容积脉搏波 (PPG)。 ECG 测量由心脏活动引起的电场。另一方面,PPG …...

web应用开发技术的一些概念
一、Servlet 1.Servlet的工作过程: Servelt的工作流程示意图 (1)客户端发起一个Http请求到服务器,请求特定的资源或者是要执行特定的操作 (2)服务器在接收到请求后,根据请求相应的URL将请求分发…...

智能优化算法应用:基于乌燕鸥算法3D无线传感器网络(WSN)覆盖优化 - 附代码
智能优化算法应用:基于乌燕鸥算法3D无线传感器网络(WSN)覆盖优化 - 附代码 文章目录 智能优化算法应用:基于乌燕鸥算法3D无线传感器网络(WSN)覆盖优化 - 附代码1.无线传感网络节点模型2.覆盖数学模型及分析3.乌燕鸥算法4.实验参数设定5.算法结果6.参考文…...

超聚变服务器(原华为服务器)网站模拟器
一、超聚变服务器(原华为服务器)网站模拟器: 原来了解服务器可以从他的网站上进行了解,模拟器做的很好了。 https://support.xfusion.com/server-simulators/ 有很多的模拟器,今天主要看下BMC的设置 有很多的在线工具…...

Linux常见压缩指令小结
为什么需要压缩技术 我们都知道文件是以byte作为单位的,如果我们的文件仅仅在低位占一个1 0000 0001这种情况我们完全可以压缩一下,将高位的0全部抹掉即可。 如上所说是一种压缩技术,还有一种就是将1111(此处省略96个)一共100个1࿰…...

OpenSSL的源码在哪里下载?
官方网站去下载,网址: https://www.openssl.org/source/ 比较老的版本的下载页面地址: https://www.openssl.org/source/old/ 由于某面板的OpenSSL模块的安装配置语句如下: --with-openssl/root/rpmbuild/BUILD/openssl-1.0.2u所…...

使用create-react-app脚手架创建react项目
文章目录 1、安装create-react-app脚手架2、创建 React 项目,项目名为 react-demo3、项目创建成功4、使用vscode打开项目并运行5、项目运行成功node_modules:存放项目所依赖的一些第三方包文件public:静态资源文件夹src:源码文件夹其它文件 1…...

【网络安全】网络防护之旅 - 点燃网络安全战场的数字签名烟火
🌈个人主页:Sarapines Programmer🔥 系列专栏:《网络安全之道 | 数字征程》⏰墨香寄清辞:千里传信如电光,密码奥妙似仙方。 挑战黑暗剑拔弩张,网络战场誓守长。 目录 😈1. 初识…...

JVM基础扫盲
什么是JVM JVM是Java设计者用于屏蔽多平台差异,基于操作系统之上的一个"小型虚拟机",正是因为JVM的存在,使得Java应用程序运行时不需要关注底层操作系统的差异。使得Java程序编译只需编译一次,在任何操作系统都可以以相…...

SpringBoot基于gRPC进行RPC调用
SpringBoot基于gRPC进行RPC调用 一、gRPC1.1 什么是gRPC?1.2 如何编写proto1.3 数据类型及对应关系1.4 枚举1.5 数组1.6 map类型1.7 嵌套对象 二、SpringBoot gRPC2.1 工程目录2.2 jrpc-api2.2.1 引入gRPC依赖2.2.2 编写 .proto 文件2.2.3 使用插件机制生产proto相关…...

浏览器的事件循环机制(Event loop)
事件循环 浏览器的进程模型 何为进程? 程序运行需要有它自己专属的内存空间,可以把这块内存空间简单的理解为进程 每个应用至少有一个进程,进程之间相互独立,即使要通信,也需要双方同意。 何为线程? …...

THEMIS---Beta Sprint Summary Essay Blog
Which course does this assignment belong to2301-MUSE社区-CSDN社区云What are the requirements for this assignmentbeta SprintThe goal of this assignmentTo summarize the beta task progress and the teams sprintsTeam NameThemisTop-of-the-line collection of essa…...
Vue中实现分布式动态路由的基本实现步骤介绍
设想一下,我们在做一个体量非常大的项目,这个项目有很多的模块和相当多的页面。当我们想修改一个路由的时候,我们打开了router文件夹下的index.js文件时,一串长到鼠标滚轮需要滚大半天才滚到底的路由简直让人头皮发麻。 在开始之前…...
【Leetcode】计算器
思路 用栈来完成; 考虑到运算关系,先乘除后加减;此外,一般计算式首个数字式正数;判断字符是否为数字,str.isdigit()字符转数字:ord(str) - ord(‘0’)遇到加减符,压栈数字…...

抖音增长新引擎:品融电商,一站式全案代运营领跑者
抖音增长新引擎:品融电商,一站式全案代运营领跑者 在抖音这个日活超7亿的流量汪洋中,品牌如何破浪前行?自建团队成本高、效果难控;碎片化运营又难成合力——这正是许多企业面临的增长困局。品融电商以「抖音全案代运营…...
在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module
1、为什么要修改 CONNECT 报文? 多租户隔离:自动为接入设备追加租户前缀,后端按 ClientID 拆分队列。零代码鉴权:将入站用户名替换为 OAuth Access-Token,后端 Broker 统一校验。灰度发布:根据 IP/地理位写…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一)
宇树机器人多姿态起立控制强化学习框架论文解析 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(一) 论文解读:交大&港大&上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化…...

ElasticSearch搜索引擎之倒排索引及其底层算法
文章目录 一、搜索引擎1、什么是搜索引擎?2、搜索引擎的分类3、常用的搜索引擎4、搜索引擎的特点二、倒排索引1、简介2、为什么倒排索引不用B+树1.创建时间长,文件大。2.其次,树深,IO次数可怕。3.索引可能会失效。4.精准度差。三. 倒排索引四、算法1、Term Index的算法2、 …...

select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
Device Mapper 机制
Device Mapper 机制详解 Device Mapper(简称 DM)是 Linux 内核中的一套通用块设备映射框架,为 LVM、加密磁盘、RAID 等提供底层支持。本文将详细介绍 Device Mapper 的原理、实现、内核配置、常用工具、操作测试流程,并配以详细的…...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...

算法笔记2
1.字符串拼接最好用StringBuilder,不用String 2.创建List<>类型的数组并创建内存 List arr[] new ArrayList[26]; Arrays.setAll(arr, i -> new ArrayList<>()); 3.去掉首尾空格...

Python基于历史模拟方法实现投资组合风险管理的VaR与ES模型项目实战
说明:这是一个机器学习实战项目(附带数据代码文档),如需数据代码文档可以直接到文章最后关注获取。 1.项目背景 在金融市场日益复杂和波动加剧的背景下,风险管理成为金融机构和个人投资者关注的核心议题之一。VaR&…...