Ejemplo n.º 1
0
    def test_faces_verts_textures(self):
        device = torch.device("cuda:0")
        N, F, R = 2, 2, 8
        num_faces = torch.randint(low=1, high=F, size=(N, ))
        faces_atlas = [
            torch.rand(size=(num_faces[i].item(), R, R, 3), device=device)
            for i in range(N)
        ]
        tex = TexturesAtlas(atlas=faces_atlas)

        # faces_verts naive
        faces_verts = []
        for n in range(N):
            ff = num_faces[n].item()
            temp = torch.zeros(ff, 3, 3)
            for f in range(ff):
                t0 = faces_atlas[n][f, 0, -1]  # for v0, bary = (1, 0)
                t1 = faces_atlas[n][f, -1, 0]  # for v1, bary = (0, 1)
                t2 = faces_atlas[n][f, 0, 0]  # for v2, bary = (0, 0)
                temp[f, 0] = t0
                temp[f, 1] = t1
                temp[f, 2] = t2
            faces_verts.append(temp)
        faces_verts = torch.cat(faces_verts, 0)

        self.assertClose(faces_verts, tex.faces_verts_textures_packed().cpu())
Ejemplo n.º 2
0
    def test_sample_textures_error(self):
        N = 1
        V = 20
        F = 10
        verts = torch.rand(size=(5, V, 3))
        faces = torch.randint(size=(5, F, 3), high=V)
        meshes = Meshes(verts=verts, faces=faces)

        # TexturesAtlas have the wrong batch dim
        tex = TexturesAtlas(atlas=torch.randn(size=(1, F, 4, 4, 3)))
        with self.assertRaisesRegex(ValueError, "do not match the dimensions"):
            Meshes(verts=verts, faces=faces, textures=tex)

        # TexturesAtlas have the wrong number of faces
        tex = TexturesAtlas(atlas=torch.randn(size=(N, 15, 4, 4, 3)))
        with self.assertRaisesRegex(ValueError, "do not match the dimensions"):
            Meshes(verts=verts, faces=faces, textures=tex)

        meshes = Meshes(verts=verts, faces=faces)
        meshes.textures = tex

        # Cannot use the texture attribute set on meshes for sampling
        # textures if the dimensions don't match
        with self.assertRaisesRegex(ValueError, "do not match the dimensions"):
            meshes.sample_textures(None)
Ejemplo n.º 3
0
    def test_textures_atlas_init_fail(self):
        # Incorrect sized tensors
        with self.assertRaisesRegex(ValueError, "atlas"):
            TexturesAtlas(atlas=torch.rand(size=(5, 10, 3)))

        # Not a list or a tensor
        with self.assertRaisesRegex(ValueError, "atlas"):
            TexturesAtlas(atlas=(1, 1, 1))
Ejemplo n.º 4
0
 def test_detach(self):
     tex = TexturesAtlas(atlas=torch.rand(size=(1, 10, 2, 2, 3), requires_grad=True))
     tex.atlas_list()
     tex_detached = tex.detach()
     self.assertFalse(tex_detached._atlas_padded.requires_grad)
     self.assertClose(tex_detached._atlas_padded, tex._atlas_padded)
     for i in range(tex._N):
         self.assertFalse(tex_detached._atlas_list[i].requires_grad)
         self.assertClose(tex._atlas_list[i], tex_detached._atlas_list[i])
Ejemplo n.º 5
0
 def test_clone(self):
     tex = TexturesAtlas(atlas=torch.rand(size=(1, 10, 2, 2, 3)))
     tex.atlas_list()
     tex_cloned = tex.clone()
     self.assertSeparate(tex._atlas_padded, tex_cloned._atlas_padded)
     self.assertClose(tex._atlas_padded, tex_cloned._atlas_padded)
     self.assertSeparate(tex.valid, tex_cloned.valid)
     self.assertTrue(tex.valid.eq(tex_cloned.valid).all())
     for i in range(tex._N):
         self.assertSeparate(tex._atlas_list[i], tex_cloned._atlas_list[i])
         self.assertClose(tex._atlas_list[i], tex_cloned._atlas_list[i])
