mirror of
https://github.com/facebookresearch/pytorch3d.git
synced 2025-12-19 05:40:34 +08:00
screen cameras lose -1
Summary: All the renderers in PyTorch3D (pointclouds including pulsar, meshes, raysampling) use align_corners=False style. NDC space goes between the edges of the outer pixels. For a non square image with W>H, the vertical NDC space goes from -1 to 1 and the horizontal from -W/H to W/H. However it was recently pointed out that functionality which deals with screen space inside the camera classes is inconsistent with this. It unintentionally uses align_corners=True. This fixes that. This would change behaviour of the following: - If you create a camera in screen coordinates, i.e. setting in_ndc=False, then anything you do with the camera which touches NDC space may be affected, including trying to use renderers. The transform_points_screen function will not be affected... - If you call the function “transform_points_screen” on a camera defined in NDC space results will be different. I have illustrated in the diff how to get the old results from the new results but this probably isn’t the right long-term solution.. Reviewed By: gkioxari Differential Revision: D32536305 fbshipit-source-id: 377325a9137282971dcb7ca11a6cba3fc700c9ce
This commit is contained in:
committed by
Facebook GitHub Bot
parent
cff4876131
commit
bf3bc6f8e3
@@ -130,9 +130,9 @@ def ndc_to_screen_points_naive(points, imsize):
|
||||
"""
|
||||
height, width = imsize.unbind(1)
|
||||
width = width.view(-1, 1)
|
||||
half_width = (width - 1.0) / 2.0
|
||||
half_width = width / 2.0
|
||||
height = height.view(-1, 1)
|
||||
half_height = (height - 1.0) / 2.0
|
||||
half_height = height / 2.0
|
||||
|
||||
scale = (
|
||||
half_width * (height > width).float() + half_height * (height <= width).float()
|
||||
@@ -524,7 +524,7 @@ class TestCamerasCommon(TestCaseMixin, unittest.TestCase):
|
||||
# (height, width)
|
||||
image_size = torch.randint(low=2, high=64, size=(batch_size, 2))
|
||||
# scale
|
||||
scale = (image_size.min(dim=1, keepdim=True).values - 1.0) / 2.0
|
||||
scale = (image_size.min(dim=1, keepdim=True).values) / 2.0
|
||||
|
||||
ndc_cam_params["focal_length"] = fcl
|
||||
ndc_cam_params["principal_point"] = prc
|
||||
@@ -533,7 +533,7 @@ class TestCamerasCommon(TestCaseMixin, unittest.TestCase):
|
||||
screen_cam_params["image_size"] = image_size
|
||||
screen_cam_params["focal_length"] = fcl * scale
|
||||
screen_cam_params["principal_point"] = (
|
||||
image_size[:, [1, 0]] - 1.0
|
||||
image_size[:, [1, 0]]
|
||||
) / 2.0 - prc * scale
|
||||
screen_cam_params["in_ndc"] = False
|
||||
else:
|
||||
@@ -821,7 +821,7 @@ class TestFoVPerspectiveProjection(TestCaseMixin, unittest.TestCase):
|
||||
def test_perspective_type(self):
|
||||
cam = FoVPerspectiveCameras(znear=1.0, zfar=10.0, fov=60.0)
|
||||
self.assertTrue(cam.is_perspective())
|
||||
self.assertEquals(cam.get_znear(), 1.0)
|
||||
self.assertEqual(cam.get_znear(), 1.0)
|
||||
|
||||
|
||||
############################################################
|
||||
@@ -917,7 +917,7 @@ class TestFoVOrthographicProjection(TestCaseMixin, unittest.TestCase):
|
||||
def test_perspective_type(self):
|
||||
cam = FoVOrthographicCameras(znear=1.0, zfar=10.0)
|
||||
self.assertFalse(cam.is_perspective())
|
||||
self.assertEquals(cam.get_znear(), 1.0)
|
||||
self.assertEqual(cam.get_znear(), 1.0)
|
||||
|
||||
|
||||
############################################################
|
||||
@@ -974,7 +974,7 @@ class TestOrthographicProjection(TestCaseMixin, unittest.TestCase):
|
||||
def test_perspective_type(self):
|
||||
cam = OrthographicCameras(focal_length=5.0, principal_point=((2.5, 2.5),))
|
||||
self.assertFalse(cam.is_perspective())
|
||||
self.assertEquals(cam.get_znear(), None)
|
||||
self.assertIsNone(cam.get_znear())
|
||||
|
||||
|
||||
############################################################
|
||||
@@ -1026,4 +1026,4 @@ class TestPerspectiveProjection(TestCaseMixin, unittest.TestCase):
|
||||
def test_perspective_type(self):
|
||||
cam = PerspectiveCameras(focal_length=5.0, principal_point=((2.5, 2.5),))
|
||||
self.assertTrue(cam.is_perspective())
|
||||
self.assertEquals(cam.get_znear(), None)
|
||||
self.assertIsNone(cam.get_znear())
|
||||
|
||||
@@ -250,23 +250,14 @@ class TestRenderMeshes(TestCaseMixin, unittest.TestCase):
|
||||
raster_settings = RasterizationSettings(
|
||||
image_size=512, blur_radius=0.0, faces_per_pixel=1
|
||||
)
|
||||
half_half = (512.0 / 2.0, 512.0 / 2.0)
|
||||
for cam_type in (PerspectiveCameras, OrthographicCameras):
|
||||
cameras = cam_type(
|
||||
device=device,
|
||||
R=R,
|
||||
T=T,
|
||||
principal_point=(
|
||||
(
|
||||
(512.0 - 1.0) / 2.0,
|
||||
(512.0 - 1.0) / 2.0,
|
||||
),
|
||||
),
|
||||
focal_length=(
|
||||
(
|
||||
(512.0 - 1.0) / 2.0,
|
||||
(512.0 - 1.0) / 2.0,
|
||||
),
|
||||
),
|
||||
principal_point=(half_half,),
|
||||
focal_length=(half_half,),
|
||||
image_size=((512, 512),),
|
||||
in_ndc=False,
|
||||
)
|
||||
@@ -285,6 +276,10 @@ class TestRenderMeshes(TestCaseMixin, unittest.TestCase):
|
||||
images = renderer(sphere_mesh)
|
||||
rgb = images[0, ..., :3].squeeze().cpu()
|
||||
filename = "test_simple_sphere_light_phong_%s.png" % cam_type.__name__
|
||||
if DEBUG:
|
||||
Image.fromarray((rgb.numpy() * 255).astype(np.uint8)).save(
|
||||
DATA_DIR / f"{filename}_.png"
|
||||
)
|
||||
|
||||
image_ref = load_rgb_image(filename, DATA_DIR)
|
||||
self.assertClose(rgb, image_ref, atol=0.05)
|
||||
|
||||
Reference in New Issue
Block a user