Beispiel #1
0
 def test_all_empty_meshes(self):
     """
     Check sample_points_from_meshes raises an exception if all meshes are
     invalid.
     """
     device = torch.device("cuda:0")
     verts1 = torch.tensor([], dtype=torch.float32, device=device)
     faces1 = torch.tensor([], dtype=torch.int64, device=device)
     meshes = Meshes(verts=[verts1, verts1, verts1],
                     faces=[faces1, faces1, faces1])
     with self.assertRaises(ValueError) as err:
         sample_points_from_meshes(meshes,
                                   num_samples=100,
                                   return_normals=True)
     self.assertTrue("Meshes are empty." in str(err.exception))
def init_cube_point_cloud(batch_size: int = 10,
                          n_points: int = 100000,
                          rotate_y: bool = True):
    """
    Generate a random point cloud of `n_points` whose points of
    which are sampled from faces of a 3D cube.
    """

    # create the cube mesh batch_size times
    meshes = TestPointsToVolumes.init_cube_mesh(batch_size)

    # generate point clouds by sampling points from the meshes
    pcl = sample_points_from_meshes(meshes,
                                    num_samples=n_points,
                                    return_normals=False)

    # colors of the cube sides
    clrs = [
        [1.0, 0.0, 0.0],
        [1.0, 1.0, 0.0],
        [0.0, 1.0, 0.0],
        [0.0, 1.0, 1.0],
        [1.0, 1.0, 1.0],
        [1.0, 0.0, 1.0],
    ]

    # init the color tensor "rgb"
    rgb = torch.zeros_like(pcl)

    # color each side of the cube with a constant color
    clri = 0
    for dim in (0, 1, 2):
        for offs in (0.0, 1.0):
            current_face_verts = (pcl[:, :, dim] - offs).abs() <= 1e-2
            for bi in range(batch_size):
                rgb[bi, current_face_verts[bi], :] = torch.tensor(
                    clrs[clri]).type_as(pcl)
            clri += 1

    if rotate_y:
        # uniformly spaced rotations around y axis
        R = init_uniform_y_rotations(batch_size=batch_size)
        # rotate the point clouds around y axis
        pcl = torch.bmm(pcl - 0.5, R) + 0.5

    return pcl, rgb
    def test_sampling_output(self):
        """
        Check outputs of sampling are correct for different meshes.
        For an ico_sphere, the sampled vertices should lie on a unit sphere.
        For an empty mesh, the samples and normals should be 0.
        """
        device = torch.device("cuda:0")

        # Unit simplex.
        verts_pyramid = torch.tensor(
            [
                [0.0, 0.0, 0.0],
                [1.0, 0.0, 0.0],
                [0.0, 1.0, 0.0],
                [0.0, 0.0, 1.0],
            ],
            dtype=torch.float32,
            device=device,
        )
        faces_pyramid = torch.tensor(
            [[0, 1, 2], [0, 2, 3], [0, 1, 3], [1, 2, 3]],
            dtype=torch.int64,
            device=device,
        )
        sphere_mesh = ico_sphere(9, device)
        verts_sphere, faces_sphere = sphere_mesh.get_mesh_verts_faces(0)
        verts_empty = torch.tensor([], dtype=torch.float32, device=device)
        faces_empty = torch.tensor([], dtype=torch.int64, device=device)
        num_samples = 10
        meshes = Meshes(
            verts=[verts_empty, verts_sphere, verts_pyramid],
            faces=[faces_empty, faces_sphere, faces_pyramid],
        )
        samples, normals = sample_points_from_meshes(
            meshes, num_samples=num_samples, return_normals=True
        )
        samples = samples.cpu()
        normals = normals.cpu()

        self.assertEqual(samples.shape, (3, num_samples, 3))
        self.assertEqual(normals.shape, (3, num_samples, 3))

        # Empty meshes: should have all zeros for samples and normals.
        self.assertTrue(
            torch.allclose(samples[0, :], torch.zeros((1, num_samples, 3)))
        )
        self.assertTrue(
            torch.allclose(normals[0, :], torch.zeros((1, num_samples, 3)))
        )

        # Sphere: points should have radius 1.
        x, y, z = samples[1, :].unbind(1)
        radius = torch.sqrt(x ** 2 + y ** 2 + z ** 2)

        self.assertTrue(torch.allclose(radius, torch.ones((num_samples))))

        # Pyramid: points shoudl lie on one of the faces.
        pyramid_verts = samples[2, :]
        pyramid_normals = normals[2, :]

        self.assertTrue(
            torch.allclose(
                pyramid_verts.lt(1).float(), torch.ones_like(pyramid_verts)
            )
        )
        self.assertTrue(
            torch.allclose(
                (pyramid_verts >= 0).float(), torch.ones_like(pyramid_verts)
            )
        )

        # Face 1: z = 0,  x + y <= 1, normals = (0, 0, 1).
        face_1_idxs = pyramid_verts[:, 2] == 0
        face_1_verts, face_1_normals = (
            pyramid_verts[face_1_idxs, :],
            pyramid_normals[face_1_idxs, :],
        )
        self.assertTrue(
            torch.all((face_1_verts[:, 0] + face_1_verts[:, 1]) <= 1)
        )
        self.assertTrue(
            torch.allclose(
                face_1_normals,
                torch.tensor([0, 0, 1], dtype=torch.float32).expand(
                    face_1_normals.size()
                ),
            )
        )

        # Face 2: x = 0,  z + y <= 1, normals = (1, 0, 0).
        face_2_idxs = pyramid_verts[:, 0] == 0
        face_2_verts, face_2_normals = (
            pyramid_verts[face_2_idxs, :],
            pyramid_normals[face_2_idxs, :],
        )
        self.assertTrue(
            torch.all((face_2_verts[:, 1] + face_2_verts[:, 2]) <= 1)
        )
        self.assertTrue(
            torch.allclose(
                face_2_normals,
                torch.tensor([1, 0, 0], dtype=torch.float32).expand(
                    face_2_normals.size()
                ),
            )
        )

        # Face 3: y = 0, x + z <= 1, normals = (0, -1, 0).
        face_3_idxs = pyramid_verts[:, 1] == 0
        face_3_verts, face_3_normals = (
            pyramid_verts[face_3_idxs, :],
            pyramid_normals[face_3_idxs, :],
        )
        self.assertTrue(
            torch.all((face_3_verts[:, 0] + face_3_verts[:, 2]) <= 1)
        )
        self.assertTrue(
            torch.allclose(
                face_3_normals,
                torch.tensor([0, -1, 0], dtype=torch.float32).expand(
                    face_3_normals.size()
                ),
            )
        )

        # Face 4: x + y + z = 1, normals = (1, 1, 1)/sqrt(3).
        face_4_idxs = pyramid_verts.gt(0).all(1)
        face_4_verts, face_4_normals = (
            pyramid_verts[face_4_idxs, :],
            pyramid_normals[face_4_idxs, :],
        )
        self.assertTrue(
            torch.allclose(
                face_4_verts.sum(1), torch.ones(face_4_verts.size(0))
            )
        )
        self.assertTrue(
            torch.allclose(
                face_4_normals,
                (
                    torch.tensor([1, 1, 1], dtype=torch.float32)
                    / torch.sqrt(torch.tensor(3, dtype=torch.float32))
                ).expand(face_4_normals.size()),
            )
        )
 def sample_points():
     sample_points_from_meshes(
         meshes, num_samples=num_samples, return_normals=True
     )
     torch.cuda.synchronize()