Ejemplo n.º 6
0
    def test_extend(self):
        B = 10
        mesh = init_mesh(B, 30, 50)
        F = mesh._F
        tex_uv = TexturesAtlas(atlas=torch.randn((B, F, 2, 2, 3)))
        tex_mesh = Meshes(verts=mesh.verts_padded(),
                          faces=mesh.faces_padded(),
                          textures=tex_uv)
        N = 20
        new_mesh = tex_mesh.extend(N)

        self.assertEqual(len(tex_mesh) * N, len(new_mesh))

        tex_init = tex_mesh.textures
        new_tex = new_mesh.textures

        for i in range(len(tex_mesh)):
            for n in range(N):
                self.assertClose(tex_init.atlas_list()[i],
                                 new_tex.atlas_list()[i * N + n])
                self.assertClose(
                    tex_init._num_faces_per_mesh[i],
                    new_tex._num_faces_per_mesh[i * N + n],
                )

        self.assertAllSeparate(
            [tex_init.atlas_padded(),
             new_tex.atlas_padded()])

        with self.assertRaises(ValueError):
            tex_mesh.extend(N=-1)
Ejemplo n.º 7
0
 def test_textures_atlas_grad(self):
     N, F, R = 1, 2, 2
     verts = torch.randn((4, 3), dtype=torch.float32)
     faces = torch.tensor([[2, 1, 0], [3, 1, 0]], dtype=torch.int64)
     faces_atlas = torch.rand(size=(N, F, R, R, 3), requires_grad=True)
     tex = TexturesAtlas(atlas=faces_atlas)
     mesh = Meshes(verts=[verts], faces=[faces], textures=tex)
     pix_to_face = torch.tensor([0, 1], dtype=torch.int64).view(1, 1, 1, 2)
     barycentric_coords = torch.tensor([[0.5, 0.3, 0.2], [0.3, 0.6, 0.1]],
                                       dtype=torch.float32).view(
                                           1, 1, 1, 2, -1)
     fragments = Fragments(
         pix_to_face=pix_to_face,
         bary_coords=barycentric_coords,
         zbuf=torch.ones_like(pix_to_face),
         dists=torch.ones_like(pix_to_face),
     )
     texels = mesh.textures.sample_textures(fragments)
     grad_tex = torch.rand_like(texels)
     grad_expected = torch.zeros_like(faces_atlas)
     grad_expected[0, 0, 0, 1, :] = grad_tex[..., 0:1, :]
     grad_expected[0, 1, 1, 0, :] = grad_tex[..., 1:2, :]
     texels.backward(grad_tex)
     self.assertTrue(hasattr(faces_atlas, "grad"))
     self.assertTrue(torch.allclose(faces_atlas.grad, grad_expected))
Ejemplo n.º 8
0
    def test_sample_texture_atlas(self):
        N, F, R = 1, 2, 2
        verts = torch.randn((4, 3), dtype=torch.float32)
        faces = torch.tensor([[2, 1, 0], [3, 1, 0]], dtype=torch.int64)
        faces_atlas = torch.rand(size=(N, F, R, R, 3))
        tex = TexturesAtlas(atlas=faces_atlas)
        mesh = Meshes(verts=[verts], faces=[faces], textures=tex)
        pix_to_face = torch.tensor([0, 1], dtype=torch.int64).view(1, 1, 1, 2)
        barycentric_coords = torch.tensor([[0.5, 0.3, 0.2], [0.3, 0.6, 0.1]],
                                          dtype=torch.float32).view(
                                              1, 1, 1, 2, -1)
        expected_vals = torch.tensor([[0.5, 1.0, 0.3], [0.3, 1.0, 0.9]],
                                     dtype=torch.float32)
        expected_vals = torch.zeros((1, 1, 1, 2, 3), dtype=torch.float32)
        expected_vals[..., 0, :] = faces_atlas[0, 0, 0, 1, ...]
        expected_vals[..., 1, :] = faces_atlas[0, 1, 1, 0, ...]

        fragments = Fragments(
            pix_to_face=pix_to_face,
            bary_coords=barycentric_coords,
            zbuf=torch.ones_like(pix_to_face),
            dists=torch.ones_like(pix_to_face),
        )
        texels = mesh.textures.sample_textures(fragments)
        self.assertTrue(torch.allclose(texels, expected_vals))
