linking
sleap_nn.tracking.mot.linking
¶
Identity linking: object-level long-term memory for tracked videos.
:func:link_tracklets runs once per video AFTER tracking (any tracker, the
classic one included). It treats every track as an identity made of
tracklets and:
- Corrects swaps at crossings (needs calibrated appearance): around each ambiguity event (two or more identities' boxes overlapping), it compares each identity's appearance gallery from before the event with the vectors right after it, and applies a permutation only when appearance prefers it by the calibrated margin.
- Links tracklets across gaps (re-identification): an identity that ends and one that starts later, that never co-occur (cannot-link) and are spatially plausible given the gap, are merged when their appearance agrees (calibrated threshold and margin), or -- without usable appearance -- when the match is spatially unique within a short gap (an identity's own later fragments, reachable through the candidate, do not count as competitors).
- Enforces a closed set when the number of animals
Nis known: theNbest-supported identities that are present together become anchors (one per animal), and every other tracklet is assigned to a compatible anchor -- one it never co-occurs with, apart from frames where it merely duplicates the anchor's detection -- by spatial continuity and appearance. Only duplicate detections and tracklets that fit no anchor are untracked; a real fragment is never dropped because some other, short false-positive identity happened to co-occur with it.
Every vector already exists when tracking runs in sleap-nn (offline flow), so linking decides with full tracklets on both sides of every gap -- more evidence than an online re-ID decision at track confirmation could use.
Conventions used throughout:
- Identity: one distinct
sio.Trackobject among the tracked detections. - Tracklet: a maximal run of an identity's detections with no gap longer
than
track_buffersteps. - Time is counted in steps, exactly as the trackers count them: the
calibration's resolved
time_baseand stride through :func:~sleap_nn.tracking.mot.calibration.frame_steps(frame-index deltas divided byframe_stepin the"frames"time base, one step per processed frame in"steps"). - Gated vector: the appearance vector of a detection that is confident
(score
>= high_threshold), mostly visible (at least half of its nodes) and isolated (padded-box IoU below 0.1 against every other detection of its frame). Only gated vectors enter galleries: crops of overlapping animals are contaminated. - Linking statistic
s_link(Q, G): the mean over query vectorsqof the mean of the top-5 cosines ofqagainst galleryG-- the statistic :func:~sleap_nn.tracking.mot.calibration.calibratecalibrates the linking rule on, for every query length (link_thresh_by_len): a decision on ann-vector query uses the threshold and margin ofnvectors. - Cannot-link: two identities whose temporal extents overlap are never linked by the open-set rules (an identity is linked only to one that starts after it ends); identities that share a frame are different animals for certain, which is what makes them the competitors that appearance margins are measured against.
- Duplicate: two same-frame detections whose raw boxes overlap by at least
DUPLICATE_IOMINof the smaller one, or whose centroids are closer thanDUPLICATE_CENTROID_BODYbody sizes -- one animal detected twice.
Scaling: the open set keeps a sparse set of candidate pairs per identity (every
pair inside the spatial-only window plus the best appearance candidates), not
dense identity x identity matrices, and the closed set is linear in the number
of tracklets times N.
Classes:
| Name | Description |
|---|---|
LinkingResult |
Outcome of :func: |
Functions:
| Name | Description |
|---|---|
link_tracklets |
Link a tracked video's identities across gaps and crossings, in place. |
LinkingResult
¶
Outcome of :func:link_tracklets for one video.
Attributes:
| Name | Type | Description |
|---|---|---|
n_identities_before |
int
|
Identities (tracks) before linking. |
n_identities |
int
|
Identities after linking. |
n_merges |
int
|
Gap links applied (appearance or spatial). |
n_forced_merges |
int
|
Closed-set assignments of a tracklet to an anchor. |
n_swaps |
int
|
Swap corrections applied. |
n_untracked |
int
|
Detections set to untracked by the closed-set rule. |
notes |
List[str]
|
Human-readable decisions worth logging. |
Methods:
| Name | Description |
|---|---|
as_dict |
JSON-serializable dict. |
Source code in sleap_nn/tracking/mot/linking.py
link_tracklets(frames, *, carrier='pose', calibration=None, max_tracks=None, track_buffer=30, swap_correction=True, spatial_gate_frames=300, box_padding=0.1, high_threshold=0.5, score_mode='auto', score_normalizer=None, time_base='auto', body_size=None, track_objects=None)
¶
Link a tracked video's identities across gaps and crossings, in place.
Steps, in order (see the module docstring for the definitions):
- Swap correction (when
swap_correctionand the calibration reportsappearance_for_linking): for each ambiguity event over at mostMAX_EVENT_IDENTITIESidentities, the post-event vectors of each identity are scored against every identity's pre-event gallery; the best permutation is applied to the moved identities' detections after the event when its total gain is at least the calibrated margin per moved identity and every moved pair clears the calibrated threshold and beats its unswapped pair by the margin (the rule of each query's own length). - Gap linking, greedily best-first (appearance before spatial, score
desc, gap asc, start asc, name asc) until nothing is accepted, between an
identity that ends and one that starts later within the spatial gate
body + 3 * s * (gap if gap <= 10 else sqrt(10 * gap))withsthe calibratedstep_p95floored at 0.05 body per step (no gate beyondspatial_gate_framessteps or whenstep_p95is unknown). Pairs with gated vectors on both sides (and calibrated appearance) are decided by appearance (the threshold for the later identity's head length, then the margin over the competing candidates that provably are other animals); others are linked only when the gap is at most 4 track buffers and the pair is unique on that window's frontier (a candidate that starts after the nearest one ends can follow through it, so it is no competitor). A link that would skip over another candidate of the same identity waits for it (so that fragment is not stranded inside the merged identity's gap). - Closed set (
max_tracks): while more identities remain, themax_tracksbest-supported identities present together become anchors; every other tracklet, most constrained first (a single viable anchor before a choice; decisive choices before close calls), joins the anchor it never co-occurs with (frames where it only duplicates the anchor's detection are resolved: the higher-scoring detection stays), ranked by appearance agreement, then a gap-aware geometric cost of its junctions (gated first; past the gate only when appearance agrees, or for a tracklet longer thantrack_bufferthat appearance does not contradict). A tracklet that fits no anchor is untracked.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
frames
|
Sequence[Tuple[int, Sequence[Any]]]
|
|
required |
carrier
|
str
|
|
'pose'
|
calibration
|
Optional[VideoCalibration]
|
The video's calibration (computes one from |
None
|
max_tracks
|
Optional[int]
|
Known number of animals: closed-set linking. |
None
|
track_buffer
|
int
|
Gap (steps) below which a track's detections form one tracklet; also scales the spatial-only rule. |
30
|
swap_correction
|
bool
|
Correct swaps at crossings (appearance only). |
True
|
spatial_gate_frames
|
int
|
Gaps longer than this (steps) are not spatially gated. |
300
|
box_padding
|
float
|
Box padding used for overlap tests. |
0.1
|
high_threshold
|
float
|
Minimum score for a vector to enter a gallery. |
0.5
|
score_mode
|
str
|
Detection score mode (see |
'auto'
|
score_normalizer
|
Optional[float]
|
The tracker's per-video score normalizer
( |
None
|
time_base
|
str
|
|
'auto'
|
body_size
|
Optional[float]
|
A known body size (px, |
None
|
track_objects
|
Optional[Dict[int, Track]]
|
The tracker's |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
LinkingResult
|
class: |
Source code in sleap_nn/tracking/mot/linking.py
1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 | |