当前位置: 首页 > news >正文

【视点合成】代码解读:生成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中:

  1. 计算深度
  2. 计算视点变换
  3. 执行变换
  4. 帧序列到视频
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轴方向上的摆动半径"""# 创建了一个从01等间距的一维张量 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&#xff0…...

直线检测算子

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&#xff0…...

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’)遇到加减符,压栈数字&#xf…...

定时器任务——若依源码分析

分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...

什么是库存周转?如何用进销存系统提高库存周转率?

你可能听说过这样一句话: “利润不是赚出来的,是管出来的。” 尤其是在制造业、批发零售、电商这类“货堆成山”的行业,很多企业看着销售不错,账上却没钱、利润也不见了,一翻库存才发现: 一堆卖不动的旧货…...

Java 加密常用的各种算法及其选择

在数字化时代,数据安全至关重要,Java 作为广泛应用的编程语言,提供了丰富的加密算法来保障数据的保密性、完整性和真实性。了解这些常用加密算法及其适用场景,有助于开发者在不同的业务需求中做出正确的选择。​ 一、对称加密算法…...

Java面试专项一-准备篇

一、企业简历筛选规则 一般企业的简历筛选流程:首先由HR先筛选一部分简历后,在将简历给到对应的项目负责人后再进行下一步的操作。 HR如何筛选简历 例如:Boss直聘(招聘方平台) 直接按照条件进行筛选 例如&#xff1a…...

docker 部署发现spring.profiles.active 问题

报错: org.springframework.boot.context.config.InvalidConfigDataPropertyException: Property spring.profiles.active imported from location class path resource [application-test.yml] is invalid in a profile specific resource [origin: class path re…...

JVM虚拟机:内存结构、垃圾回收、性能优化

1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...

音视频——I2S 协议详解

I2S 协议详解 I2S (Inter-IC Sound) 协议是一种串行总线协议,专门用于在数字音频设备之间传输数字音频数据。它由飞利浦(Philips)公司开发,以其简单、高效和广泛的兼容性而闻名。 1. 信号线 I2S 协议通常使用三根或四根信号线&a…...

mac 安装homebrew (nvm 及git)

mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...

前端调试HTTP状态码

1xx(信息类状态码) 这类状态码表示临时响应,需要客户端继续处理请求。 100 Continue 服务器已收到请求的初始部分,客户端应继续发送剩余部分。 2xx(成功类状态码) 表示请求已成功被服务器接收、理解并处…...

Python 高级应用10:在python 大型项目中 FastAPI 和 Django 的相互配合

无论是python,或者java 的大型项目中,都会涉及到 自身平台微服务之间的相互调用,以及和第三发平台的 接口对接,那在python 中是怎么实现的呢? 在 Python Web 开发中,FastAPI 和 Django 是两个重要但定位不…...