:orphan: :py:mod:`traccuracy.metrics._compute_complete_tracks_by_length` =============================================================== .. py:module:: traccuracy.metrics._compute_complete_tracks_by_length Module Contents --------------- Functions ~~~~~~~~~ .. autoapisummary:: traccuracy.metrics._compute_complete_tracks_by_length.compute_complete_tracks_by_length Attributes ~~~~~~~~~~ .. autoapisummary:: traccuracy.metrics._compute_complete_tracks_by_length.EMPTY traccuracy.metrics._compute_complete_tracks_by_length.CORRECT traccuracy.metrics._compute_complete_tracks_by_length.INCORRECT .. py:data:: EMPTY .. py:data:: CORRECT :value: 1 .. py:data:: INCORRECT :value: 0 .. py:function:: compute_complete_tracks_by_length(matched: traccuracy.matchers.Matched, max_length: int, lineages: bool = True, error_type: Literal[basic, ctc] = 'basic', relax_skips_gt: bool = False, relax_skips_pred: bool = False) -> dict[int, tuple[int, int]] Compute the fraction of GT track segments correctly reconstructed, by length. For each component (lineage or tracklet), builds a 2D grid of per-frame-step correctness values (see ``_build_grid``), then uses dynamic programming to combine adjacent frame steps into longer segments. Segments are accumulated via a sliding window over the timeline, one window per segment length. Length is measured in frames (time difference), not edge count. Skip edges spanning multiple frames are interpolated to fill intermediate frame steps with the same correctness status. This means that if a skip edge exceeds the length, the part of it inside the window still counts towards the correctness of the segment. Example — A->A' then A' divides into B and C, with an error on the C->C' edge (1 = correct, 0 = incorrect, empty = no track):: GT graph (6 nodes, 5 edges): t=0 t=1 t=2 t=3 / B ---- B' A ---- A'< \ C -x-- C' (error on C->C') base grid (window=1): one entry per edge Each column is frame span ((0-1) covers frames 0->1, etc.) (0-1)(1-2)(2-3) ┌─────────┬────┬────┬────┐ │track. A │ 1 │ │ │ edge A->A' ├─────────┼────┼────┼────┤ │track. B │ │ 1 │ 1 │ edges A'->B, B->B' ├─────────┼────┼────┼────┤ │track. C │ │ 1 │ 0 │ edges A'->C, C->C' (error) └─────────┴────┴────┴────┘ w=2 grid (combine base[t] with base[t+1] via division links): (0-2)(1-3) ┌─────────┬────┬────┐ │track. A │ 1 │ │ AND(A->A'=1, A'->B=1, A'->C=1) = 1 ├─────────┼────┼────┤ │track. B │ │ 1 │ AND(A'->B=1, B->B'=1) = 1 ├─────────┼────┼────┤ │track. C │ │ 0 │ AND(A'->C=1, C->C'=0) = 0 └─────────┴────┴────┘ w=3 grid: (0-3) ┌─────────┬────┐ │track. A │ 0 │ AND(A->A'=1, w2_B=1, w2_C=0) = 0 ├─────────┼────┤ │track. B │ │ ├─────────┼────┤ │track. C │ │ └─────────┴────┘ At each length, non-empty entries are counted as segments. length 1: 5 (4 correct). length 2: 3 (2 correct). length 3: 1 (0 correct). GT tracks shorter than a given length still count once for that length (correct iff the entire track is correct). :param matched: Matched data object with annotated errors :param max_length: Maximum track length to evaluate (in frames) :param lineages: If True, evaluate on full lineages. If False, on tracklets. :param error_type: "basic" or "ctc" - which error classification was used :param relax_skips_gt: If True, SKIP_TRUE_POS edges in GT count as correct :param relax_skips_pred: If True, SKIP_TRUE_POS edges in pred count as correct :returns: Dictionary mapping track length (int) to tuple of (correct_count, total_count) for each length from 1 to max_length