rpx_benchmark.metrics.keypoints

Keypoint correspondence metric calculators.

 1"""Keypoint correspondence metric calculators."""
 2
 3from __future__ import annotations
 4
 5from typing import Dict
 6
 7from ..api import (
 8    KeypointCorrespondenceGroundTruth,
 9    KeypointCorrespondencePrediction,
10    TaskType,
11)
12from ..exceptions import MetricError
13from .registry import MetricCalculator, register_metric
14
15
16@register_metric(TaskType.KEYPOINT_MATCHING)
17class KeypointAccuracy(MetricCalculator):
18    """% of predicted matches within a pixel threshold + mean error.
19
20    Parameters
21    ----------
22    px_threshold : float
23        Pixel radius in frame B at which a predicted correspondence is
24        counted as correct. Default 3 px matches the standard
25        ScanNet/InteriorNet evaluation protocol.
26    """
27
28    name = "keypoint_accuracy"
29
30    def __init__(self, px_threshold: float = 3.0) -> None:
31        self.px_threshold = px_threshold
32
33    def compute(
34        self,
35        prediction: KeypointCorrespondencePrediction,
36        ground_truth: KeypointCorrespondenceGroundTruth,
37    ) -> Dict[str, float]:
38        if not isinstance(prediction, KeypointCorrespondencePrediction):
39            raise MetricError(
40                f"KeypointAccuracy expected "
41                f"KeypointCorrespondencePrediction, got "
42                f"{type(prediction).__name__}",
43            )
44        if not isinstance(ground_truth, KeypointCorrespondenceGroundTruth):
45            raise MetricError(
46                f"KeypointAccuracy expected "
47                f"KeypointCorrespondenceGroundTruth, got "
48                f"{type(ground_truth).__name__}",
49            )
50        from ..evaluators import keypoint_metrics
51
52        return keypoint_metrics(
53            pred_p0=prediction.points0,
54            pred_p1=prediction.points1,
55            gt_p0=ground_truth.points0,
56            gt_p1=ground_truth.points1,
57            visibility=ground_truth.visibility,
58            px_threshold=self.px_threshold,
59        )
@register_metric(TaskType.KEYPOINT_MATCHING)
class KeypointAccuracy(rpx_benchmark.metrics.registry.MetricCalculator):
17@register_metric(TaskType.KEYPOINT_MATCHING)
18class KeypointAccuracy(MetricCalculator):
19    """% of predicted matches within a pixel threshold + mean error.
20
21    Parameters
22    ----------
23    px_threshold : float
24        Pixel radius in frame B at which a predicted correspondence is
25        counted as correct. Default 3 px matches the standard
26        ScanNet/InteriorNet evaluation protocol.
27    """
28
29    name = "keypoint_accuracy"
30
31    def __init__(self, px_threshold: float = 3.0) -> None:
32        self.px_threshold = px_threshold
33
34    def compute(
35        self,
36        prediction: KeypointCorrespondencePrediction,
37        ground_truth: KeypointCorrespondenceGroundTruth,
38    ) -> Dict[str, float]:
39        if not isinstance(prediction, KeypointCorrespondencePrediction):
40            raise MetricError(
41                f"KeypointAccuracy expected "
42                f"KeypointCorrespondencePrediction, got "
43                f"{type(prediction).__name__}",
44            )
45        if not isinstance(ground_truth, KeypointCorrespondenceGroundTruth):
46            raise MetricError(
47                f"KeypointAccuracy expected "
48                f"KeypointCorrespondenceGroundTruth, got "
49                f"{type(ground_truth).__name__}",
50            )
51        from ..evaluators import keypoint_metrics
52
53        return keypoint_metrics(
54            pred_p0=prediction.points0,
55            pred_p1=prediction.points1,
56            gt_p0=ground_truth.points0,
57            gt_p1=ground_truth.points1,
58            visibility=ground_truth.visibility,
59            px_threshold=self.px_threshold,
60        )

% of predicted matches within a pixel threshold + mean error.

Parameters

px_threshold : float Pixel radius in frame B at which a predicted correspondence is counted as correct. Default 3 px matches the standard ScanNet/InteriorNet evaluation protocol.

KeypointAccuracy(px_threshold: float = 3.0)
31    def __init__(self, px_threshold: float = 3.0) -> None:
32        self.px_threshold = px_threshold
name = 'keypoint_accuracy'
px_threshold
def compute( self, prediction: rpx_benchmark.api.KeypointCorrespondencePrediction, ground_truth: rpx_benchmark.api.KeypointCorrespondenceGroundTruth) -> Dict[str, float]:
34    def compute(
35        self,
36        prediction: KeypointCorrespondencePrediction,
37        ground_truth: KeypointCorrespondenceGroundTruth,
38    ) -> Dict[str, float]:
39        if not isinstance(prediction, KeypointCorrespondencePrediction):
40            raise MetricError(
41                f"KeypointAccuracy expected "
42                f"KeypointCorrespondencePrediction, got "
43                f"{type(prediction).__name__}",
44            )
45        if not isinstance(ground_truth, KeypointCorrespondenceGroundTruth):
46            raise MetricError(
47                f"KeypointAccuracy expected "
48                f"KeypointCorrespondenceGroundTruth, got "
49                f"{type(ground_truth).__name__}",
50            )
51        from ..evaluators import keypoint_metrics
52
53        return keypoint_metrics(
54            pred_p0=prediction.points0,
55            pred_p1=prediction.points1,
56            gt_p0=ground_truth.points0,
57            gt_p1=ground_truth.points1,
58            visibility=ground_truth.visibility,
59            px_threshold=self.px_threshold,
60        )

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.