基于可微分渲染器的相机位置优化【PyTorch3D】

在这个教程中,我们将使用可微渲染学习给定参考图像的相机的 [x, y, z] 位置。

我们将首先使用相机的起始位置初始化渲染器。 然后,我们将使用它来生成图像,使用参考图像计算损失,最后通过整个管道进行反向传播以更新相机的位置。

NSDT在线工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器

本教程展示如何:

  • 从 .obj 文件加载网格
  • 初始化相机、着色器和渲染器,
  • 渲染网格
  • 使用损失函数和优化器设置优化循环

首先确保已安装torch和torchvision,并使用以下代码安装pytorch3d:

import os
import sys
import torch
need_pytorch3d=False
try:import pytorch3d
except ModuleNotFoundError:need_pytorch3d=True
if need_pytorch3d:if torch.__version__.startswith("2.1.") and sys.platform.startswith("linux"):# We try to install PyTorch3D via a released wheel.pyt_version_str=torch.__version__.split("+")[0].replace(".", "")version_str="".join([f"py3{sys.version_info.minor}_cu",torch.version.cuda.replace(".",""),f"_pyt{pyt_version_str}"])!pip install fvcore iopath!pip install --no-index --no-cache-dir pytorch3d -f https://dl.fbaipublicfiles.com/pytorch3d/packaging/wheels/{version_str}/download.htmlelse:# We try to install PyTorch3D from source.!pip install 'git+https://github.com/facebookresearch/pytorch3d.git@stable'

导入模块:

import os
import torch
import numpy as np
from tqdm.notebook import tqdm
import imageio
import torch.nn as nn
import torch.nn.functional as F
import matplotlib.pyplot as plt
from skimage import img_as_ubyte# io utils
from pytorch3d.io import load_obj# datastructures
from pytorch3d.structures import Meshes# 3D transformations functions
from pytorch3d.transforms import Rotate, Translate# rendering components
from pytorch3d.renderer import (FoVPerspectiveCameras, look_at_view_transform, look_at_rotation, RasterizationSettings, MeshRenderer, MeshRasterizer, BlendParams,SoftSilhouetteShader, HardPhongShader, PointLights, TexturesVertex,
)

1、加载obj模型

我们将加载一个 obj 文件并创建一个 Meshes 对象。 网格是 PyTorch3D 中提供的独特数据结构,用于处理批量不同大小的网格。 它有几个在渲染管道中使用的有用的类方法:

# Set the cuda device 
if torch.cuda.is_available():device = torch.device("cuda:0")torch.cuda.set_device(device)
else:device = torch.device("cpu")# Load the obj and ignore the textures and materials.
verts, faces_idx, _ = load_obj("./data/teapot.obj")
faces = faces_idx.verts_idx# Initialize each vertex to be white in color.
verts_rgb = torch.ones_like(verts)[None]  # (1, V, 3)
textures = TexturesVertex(verts_features=verts_rgb.to(device))# Create a Meshes object for the teapot. Here we have only one mesh in the batch.
teapot_mesh = Meshes(verts=[verts.to(device)],   faces=[faces.to(device)], textures=textures
)

如果在克隆 PyTorch3D 存储库后在本地运行此笔记本,则网格将已经可用。 如果使用 Google Colab,请获取网格并将其保存在路径 data/ 中:

!mkdir -p data
!wget -P data https://dl.fbaipublicfiles.com/pytorch3d/data/teapot/teapot.obj

2、优化设置

PyTorch3D 中的渲染器由光栅器和着色器组成,每个组件都有许多子组件,例如相机(正交/透视)。 在这里,我们初始化其中一些组件,并对其余组件使用默认值。

2.1 创建渲染器

为了优化相机位置,我们将使用渲染器,它仅生成对象的轮廓,而不应用任何照明或阴影。 我们还将初始化另一个应用完整 Phong 着色的渲染器,并使用它来可视化输出。

# Initialize a perspective camera.
cameras = FoVPerspectiveCameras(device=device)# To blend the 100 faces we set a few parameters which control the opacity and the sharpness of 
# edges. Refer to blending.py for more details. 
blend_params = BlendParams(sigma=1e-4, gamma=1e-4)# Define the settings for rasterization and shading. Here we set the output image to be of size
# 256x256. To form the blended image we use 100 faces for each pixel. We also set bin_size and max_faces_per_bin to None which ensure that 
# the faster coarse-to-fine rasterization method is used. Refer to rasterize_meshes.py for 
# explanations of these parameters. Refer to docs/notes/renderer.md for an explanation of 
# the difference between naive and coarse-to-fine rasterization. 
raster_settings = RasterizationSettings(image_size=256, blur_radius=np.log(1. / 1e-4 - 1.) * blend_params.sigma, faces_per_pixel=100, 
)# Create a silhouette mesh renderer by composing a rasterizer and a shader. 
silhouette_renderer = MeshRenderer(rasterizer=MeshRasterizer(cameras=cameras, raster_settings=raster_settings),shader=SoftSilhouetteShader(blend_params=blend_params)
)# We will also create a Phong renderer. This is simpler and only needs to render one face per pixel.
raster_settings = RasterizationSettings(image_size=256, blur_radius=0.0, faces_per_pixel=1, 
)
# We can add a point light in front of the object. 
lights = PointLights(device=device, location=((2.0, 2.0, -2.0),))
phong_renderer = MeshRenderer(rasterizer=MeshRasterizer(cameras=cameras, raster_settings=raster_settings),shader=HardPhongShader(device=device, cameras=cameras, lights=lights)
)

