Pose#

kornia.metrics.angle_error_mat(R1, R2)[source]#

Geodesic angle (in degrees) between two rotation matrices.

The relative rotation \(R_1^\top R_2\) has trace \(1 + 2\cos\theta\), so the geodesic angle is \(\theta = \arccos\!\big((\mathrm{tr}(R_1^\top R_2) - 1) / 2\big)\).

Parameters:
  • R1 (Tensor) – a rotation matrix of shape \((*, 3, 3)\).

  • R2 (Tensor) – a rotation matrix of shape \((*, 3, 3)\).

Return type:

Tensor

Returns:

the per-matrix angle in degrees, with shape \((*,)\).

Note

The gradient is infinite/NaN exactly at \(0^\circ\) and \(180^\circ\) (identical or opposite rotations), because \(\frac{d}{dx}\arccos(x) \to \infty\) at \(x = \pm 1\). This is inherent to every geodesic/angular metric; it only bites if you backpropagate through a perfect or exactly-opposite match.

Example

>>> angle_error_mat(torch.eye(3), torch.eye(3))
tensor(0.)
kornia.metrics.angle_error_vec(v1, v2)[source]#

Angle (in degrees) between two vectors.

The angle is \(\theta = \arccos\!\big((v_1 \cdot v_2) / (\lVert v_1 \rVert \lVert v_2 \rVert)\big)\).

Parameters:
  • v1 (Tensor) – a vector of shape \((*, 3)\).

  • v2 (Tensor) – a vector of shape \((*, 3)\).

Return type:

Tensor

Returns:

the per-vector angle in degrees, with shape \((*,)\).

Note

The gradient is infinite/NaN exactly at \(0^\circ\) and \(180^\circ\) (identical or opposite vectors), because \(\frac{d}{dx}\arccos(x) \to \infty\) at \(x = \pm 1\). This is inherent to every geodesic/angular metric; it only bites if you backpropagate through a perfect or exactly-opposite match.

Note

A zero-length vector gives NaN rather than raising, since the angle is undefined there. Mask those entries before reducing.

Example

>>> v = torch.tensor([1.0, 0.0, 0.0])
>>> angle_error_vec(v, v)
tensor(0.)
kornia.metrics.translation_ate(t, t_gt)[source]#

Absolute translation error (ATE) between two translations.

Computes the raw Euclidean distance \(\lVert t - t_{gt} \rVert_2\). Unlike angle_error_vec(), this keeps the magnitude and is therefore only meaningful when both translations share a common metric scale (it is not scale-invariant, so it is not suitable for raw essential-matrix translations).

Parameters:
  • t (Tensor) – an estimated translation of shape \((*, 3)\).

  • t_gt (Tensor) – a ground-truth translation of the same shape as t.

Return type:

Tensor

Returns:

the per-sample translation error, with shape \((*,)\). An unbatched \((3,)\) input is treated as a single sample and returns shape \((1,)\).

Note

Unlike the angle_error_vec() / angle_error_mat() angular metrics, this has no arccos singularity: the gradient stays finite even at zero distance, where norm returns the subgradient 0.

Example

>>> t = torch.tensor([0.0, 0.0, 0.0])
>>> t_gt = torch.tensor([3.0, 4.0, 0.0])
>>> translation_ate(t, t_gt)
tensor([5.])
kornia.metrics.pose_errors(P, P_gt, fold_translation=True)[source]#

Rotation and translation angular error (in degrees) between two relative poses.

Parameters:
  • P (Tensor) – an estimated relative pose [R | t] of shape \((3, 4)\), \((4, 4)\), or batched \((B, 3, 4)\) / \((B, 4, 4)\).

  • P_gt (Tensor) – a ground-truth relative pose of the same shape.

  • fold_translation (bool, optional) – if True (default), fold the translation error into \([0, 90]\) via \(\min(e, 180 - e)\) to absorb the sign ambiguity of an essential-matrix translation. Default: True

Returns:

"R_err" (rotation), "t_err" (translation) and "max_err" (element-wise max of the two).

Return type:

a dict of per-pose errors of shape \((B,)\)

Note

A pose with zero translation gives NaN for "t_err" and "max_err", and auc_from_errors() propagates that into the AUC. Mask those entries first.

Example

>>> P = torch.eye(4)
>>> P[0, 3] = 1.0
>>> errs = pose_errors(P, P)
>>> errs["R_err"], errs["t_err"]
(tensor([0.]), tensor([0.]))
kornia.metrics.auc_from_errors(errors, thresholds=(1, 3, 5, 10))[source]#

Area under the cumulative error curve at one or more thresholds.

The metric is generic: any non-negative error array works. Pose-error metrics (e.g. the "max_err" of pose_errors()) are one common source, but the thresholds simply need to be in the same units as errors.

Parameters:
  • errors (Tensor) – per-sample error values of shape \((B,)\). Must be non-negative. Integer and half-precision inputs are promoted to the default floating dtype before accumulating.

  • thresholds (float | Sequence[float], optional) – a single threshold or a sequence of thresholds, in the same units as errors. Must be strictly positive. Defaults to (1, 3, 5, 10). Default: (1, 3, 5, 10)

Return type:

dict[float, float]

Returns:

a dict mapping each threshold to its AUC in \([0, 100]\), or NaN at every threshold if any error is NaN.

Note

An error exactly equal to a threshold contributes no area there, so errors all equal to thr score 0 at thr. This follows the reference implementations.

Example

>>> auc_from_errors(torch.zeros(1), thresholds=5.0)
{5.0: 100.0}