Skip to content

Commit 838b73d

Browse files
nikhilaravifacebook-github-bot
authored andcommitted
Updates to cameras and rasterizer to infer camera type correctly
Summary: Small update to the cameras and rasterizer to correctly infer the type of camera (perspective vs orthographic). Reviewed By: jcjohnson Differential Revision: D26267225 fbshipit-source-id: a58ed3bc2ab25553d2a4307c734204c1d41b5176
1 parent 39f49c2 commit 838b73d

File tree

5 files changed

+65
-11
lines changed

5 files changed

+65
-11
lines changed

pytorch3d/renderer/cameras.py

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,16 @@ class CamerasBase(TensorProperties):
4242
4343
It defines methods that are common to all camera models:
4444
- `get_camera_center` that returns the optical center of the camera in
45-
world coordinates
45+
world coordinates
4646
- `get_world_to_view_transform` which returns a 3D transform from
47-
world coordinates to the camera view coordinates (R, T)
47+
world coordinates to the camera view coordinates (R, T)
4848
- `get_full_projection_transform` which composes the projection
49-
transform (P) with the world-to-view transform (R, T)
49+
transform (P) with the world-to-view transform (R, T)
5050
- `transform_points` which takes a set of input points in world coordinates and
51-
projects to NDC coordinates ranging from [-1, -1, znear] to [+1, +1, zfar].
51+
projects to NDC coordinates ranging from [-1, -1, znear] to [+1, +1, zfar].
5252
- `transform_points_screen` which takes a set of input points in world coordinates and
53-
projects them to the screen coordinates ranging from [0, 0, znear] to [W-1, H-1, zfar]
53+
projects them to the screen coordinates ranging from
54+
[0, 0, znear] to [W-1, H-1, zfar]
5455
5556
For each new camera, one should implement the `get_projection_transform`
5657
routine that returns the mapping from camera view coordinates to NDC coordinates.
@@ -268,6 +269,12 @@ def clone(self):
268269
other = cam_type(device=self.device)
269270
return super().clone(other)
270271

272+
def is_perspective(self):
273+
raise NotImplementedError()
274+
275+
def get_znear(self):
276+
return self.znear if hasattr(self, "znear") else None
277+
271278

