diff --git a/src/pyrecest/evaluation/tracking_metrics/_clear_identity.py b/src/pyrecest/evaluation/tracking_metrics/_clear_identity.py index 46f898a67..e4debd70d 100644 --- a/src/pyrecest/evaluation/tracking_metrics/_clear_identity.py +++ b/src/pyrecest/evaluation/tracking_metrics/_clear_identity.py @@ -46,9 +46,11 @@ def evaluate_clear(data: TrackingSequence, *, threshold: float) -> ClearCounts: ): if len(gt_ids) == 0: fp += len(tracker_ids) + previous_timestep_id[:] = np.nan continue if len(tracker_ids) == 0: fn += len(gt_ids) + previous_timestep_id[:] = np.nan continue continuity = tracker_ids[np.newaxis, :] == previous_timestep_id[gt_ids[:, None]] score = continuity.astype(float) * 1000.0 + similarity diff --git a/tests/evaluation/test_tracking_metrics_clear_gap.py b/tests/evaluation/test_tracking_metrics_clear_gap.py new file mode 100644 index 000000000..578472b99 --- /dev/null +++ b/tests/evaluation/test_tracking_metrics_clear_gap.py @@ -0,0 +1,60 @@ +from __future__ import annotations + +import numpy as np +import pytest +from pyrecest.evaluation.tracking_metrics import TrackingSequence, evaluate_clear + + +@pytest.mark.parametrize( + ("gap_gt_ids", "gap_tracker_ids", "gap_similarity", "expected_fp", "expected_fn"), + [ + ( + np.empty(0, dtype=int), + np.array([0], dtype=int), + np.empty((0, 1), dtype=float), + 1, + 0, + ), + ( + np.array([0, 1], dtype=int), + np.empty(0, dtype=int), + np.empty((2, 0), dtype=float), + 0, + 2, + ), + ], +) +def test_clear_continuity_does_not_cross_empty_frame( + gap_gt_ids: np.ndarray, + gap_tracker_ids: np.ndarray, + gap_similarity: np.ndarray, + expected_fp: int, + expected_fn: int, +) -> None: + data = TrackingSequence( + gt_ids=( + np.array([0, 1], dtype=int), + gap_gt_ids, + np.array([0, 1], dtype=int), + ), + tracker_ids=( + np.array([0, 1], dtype=int), + gap_tracker_ids, + np.array([0, 1], dtype=int), + ), + similarity_scores=( + np.eye(2, dtype=float), + gap_similarity, + np.array([[0.6, 0.9], [0.9, 0.6]], dtype=float), + ), + num_gt_ids=2, + num_tracker_ids=2, + ) + + counts = evaluate_clear(data, threshold=0.5) + + assert counts.tp == 4 + assert counts.fp == expected_fp + assert counts.fn == expected_fn + assert counts.id_switches == 2 + assert counts.motp_sum == pytest.approx(3.8)