calibration
sleap_nn.tracking.mot.calibration
¶
Per-video self-calibration for the MOT trackers.
:func:calibrate looks at every detection of a video BEFORE tracking it (all
vectors already exist in sleap-nn's offline tracking flow) and measures:
- Geometry: body size, nearest-neighbor spacing, the processing stride and per-step motion, from anchor tracklets -- detections chained frame-to-frame only where the association is unambiguous (mutual nearest neighbors, well separated from any competitor), cut at any doubt.
- Time base: the stride and how time advances between processed frames,
through the shared step helpers (:func:
stride_from_counts, :func:resolve_time_base, :func:steps_between, :func:frame_steps) that the trackers and the identity linker use too, so all of them count the same steps. - Scores: detection-confidence quantiles (:func:
score_normalizerturns them into the per-video score normalizer ofMOTParams.normalize_scores). - Appearance (when detections carry re-ID vectors): the distributions of the exact DECISION STATISTICS the trackers and the identity linker use, measured on synthetic trials over anchor tracklets. Two anchors that overlap in time are guaranteed to be different animals, so co-occurring anchors provide true negatives; later vectors of the same anchor provide positives. Calibrating the statistic that is thresholded (EMA cosine, gallery max, tracklet-to-gallery top-k mean) -- not single-pair cosines -- keeps the thresholds' error rates meaningful.
When there is not enough evidence (no vectors, a single animal, too few trials)
the appearance part reports status != "ok" and every "auto" threshold
disables appearance rather than falling back to a constant tuned on person re-ID.
Classes:
| Name | Description |
|---|---|
VideoCalibration |
Calibration of one video. Every field is a plain Python type. |
Functions:
| Name | Description |
|---|---|
calibrate |
Calibrate a video from all of its frames' detections. |
frame_steps |
Step position of each processed frame (the first at step 0). |
frame_stride |
|
link_rule_tables |
The calibrated linking rule for each query length. |
pair_geometry |
Same-frame spacing of |
resolve_body_size |
The body size (px) and its source (the shared fallback chain). |
resolve_time_base |
Resolve |
score_normalizer |
Per-video score normalizer of |
steps_between |
Time steps between two processed frames |
stride_from_counts |
Processing stride from the counts of the positive frame-index deltas. |
VideoCalibration
¶
Calibration of one video. Every field is a plain Python type.
Attributes:
| Name | Type | Description |
|---|---|---|
status |
str
|
Appearance-calibration status: |
n_frames |
int
|
Frames seen. |
n_detections |
int
|
Valid detections seen. |
frame_step |
int
|
Most common positive frame-index delta (1 if unknown). |
regular_stride |
bool
|
Whether at least half of the deltas equal |
time_base |
str
|
The RESOLVED time base, |
body_size |
float
|
Body size (px), from the fallback chain of
:func: |
body_size_source |
str
|
Where |
nn_distance |
float
|
Median same-frame nearest-neighbor centroid distance (px),
ignoring duplicate pairs (IoMin > 0.5); falls back to |
step_p95 |
float
|
95th percentile per-step centroid displacement along anchors (px). |
step_p99 |
float
|
99th percentile per-step centroid displacement along anchors (px). |
score_quantiles |
tuple
|
Score quantiles at 0.05, 0.25, 0.5, 0.75 and 0.95, of the RAW detection scores (before any normalization). |
n_anchors |
int
|
Anchor tracklets found. |
n_trials |
int
|
Appearance trials run at |
assoc_rank1 |
Optional[float]
|
Fraction of |
m_assoc |
Optional[float]
|
Association margin: |
ema_cos_gate |
Optional[float]
|
q95 of competitor EMA cosines at |
gallery_cos_gate |
Optional[float]
|
q95 of competitor gallery-max cosines at |
mu_pos |
Optional[float]
|
Median true EMA cosine at |
mu_neg |
Optional[float]
|
Median competitor EMA cosine at |
link_thresh |
Optional[float]
|
q99 of competitor linking statistics at the long gap, for
a full query (:data: |
link_margin |
Optional[float]
|
Smallest margin in :data: |
link_recall |
Optional[float]
|
Recall of the calibrated linking rule on the trials. |
link_thresh_by_len |
tuple
|
|
link_margin_by_len |
tuple
|
|
neg_collision_rate |
Optional[float]
|
Fraction of same-frame negative pairs whose cosine is
at or above the q05 of |
appearance_for_association |
bool
|
|
appearance_for_linking |
bool
|
|
Methods:
| Name | Description |
|---|---|
as_dict |
JSON-serializable dict (NaN becomes |
summary |
One-line human-readable summary for logs. |
Source code in sleap_nn/tracking/mot/calibration.py
100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 | |
as_dict()
¶
summary()
¶
One-line human-readable summary for logs.
Source code in sleap_nn/tracking/mot/calibration.py
calibrate(frames, *, track_buffer=30, gallery_size=30, query_len=LINK_QUERY_LEN, ema_alpha=0.8, max_trials=2000, seed=0, time_base='auto', body_size=None, appearance=True)
¶
Calibrate a video from all of its frames' detections.
Procedure (deterministic given seed):
- Geometry:
frame_step/regular_stridefrom the frame indices and the resolvedtime_base(:func:frame_stride, :func:resolve_time_base; step positions from :func:frame_steps);nn_distance(median same-frame nearest-neighbor centroid distance, duplicate pairs ignored) and the score quantiles of the valid detections. - Anchor tracklets: detections of consecutive processed frames are
chained when they are mutual nearest neighbors closer than
0.5 * nn_distance(no distance gate when no frame holds two detections: a lone detection has no competitor), the runner-up is >= 2x farther in both directions, and neither is a same-frame duplicate (IoMin > 0.5); chains are cut at any violation and kept when >= :data:MIN_ANCHOR_LENlong.step_p95/step_p99are per-STEP displacements along the anchor links. - Body size (:func:
resolve_body_size): the median raw-box diagonal of valid masks and poses with >= 2 visible nodes; else (single-node poses)MOTION_BODY_FACTOR * step_p99clipped to[MIN_MOTION_BODY, nn_distance]; elsenn_distance; else 50 px.body_size_sourcerecords which; a WARNING is logged when only the spacing or the default was left. - Appearance trials at
g = 1andg = track_buffersteps: for anchorasplit everystridevectors (clip(candidates // max_trials, 1, MAX_TRIAL_STRIDE)) at stept, the true memory isa's lastgallery_sizevectors at or beforet - gplus its running EMA there (seeded and renormalized like :class:~sleap_nn.tracking.mot.appearance.AppearanceMemory), the query isa's nextquery_lenvectors fromt, and the competitors are the anchors with a vector in the true gallery's time window (they share a frame witha, so they are different animals), with memories built the same way. Statistics:s_ema = cos(q, ema),s_gal = max cos(q, gallery)(qthe first query vector) ands_link= mean over the query of the top-5 mean gallery cosine. See :class:VideoCalibrationfor the thresholds. At mostmax_trialsper gap (subsampled withseed).statusis"no_vectors"without vectors and"insufficient"with fewer than :data:MIN_TRIALSg = 1trials having a co-occurring competitor (e.g. a single animal); linking thresholds also need :data:MIN_TRIALStrials at the long gap. The long-gap (linking) trials always use the linker's gallery length :data:LINK_GALLERY_LENand calibrate the rule for every query length up toquery_len(link_thresh_by_len).
Logs a one-line INFO summary, and a WARNING when more than
:data:NEG_COLLISION_WARN of the same-frame pairs of different animals look
like the same animal (the embedding may encode class/sex, not identity).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
frames
|
Sequence[FrameDetections]
|
The video's :class: |
required |
track_buffer
|
int
|
Long-gap length (steps) for the linking statistic. |
30
|
gallery_size
|
int
|
Gallery length of the |
30
|
query_len
|
int
|
Query tracklet length used for the linking statistic. |
LINK_QUERY_LEN
|
ema_alpha
|
float
|
EMA momentum used for the EMA statistic. |
0.8
|
max_trials
|
int
|
Cap on trials per gap (subsampled deterministically). |
2000
|
seed
|
int
|
Seed for subsampling. |
0
|
time_base
|
str
|
How time advances between processed frames, as
:class: |
'auto'
|
body_size
|
Optional[float]
|
A known body size (px, e.g. |
None
|
appearance
|
bool
|
Calibrate the appearance part. |
True
|
Returns:
| Name | Type | Description |
|---|---|---|
The |
VideoCalibration
|
class: |
Raises:
| Type | Description |
|---|---|
ValueError
|
On an unknown |
Source code in sleap_nn/tracking/mot/calibration.py
1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 | |
frame_steps(frame_indices, time_base, frame_step=1)
¶
Step position of each processed frame (the first at step 0).
"frames": consecutive frames are :func:steps_between steps apart, so
a strided video behaves like a dense one and genuine gaps still count;
"steps": one step per processed frame. With a calibration, call it as
frame_steps(idx, cal.time_base, cal.frame_step).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
frame_indices
|
Sequence[int]
|
Frame indices of the processed frames, in processing order. |
required |
time_base
|
str
|
The RESOLVED time base, |
required |
frame_step
|
int
|
The stride (used in the |
1
|
Returns:
| Type | Description |
|---|---|
ndarray
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
On a time base other than |
Source code in sleap_nn/tracking/mot/calibration.py
frame_stride(frame_indices)
¶
(frame_step, regular) of a sequence of frame indices.
See :func:stride_from_counts (applied to the positive consecutive deltas).
Source code in sleap_nn/tracking/mot/calibration.py
link_rule_tables(calibration, query_len=LINK_QUERY_LEN)
¶
The calibrated linking rule for each query length.
Entry n - 1 is the (threshold, margin) for a query of n vectors
(n = 1 .. query_len; longer calibrated tables are cut, shorter ones
repeat their last entry). Without per-length tables (a hand-built or older
calibration) the full-length link_thresh / link_margin apply to every
length. A length whose margin is unknown (no grid margin reached the
precision there) gets NaN for BOTH: appearance cannot decide such a query.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
calibration
|
Optional[VideoCalibration]
|
The video's calibration, or |
required |
query_len
|
int
|
Longest query. |
LINK_QUERY_LEN
|
Returns:
| Type | Description |
|---|---|
Tuple[ndarray, ndarray]
|
|
Source code in sleap_nn/tracking/mot/calibration.py
pair_geometry(prev, cur, max_dist=None)
¶
Same-frame spacing of cur and its unambiguous links to prev.
The online counterpart of :func:calibrate's geometry (used by uncalibrated
trackers), with the same rules: duplicate pairs (IoMin > 0.5) are not
neighbors, and a prev -> cur link needs mutual nearest neighbors closer
than max_dist whose runner-ups are at least twice farther.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
prev
|
Optional[FrameDetections]
|
The previous processed frame's detections ( |
required |
cur
|
FrameDetections
|
This frame's detections. Pose pseudo boxes (degenerate geometry
extracted with a |
required |
max_dist
|
Optional[float]
|
Link gate (px). |
None
|
Returns:
| Type | Description |
|---|---|
Tuple[ndarray, ndarray]
|
|
Source code in sleap_nn/tracking/mot/calibration.py
resolve_body_size(measured, step_p99, nn_distance)
¶
The body size (px) and its source (the shared fallback chain).
Used by :func:calibrate and by the uncalibrated trackers:
measured(median raw-box diagonal of sized detections) ->"measured".- Else (single-node detections have no extent) the per-step motion:
MOTION_BODY_FACTOR * step_p99, at least :data:MIN_MOTION_BODYand at mostnn_distance(when known) ->"motion". Inter-animal spacing is not a body length: in a sparse arena it would open the centroid gate (scalebody / 2) most of the way to the next animal. - Else
nn_distance->"nn_distance". - Else :data:
DEFAULT_BODY_SIZE(50 px) ->"default".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
measured
|
float
|
Measured body size (NaN if none). |
required |
step_p99
|
float
|
99th percentile per-step displacement (NaN if unknown). |
required |
nn_distance
|
float
|
Same-frame nearest-neighbor spacing (NaN if unknown). |
required |
Returns:
| Type | Description |
|---|---|
Tuple[float, str]
|
|
Source code in sleap_nn/tracking/mot/calibration.py
resolve_time_base(time_base, regular)
¶
Resolve MOTParams.time_base to "frames" or "steps".
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
time_base
|
str
|
|
required |
regular
|
bool
|
Whether the processed frames are regularly strided. |
required |
Returns:
| Type | Description |
|---|---|
str
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
On an unknown |
Source code in sleap_nn/tracking/mot/calibration.py
score_normalizer(calibration)
¶
Per-video score normalizer of MOTParams.normalize_scores.
max(q95, SCORE_NORMALIZER_FLOOR) of the calibration's (raw) score
quantiles; 1.0 without a calibration or scores. Dividing a detection score by
it (then clipping to [0, 1], see
:func:~sleap_nn.tracking.mot.detections.normalize_scores) maps a typical
detection of the video to ~0.85-1.0 whatever the model's score scale.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
calibration
|
Optional[VideoCalibration]
|
The video's calibration, or |
required |
Returns:
| Type | Description |
|---|---|
float
|
The normalizer (> 0). |
Source code in sleap_nn/tracking/mot/calibration.py
steps_between(delta, frame_step)
¶
Time steps between two processed frames delta frame indices apart.
The "frames" time base: max(1, round(delta / frame_step)), rounding
half to even (np.rint, like Python's round) -- the ONE rounding rule
of the trackers, :func:calibrate and the identity linker. A non-positive
delta (a repeated or backwards frame) counts one step. In the
"steps" time base every processed frame is one step and this is not used.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
delta
|
Union[int, float, ndarray]
|
Frame-index difference(s) to the previous processed frame. |
required |
frame_step
|
int
|
The stride (floored at 1). |
required |
Returns:
| Type | Description |
|---|---|
Union[int, ndarray]
|
An |
Source code in sleap_nn/tracking/mot/calibration.py
stride_from_counts(counts)
¶
Processing stride from the counts of the positive frame-index deltas.
The stride (frame_step) is the most common positive delta (ties: the
smallest); it is regular when at least half of the deltas equal it. This is
the rule of :func:calibrate (over the whole video) and of an uncalibrated
tracker (over the deltas seen so far).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
counts
|
Mapping[int, int]
|
|
required |
Returns:
| Type | Description |
|---|---|
Tuple[int, bool]
|
|