pytorch3d导入maya相机位姿踩坑

devtools/2024/11/7 10:03:38/

目的是将maya中的相机无缝导入到pytorch3d

mayaTrans_pytorch3d_2">坑1: 直接导出maya中相机的欧拉角以及Trans, 然后直接导入pytorch3d

问题所在: maya中直接导出的相机旋转角以及Trans是 c2w, 而根据文档https://pytorch3d.org/docs/cameras 中的一句话, 经过R可以实现world to view的变换, 所以可以确定这个地方需要输入的参数其实是w2c
M c 2 w = [ R T 0 1 ] M_{c2w} = \begin{bmatrix} R & T \\ 0 & 1 \end{bmatrix} Mc2w=[R0T1], M w 2 c = M c 2 w − 1 = [ R T − R T T 0 1 ] M_{w2c} =M_{c2w} ^{-1}= \begin{bmatrix} R^T & -R^T T \\ 0 & 1 \end{bmatrix} Mw2c=Mc2w1=[RT0RTT1]
转换后输入即可

坑2: 坐标系不同, 需要先进行坐标系变换在这里插入图片描述

各个系统的坐标系如上图所示, 其中maya的坐标系与OpenGL相同, pytorch3d的坐标系需要将xz轴反向, 具体实现代码如下:

        R_py3d = R.clone().TT_py3d = T.clone()R_py3d[:, [0, 2]] *= -1  # 变换坐标系T_py3d[[0, 2]] *= -1

这里的实现参考了 pytorch3d/renderer/camera_conversions.py 中的_cameras_from_opencv_projection 方法, 这个方法是将opencv的相机变成pytorch3d, 这2个变换的相似点是都有一个轴固定, 然后旋转180°

def _cameras_from_opencv_projection(R: torch.Tensor,tvec: torch.Tensor,camera_matrix: torch.Tensor,image_size: torch.Tensor,
) -> PerspectiveCameras:focal_length = torch.stack([camera_matrix[:, 0, 0], camera_matrix[:, 1, 1]], dim=-1)principal_point = camera_matrix[:, :2, 2]# Retype the image_size correctly and flip to width, height.image_size_wh = image_size.to(R).flip(dims=(1,))# Screen to NDC conversion:# For non square images, we scale the points such that smallest side# has range [-1, 1] and the largest side has range [-u, u], with u > 1.# This convention is consistent with the PyTorch3D renderer, as well as# the transformation function `get_ndc_to_screen_transform`.scale = image_size_wh.to(R).min(dim=1, keepdim=True)[0] / 2.0scale = scale.expand(-1, 2)c0 = image_size_wh / 2.0# Get the PyTorch3D focal length and principal point.focal_pytorch3d = focal_length / scalep0_pytorch3d = -(principal_point - c0) / scale# For R, T we flip x, y axes (opencv screen space has an opposite# orientation of screen axes).# We also transpose R (opencv multiplies points from the opposite=left side).R_pytorch3d = R.clone().permute(0, 2, 1)T_pytorch3d = tvec.clone()R_pytorch3d[:, :, :2] *= -1T_pytorch3d[:, :2] *= -1return PerspectiveCameras(R=R_pytorch3d,T=T_pytorch3d,focal_length=focal_pytorch3d,principal_point=p0_pytorch3d,image_size=image_size,device=R.device,)

其他变换相关的参考资料
blender to pytorch3d camera: https://github.com/facebookresearch/pytorch3d/issues/1105

坑3: 内参的导入问题

读取代码

        focal_length = torch.tensor([K[0, 0], K[1, 1]], dtype=torch.float32).unsqueeze(0)principal_point = torch.tensor([K[0, 2], K[1, 2]], dtype=torch.float32).unsqueeze(0)cameras = PerspectiveCameras(device=self.device, R=R_py3d.unsqueeze(0), T=T_py3d.unsqueeze(0),focal_length=focal_length, principal_point=principal_point, in_ndc=False, image_size=[[1024, 1024]])

这里需要注意, 当输入focal_length与principal_point时, 一定要注意 in_ndc 这个选项!
还需要注意分辨率要与maya设置的渲染分辨率对上, 根据目前的观测, 就是K[0][2] * 2

最终完整代码:

