Exemple #1
0
def from_euler(angles, name=None):
  r"""Converts Euler angles to an axis-angle representation.

  Note:
    The conversion is performed by first converting to a quaternion
    representation, and then by converting the quaternion to an axis-angle.

  Note:
    In the following, A1 to An are optional batch dimensions.

  Args:
    angles: A tensor of shape `[A1, ..., An, 3]`, where the last dimension
      represents the three Euler angles. `[A1, ..., An, 0]` is the angle about
      `x` in radians `[A1, ..., An, 1]` is the angle about `y` in radians and
      `[A1, ..., An, 2]` is the angle about `z` in radians.
    name: A name for this op that defaults to "axis_angle_from_euler".

  Returns:
    A tuple of two tensors, respectively of shape `[A1, ..., An, 3]` and
    `[A1, ..., An, 1]`, where the first tensor represents the axis, and the
    second represents the angle. The resulting axis is a normalized vector.
  """
  with tf.compat.v1.name_scope(name, "axis_angle_from_euler", [angles]):
    quaternion = quaternion_lib.from_euler(angles)
    return from_quaternion(quaternion)
Exemple #2
0
    def test_energy_preset(self):
        """Checks that energy returns the expected value."""
        vertices_rest_pose = np.array(((1.0, 0.0, 0.0), (-1.0, 0.0, 0.0)))
        vertices_deformed_pose = 2.0 * vertices_rest_pose
        quaternions = quaternion.from_euler(
            np.zeros(shape=vertices_deformed_pose.shape))
        edges = ((0, 1), )

        all_weights_1_energy = as_conformal_as_possible.energy(
            vertices_rest_pose, vertices_deformed_pose, quaternions, edges)
        all_weights_1_gt = 4.0
        vertex_weights = np.array((2.0, 1.0))
        vertex_weights_energy = as_conformal_as_possible.energy(
            vertices_rest_pose=vertices_rest_pose,
            vertices_deformed_pose=vertices_deformed_pose,
            quaternions=quaternions,
            edges=edges,
            vertex_weight=vertex_weights)
        vertex_weights_gt = 10.0
        edge_weights = np.array((2.0, ))
        edge_weights_energy = as_conformal_as_possible.energy(
            vertices_rest_pose=vertices_rest_pose,
            vertices_deformed_pose=vertices_deformed_pose,
            quaternions=quaternions,
            edges=edges,
            edge_weight=edge_weights)
        edge_weights_gt = 16.0

        with self.subTest(name="all_weights_1"):
            self.assertAllClose(all_weights_1_energy, all_weights_1_gt)
        with self.subTest(name="vertex_weights"):
            self.assertAllClose(vertex_weights_energy, vertex_weights_gt)
        with self.subTest(name="edge_weights"):
            self.assertAllClose(edge_weights_energy, edge_weights_gt)
Exemple #3
0
    def test_energy_identity(self):
        """Checks that energy evaluated between the rest pose and itself is zero."""
        number_vertices = np.random.randint(3, 10)
        batch_size = np.random.randint(3)
        batch_shape = np.random.randint(1, 10, size=(batch_size)).tolist()
        vertices_rest_pose = np.random.uniform(size=(number_vertices, 3))
        vertices_deformed_pose = tf.broadcast_to(vertices_rest_pose,
                                                 shape=batch_shape +
                                                 [number_vertices, 3])
        quaternions = quaternion.from_euler(
            np.zeros(shape=batch_shape + [number_vertices, 3]))
        num_edges = int(round(number_vertices / 2))
        edges = np.zeros(shape=(num_edges, 2), dtype=np.int32)
        edges[..., 0] = np.linspace(0,
                                    number_vertices / 2 - 1,
                                    num_edges,
                                    dtype=np.int32)
        edges[..., 1] = np.linspace(number_vertices / 2,
                                    number_vertices - 1,
                                    num_edges,
                                    dtype=np.int32)

        energy = as_conformal_as_possible.energy(
            vertices_rest_pose=vertices_rest_pose,
            vertices_deformed_pose=vertices_deformed_pose,
            quaternions=quaternions,
            edges=edges,
            conformal_energy=False)

        self.assertAllClose(energy, tf.zeros_like(energy))
