Esempio n. 1
0
  def test_inverse_random(self):
    """Checks that inverting rotated points results in no transformation."""
    random_euler_angle = test_helpers.generate_random_test_euler_angles()
    tensor_tile = random_euler_angle.shape[:-1]
    random_matrix = rotation_matrix_3d.from_euler(random_euler_angle)
    random_point = np.random.normal(size=tensor_tile + (3,))

    rotated_random_points = rotation_matrix_3d.rotate(random_point,
                                                      random_matrix)
    predicted_invert_random_matrix = rotation_matrix_3d.inverse(random_matrix)
    predicted_invert_rotated_random_points = rotation_matrix_3d.rotate(
        rotated_random_points, predicted_invert_random_matrix)

    self.assertAllClose(
        random_point, predicted_invert_rotated_random_points, rtol=1e-6)
    def test_rotate_vs_rotate_quaternion_random(self):
        """Tests that the rotate provide the same results as quaternion.rotate."""
        random_euler_angle = test_helpers.generate_random_test_euler_angles()
        tensor_tile = random_euler_angle.shape[:-1]

        random_matrix = rotation_matrix_3d.from_euler(random_euler_angle)
        random_quaternion = quaternion.from_rotation_matrix(random_matrix)
        random_point = np.random.normal(size=tensor_tile + (3, ))
        ground_truth = quaternion.rotate(random_point, random_quaternion)
        prediction = rotation_matrix_3d.rotate(random_point, random_matrix)

        self.assertAllClose(ground_truth, prediction, rtol=1e-6)
Esempio n. 3
0
  def test_from_euler_random(self):
    """Tests that quaternions can be constructed from Euler angles."""
    random_euler_angles = test_helpers.generate_random_test_euler_angles()
    tensor_shape = random_euler_angles.shape[:-1]

    random_matrix = rotation_matrix_3d.from_euler(random_euler_angles)
    random_quaternion = quaternion.from_euler(random_euler_angles)
    random_point = np.random.normal(size=tensor_shape + (3,))
    rotated_with_matrix = rotation_matrix_3d.rotate(random_point, random_matrix)
    rotated_with_quaternion = quaternion.rotate(random_point, random_quaternion)

    self.assertAllClose(rotated_with_matrix, rotated_with_quaternion)
Esempio n. 4
0
    def test_rotate_jacobian_random(self):
        """Test the Jacobian of the rotate function."""
        x_matrix_init = test_helpers.generate_random_test_rotation_matrix_3d()
        x_matrix = tf.convert_to_tensor(value=x_matrix_init)
        tensor_shape = x_matrix.shape[:-1]
        x_point_init = np.random.uniform(size=tensor_shape)
        x_point = tf.convert_to_tensor(value=x_point_init)

        y = rotation_matrix_3d.rotate(x_point, x_matrix)

        self.assert_jacobian_is_correct(x_matrix, x_matrix_init, y)
        self.assert_jacobian_is_correct(x_point, x_point_init, y)
Esempio n. 5
0
  def test_from_euler_random(self):
    """Tests that from_euler allows to perform the expect rotation of points."""
    random_euler_angles = test_helpers.generate_random_test_euler_angles()
    tensor_shape = random_euler_angles.shape[:-1]
    random_point = np.random.normal(size=tensor_shape + (3,))

    random_matrix = rotation_matrix_3d.from_euler(random_euler_angles)
    random_axis, random_angle = axis_angle.from_euler(random_euler_angles)
    rotated_with_matrix = rotation_matrix_3d.rotate(random_point, random_matrix)
    rotated_with_axis_angle = axis_angle.rotate(random_point, random_axis,
                                                random_angle)

    self.assertAllClose(rotated_with_matrix, rotated_with_axis_angle)
Esempio n. 6
0
  def test_rotate_random(self):
    """Tests the rotation using a quaternion vs a rotation matrix."""
    random_quaternion = test_helpers.generate_random_test_quaternions()
    tensor_shape = random_quaternion.shape[:-1]
    random_point = np.random.normal(size=tensor_shape + (3,))

    rotated_point_quaternion = quaternion.rotate(random_point,
                                                 random_quaternion)
    matrix = rotation_matrix_3d.from_quaternion(random_quaternion)
    rotated_point_matrix = rotation_matrix_3d.rotate(random_point, matrix)

    self.assertAllClose(
        rotated_point_matrix, rotated_point_quaternion, rtol=1e-3)
