def test_unscaled(self): D = 5 P = 1000 B, C, H, W = 2, 3, D, D densities = torch.zeros(B, 1, D, H, W) features = torch.zeros(B, C, D, H, W) volumes = Volumes(densities=densities, features=features) points = torch.rand(B, 1000, 3) * (D - 1) - ((D - 1) * 0.5) point_features = torch.rand(B, 1000, C) pointclouds = Pointclouds(points=points, features=point_features) volumes2 = add_pointclouds_to_volumes(pointclouds, volumes, rescale_features=False) self.assertConstant(volumes2.densities().sum([2, 3, 4]) / P, 1, atol=1e-5) self.assertConstant(volumes2.features().sum([2, 3, 4]) / P, 0.5, atol=0.03)
def test_from_point_cloud(self, interp_mode="trilinear"): """ Generates a volume from a random point cloud sampled from faces of a 3D cube. Since each side of the cube is homogenously colored with a different color, this should result in a volume with a predefined homogenous color of the cells along its borders and black interior. The test is run for both cube and non-cube shaped volumes. """ # batch_size = 4 sides of the cube batch_size = 4 for volume_size in ([25, 25, 25], [30, 25, 15]): for interp_mode in ("trilinear", "nearest"): (pointclouds, initial_volumes) = init_volume_boundary_pointcloud( volume_size=volume_size, n_points=int(1e5), interp_mode=interp_mode, batch_size=batch_size, require_grad=True, ) volumes = add_pointclouds_to_volumes( pointclouds, initial_volumes, mode=interp_mode ) V_color, V_density = volumes.features(), volumes.densities() # expected colors of different cube sides clr_sides = torch.tensor( [ [[1.0, 1.0, 1.0], [1.0, 0.0, 1.0]], [[1.0, 0.0, 0.0], [1.0, 1.0, 0.0]], [[1.0, 0.0, 1.0], [1.0, 1.0, 1.0]], [[1.0, 1.0, 0.0], [1.0, 0.0, 0.0]], ], dtype=V_color.dtype, device=V_color.device, ) clr_ambient = torch.tensor( [0.0, 0.0, 0.0], dtype=V_color.dtype, device=V_color.device ) clr_top_bot = torch.tensor( [[0.0, 1.0, 0.0], [0.0, 1.0, 1.0]], dtype=V_color.dtype, device=V_color.device, ) if DEBUG: outdir = tempfile.gettempdir() + "/test_points_to_volumes" os.makedirs(outdir, exist_ok=True) for slice_dim in (1, 2): for vidx in range(V_color.shape[0]): vim = V_color.detach()[vidx].split(1, dim=slice_dim) vim = torch.stack([v.squeeze() for v in vim]) vim = TestPointsToVolumes.stack_4d_tensor_to_3d(vim.cpu()) im = Image.fromarray( (vim.numpy() * 255.0) .astype(np.uint8) .transpose(1, 2, 0) ) outfile = ( outdir + f"/rgb_{interp_mode}" + f"_{str(volume_size).replace(' ','')}" + f"_{vidx:003d}_sldim{slice_dim}.png" ) im.save(outfile) print("exported %s" % outfile) # check the density V_density # first binarize the density V_density_bin = (V_density > 1e-4).type_as(V_density) d_one = V_density.new_ones(1) d_zero = V_density.new_zeros(1) for vidx in range(V_color.shape[0]): # the first/last depth-wise slice has to be filled with 1.0 self._check_volume_slice_color_density( V_density_bin[vidx], 1, interp_mode, d_one, "first" ) self._check_volume_slice_color_density( V_density_bin[vidx], 1, interp_mode, d_one, "last" ) # the middle depth-wise slices have to be empty self._check_volume_slice_color_density( V_density_bin[vidx], 1, interp_mode, d_zero, "middle" ) # the top/bottom slices have to be filled with 1.0 self._check_volume_slice_color_density( V_density_bin[vidx], 2, interp_mode, d_one, "first" ) self._check_volume_slice_color_density( V_density_bin[vidx], 2, interp_mode, d_one, "last" ) # check the colors for vidx in range(V_color.shape[0]): self._check_volume_slice_color_density( V_color[vidx], 1, interp_mode, clr_sides[vidx][0], "first" ) self._check_volume_slice_color_density( V_color[vidx], 1, interp_mode, clr_sides[vidx][1], "last" ) self._check_volume_slice_color_density( V_color[vidx], 1, interp_mode, clr_ambient, "middle" ) self._check_volume_slice_color_density( V_color[vidx], 2, interp_mode, clr_top_bot[0], "first" ) self._check_volume_slice_color_density( V_color[vidx], 2, interp_mode, clr_top_bot[1], "last" ) # check differentiability loss = V_color.mean() + V_density.mean() loss.backward() rgb = pointclouds.features_padded() xyz = pointclouds.points_padded() for field in (xyz, rgb): if interp_mode == "nearest" and (field is xyz): # this does not produce grads w.r.t. xyz self.assertIsNone(field.grad) else: self.assertTrue(field.grad.data.isfinite().all())
def _add_points_to_volumes(): add_pointclouds_to_volumes(pointclouds, initial_volumes, mode=interp_mode)
def _add_points_to_volumes(): add_pointclouds_to_volumes(pointclouds, initial_volumes, mode=interp_mode) torch.cuda.synchronize()