rpx_benchmark.metrics.pose

Relative camera pose metric calculators.

 1"""Relative camera pose metric calculators."""
 2
 3from __future__ import annotations
 4
 5from typing import Dict
 6
 7from ..api import RelativePoseGroundTruth, RelativePosePrediction, TaskType
 8from ..exceptions import MetricError
 9from .registry import MetricCalculator, register_metric
10
11
12@register_metric(TaskType.RELATIVE_CAMERA_POSE)
13class RelativePoseError(MetricCalculator):
14    """Rotation geodesic (degrees) + translation L2 (metres).
15
16    Notes
17    -----
18    Rotations are compared in SO(3) via the geodesic distance
19    ``arccos((trace(R_pred^T R_gt) - 1) / 2)``. Quaternion inputs (4-
20    vectors) are accepted and converted to rotation matrices.
21    Translations are compared in metres with straight L2.
22    """
23
24    name = "relative_pose_error"
25
26    def compute(
27        self,
28        prediction: RelativePosePrediction,
29        ground_truth: RelativePoseGroundTruth,
30    ) -> Dict[str, float]:
31        if not isinstance(prediction, RelativePosePrediction):
32            raise MetricError(
33                f"RelativePoseError expected RelativePosePrediction, got "
34                f"{type(prediction).__name__}",
35            )
36        if not isinstance(ground_truth, RelativePoseGroundTruth):
37            raise MetricError(
38                f"RelativePoseError expected RelativePoseGroundTruth, got "
39                f"{type(ground_truth).__name__}",
40            )
41        from ..evaluators import pose_metrics
42
43        return pose_metrics(
44            prediction.rotation,
45            prediction.translation,
46            ground_truth.rotation,
47            ground_truth.translation,
48        )
@register_metric(TaskType.RELATIVE_CAMERA_POSE)
class RelativePoseError(rpx_benchmark.metrics.registry.MetricCalculator):
13@register_metric(TaskType.RELATIVE_CAMERA_POSE)
14class RelativePoseError(MetricCalculator):
15    """Rotation geodesic (degrees) + translation L2 (metres).
16
17    Notes
18    -----
19    Rotations are compared in SO(3) via the geodesic distance
20    ``arccos((trace(R_pred^T R_gt) - 1) / 2)``. Quaternion inputs (4-
21    vectors) are accepted and converted to rotation matrices.
22    Translations are compared in metres with straight L2.
23    """
24
25    name = "relative_pose_error"
26
27    def compute(
28        self,
29        prediction: RelativePosePrediction,
30        ground_truth: RelativePoseGroundTruth,
31    ) -> Dict[str, float]:
32        if not isinstance(prediction, RelativePosePrediction):
33            raise MetricError(
34                f"RelativePoseError expected RelativePosePrediction, got "
35                f"{type(prediction).__name__}",
36            )
37        if not isinstance(ground_truth, RelativePoseGroundTruth):
38            raise MetricError(
39                f"RelativePoseError expected RelativePoseGroundTruth, got "
40                f"{type(ground_truth).__name__}",
41            )
42        from ..evaluators import pose_metrics
43
44        return pose_metrics(
45            prediction.rotation,
46            prediction.translation,
47            ground_truth.rotation,
48            ground_truth.translation,
49        )

Rotation geodesic (degrees) + translation L2 (metres).

Notes

Rotations are compared in SO(3) via the geodesic distance arccos((trace(R_pred^T R_gt) - 1) / 2). Quaternion inputs (4- vectors) are accepted and converted to rotation matrices. Translations are compared in metres with straight L2.

name = 'relative_pose_error'
def compute( self, prediction: rpx_benchmark.api.RelativePosePrediction, ground_truth: rpx_benchmark.api.RelativePoseGroundTruth) -> Dict[str, float]:
27    def compute(
28        self,
29        prediction: RelativePosePrediction,
30        ground_truth: RelativePoseGroundTruth,
31    ) -> Dict[str, float]:
32        if not isinstance(prediction, RelativePosePrediction):
33            raise MetricError(
34                f"RelativePoseError expected RelativePosePrediction, got "
35                f"{type(prediction).__name__}",
36            )
37        if not isinstance(ground_truth, RelativePoseGroundTruth):
38            raise MetricError(
39                f"RelativePoseError expected RelativePoseGroundTruth, got "
40                f"{type(ground_truth).__name__}",
41            )
42        from ..evaluators import pose_metrics
43
44        return pose_metrics(
45            prediction.rotation,
46            prediction.translation,
47            ground_truth.rotation,
48            ground_truth.translation,
49        )

Return a dict of metric name → scalar for one sample.

Parameters

prediction : Any Task-specific Prediction dataclass (e.g. DepthPrediction). The concrete type is whatever the calculator is designed for. ground_truth : Any Task-specific GroundTruth dataclass (e.g. DepthGroundTruth).

Returns

dict[str, float] Metric values. Keys should be short snake_case names; values must be numeric so the runner can average them.

Raises

MetricError When inputs have the wrong shape/type/content.