Ejemplo n.º 9
0
    def test_getitem(self):
        N = 5
        V = 20
        source = {"atlas": torch.randn(size=(N, 10, 4, 4, 3))}
        tex = TexturesAtlas(atlas=source["atlas"])

        verts = torch.rand(size=(N, V, 3))
        faces = torch.randint(size=(N, 10, 3), high=V)
        meshes = Meshes(verts=verts, faces=faces, textures=tex)

        tryindex(self, 2, tex, meshes, source)
        tryindex(self, slice(0, 2, 1), tex, meshes, source)
        index = torch.tensor([1, 0, 1, 0, 0], dtype=torch.bool)
        tryindex(self, index, tex, meshes, source)
        index = torch.tensor([0, 0, 0, 0, 0], dtype=torch.bool)
        tryindex(self, index, tex, meshes, source)
        index = torch.tensor([1, 2], dtype=torch.int64)
        tryindex(self, index, tex, meshes, source)
        tryindex(self, [2, 4], tex, meshes, source)
Ejemplo n.º 10
0
    def test_padded_to_packed(self):
        # Case where each face in the mesh has 3 unique uv vertex indices
        # - i.e. even if a vertex is shared between multiple faces it will
        # have a unique uv coordinate for each face.
        R = 2
        N = 20
        num_faces_per_mesh = torch.randint(size=(N, ), low=0, high=30)
        atlas_list = [torch.rand(f, R, R, 3) for f in num_faces_per_mesh]
        tex = TexturesAtlas(atlas=atlas_list)

        # This is set inside Meshes when textures is passed as an input.
        # Here we set _num_faces_per_mesh explicity.
        tex1 = tex.clone()
        tex1._num_faces_per_mesh = num_faces_per_mesh.tolist()
        atlas_packed = tex1.atlas_packed()
        atlas_list_new = tex1.atlas_list()
        atlas_padded = tex1.atlas_padded()

        for f1, f2 in zip(atlas_list_new, atlas_list):
            self.assertTrue((f1 == f2).all().item())

        sum_F = num_faces_per_mesh.sum()
        max_F = num_faces_per_mesh.max().item()
        self.assertTrue(atlas_packed.shape == (sum_F, R, R, 3))
        self.assertTrue(atlas_padded.shape == (N, max_F, R, R, 3))

        # Case where num_faces_per_mesh is not set and textures
        # are initialized with a padded tensor.
        atlas_list_padded = _list_to_padded_wrapper(atlas_list)
        tex2 = TexturesAtlas(atlas=atlas_list_padded)
        atlas_packed = tex2.atlas_packed()
        atlas_list_new = tex2.atlas_list()

        # Packed is just flattened padded as num_faces_per_mesh
        # has not been provided.
        self.assertTrue(atlas_packed.shape == (N * max_F, R, R, 3))

        for i, (f1, f2) in enumerate(zip(atlas_list_new, atlas_list)):
            n = num_faces_per_mesh[i]
            self.assertTrue((f1[:n] == f2).all().item())
Ejemplo n.º 11
0
 def test_clone(self):
     tex = TexturesAtlas(atlas=torch.rand(size=(1, 10, 2, 2, 3)))
     tex_cloned = tex.clone()
     self.assertSeparate(tex._atlas_padded, tex_cloned._atlas_padded)
     self.assertSeparate(tex.valid, tex_cloned.valid)