Beispiel #1
0
def pose_estimation_loss(ori_vertices, y_true, y_pred):
    """Pose estimation loss used for training.

  This loss measures the average of squared distance between some vertices
  of the mesh in 'rest pose' and the transformed mesh to which the predicted
  inverse pose is applied. Comparing this loss with a regular L2 loss on the
  quaternion and translation values is left as exercise to the interested
  reader.

  Args:
    y_true: The ground-truth value. [n,c]
    y_pred: The prediction we want to evaluate the loss for. [b,4]

  Returns:
    A scalar value containing the loss described in the description above.
  """

    # vertices.shape: (num_vertices, 3)
    # corners.shape:(num_vertices, 1, 3)
    corners = tf.expand_dims(ori_vertices, axis=1)
    # corners = ori_vertices

    # transformed_corners.shape: (num_vertices, batch, 3)
    # q and t shapes get pre-pre-padded with 1's following standard broadcast rules.
    transformed_corners = quaternion.rotate(corners, y_pred)

    # recovered_corners.shape: (num_vertices, batch, 3)
    recovered_corners = quaternion.rotate(transformed_corners,
                                          quaternion.inverse(y_true))

    # vertex_error.shape: (num_vertices, batch)
    vertex_error = tf.reduce_sum((recovered_corners - corners)**2, axis=-1)

    return tf.reduce_mean(vertex_error)
Beispiel #2
0
def to_rotation_translation(
        dual_quaternion: type_alias.TensorLike,
        name: str = "dual_quaternion_to_rot_trans"
) -> Tuple[tf.Tensor, tf.Tensor]:
    """Converts a dual quaternion into a quaternion for rotation and translation.

  Args:
    dual_quaternion: A `[A1, ..., An, 8]`-tensor, where the last dimension
      represents a qual quaternion.
    name: A name for this op that defaults to "dual_quaternion_to_rot_trans".

  Returns:
    A tuple with a `[A1, ..., An, 4]`-tensor for rotation in quaternion form,
    and a `[A1, ..., An, 3]`-tensor for translation, in that order.
  """
    with tf.name_scope(name):
        dual_quaternion = tf.convert_to_tensor(value=dual_quaternion)

        shape.check_static(tensor=dual_quaternion,
                           tensor_name="dual_quaternion",
                           has_dim_equals=(-1, 8))

        rotation = dual_quaternion[..., 0:4]
        translation = 2 * quaternion.multiply(dual_quaternion[..., 4:8],
                                              quaternion.inverse(rotation))
        translation = translation[..., 0:3]

        return rotation, translation
Beispiel #3
0
def eval_accuracy(X, Y, Y_hat, X_train, Y_train, X_test, Y_test, t_treshold, r_threshold):
  # Have to swap axes due to how tensorflow quaternions work
  Yq = tf.transpose(Y[:4], [1, 0])
  Yq_hat = tf.transpose(Y_hat[:4], [1, 0])
  # Compute difference quaternion then swap axes back
  diff = tfq.multiply(tfq.normalize(Yq), tfq.inverse(tfq.normalize(Yq_hat)))
  diff = tf.transpose(diff, [1, 0])
  # Compute angle difference in degrees
  diffW = tf.clip_by_value(diff[3], clip_value_min=-1.0, clip_value_max=1.0)
  angle_diff = tf_rad2deg(math.pi - tf.math.abs(2 * tf.math.acos(diffW) - math.pi))

  correct_rot = tf.cast(tf.less(angle_diff, [r_threshold]), "float")
  correct_trans = tf.cast(tf.less(tf.norm(Y[4:] - Y_hat[4:], axis = 0), [t_treshold]), "float")

  t_accuracy = tf.reduce_mean(tf.cast(correct_trans, "float"))
  r_accuracy = tf.reduce_mean(tf.cast(correct_rot, "float"))
  accuracy = tf.reduce_mean(tf.cast(correct_trans * correct_rot, "float"))

  print('\n--------------')
  print("Evaluating accuracy with rotation threshold of " + str(r_threshold) + " and translation treshold of " + str(t_treshold))
  print('')
  print ("Train Accuracy:", accuracy.eval({X: X_train, Y: Y_train}))
  print ("Test Accuracy:", accuracy.eval({X: X_test, Y: Y_test}))
  print('')

  print ("Train Accuracy on just translation:", t_accuracy.eval({X: X_train, Y: Y_train}))
  print ("Test Accuracy on just translation:", t_accuracy.eval({X: X_test, Y: Y_test}))
  print('')

  print ("Train Accuracy on just rotation:", r_accuracy.eval({X: X_train, Y: Y_train}))
  print ("Test Accuracy on just rotation:", r_accuracy.eval({X: X_test, Y: Y_test}))
  print('\n--------------')
  def test_inverse_jacobian_random(self):
    """Test the Jacobian of the inverse function."""
    x_init = test_helpers.generate_random_test_quaternions()
    x = tf.convert_to_tensor(value=x_init)

    y = quaternion.inverse(x)

    self.assert_jacobian_is_correct(x, x_init, y)
Beispiel #5
0
  def test_inverse_normalized_random(self):
    """Tests that the inverse function returns normalized quaternions."""
    random_quaternion = test_helpers.generate_random_test_quaternions()

    inverse_quaternion = quaternion.inverse(random_quaternion)

    self.assertAllEqual(
        quaternion.is_normalized(inverse_quaternion),
        np.ones(shape=random_quaternion.shape[:-1] + (1,), dtype=bool))
Beispiel #6
0
  def test_inverse_random(self):
    """Tests that multiplying with the inverse gives identity."""
    random_quaternion = test_helpers.generate_random_test_quaternions()

    inverse_quaternion = quaternion.inverse(random_quaternion)
    final_quaternion = quaternion.multiply(random_quaternion,
                                           inverse_quaternion)
    tensor_shape = random_quaternion.shape[:-1]
    identity_quaternion = np.array((0.0, 0.0, 0.0, 1.0), dtype=np.float32)
    identity_quaternion = np.tile(identity_quaternion, tensor_shape + (1,))

    self.assertAllClose(final_quaternion, identity_quaternion, rtol=1e-3)