maya相机参数通过如下代码获得:

    def query_cam_pos(self, camera_name):cam, cam_shape = self.scene["cameras"][camera_name]focal_length = cmds.camera(cam_shape, q=True, fl=True)inches_to_mm = 25.4app_horiz = cmds.camera(cam_shape, q=True, hfa=True) * inches_to_mmapp_vert = cmds.camera(cam_shape, q=True, vfa=True) * inches_to_mmpixel_width = self.config['resolution'][0]pixel_height = self.config['resolution'][1]focal_length_x_pixel = pixel_width * focal_length / app_horizfocal_length_y_pixel = pixel_height * focal_length / app_verttranslate = cmds.getAttr(cam + ".translate")[0]eular_rot = cmds.getAttr(cam + ".rotate")[0]# convert_to_opencv_matrixK = np.eye(3)K[0, 0] = focal_length_x_pixelK[1, 1] = focal_length_y_pixelK[0, 2] = pixel_width / 2.0K[1, 2] = pixel_height / 2.0R = utils.eulerAngleToRoatationMatrix((math.radians(eular_rot[0]), math.radians(eular_rot[1]), math.radians(eular_rot[2])))return K, R, translate

pytorch3d中相机参数的读取代码

		# 将c2w变成w2cR = R.TT = - R @ T# 然后变换坐标轴, 绕y轴转180°R_py3d = R.clone().TT_py3d = T.clone()R_py3d[:, [0, 2]] *= -1  # 变换坐标系T_py3d[[0, 2]] *= -1focal_length = torch.tensor([K[0, 0], K[1, 1]], dtype=torch.float32).unsqueeze(0)principal_point = torch.tensor([K[0, 2], K[1, 2]], dtype=torch.float32).unsqueeze(0)cameras = PerspectiveCameras(device=self.device, R=R_py3d.unsqueeze(0), T=T_py3d.unsqueeze(0), focal_length=focal_length, principal_point=principal_point, in_ndc=False,image_size=[[1024, 1024]])

http://www.ppmy.cn/devtools/131985.html

相关文章

【go从零单排】go中的基本数据类型和变量

Don’t worry , just coding! 内耗与overthinking只会削弱你的精力,虚度你的光阴,每天迈出一小步,回头时发现已经走了很远。 基本类型 go中的string、int、folat都可以用连接boolen可以用逻辑表达式计算 package mainimport "fmt&quo…

多模卫星手持电话|5G+天通卫星移动终端|卫星通信终端

全星魅5G天通北斗多模卫星移动终端QM630BS,作为新一代高端天通多模终端的杰出代表,凭借其强大的多模通信能力和丰富的功能配置,在户外通讯、应急通信、森林消防、水利防汛等特殊行业中展现出了卓越的性能与广泛的应用前景。本文将详细解析QM6…

「Mac畅玩鸿蒙与硬件28」UI互动应用篇5 - 滑动选择器实现

本篇将带你实现一个滑动选择器应用,用户可以通过滑动条选择不同的数值,并实时查看选定的值和提示。这是一个学习如何使用 Slider 组件、状态管理和动态文本更新的良好实践。 关键词 UI互动应用Slider 组件状态管理动态数值更新用户交互 一、功能说明 在…

七. RESTful

文章目录 1. RESTful简介2. RESTful的实现3. HiddenHttpMethodFilter 1. RESTful简介 2. RESTful的实现 3. HiddenHttpMethodFilter

鸥柏(OBOO)户外触摸广告屏科技创新 高速服务区收费站案例

鸥柏,作为户外液晶显示技术的品牌高端领先者,其新产品鸥柏户外触摸屏在高速服务区收费站入口处得到了真实且广泛的应用。OBOO鸥柏户外广告机能够存储和展示海量信息,包括新闻、政策、天气预报、实时路况等,为过往司乘人员提供丰富…

Docker篇(基础命令)

目录 一、启动与停止 二、镜像相关的命令 1. 查看镜像 2. 搜索镜像 3. 拉取镜像 4. 删除镜像 三、容器创建与启动容器 1. 查看容器 2. 创建容器 交互式方式创建容器 守护式方式创建容器 3. 容器启动与停止 四、容器操作命令 1. 文件拷贝 2. 目录(文件…

微信小程序uniapp+vue飞机订票航空售票系统

文章目录 项目介绍具体实现截图技术介绍mvc设计模式小程序框架以及目录结构介绍错误处理和异常处理java类核心代码部分展示详细视频演示源码获取 项目介绍 对于小程序飞机订票信息管理所牵扯的信息管理及数据保存都是非常多的,举例像所有的管理员;管理员…

Axios-Mock-Adapter mock数据

摘要:最近一个项目没有后端配合,临时使用使用Axios-Mock-Adapter来mock数据的逻辑,简单记录下使用步骤如下 1. 安装Axios-Mock-Adapter 首先,安装Axios-Mock-Adapter。Axios Mock Adapter 是一个用于模拟 Axios 请求和响应的库&a…