2.2 创建参考图像

我们将首先定位茶壶并生成图像。 我们使用辅助函数将茶壶旋转到所需的视角。 然后我们可以使用渲染器来生成图像。 在这里,我们将使用两个渲染器并可视化轮廓和全着色图像。

世界坐标系定义为+Y向上、+X向左和+Z向内。世界坐标中的茶壶的壶嘴指向左侧。

我们定义了一个位于 z 轴正方向上的相机,因此可以看到右侧的喷口。

# Select the viewpoint using spherical angles  
distance = 3   # distance from camera to the object
elevation = 50.0   # angle of elevation in degrees
azimuth = 0.0  # No rotation so the camera is positioned on the +Z axis. # Get the position of the camera based on the spherical angles
R, T = look_at_view_transform(distance, elevation, azimuth, device=device)# Render the teapot providing the values of R and T. 
silhouette = silhouette_renderer(meshes_world=teapot_mesh, R=R, T=T)
image_ref = phong_renderer(meshes_world=teapot_mesh, R=R, T=T)silhouette = silhouette.cpu().numpy()
image_ref = image_ref.cpu().numpy()plt.figure(figsize=(10, 10))
plt.subplot(1, 2, 1)
plt.imshow(silhouette.squeeze()[..., 3])  # only plot the alpha channel of the RGBA image
plt.grid(False)
plt.subplot(1, 2, 2)
plt.imshow(image_ref.squeeze())
plt.grid(False)

输出如下:

2.3 创建基础模型

这里我们创建一个简单的模型类并初始化相机位置的参数。

class Model(nn.Module):def __init__(self, meshes, renderer, image_ref):super().__init__()self.meshes = meshesself.device = meshes.deviceself.renderer = renderer# Get the silhouette of the reference RGB image by finding all non-white pixel values. image_ref = torch.from_numpy((image_ref[..., :3].max(-1) != 1).astype(np.float32))self.register_buffer('image_ref', image_ref)# Create an optimizable parameter for the x, y, z position of the camera. self.camera_position = nn.Parameter(torch.from_numpy(np.array([3.0,  6.9, +2.5], dtype=np.float32)).to(meshes.device))def forward(self):# Render the image using the updated camera position. Based on the new position of the # camera we calculate the rotation and translation matricesR = look_at_rotation(self.camera_position[None, :], device=self.device)  # (1, 3, 3)T = -torch.bmm(R.transpose(1, 2), self.camera_position[None, :, None])[:, :, 0]   # (1, 3)image = self.renderer(meshes_world=self.meshes.clone(), R=R, T=T)# Calculate the silhouette lossloss = torch.sum((image[..., 3] - self.image_ref) ** 2)return loss, image

3、初始化模型和优化器

现在我们可以创建上述模型的实例并为相机位置参数设置优化器。

# We will save images periodically and compose them into a GIF.
filename_output = "./teapot_optimization_demo.gif"
writer = imageio.get_writer(filename_output, mode='I', duration=0.3)# Initialize a model using the renderer, mesh and reference image
model = Model(meshes=teapot_mesh, renderer=silhouette_renderer, image_ref=image_ref).to(device)# Create an optimizer. Here we are using Adam and we pass in the parameters of the model
optimizer = torch.optim.Adam(model.parameters(), lr=0.05)

可视化起始位置和参考位置:

plt.figure(figsize=(10, 10))_, image_init = model()
plt.subplot(1, 2, 1)
plt.imshow(image_init.detach().squeeze().cpu().numpy()[..., 3])
plt.grid(False)
plt.title("Starting position")plt.subplot(1, 2, 2)
plt.imshow(model.image_ref.cpu().numpy().squeeze())
plt.grid(False)
plt.title("Reference silhouette");

输出如下:

4、运行优化

我们运行前向和后向传递的多次迭代,并每 10 次迭代保存输出。