Exemple #4
0
def generate_preset_test_quaternions():
    """Generates pre-set test quaternions."""
    angles = generate_preset_test_euler_angles()
    preset_quaternion = quaternion.from_euler(angles)
    if tf.executing_eagerly():
        return np.array(preset_quaternion)
    with tf.compat.v1.Session() as sess:
        return np.array(sess.run([preset_quaternion]))
  def test_from_euler_jacobian_random(self):
    """Test the Jacobian of the from_euler function."""
    x_init = test_helpers.generate_random_test_euler_angles()
    x = tf.convert_to_tensor(value=x_init)

    y = quaternion.from_euler(x)

    self.assert_jacobian_is_correct(x, x_init, y)
Exemple #6
0
  def test_from_quaternion_normalized_preset(self):
    """Tests that from_quaternion returns normalized axis-angles."""
    euler_angles = test_helpers.generate_preset_test_euler_angles()

    quat = quaternion.from_euler(euler_angles)
    axis, angle = axis_angle.from_quaternion(quat)

    self.assertAllEqual(
        axis_angle.is_normalized(axis, angle), np.ones(angle.shape, dtype=bool))
Exemple #7
0
  def test_from_quaternion_preset(self):
    """Checks that Euler angles can be retrieved from quaternions."""
    preset_euler_angles = test_helpers.generate_preset_test_euler_angles()

    preset_matrix = rotation_matrix_3d.from_euler(preset_euler_angles)
    preset_quaternion = quaternion.from_euler(preset_euler_angles)
    predicted_matrix = rotation_matrix_3d.from_quaternion(preset_quaternion)

    self.assertAllClose(preset_matrix, predicted_matrix, atol=2e-3)
    def test_from_euler_normalized_random(self):
        """Tests that quaternions.from_euler returns normalized quaterions."""
        random_euler_angles = test_helpers.generate_random_test_euler_angles()
        tensor_shape = random_euler_angles.shape[:-1]

        random_quaternion = quaternion.from_euler(random_euler_angles)

        self.assertAllEqual(quaternion.is_normalized(random_quaternion),
                            np.ones(shape=tensor_shape + (1, ), dtype=bool))
    def test_from_quaternion_normalized_preset(self):
        """Tests that quaternions can be converted to rotation matrices."""
        euler_angles = test_helpers.generate_preset_test_euler_angles()

        quat = quaternion.from_euler(euler_angles)
        matrix_quat = rotation_matrix_3d.from_quaternion(quat)

        self.assertAllEqual(rotation_matrix_3d.is_valid(matrix_quat),
                            np.ones(euler_angles.shape[0:-1] + (1, )))
Exemple #10
0
    def test_from_quaternion_random(self):
        """Tests that axis_angle.from_quaternion produces the expected result."""
        random_euler_angles = test_helpers.generate_random_test_euler_angles()

        random_quaternions = quaternion.from_euler(random_euler_angles)
        random_axis_angle = axis_angle.from_euler(random_euler_angles)

        self.assertAllClose(random_axis_angle,
                            axis_angle.from_quaternion(random_quaternions),
                            rtol=1e-3)
Exemple #11
0
    def test_from_quaternion_preset(self):
        """Tests that axis_angle.from_quaternion produces the expected result."""
        preset_euler_angles = test_helpers.generate_preset_test_euler_angles()

        preset_quaternions = quaternion.from_euler(preset_euler_angles)
        preset_axis_angle = axis_angle.from_euler(preset_euler_angles)

        self.assertAllClose(preset_axis_angle,
                            axis_angle.from_quaternion(preset_quaternions),
                            rtol=1e-3)
Exemple #12
0
  def test_from_quaternion_random(self):
    """Tests conversion to matrix."""
    random_euler_angles = test_helpers.generate_random_test_euler_angles()

    random_quaternions = quaternion.from_euler(random_euler_angles)
    random_rotation_matrices = rotation_matrix_3d.from_euler(
        random_euler_angles)

    self.assertAllClose(random_rotation_matrices,
                        rotation_matrix_3d.from_quaternion(random_quaternions))
  def test_from_axis_angle_random(self):
    """Tests converting an axis-angle to a quaternion."""
    random_euler_angles = test_helpers.generate_random_test_euler_angles()

    axis, angle = axis_angle.from_euler(random_euler_angles)
    grountruth = rotation_matrix_3d.from_quaternion(
        quaternion.from_euler(random_euler_angles))
    prediction = rotation_matrix_3d.from_quaternion(
        quaternion.from_axis_angle(axis, angle))

    self.assertAllClose(grountruth, prediction, rtol=1e-3)