Esempio n. 7
0
def generate_ground_image(height,
                          width,
                          focal,
                          principal_point,
                          camera_rotation_matrix,
                          camera_translation_vector,
                          ground_color=(0.43, 0.43, 0.8)):
  """Generate an image depicting only the ground."""
  batch_size = camera_rotation_matrix.shape[0]
  background_image = np.ones((batch_size, height, width, 1, 1),
                             dtype=np.float32)
  background_image[:, -1, ...] = 0  # Zero the bottom line for proper sampling

  # The projection of the ground depends on the top right corner (approximation)
  plane_point_np = np.tile(np.array([[3.077984, 2.905388, 0.]],
                                    dtype=np.float32), (batch_size, 1))
  plane_point_rotated = rotation_matrix_3d.rotate(plane_point_np,
                                                  camera_rotation_matrix)
  plane_point_translated = plane_point_rotated + camera_translation_vector
  plane_point2d = \
    perspective.project(plane_point_translated, focal, principal_point)
  _, y = tf.split(plane_point2d, [1, 1], axis=-1)
  sfactor = height/y
  helper_matrix1 = np.tile(np.array([[[1, 0, 0],
                                      [0, 0, 0],
                                      [0, 0, 0]]]), (batch_size, 1, 1))
  helper_matrix2 = np.tile(np.array([[[0, 0, 0],
                                      [0, 1, 0],
                                      [0, 0, 1]]]), (batch_size, 1, 1))
  transformation_matrix = tf.multiply(tf.expand_dims(sfactor, -1),
                                      helper_matrix1) + helper_matrix2
  plane_points = grid.generate((0., 0., 0.),
                               (float(height), float(width), 0.),
                               (height, width, 1))
  plane_points = tf.reshape(plane_points, [-1, 3])
  transf_plane_points = tf.matmul(transformation_matrix,
                                  plane_points,
                                  transpose_b=True)
  interpolated_points = \
    trilinear.interpolate(background_image,
                          tf.linalg.matrix_transpose(transf_plane_points))
  ground_alpha = (1- tf.reshape(interpolated_points,
                                [batch_size, height, width, 1]))
  ground_image = tf.ones((batch_size, height, width, 3))*ground_color
  return ground_image, ground_alpha
Esempio n. 8
0
def generate_ground_image(height,
                          width,
                          focal,
                          principal_point,
                          camera_rotation_matrix,
                          camera_translation_vector,
                          ground_color=(0.43, 0.43, 0.8)):
    """Generate an image depicting only the ground."""
    background_image = np.ones((height, width, 1, 1), dtype=np.float32)
    background_image[-1,
                     ...] = 0  # Set the bottom line to 0 for proper sampling

    # The projection of the ground depends on the top right corner (approximation)
    plane_point_np = np.array([[3.077984, 2.905388, 0.]], dtype=np.float32)
    plane_point2d = \
      perspective.project(rotation_matrix_3d.rotate(plane_point_np,
                                                    camera_rotation_matrix) +
                          camera_translation_vector.T, focal, principal_point)
    _, y = tf.split(plane_point2d, [1, 1], axis=-1)
    sfactor = y / 256.
    transformation_matrix = (1/sfactor)*np.array([[1, 0, 0],
                                                  [0, 0, 0],
                                                  [0, 0, 0]]) + \
                            np.array([[0, 0, 0],
                                      [0, 1, 0],
                                      [0, 0, 1]])
    plane_points = grid.generate(
        (0., 0., 0.), (float(height), float(width), 0.), (height, width, 1))
    plane_points = tf.reshape(plane_points, [-1, 3])
    transf_plane_points = tf.matmul(transformation_matrix,
                                    plane_points,
                                    transpose_b=True)
    interpolated_points = \
      trilinear.interpolate(background_image, tf.transpose(transf_plane_points))
    ground_alpha = (1 - tf.reshape(interpolated_points, [256, 256, 1]))
    ground_image = tf.ones((256, 256, 3)) * ground_color
    return ground_image, ground_alpha
Esempio n. 9
0
    def __getitem__(self, idx: int):
        # Fetch data for this batch
        batch_slice = slice(idx * self.batch_size,
                            min((idx + 1) * self.batch_size, self.len))
        src = self.data[batch_slice]
        batch_len = len(src)

        # Compute true transformation
        euler_angles = np.random.uniform(low=-np.pi,
                                         high=np.pi,
                                         size=(batch_len, 1,
                                               3)).astype(np.float32)
        R_true = rotation_matrix_3d.from_euler(euler_angles)
        t_true = np.random.uniform(low=-0.5, high=0.5,
                                   size=(batch_len, 1, 3)).astype(np.float32)

        # Output batch
        tgt = rotation_matrix_3d.rotate(src, R_true) + t_true
        src = tf.expand_dims(src, axis=1)
        tgt = tf.expand_dims(tgt, axis=1)
        x = tf.concat([src, tgt], 1)
        y_true = tf.concat([tf.squeeze(R_true), t_true], 1)

        return x, y_true
