Ejemplo n.º 1
0
    def testInternalRenderGradientComputation(self):
        """Isolates and verifies the Jacobian matrix for the custom kernel."""
        image_height = 21
        image_width = 28

        clip_coordinates = tf.placeholder(tf.float32, shape=[8, 4])

        barycentric_coordinates, _, _ = (
            rasterize_triangles.rasterize_triangles_module.rasterize_triangles(
                clip_coordinates, self.cube_triangles, image_width,
                image_height))

        with self.test_session():
            # Precomputed transformation of the simple cube to normalized device
            # coordinates, in order to isolate the rasterization gradient.
            # pyformat: disable
            ndc_init = np.array([[-0.43889722, -0.53184521, 0.85293502, 1.0],
                                 [-0.37635487, 0.22206162, 0.90555805, 1.0],
                                 [-0.22849123, 0.76811147, 0.80993629, 1.0],
                                 [-0.2805393, -0.14092168, 0.71602166, 1.0],
                                 [0.18631913, -0.62634289, 0.88603103, 1.0],
                                 [0.16183566, 0.08129397, 0.93020856, 1.0],
                                 [0.44147962, 0.53497446, 0.85076219, 1.0],
                                 [0.53008741, -0.31276882, 0.77620775, 1.0]],
                                dtype=np.float32)
            # pyformat: enable
            theoretical, numerical = tf.test.compute_gradient(
                clip_coordinates, (8, 4),
                barycentric_coordinates, (image_height, image_width, 3),
                x_init_value=ndc_init,
                delta=4e-2)
            jacobians_match, message = (
                test_utils.check_jacobians_are_nearly_equal(
                    theoretical, numerical, 0.01, 0.01))
            self.assertTrue(jacobians_match, message)
  def testSimpleTriangleGradientComputation(self):
    """Verifies the Jacobian matrix for a single pixel.

    The pixel is in the center of a triangle facing the camera. This makes it
    easy to check which entries of the Jacobian might not make sense without
    worrying about corner cases.
    """
    test_pixel_x = 325
    test_pixel_y = 245

    clip_coordinates = tf.placeholder(tf.float32, shape=[3, 4])

    triangles = tf.constant([[0, 1, 2]], dtype=tf.int32)

    barycentric_coordinates, _ = (
        rasterize_triangles.rasterize_triangles_module.rasterize_triangles(
            clip_coordinates, triangles, self.image_width, self.image_height))

    pixels_to_compare = barycentric_coordinates[
        test_pixel_y:test_pixel_y + 1, test_pixel_x:test_pixel_x + 1, :]

    with self.test_session():
      ndc_init = np.array(
          [[-0.5, -0.5, 0.8, 1.0], [0.0, 0.5, 0.3, 1.0], [0.5, -0.5, 0.3, 1.0]],
          dtype=np.float32)
      theoretical, numerical = tf.test.compute_gradient(
          clip_coordinates, (3, 4),
          pixels_to_compare, (1, 1, 3),
          x_init_value=ndc_init,
          delta=4e-2)
      jacobians_match, message = (
          test_utils.check_jacobians_are_nearly_equal(
              theoretical, numerical, 0.01, 0.0, True))
      self.assertTrue(jacobians_match, message)
Ejemplo n.º 3
0
    def testFullRenderGradientComputation(self):
        """Verifies the Jacobian matrix for the entire renderer.

    This ensures correct gradients are propagated backwards through the entire
    process, not just through the rasterization kernel. Uses the simple cube
    forward pass.
    """
        image_height = 21
        image_width = 28

        # rotate the cube for the test:
        model_transforms = camera_utils.euler_matrices([[-20.0, 0.0, 60.0],
                                                        [45.0, 60.0,
                                                         0.0]])[:, :3, :3]

        vertices_world_space = tf.matmul(tf.stack(
            [self.cube_vertices, self.cube_vertices]),
                                         model_transforms,
                                         transpose_b=True)

        normals_world_space = tf.matmul(tf.stack(
            [self.cube_normals, self.cube_normals]),
                                        model_transforms,
                                        transpose_b=True)

        # camera position:
        eye = tf.constant([0.0, 0.0, 6.0], dtype=tf.float32)
        center = tf.constant([0.0, 0.0, 0.0], dtype=tf.float32)
        world_up = tf.constant([0.0, 1.0, 0.0], dtype=tf.float32)

        # Scene has a single light from the viewer's eye.
        light_positions = tf.expand_dims(tf.stack([eye, eye], axis=0), axis=1)
        light_intensities = tf.ones([2, 1, 3], dtype=tf.float32)

        vertex_diffuse_colors = tf.ones_like(vertices_world_space,
                                             dtype=tf.float32)

        rendered = mesh_renderer.mesh_renderer(
            vertices_world_space, self.cube_triangles, normals_world_space,
            vertex_diffuse_colors, eye, center, world_up, light_positions,
            light_intensities, image_width, image_height)

        with self.test_session():
            theoretical, numerical = tf.test.compute_gradient(
                self.cube_vertices, (8, 3),
                rendered, (2, image_height, image_width, 4),
                x_init_value=self.cube_vertices.eval(),
                delta=1e-3)
            jacobians_match, message = (
                test_utils.check_jacobians_are_nearly_equal(
                    theoretical, numerical, 0.01, 0.01))
            self.assertTrue(jacobians_match, message)
    def testInternalRenderGradientComputation(self):
        """Isolates and verifies the Jacobian matrix for the custom kernel."""
        image_height = 21
        image_width = 28

        def get_barycentric_coordinates(clip_coordinates):
            _, barycentric_coords, _ = (BarycentricRasterizer.apply(
                clip_coordinates, self.cube_triangles, image_width,
                image_height))
            return barycentric_coords

        # Precomputed transformation of the simple cube to normalized device
        # coordinates, in order to isolate the rasterization gradient.
        test_clip_coordinates = torch.tensor(
            [[-0.43889722, -0.53184521, 0.85293502, 1.0],
             [-0.37635487, 0.22206162, 0.90555805, 1.0],
             [-0.22849123, 0.76811147, 0.80993629, 1.0],
             [-0.2805393, -0.14092168, 0.71602166, 1.0],
             [0.18631913, -0.62634289, 0.88603103, 1.0],
             [0.16183566, 0.08129397, 0.93020856, 1.0],
             [0.44147962, 0.53497446, 0.85076219, 1.0],
             [0.53008741, -0.31276882, 0.77620775, 1.0]],
            dtype=torch.float32,
            requires_grad=True)
        raster_out = get_barycentric_coordinates(test_clip_coordinates)
        analytical = test_utils.get_analytical_jacobian(
            test_clip_coordinates, raster_out)
        numerical = test_utils.get_numerical_jacobian(
            get_barycentric_coordinates, test_clip_coordinates, eps=4e-2)

        jacobians_match = (test_utils.check_jacobians_are_nearly_equal(
            analytical, numerical, 0.01, 0.01))
        self.assertTrue(
            jacobians_match,
            "Analytical and numerical jacobians have too many relative or "
            "absolute outliers")