From 8d10ba52b2c8aa59d6c54a193145492b1c196d4d Mon Sep 17 00:00:00 2001 From: Tristan Rice Date: Mon, 11 Jul 2022 21:22:45 -0700 Subject: [PATCH] renderer: add support for rendering high dimensional textures for classification/segmentation use cases (#1248) Summary: For 3D segmentation problems it's really useful to be able to train the models from multiple viewpoints using Pytorch3D as the renderer. Currently due to hardcoded assumptions in a few spots the mesh renderer only supports rendering RGB (3 dimensional) data. You can encode the classification information as 3 channel data but if you have more than 3 classes you're out of luck. This relaxes the assumptions to make rendering semantic classes work with `HardFlatShader` and `AmbientLights` with no diffusion/specular. The other shaders/lights don't make any sense for classification since they mutate the texture values in some way. This only requires changes in `Materials` and `AmbientLights`. The bulk of the code is the unit test. Pull Request resolved: https://github.com/facebookresearch/pytorch3d/pull/1248 Test Plan: Added unit test that renders a 5 dimensional texture and compare dimensions 2-5 to a stored picture. Reviewed By: bottler Differential Revision: D37764610 Pulled By: d4l3k fbshipit-source-id: 031895724d9318a6f6bab5b31055bb3f438176a5 --- pytorch3d/renderer/lighting.py | 19 ++++++-- pytorch3d/renderer/materials.py | 16 ++++--- tests/data/test_nd_sphere.png | Bin 0 -> 57278 bytes tests/test_render_meshes.py | 78 ++++++++++++++++++++++++++++++++ 4 files changed, 101 insertions(+), 12 deletions(-) create mode 100644 tests/data/test_nd_sphere.png diff --git a/pytorch3d/renderer/lighting.py b/pytorch3d/renderer/lighting.py index 3ca81ca77..a11ffbe40 100644 --- a/pytorch3d/renderer/lighting.py +++ b/pytorch3d/renderer/lighting.py @@ -292,6 +292,9 @@ class AmbientLights(TensorProperties): A light object representing the same color of light everywhere. By default, this is white, which effectively means lighting is not used in rendering. + + Unlike other lights this supports an arbitrary number of channels, not just 3 for RGB. + The ambient_color input determines the number of channels. """ def __init__(self, *, ambient_color=None, device: Device = "cpu") -> None: @@ -304,9 +307,11 @@ def __init__(self, *, ambient_color=None, device: Device = "cpu") -> None: device: Device (as str or torch.device) on which the tensors should be located The ambient_color if provided, should be - - 3 element tuple/list or list of lists - - torch tensor of shape (1, 3) - - torch tensor of shape (N, 3) + - tuple/list of C-element tuples of floats + - torch tensor of shape (1, C) + - torch tensor of shape (N, C) + where C is the number of channels and N is batch size. + For RGB, C is 3. """ if ambient_color is None: ambient_color = ((1.0, 1.0, 1.0),) @@ -317,10 +322,14 @@ def clone(self): return super().clone(other) def diffuse(self, normals, points) -> torch.Tensor: - return torch.zeros_like(points) + return self._zeros_channels(points) def specular(self, normals, points, camera_position, shininess) -> torch.Tensor: - return torch.zeros_like(points) + return self._zeros_channels(points) + + def _zeros_channels(self, points: torch.Tensor) -> torch.Tensor: + ch = self.ambient_color.shape[-1] + return torch.zeros(*points.shape[:-1], ch, device=points.device) def _validate_light_properties(obj) -> None: diff --git a/pytorch3d/renderer/materials.py b/pytorch3d/renderer/materials.py index 738808b72..27558ed8a 100644 --- a/pytorch3d/renderer/materials.py +++ b/pytorch3d/renderer/materials.py @@ -27,9 +27,9 @@ def __init__( ) -> None: """ Args: - ambient_color: RGB ambient reflectivity of the material - diffuse_color: RGB diffuse reflectivity of the material - specular_color: RGB specular reflectivity of the material + ambient_color: ambient reflectivity of the material + diffuse_color: diffuse reflectivity of the material + specular_color: specular reflectivity of the material shininess: The specular exponent for the material. This defines the focus of the specular highlight with a high value resulting in a concentrated highlight. Shininess values @@ -37,7 +37,8 @@ def __init__( device: Device (as str or torch.device) on which the tensors should be located ambient_color, diffuse_color and specular_color can be of shape - (1, 3) or (N, 3). shininess can be of shape (1) or (N). + (1, C) or (N, C) where C is typically 3 (for RGB). shininess can be of shape (1,) + or (N,). The colors and shininess are broadcast against each other so need to have either the same batch dimension or batch dimension = 1. @@ -49,11 +50,12 @@ def __init__( specular_color=specular_color, shininess=shininess, ) + C = self.ambient_color.shape[-1] for n in ["ambient_color", "diffuse_color", "specular_color"]: t = getattr(self, n) - if t.shape[-1] != 3: - msg = "Expected %s to have shape (N, 3); got %r" - raise ValueError(msg % (n, t.shape)) + if t.shape[-1] != C: + msg = "Expected %s to have shape (N, %d); got %r" + raise ValueError(msg % (n, C, t.shape)) if self.shininess.shape != torch.Size([self._N]): msg = "shininess should have shape (N); got %r" raise ValueError(msg % repr(self.shininess.shape)) diff --git a/tests/data/test_nd_sphere.png b/tests/data/test_nd_sphere.png new file mode 100644 index 0000000000000000000000000000000000000000..cf2f9a9eaef249f834dd2031de1593add12574cc GIT binary patch literal 57278 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 D&YqQC literal 0 HcmV?d00001 diff --git a/tests/test_render_meshes.py b/tests/test_render_meshes.py index b47a78f2f..1dcd8e1cc 100644 --- a/tests/test_render_meshes.py +++ b/tests/test_render_meshes.py @@ -1236,3 +1236,81 @@ def test_cameras_kwarg(self): "test_simple_sphere_light_phong_%s.png" % cam_type.__name__, DATA_DIR ) self.assertClose(rgb, image_ref, atol=0.05) + + def test_nd_sphere(self): + """ + Test that the render can handle textures with more than 3 channels and + not just 3 channel RGB. + """ + torch.manual_seed(1) + device = torch.device("cuda:0") + C = 5 + WHITE = ((1.0,) * C,) + BLACK = ((0.0,) * C,) + + # Init mesh + sphere_mesh = ico_sphere(5, device) + verts_padded = sphere_mesh.verts_padded() + faces_padded = sphere_mesh.faces_padded() + feats = torch.ones(*verts_padded.shape[:-1], C, device=device) + n_verts = feats.shape[1] + # make some non-uniform pattern + feats *= torch.arange(0, 10, step=10 / n_verts, device=device).unsqueeze(1) + textures = TexturesVertex(verts_features=feats) + sphere_mesh = Meshes(verts=verts_padded, faces=faces_padded, textures=textures) + + # No elevation or azimuth rotation + R, T = look_at_view_transform(2.7, 0.0, 0.0) + + cameras = PerspectiveCameras(device=device, R=R, T=T) + + # Init shader settings + materials = Materials( + device=device, + ambient_color=WHITE, + diffuse_color=WHITE, + specular_color=WHITE, + ) + lights = AmbientLights( + device=device, + ambient_color=WHITE, + ) + lights.location = torch.tensor([0.0, 0.0, +2.0], device=device)[None] + + raster_settings = RasterizationSettings( + image_size=512, blur_radius=0.0, faces_per_pixel=1 + ) + rasterizer = MeshRasterizer(cameras=cameras, raster_settings=raster_settings) + blend_params = BlendParams( + 1e-4, + 1e-4, + background_color=BLACK[0], + ) + + # only test HardFlatShader since that's the only one that makes + # sense for classification + shader = HardFlatShader( + lights=lights, + cameras=cameras, + materials=materials, + blend_params=blend_params, + ) + renderer = MeshRenderer(rasterizer=rasterizer, shader=shader) + images = renderer(sphere_mesh) + + self.assertEqual(images.shape[-1], C + 1) + self.assertClose(images.amax(), torch.tensor(10.0), atol=0.01) + self.assertClose(images.amin(), torch.tensor(0.0), atol=0.01) + + # grab last 3 color channels + rgb = (images[0, ..., C - 3 : C] / 10).squeeze().cpu() + filename = "test_nd_sphere.png" + + if DEBUG: + debug_filename = "DEBUG_%s" % filename + Image.fromarray((rgb.numpy() * 255).astype(np.uint8)).save( + DATA_DIR / debug_filename + ) + + image_ref = load_rgb_image(filename, DATA_DIR) + self.assertClose(rgb, image_ref, atol=0.05)