Exemple #14
0
  def test_from_quaternion_gimbal(self, gimbal_configuration):
    """Checks that from_quaternion works when Ry = pi/2 or -pi/2."""
    random_euler_angles = test_helpers.generate_random_test_euler_angles()
    random_euler_angles[..., 1] = gimbal_configuration

    random_quaternion = quaternion.from_euler(random_euler_angles)
    random_matrix = rotation_matrix_3d.from_euler(random_euler_angles)
    reconstructed_random_matrices = rotation_matrix_3d.from_quaternion(
        random_quaternion)

    self.assertAllClose(reconstructed_random_matrices, random_matrix, atol=2e-3)
  def test_from_rotation_matrix_random(self):
    """Tests that from_rotation_matrix produces the expected quaternions."""
    random_euler_angles = test_helpers.generate_random_test_euler_angles()

    random_rotation_matrix_3d = rotation_matrix_3d.from_euler(
        random_euler_angles)
    groundtruth = rotation_matrix_3d.from_quaternion(
        quaternion.from_euler(random_euler_angles))
    prediction = rotation_matrix_3d.from_quaternion(
        quaternion.from_rotation_matrix(random_rotation_matrix_3d))

    self.assertAllClose(groundtruth, prediction)
  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)
  def test_from_euler_with_small_angles_approximation_random(self):
    # Only generate small angles. For a test tolerance of 1e-3, 0.33 was found
    # empirically to be the range where the small angle approximation works.
    random_euler_angles = test_helpers.generate_random_test_euler_angles(
        min_angle=-0.33, max_angle=0.33)

    exact_quaternion = quaternion.from_euler(random_euler_angles)
    approximate_quaternion = (
        quaternion.from_euler_with_small_angles_approximation(
            random_euler_angles))

    self.assertAllClose(exact_quaternion, approximate_quaternion, atol=1e-3)
Exemple #18
0
def rotate(vertices, features, num_samples, rot_range, angle_fixed):
    '''
    
    :param vertices: [num_vertices, 3]
    :param features: [FEAT_CAP, 4]
    :param num_samples:
    :return:
    '''
    vertices = vertices.astype(np.float32)
    # [FEAT_CAP]
    mask = features[:, 0].astype(np.bool)
    # [FEAT_CAP, 3]
    features = features[:, 1:].astype(np.float32)
    if angle_fixed:
        vertices = vertices[np.newaxis, :, :]
        features = features[np.newaxis, :, :]
        return vertices, features, mask

    random_angles_x = np.random.uniform(-rot_range[0], rot_range[0],
                                        (num_samples)).astype(np.float32)
    random_angles_y = np.random.uniform(-rot_range[1], rot_range[1],
                                        (num_samples)).astype(np.float32)
    random_angles_z = np.random.uniform(-rot_range[2], rot_range[2],
                                        (num_samples)).astype(np.float32)

    # random_angles.shape: (num_samples, 3)
    random_angles = np.stack(
        [random_angles_x, random_angles_y, random_angles_z], axis=1)
    ## debug
    regular_angles = np.concatenate([
        np.linspace(-np.pi, np.pi, num_samples)[:, np.newaxis],
        np.zeros((num_samples, 2))
    ],
                                    axis=-1).astype(np.float32)

    # random_quaternion.shape: (num_samples, 4)
    random_quaternion = quaternion.from_euler(random_angles)

    # vertices.shape : (num_samples, num_vertices, 3)
    vertices = quaternion.rotate(vertices[tf.newaxis, :, :],
                                 random_quaternion[:, tf.newaxis, :])
    # features.shape : (num_samples, FEAT_CAP, 3)
    features = quaternion.rotate(features[tf.newaxis, :, :],
                                 random_quaternion[:, tf.newaxis, :])

    return np.array(vertices), np.array(features), mask