def blend(points,
          skinning_weights,
          bone_rotations,
          bone_translations,
          name=None):
  """Transforms the points using Linear Blend Skinning.

  Note:
    In the following, A1 to An are optional batch dimensions, which must be
    broadcast compatible and allow transforming full 3D shapes at once.
    In the following, B1 to Bm are optional batch dimensions, which allow
    transforming multiple poses at once.

  Args:
    points: A tensor of shape `[A1, ..., An, 3]`, where the last dimension
      represents a 3d point.
    skinning_weights: A tensor of shape `[A1, ..., An, W]`, where the last
      dimension represents the skinning weights of each bone.
    bone_rotations: A tensor of shape `[B1, ..., Bm, W, 3, 3]`, which represents
      the 3d rotations applied to each bone.
    bone_translations: A tensor of shape `[B1, ..., Bm, W, 3]`, which represents
      the 3d translation vectors applied to each bone.
    name: A name for this op that defaults to "linear_blend_skinning_blend".

  Returns:
    A tensor of shape `[B1, ..., Bm, A1, ..., An, 3]`, where the last dimension
    represents a 3d point.

  Raises:
    ValueError: If the shape of the input tensors are not supported.
  """
  with tf.compat.v1.name_scope(
      name, "linear_blend_skinning_blend",
      [points, skinning_weights, bone_rotations, bone_translations]):
    points = tf.convert_to_tensor(value=points)
    skinning_weights = tf.convert_to_tensor(value=skinning_weights)
    bone_rotations = tf.convert_to_tensor(value=bone_rotations)
    bone_translations = tf.convert_to_tensor(value=bone_translations)

    shape.check_static(
        tensor=points, tensor_name="points", has_dim_equals=(-1, 3))
    shape.check_static(
        tensor=bone_rotations,
        tensor_name="bone_rotations",
        has_rank_greater_than=2,
        has_dim_equals=((-2, 3), (-1, 3)))
    shape.check_static(
        tensor=bone_translations,
        tensor_name="bone_translations",
        has_rank_greater_than=1,
        has_dim_equals=(-1, 3))
    shape.compare_dimensions(
        tensors=(skinning_weights, bone_rotations),
        tensor_names=("skinning_weights", "bone_rotations"),
        axes=(-1, -3))
    shape.compare_dimensions(
        tensors=(skinning_weights, bone_translations),
        tensor_names=("skinning_weights", "bone_translations"),
        axes=(-1, -2))
    shape.compare_batch_dimensions(
        tensors=(points, skinning_weights),
        tensor_names=("points", "skinning_weights"),
        last_axes=(-2, -2),
        broadcast_compatible=True)
    shape.compare_batch_dimensions(
        tensors=(bone_rotations, bone_translations),
        tensor_names=("bone_rotations", "bone_translations"),
        last_axes=(-3, -2),
        broadcast_compatible=True)

    num_bones = skinning_weights.shape[-1]

    def dim_value(dim):
      return 1 if dim is None else tf.compat.v1.dimension_value(dim)

    # TODO(b/148362025): factorize this block out
    points_batch_shape = shape.get_broadcasted_shape(
        points.shape[:-1], skinning_weights.shape[:-1])
    points_batch_shape = [dim_value(dim) for dim in points_batch_shape]

    points = tf.broadcast_to(points, points_batch_shape + [3])
    skinning_weights = tf.broadcast_to(skinning_weights,
                                       points_batch_shape + [num_bones])

    bones_batch_shape = shape.get_broadcasted_shape(
        bone_rotations.shape[:-3], bone_translations.shape[:-2])
    bones_batch_shape = [dim_value(dim) for dim in bones_batch_shape]

    bone_rotations = tf.broadcast_to(bone_rotations,
                                     bones_batch_shape + [num_bones, 3, 3])
    bone_translations = tf.broadcast_to(bone_translations,
                                        bones_batch_shape + [num_bones, 3])

    points_batch_dims = points.shape.ndims - 1
    bones_batch_dims = bone_rotations.shape.ndims - 3

    points = tf.reshape(points,
                        [1] * bones_batch_dims + points_batch_shape + [1, 3])
    skinning_weights = tf.reshape(skinning_weights, [1] * bones_batch_dims +
                                  points_batch_shape + [num_bones, 1])
    bone_rotations = tf.reshape(
        bone_rotations,
        bones_batch_shape + [1] * points_batch_dims + [num_bones, 3, 3])
    bone_translations = tf.reshape(
        bone_translations,
        bones_batch_shape + [1] * points_batch_dims + [num_bones, 3])

    transformed_points = rotation_matrix_3d.rotate(
        points, bone_rotations) + bone_translations
    weighted_points = tf.multiply(skinning_weights, transformed_points)
    blended_points = tf.reduce_sum(input_tensor=weighted_points, axis=-2)

    return blended_points
 def func(angles, point):
     matrix = rotation_matrix_3d.from_euler(angles)
     return rotation_matrix_3d.rotate(point, matrix)
 def func(axis, angle, point):
     matrix = rotation_matrix_3d.from_axis_angle(axis, angle)
     return rotation_matrix_3d.rotate(point, matrix)
Esempio n. 13
0
def rotate(points):
    """Randomly rotates a point cloud around the Y axis (UP)."""
    axis = tf.constant([[0, 1, 0]], dtype=tf.float32)  # [1, 3]
    angle = tf.random.uniform((1, 1), minval=0., maxval=2 * np.pi)  # [1, 1]
    matrix = rotation_matrix_3d.from_axis_angle(axis, angle)  # [3, 3]
    return rotation_matrix_3d.rotate(points, matrix)  # [N, 3]