def test_clone(self): """ Check that cloned transformations contain different _matrix objects. Also, the clone of a composed translation and rotation has to be the same as composition of clones of translation and rotation. """ tr = Translate(torch.FloatTensor([[1.0, 2.0, 3.0]])) R = torch.FloatTensor([[0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0]]) R = Rotate(R) # check that the _matrix property of clones of # both transforms are different for t in (R, tr): self.assertTrue(t._matrix is not t.clone()._matrix) # check that the _transforms lists of composition of R, tr contain # different objects t1 = Transform3d().compose(R, tr) for t, t_clone in (t1._transforms, t1.clone()._transforms): self.assertTrue(t is not t_clone) self.assertTrue(t._matrix is not t_clone._matrix) # check that all composed transforms are numerically equivalent t2 = Transform3d().compose(R.clone(), tr.clone()) t3 = t1.clone() for t_pair in ((t1, t2), (t1, t3), (t2, t3)): matrix1 = t_pair[0].get_matrix() matrix2 = t_pair[1].get_matrix() self.assertTrue(torch.allclose(matrix1, matrix2))
def test_init_with_custom_matrix(self): for matrix in (torch.randn(10, 4, 4), torch.randn(4, 4)): t = Transform3d(matrix=matrix) self.assertTrue(t.device == matrix.device) self.assertTrue(t._matrix.dtype == matrix.dtype) self.assertTrue( torch.allclose(t._matrix, matrix.view(t._matrix.shape)))
def test_to(self): tr = Translate(torch.FloatTensor([[1.0, 2.0, 3.0]])) R = torch.FloatTensor([[0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0]]) R = Rotate(R) t = Transform3d().compose(R, tr) for _ in range(3): t.cpu() t.cuda() t.cuda() t.cpu()
def test_rotate(self): R = so3_exp_map(torch.randn((1, 3))) t = Transform3d().rotate(R) points = torch.tensor([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.5, 0.5, 0.0]]).view(1, 3, 3) normals = torch.tensor([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 1.0, 0.0]]).view(1, 3, 3) points_out = t.transform_points(points) normals_out = t.transform_normals(normals) points_out_expected = torch.bmm(points, R) normals_out_expected = torch.bmm(normals, R) self.assertTrue(torch.allclose(points_out, points_out_expected)) self.assertTrue(torch.allclose(normals_out, normals_out_expected))
def test_scale_translate(self): t = Transform3d().scale(2, 1, 3).translate(1, 2, 3) points = torch.tensor([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.5, 0.5, 0.0]]).view(1, 3, 3) normals = torch.tensor([[1.0, 0.0, 0.0], [0.0, 1.0, 0.0], [1.0, 1.0, 0.0]]).view(1, 3, 3) points_out = t.transform_points(points) normals_out = t.transform_normals(normals) points_out_expected = torch.tensor([[3.0, 2.0, 3.0], [1.0, 3.0, 3.0], [2.0, 2.5, 3.0]]).view(1, 3, 3) normals_out_expected = torch.tensor([[0.5, 0.0, 0.0], [0.0, 1.0, 0.0], [0.5, 1.0, 0.0]]).view(1, 3, 3) self.assertTrue(torch.allclose(points_out, points_out_expected)) self.assertTrue(torch.allclose(normals_out, normals_out_expected))
def test_rotate_axis_angle(self): t = Transform3d().rotate_axis_angle(-90.0, axis="Z") points = torch.tensor([[0.0, 0.0, 0.0], [0.0, 1.0, 0.0], [0.0, 1.0, 1.0]]).view(1, 3, 3) normals = torch.tensor([[1.0, 0.0, 0.0], [1.0, 0.0, 0.0], [1.0, 0.0, 0.0]]).view(1, 3, 3) points_out = t.transform_points(points) normals_out = t.transform_normals(normals) points_out_expected = torch.tensor([[0.0, 0.0, 0.0], [-1.0, 0.0, 0.0], [-1.0, 0.0, 1.0]]).view(1, 3, 3) normals_out_expected = torch.tensor([[0.0, 1.0, 0.0], [0.0, 1.0, 0.0], [0.0, 1.0, 0.0]]).view(1, 3, 3) self.assertTrue(torch.allclose(points_out, points_out_expected)) self.assertTrue(torch.allclose(normals_out, normals_out_expected))
def test_to(self): tr = Translate(torch.FloatTensor([[1.0, 2.0, 3.0]])) R = torch.FloatTensor([[0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0]]) cpu_points = torch.rand(9, 3) cuda_points = cpu_points.cuda() R = Rotate(R) t = Transform3d().compose(R, tr) for _ in range(3): t = t.cpu() t.transform_points(cpu_points) t = t.cuda() t.transform_points(cuda_points) t = t.cuda() t = t.cpu()
def test_transform_points_eps(self): t1 = Transform3d() persp_proj = [[ [1.0, 0.0, 0.0, 0.0], [0.0, 1.0, 0.0, 0.0], [0.0, 0.0, 0.0, 1.0], [0.0, 0.0, 1.0, 0.0], ]] t1._matrix = torch.FloatTensor(persp_proj) points = torch.tensor([ [0.0, 1.0, 0.0], [0.0, 0.0, 1e-5], [-1.0, 0.0, 1e-5] ]).view(1, 3, 3) # a set of points with z-coord very close to 0 proj = t1.transform_points(points) proj_eps = t1.transform_points(points, eps=1e-4) self.assertTrue(not bool(torch.isfinite(proj.sum()))) self.assertTrue(bool(torch.isfinite(proj_eps.sum())))
def test_stack(self): rotations = random_rotations(3) transform3 = Transform3d().rotate(rotations).translate( torch.full((3, 3), 0.3)) transform1 = Scale(37) transform4 = transform1.stack(transform3) self.assertEqual(len(transform1), 1) self.assertEqual(len(transform3), 3) self.assertEqual(len(transform4), 4) self.assertClose( transform4.get_matrix(), torch.cat([transform1.get_matrix(), transform3.get_matrix()]), ) points = torch.rand(4, 5, 3) new_points_expect = torch.cat([ transform1.transform_points(points[:1]), transform3.transform_points(points[1:]), ]) new_points = transform4.transform_points(points) self.assertClose(new_points, new_points_expect)
def test_dtype_propagation(self): """ Check that a given dtype is correctly passed along to child transformations. """ # Use at least two dtypes so we avoid only testing on the # default dtype. for dtype in [torch.float32, torch.float64]: R = torch.tensor( [[0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0]], dtype=dtype, ) tf = (Transform3d(dtype=dtype).rotate(R).rotate_axis_angle( R[0], "X", ).translate(3, 2, 1).scale(0.5)) self.assertEqual(tf.dtype, dtype) for inner_tf in tf._transforms: self.assertEqual(inner_tf.dtype, dtype) transformed = tf.transform_points(R) self.assertEqual(transformed.dtype, dtype)
[-0.7, -0.70, 1.0], [0.0, -0.1, 1.0], [0.7, -0.7, 1.0], [-0.7, 0.1, 1.0], [0.0, 0.7, 1.0], [0.7, 0.1, 1.0], ], dtype=torch.float32, ) faces0 = torch.tensor([[1, 0, 2], [4, 3, 5]], dtype=torch.int64) # Points for a simple point cloud. Get the vertices from a # torus and apply rotations such that the points are no longer # symmerical in X/Y. torus_mesh = torus(r=0.25, R=1.0, sides=5, rings=2 * 5) t = (Transform3d().rotate_axis_angle(angle=90, axis="Y").rotate_axis_angle( angle=45, axis="Z").scale(0.3)) torus_points = t.transform_points(torus_mesh.verts_padded()).squeeze() def _save_debug_image(idx, image_size, bin_size, blur): """ Save a mask image from the rasterization output for debugging. """ H, W = image_size # Save out the last image for debugging rgb = (idx[-1, ..., :3].cpu() > -1).squeeze() suffix = "square" if H == W else "non_square" filename = "%s_bin_size_%s_blur_%.3f_%dx%d.png" filename = filename % (suffix, str(bin_size), blur, H, W) if DEBUG: filename = "DEBUG_%s" % filename
def test_get_item(self, batch_size=5): device = torch.device("cuda:0") matrices = torch.randn(size=[batch_size, 4, 4], device=device, dtype=torch.float32) # init the Transforms3D class t3d = Transform3d(matrix=matrices) # int index index = 1 t3d_selected = t3d[index] self.assertEqual(len(t3d_selected), 1) self._check_indexed_transforms(t3d, t3d_selected, [(0, 1)]) # negative int index index = -1 t3d_selected = t3d[index] self.assertEqual(len(t3d_selected), 1) self._check_indexed_transforms(t3d, t3d_selected, [(0, -1)]) # list index index = [1, 2] t3d_selected = t3d[index] self.assertEqual(len(t3d_selected), len(index)) self._check_indexed_transforms(t3d, t3d_selected, enumerate(index)) # empty list index index = [] t3d_selected = t3d[index] self.assertEqual(len(t3d_selected), 0) self.assertEqual(t3d_selected.get_matrix().nelement(), 0) # slice index index = slice(0, 2, 1) t3d_selected = t3d[index] self.assertEqual(len(t3d_selected), 2) self._check_indexed_transforms(t3d, t3d_selected, [(0, 0), (1, 1)]) # empty slice index index = slice(0, 0, 1) t3d_selected = t3d[index] self.assertEqual(len(t3d_selected), 0) self.assertEqual(t3d_selected.get_matrix().nelement(), 0) # bool tensor index = (torch.rand(batch_size) > 0.5).to(device) index[:2] = True # make sure smth is selected t3d_selected = t3d[index] self.assertEqual(len(t3d_selected), index.sum()) self._check_indexed_transforms( t3d, t3d_selected, zip( torch.arange(index.sum()), torch.nonzero(index, as_tuple=False).squeeze(), ), ) # all false bool tensor index = torch.zeros(batch_size).bool() t3d_selected = t3d[index] self.assertEqual(len(t3d_selected), 0) self.assertEqual(t3d_selected.get_matrix().nelement(), 0) # int tensor index = torch.tensor([1, 2], dtype=torch.int64, device=device) t3d_selected = t3d[index] self.assertEqual(len(t3d_selected), index.numel()) self._check_indexed_transforms(t3d, t3d_selected, enumerate(index.tolist())) # negative int tensor index = -(torch.tensor([1, 2], dtype=torch.int64, device=device)) t3d_selected = t3d[index] self.assertEqual(len(t3d_selected), index.numel()) self._check_indexed_transforms(t3d, t3d_selected, enumerate(index.tolist())) # invalid index for invalid_index in ( torch.tensor([1, 0, 1], dtype=torch.float32, device=device), # float tensor 1.2, # float index torch.tensor([[1, 0, 1], [1, 0, 1]], dtype=torch.int32, device=device), # multidimensional tensor ): with self.assertRaises(IndexError): t3d_selected = t3d[invalid_index]
def test_to(self): tr = Translate(torch.FloatTensor([[1.0, 2.0, 3.0]])) R = torch.FloatTensor([[0.0, 1.0, 0.0], [0.0, 0.0, 1.0], [1.0, 0.0, 0.0]]) R = Rotate(R) t = Transform3d().compose(R, tr) cpu_device = torch.device("cpu") cpu_t = t.to("cpu") self.assertEqual(cpu_device, cpu_t.device) self.assertEqual(cpu_device, t.device) self.assertEqual(torch.float32, cpu_t.dtype) self.assertEqual(torch.float32, t.dtype) self.assertIs(t, cpu_t) cpu_t = t.to(cpu_device) self.assertEqual(cpu_device, cpu_t.device) self.assertEqual(cpu_device, t.device) self.assertEqual(torch.float32, cpu_t.dtype) self.assertEqual(torch.float32, t.dtype) self.assertIs(t, cpu_t) cpu_t = t.to(dtype=torch.float64, device=cpu_device) self.assertEqual(cpu_device, cpu_t.device) self.assertEqual(cpu_device, t.device) self.assertEqual(torch.float64, cpu_t.dtype) self.assertEqual(torch.float32, t.dtype) self.assertIsNot(t, cpu_t) cuda_device = torch.device("cuda:0") cuda_t = t.to("cuda:0") self.assertEqual(cuda_device, cuda_t.device) self.assertEqual(cpu_device, t.device) self.assertEqual(torch.float32, cuda_t.dtype) self.assertEqual(torch.float32, t.dtype) self.assertIsNot(t, cuda_t) cuda_t = t.to(cuda_device) self.assertEqual(cuda_device, cuda_t.device) self.assertEqual(cpu_device, t.device) self.assertEqual(torch.float32, cuda_t.dtype) self.assertEqual(torch.float32, t.dtype) self.assertIsNot(t, cuda_t) cuda_t = t.to(dtype=torch.float64, device=cuda_device) self.assertEqual(cuda_device, cuda_t.device) self.assertEqual(cpu_device, t.device) self.assertEqual(torch.float64, cuda_t.dtype) self.assertEqual(torch.float32, t.dtype) self.assertIsNot(t, cuda_t) cpu_points = torch.rand(9, 3) cuda_points = cpu_points.cuda() for _ in range(3): t = t.cpu() t.transform_points(cpu_points) t = t.cuda() t.transform_points(cuda_points) t = t.cuda() t = t.cpu()