Exemple #19
0
def generate_preset_test_dual_quaternions():
    """Generates pre-set test quaternions."""
    angles = generate_preset_test_euler_angles()
    preset_quaternion_real = quaternion.from_euler(angles)

    translations = generate_preset_test_translations()
    translations = np.concatenate(
        (translations / 2.0, np.zeros((np.ma.size(translations, 0), 1))),
        axis=1)
    preset_quaternion_translation = tf.convert_to_tensor(value=translations)

    preset_quaternion_dual = quaternion.multiply(preset_quaternion_translation,
                                                 preset_quaternion_real)

    preset_dual_quaternion = tf.concat(
        (preset_quaternion_real, preset_quaternion_dual), axis=-1)

    return preset_dual_quaternion
Exemple #20
0
def rotate(vertices, num_samples):
    vertices = vertices.astype(np.float32)
    # random_angles.shape: (num_samples, 3)
    random_angles = np.random.uniform(-np.pi, np.pi,
                                      (num_samples, 3)).astype(np.float32)

    ## debug
    regular_angles = np.concatenate([
        np.linspace(-np.pi, np.pi, num_samples)[:, np.newaxis],
        np.zeros((num_samples, 2))
    ],
                                    axis=-1).astype(np.float32)

    ##

    # random_quaternion.shape: (num_samples, 4)
    random_quaternion = quaternion.from_euler(random_angles)

    # data.shape : (num_samples, num_vertices, 3)
    data = quaternion.rotate(vertices[tf.newaxis, :, :],
                             random_quaternion[:, tf.newaxis, :])

    return np.array(data), np.array(random_quaternion)
Exemple #21
0
def generate_random_test_dual_quaternions():
    """Generates random test dual quaternions."""
    angles = generate_random_test_euler_angles()
    random_quaternion_real = quaternion.from_euler(angles)

    min_translation = -3.0
    max_translation = 3.0
    translations = np.random.uniform(min_translation, max_translation,
                                     angles.shape)

    translations_quaternion_shape = np.asarray(translations.shape)
    translations_quaternion_shape[-1] = 1
    translations = np.concatenate(
        (translations / 2.0, np.zeros(translations_quaternion_shape)), axis=-1)

    random_quaternion_translation = tf.convert_to_tensor(value=translations)

    random_quaternion_dual = quaternion.multiply(random_quaternion_translation,
                                                 random_quaternion_real)

    random_dual_quaternion = tf.concat(
        (random_quaternion_real, random_quaternion_dual), axis=-1)

    return random_dual_quaternion
Exemple #22
0
# reduce ray sample count since it needs to be a square number
sqrt_ray_sample_count = math.floor(math.sqrt(ray_sample_count))
ray_sample_count = sqrt_ray_sample_count * sqrt_ray_sample_count

# actually want the center-to-edge distance, i.e. the 'square radius'.
source_size /= 2

# =============================================================================
# Make the source.
angle_type = "quaternion"
if angle_type == "vector":
    source_angle = np.array((0.0, -source_y_offset, target_z_distance),
                            dtype=np.float64)
else:
    rot1 = quaternion.from_euler((0.0, -PI / 2, 0.0))
    rot2 = quaternion.from_euler(
        tf.cast((math.atan2(source_y_offset, target_z_distance), 0.0, 0.0),
                dtype=tf.float64))
    source_angle = quaternion.multiply(rot2, rot1)

source_center = np.array(
    (source_x_offset, source_y_offset, -target_z_distance), dtype=np.float64)
angular_distribution = distributions.SquareRankLambertianSphere(
    ray_sample_count, source_angular_cutoff)
base_point_distribution = distributions.RandomUniformSquare(
    source_size, sqrt_ray_sample_count)
source = sources.AngularSource(3,
                               source_center,
                               source_angle,
                               angular_distribution,
Exemple #23
0
def generate_preset_test_quaternions():
    """Generates pre-set test quaternions."""
    angles = generate_preset_test_euler_angles()
    preset_quaternion = quaternion.from_euler(angles)
    return preset_quaternion