相机
相机坐标系
在处理 3D 数据时,用户需要了解 4 个坐标系
- 世界坐标系 这是物体/场景所在的系统 - 世界。
- 相机视图坐标系 这是一个原点位于图像平面,
Z
轴垂直于图像平面的系统。在 PyTorch3D 中,我们假设+X
指向左侧,+Y
指向上方,+Z
指向图像平面外。从世界坐标系到视图坐标系的变换是在应用旋转 (R
) 和平移 (T
) 后发生的。 - NDC 坐标系 这是一个归一化坐标系,它将渲染的物体/场景的一部分限制在一个体积内。也称为视景体。对于正方形图像,在 PyTorch3D 约定下,
(+1, +1, znear)
是左上角近处的角点,而(-1, -1, zfar)
是右下角远处的角点。对于非正方形图像,XY
中体积的最小长度范围为[-1, 1]
,而较大的长度范围为[-s, s]
,其中s
是纵横比,并且s > 1
(较大的边除以较小的边)。从视图到 NDC 的变换是在应用相机投影矩阵 (P
) 后发生的。 - 屏幕坐标系 这是视景体的另一种表示,其中
XY
坐标以像素空间而不是归一化空间定义。(0,0) 是左上角像素的左上角角点,(W,H) 是右下角像素的右下角角点。
下面显示了 4 个坐标系的示意图
在 PyTorch3D 中定义相机
PyTorch3D 中的相机通过首先将物体/场景转换到视图(通过变换 R
和 T
),然后通过投影矩阵 P = K[R | T]
将 3D 物体/场景投影到归一化空间来将物体/场景从世界坐标系转换到视图坐标系,其中 K
是内参矩阵。K
中的相机参数定义了归一化空间。如果用户在 NDC 空间中定义相机参数,则变换将点投影到 NDC。如果相机参数在屏幕空间中定义,则变换后的点位于屏幕空间。
请注意,基本 CamerasBase
类对坐标系不做任何假设。所有上述变换都是纯粹由 R
、T
和 K
定义的几何变换。这意味着用户可以在任何坐标系和任何变换中定义相机。方法 transform_points
将 K
、R
和 T
应用于输入点作为简单的矩阵变换。但是,如果用户希望将相机与 PyTorch3D 渲染器一起使用,则需要遵守 PyTorch3D 的坐标系假设(请参阅下文)。
我们在 PyTorch3D 中提供了常用相机类型的实例化,以及用户如何灵活地定义投影空间。
与 PyTorch3D 渲染器交互
用于网格和点云的 PyTorch3D 渲染器假设相机变换后的点(即传递给光栅化器的输入点)位于 PyTorch3D 的 NDC 空间中。因此,为了获得预期的渲染结果,用户需要确保其 3D 输入数据和相机符合这些 PyTorch3D 坐标系假设。PyTorch3D 坐标系假设 +X:left
、+Y: up
和 +Z: from us to scene
(右手系)。关于坐标系的混淆很常见,因此我们建议您花一些时间了解您的数据及其所在的坐标系,并在使用 PyTorch3D 渲染器之前相应地进行转换。
有关相机及其与 PyTorch3D 渲染器交互方式的示例,请参阅我们的教程。
相机类型
所有相机都继承自 CamerasBase
,它是所有相机的基类。PyTorch3D 提供了四种不同的相机类型。CamerasBase
定义了所有相机模型共有的方法
get_camera_center
返回世界坐标系中相机的光学中心get_world_to_view_transform
返回从世界坐标系到相机视图坐标系(R, T)
的 3D 变换get_full_projection_transform
将投影变换 (K
) 与世界到视图变换(R, T)
组合transform_points
获取世界坐标系中的一组输入点,并将其投影到 NDC 坐标系,范围从 [-1, -1, znear] 到 [+1, +1, zfar]。get_ndc_camera_transform
定义了转换为 PyTorch3D 的 NDC 空间,并在与 PyTorch3D 渲染器交互时调用。如果相机在 NDC 空间中定义,则返回单位变换。如果相机在屏幕空间中定义,则返回从屏幕到 NDC 的转换。如果用户在屏幕空间中定义自己的相机,则需要考虑屏幕到 NDC 的转换。我们为PerspectiveCameras
和OrthographicCameras
提供了示例。transform_points_ndc
获取世界坐标系中的一组点,并将其投影到 PyTorch3D 的 NDC 空间transform_points_screen
获取世界坐标系中的一组输入点,并将其投影到屏幕坐标系,范围从 [0, 0, znear] 到 [W, H, zfar]
用户可以轻松自定义自己的相机。对于每个新相机,用户应该实现 get_projection_transform
例程,该例程返回从相机视图坐标系到 NDC 坐标系的映射 P
。
FoVPerspectiveCameras、FoVOrthographicCameras
这两个相机分别遵循 OpenGL 约定中的透视相机和正交相机。用户提供近平面 znear
和远平面 zfar
,它们限制了 Z
轴上的视景体。XY
平面上的视景体由 FoVPerspectiveCameras
情况下的视野角 (fov
) 和 FoVOrthographicCameras
情况下的 min_x, min_y, max_x, max_y
定义。这些相机默认位于 NDC 空间中。
PerspectiveCameras、OrthographicCameras
这两个相机遵循多视图几何约定中的相机。用户提供焦距 (fx
、fy
) 和主点 (px
、py
)。例如,camera = PerspectiveCameras(focal_length=((fx, fy),), principal_point=((px, py),))
视图坐标系中 3D 点 (X, Y, Z)
到投影空间(NDC 或屏幕)中点 (x, y, z)
的相机投影为
# for perspective camera
x = fx * X / Z + px
y = fy * Y / Z + py
z = 1 / Z
# for orthographic camera
x = fx * X + px
y = fy * Y + py
z = Z
用户可以在 NDC 或屏幕空间中定义相机参数。屏幕空间相机参数很常见,在这种情况下,用户需要将 in_ndc
设置为 False
,并提供屏幕的 image_size=(height, width)
,即图像。
get_ndc_camera_transform
提供了从屏幕到 PyTorch3D 中 NDC 空间的变换。请注意,屏幕空间假设主点在 +X left
、+Y down
和原点位于图像左上角的空间中提供。为了转换为 NDC,我们需要考虑归一化空间的缩放以及 XY
方向的变化。
以下是分别在 NDC 和屏幕空间中等效的 PerspectiveCameras
实例化的示例。
# NDC space camera
fcl_ndc = (1.2,)
prp_ndc = ((0.2, 0.5),)
cameras_ndc = PerspectiveCameras(focal_length=fcl_ndc, principal_point=prp_ndc)
# Screen space camera
image_size = ((128, 256),) # (h, w)
fcl_screen = (76.8,) # fcl_ndc * min(image_size) / 2
prp_screen = ((115.2, 32), ) # w / 2 - px_ndc * min(image_size) / 2, h / 2 - py_ndc * min(image_size) / 2
cameras_screen = PerspectiveCameras(focal_length=fcl_screen, principal_point=prp_screen, in_ndc=False, image_size=image_size)
相机 focal_length
和 principal_point
的屏幕和 NDC 规范之间的关系由以下公式给出,其中 s = min(image_width, image_height)
。x 和 y 坐标在屏幕和 NDC 之间的变换与 px 和 py 完全相同。
fx_ndc = fx_screen * 2.0 / s
fy_ndc = fy_screen * 2.0 / s
px_ndc = - (px_screen - image_width / 2.0) * 2.0 / s
py_ndc = - (py_screen - image_height / 2.0) * 2.0 / s