loop = tqdm(range(200))
for i in loop:optimizer.zero_grad()loss, _ = model()loss.backward()optimizer.step()loop.set_description('Optimizing (loss %.4f)' % loss.data)if loss.item() < 200:break# Save outputs to create a GIF. if i % 10 == 0:R = look_at_rotation(model.camera_position[None, :], device=model.device)T = -torch.bmm(R.transpose(1, 2), model.camera_position[None, :, None])[:, :, 0]   # (1, 3)image = phong_renderer(meshes_world=model.meshes.clone(), R=R, T=T)image = image[0, ..., :3].detach().squeeze().cpu().numpy()image = img_as_ubyte(image)writer.append_data(image)plt.figure()plt.imshow(image[..., :3])plt.title("iter: %d, loss: %0.2f" % (i, loss.data))plt.axis("off")writer.close()

迭代期间输出如下:

完成后可以查看 ./teapot_optimization_demo.gif,优化过程的炫酷 gif:

5、结束语

在本教程中,我们学习了如何从 obj 文件加载网格,初始化名为 Meshes 的 PyTorch3D 数据结构,设置由光栅化器和着色器组成的渲染器,设置包括模型和损失函数的优化循环,并运行优化。


原文链接:用可微渲染优化相机位置 - BimAnt

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

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

相关文章

Django创建基本的app应用并配置URL路径-成功运行服务

开发环境&#xff1a;Pycharm2021 Win11 首先创建虚拟环境: 可参考&#xff1a; Pycharm开发环境下创建python运行的虚拟环境&#xff08;自动执行安装依赖包&#xff09;_pycharm自动下载依赖包_heda3的博客-CSDN博客 1、安装 Django 在虚拟环境下安装pip install django …

从容应对高并发:RabbitMQ与消息限流策略的完美结合

在当今互联网时代&#xff0c;高并发访问已成为许多应用系统面临的常见挑战之一。对于需要处理大量请求的系统来说&#xff0c;如何保证系统的稳定性和可靠性是一个关键问题。RabbitMQ作为一种可靠的消息队列中间件&#xff0c;可以帮助解决高并发环境下的消息处理问题。而结合…

docker基础快速入门:基础命令、网络、docker compose工具

docker基础命令快速入门 目录 docker基本命令docker 网络docker compose Docker介绍 Docker是一个虚拟环境容器&#xff0c;可以将你的开发环境、代码、配置文件等一并打包到这个容器中&#xff0c;并发布和应用到任意平台中。 Docker的三个概念 镜像 Docker镜像是一个特…

自己动手写编译器:golex 和 flex 比较研究 2

上一节我们运行了 gcc 使用的词法解析器&#xff0c;使用它从.l 文件中生成对应的词法解析程序。同时我们用相同的词法规则对 golex 进行测试&#xff0c;发现 golex 同样能实现相同功能&#xff0c;当然这个过程我们也发现了 golex 代码中的不少 bug&#xff0c;本节我们继续对…

【Linux】23、内存超详细介绍

文章目录 零、资料一、内存映射1.1 TLB1.2 多级页表1.3 大页 二、虚拟内存空间分布2.1 用户空间的段2.2 内存分配和回收2.2.1 小对象2.2.2 释放 三、查看内存使用情况3.1 Buffer 和 Cache3.1.1 proc 文件系统3.1.2 案例3.1.2.1 场景 1&#xff1a;磁盘和文件写案例3.1.2.2 场景…

【数据结构】顺序表---C语言版

【数据结构】顺序表 前言&#xff1a;一、线性表二、顺序表1.顺序表的概念及结构&#xff1a;2.顺序表的分类&#xff1a;3.顺序表缺陷&#xff1a; 三、顺序表的代码实现&#xff1a;1.头文件&#xff1a;2.函数文件&#xff1a;3.测试文件&#xff1a; 四、顺序表的相关OJ题&…

怎么给数据库某个字段建立一个前缀索引

说明&#xff1a;SQL调优中重要的一个环节是建立索引&#xff0c;其中有一条是字段值过长字段应该建立前缀索引&#xff0c;即根据字段值的前几位建立索引&#xff0c;像数据库中的密码字段、UUID字段。 因为其随机性&#xff0c;其实根据前几位就可以锁定某一条记录了。前缀索…

(附源码)SSM+成都大学体育场馆预约系统 计算机毕设37087

摘 要 21世纪的今天&#xff0c;随着社会的不断发展与进步&#xff0c;人们对于信息科学化的认识&#xff0c;已由低层次向高层次发展&#xff0c;由原来的感性认识向理性认识提高&#xff0c;管理工作的重要性已逐渐被人们所认识&#xff0c;科学化的管理&#xff0c;使信息存…

Vatee万腾的数字探险之旅:vatee科技创新的新纪元

