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 )
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.
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.