272279
############################################################
273280
# Field of View Camera Classes #
@@ -534,6 +541,9 @@ def unproject_points(
534541
unprojection_transform = to_ndc_transform.inverse()
535542
return unprojection_transform.transform_points(xy_sdepth)
536543

544+
def is_perspective(self):
545+
return True
546+
537547

538548
def OpenGLOrthographicCameras(
539549
znear=1.0,
@@ -752,6 +762,9 @@ def unproject_points(
752762
unprojection_transform = to_ndc_transform.inverse()
753763
return unprojection_transform.transform_points(xy_sdepth)
754764

765+
def is_perspective(self):
766+
return False
767+
755768

756769
############################################################
757770
# MultiView Camera Classes #
@@ -927,6 +940,9 @@ def unproject_points(
927940
)
928941
return unprojection_transform.transform_points(xy_inv_depth)
929942

943+
def is_perspective(self):
944+
return True
945+
930946

931947
def SfMOrthographicCameras(
932948
focal_length=1.0, principal_point=((0.0, 0.0),), R=_R, T=_T, device="cpu"
@@ -1086,6 +1102,9 @@ def unproject_points(
10861102
unprojection_transform = to_ndc_transform.inverse()
10871103
return unprojection_transform.transform_points(xy_depth)
10881104

1105+
def is_perspective(self):
1106+
return False
1107+
10891108

10901109
################################################
10911110
# Helper functions for cameras #

pytorch3d/renderer/mesh/rasterizer.py

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -139,16 +139,21 @@ def forward(self, meshes_world, **kwargs) -> Fragments:
139139
if clip_barycentric_coords is None:
140140
clip_barycentric_coords = raster_settings.blur_radius > 0.0
141141

142-
# TODO(jcjohns): Should we try to set perspective_correct automatically
143-
# based on the type of the camera?
142+
# If not specified, infer perspective_correct from the camera
143+
cameras = kwargs.get("cameras", self.cameras)
144+
if raster_settings.perspective_correct is not None:
145+
perspective_correct = raster_settings.perspective_correct
146+
else:
147+
perspective_correct = cameras.is_perspective()
148+
144149
pix_to_face, zbuf, bary_coords, dists = rasterize_meshes(
145150
meshes_screen,
146151
image_size=raster_settings.image_size,
147152
blur_radius=raster_settings.blur_radius,
148153
faces_per_pixel=raster_settings.faces_per_pixel,
149154
bin_size=raster_settings.bin_size,
150155
max_faces_per_bin=raster_settings.max_faces_per_bin,
151-
perspective_correct=raster_settings.perspective_correct,
156+
perspective_correct=perspective_correct,
152157
clip_barycentric_coords=clip_barycentric_coords,
153158
cull_backfaces=raster_settings.cull_backfaces,
154159
)

tests/test_cameras.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -794,6 +794,11 @@ def test_transform_points(self):
794794
new_points = cam.transform_points(points)
795795
self.assertClose(new_points, projected_points)
796796

797+
def test_perspective_type(self):
798+
cam = FoVPerspectiveCameras(znear=1.0, zfar=10.0, fov=60.0)
799+
self.assertTrue(cam.is_perspective())
800+
self.assertEquals(cam.get_znear(), 1.0)
801+
797802

798803
############################################################
799804
# FoVOrthographic Camera #
@@ -885,6 +890,11 @@ def test_orthographic_mixed_inputs_grad(self):
885890
)
886891
self.assertClose(scale_grad, grad_scale)
887892

893+
def test_perspective_type(self):
894+
cam = FoVOrthographicCameras(znear=1.0, zfar=10.0)
895+
self.assertFalse(cam.is_perspective())
896+
self.assertEquals(cam.get_znear(), 1.0)
897+
888898

889899
############################################################
890900
# Orthographic Camera #
@@ -937,6 +947,11 @@ def test_orthographic_kwargs(self):
937947
v1 = P.transform_points(vertices)
938948
self.assertClose(v1, projected_verts)
939949

950+
def test_perspective_type(self):
951+
cam = OrthographicCameras(focal_length=5.0, principal_point=((2.5, 2.5),))
952+
self.assertFalse(cam.is_perspective())
953+
self.assertEquals(cam.get_znear(), None)
954+
940955

941956
############################################################
942957
# Perspective Camera #
@@ -983,3 +998,8 @@ def test_perspective_kwargs(self):
983998
v1 = P.transform_points(vertices)
984999
v2 = sfm_perspective_project_naive(vertices, fx=2.0, fy=2.0, p0x=2.5, p0y=3.5)
9851000
self.assertClose(v1, v2, atol=1e-6)
1001+
1002+
def test_perspective_type(self):
1003+
cam = PerspectiveCameras(focal_length=5.0, principal_point=((2.5, 2.5),))
1004+
self.assertTrue(cam.is_perspective())
1005+
self.assertEquals(cam.get_znear(), None)

tests/test_render_implicit.py

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,10 @@ def test_compare_with_meshes_renderer(
242242
rasterizer=MeshRasterizer(
243243
cameras=cameras_randomized,
244244
raster_settings=RasterizationSettings(
245-
image_size=image_size, blur_radius=1e-3, faces_per_pixel=10
245+
image_size=image_size,
246+
blur_radius=1e-3,
247+
faces_per_pixel=10,
248+
perspective_correct=False,
246249
),
247250
),
248251
shader=SoftPhongShader(

tests/test_render_meshes.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -500,6 +500,7 @@ def test_texture_map(self):
500500
blur_radius=np.log(1.0 / 1e-4 - 1.0) * blend_params.sigma,
501501
faces_per_pixel=100,
502502
clip_barycentric_coords=True,
503+
perspective_correct=False,
503504
)
504505

505506
# Load reference image
@@ -844,7 +845,10 @@ def test_join_atlas(self):
844845
cameras = FoVPerspectiveCameras(device=device, R=R, T=T)
845846

846847
raster_settings = RasterizationSettings(
847-
image_size=512, blur_radius=0.0, faces_per_pixel=1
848+
image_size=512,
849+
blur_radius=0.0,
850+
faces_per_pixel=1,
851+
perspective_correct=False,
848852
)
849853

850854
lights = PointLights(
@@ -919,7 +923,10 @@ def test_joined_spheres(self):
919923
R, T = look_at_view_transform(2.7, 0.0, 0.0)
920924
cameras = FoVPerspectiveCameras(device=device, R=R, T=T)
921925
raster_settings = RasterizationSettings(
922-
image_size=512, blur_radius=0.0, faces_per_pixel=1
926+
image_size=512,
927+
blur_radius=0.0,
928+
faces_per_pixel=1,
929+
perspective_correct=False,
923930
)
924931

925932
# Init shader settings

0 commit comments

Comments
 (0)