在数字时代的潮流中&#xff0c;Vatee万腾以其独特的数字探险之旅引领着科技创新的新纪元。这不仅是一次技术的进步&#xff0c;更是一场数字领域的探险&#xff0c;让我们一同探索Vatee在科技创新中的前沿地带。 Vatee万腾的数字探险起源于对未知的渴望和对创新的不懈追求。在…

【PUSDN】WebStorm中报错Switch language version to React JSX

简述 WebStorm中报错Switch language version to React JSX 可能本页面的写法是其他语法。所以可以不用管。 测试项目&#xff1a;ant design vue pro 前情提示 系统&#xff1a; 一说 同步更新最新版、完整版请移步PUSDN Powered By PUSDN - 平行宇宙软件开发者网www.pusdn…

《opencv实用探索·三》opencv Mat与数组互转

1、利用Mat来存储数据&#xff0c;避免使用数组等操作 //创建一个两行一列的矩阵cv::Mat mean (cv::Mat_<float>(2, 1) << 0.77, 0.33);std::cout() << mean << std::endl;float a mean.at<float>(0, 0); //0.77float b mean.at<float&…

使用vscode中编写c语言——无法打开 源 文件 “stdlib.h“C/C++(1696)问题

出现这个问题原因如下&#xff1a; 1、没有下载编辑器或者是没有配置好该编辑器的环境变量。 可以通过如下方法检查是否安装并配置好编辑器&#xff1a;打开终端&#xff1a;按winR cmd&#xff0c;然后输入gcc-v&#xff0c;查看是否有mingw64编辑器&#xff0c;如下图是已经…

TUP通信——与多个客户端同时通信

一&#xff0c;概括&#xff1a;可以通过多线程思想每加一个客户端由线程池中的主线程交给一个子线程管理 二&#xff0c;案例 &#xff08;1&#xff09;&#xff0c;线程池 &#xff08;2&#xff09;&#xff0c;服务端 &#xff08;3&#xff09;&#xff0c;客户端

【Qt】QStackedWidget、QRadioButton、QPushButton及布局实现程序首页自动展示功能

效果 在程序启动后&#xff0c;有时不会进入到工作页面&#xff0c;会进入到产品展示页面。 动画如下&#xff1a; 首页展示 页面操作 当不点击时&#xff0c;一秒自动刷新一次&#xff1b;当点击时&#xff0c;会自动跳转到对应页面&#xff1b;点击上一页、下一页、及跳转页…

03、K-means聚类实现步骤与基于K-means聚类的图像压缩

03、K-means聚类实现步骤与基于K-means聚类的图像压缩&#xff08;1&#xff09; K-means聚类实现步骤 开始学习机器学习啦&#xff0c;已经把吴恩达的课全部刷完了&#xff0c;现在开始熟悉一下复现代码。对这个手写数字实部比较感兴趣&#xff0c;作为入门的素材非常合适。…

理解Android无埋点技术

首先什么是无埋点呢&#xff0c;其实所谓无埋点就是开发者无需再对追踪点进行埋码&#xff0c;而是脱离代码&#xff0c;只需面对应用界面圈圈点点即可追加随时生效的事件数据点。 无埋点的好处 其实无埋点并不是完全不用写代码&#xff0c;而是尽可能的少写代码。开发者将SDK集…

零基础学编程轻松学编程,分享一款中文编程工具,编程构件简介

零基础学编程轻松学编程&#xff0c;分享一款中文编程工具&#xff0c;编程构件简介 中文编程开发语言工具编辑区界面截图如上图。 给大家分享一款中文编程工具 零基础轻松学编程&#xff0c;不需英语基础&#xff0c;编程工具可下载。 这款工具不但可以连接部分硬件&#…

数据库应用:Ubuntu 20.04 安装MongoDB

目录 一、理论 1.MongoDB 二、实验 1.Ubuntu 20.04 安装MongoDB 三、问题 1.Ubuntu Linux的apt 包管理器更新安装软件报错 2.Ubuntu20.04安装vim报错 3.Ubuntu20.04如何更换阿里源 4.Ubuntu22.04如何更换阿里源 一、理论 1.MongoDB &#xff08;1&#xff09;概念 …

6、Qt使用Log4Qt日志

一、知识点 1、Log4Qt有三部分 logger&#xff1a;负责捕获日志信息 layout&#xff1a;负责使用不同的样式输出日志 appender&#xff1a;负责输出信息到不同的目的地&#xff0c;比如数据库、文件、控制台等等 2、 日志级别如下&#xff0c;从上往下依次递增 ALL&#xff1a;…

css之svg 制作圆及旋转

1.代码 <template><div class"loading-box"><div class"circle-container"><svg width"75" height"75" class"move-left-to-right"><circle cx"37.5" cy"37.5" r"26&…