feat: tracker owns no state; association is frame-dependent and calibrated
Three requirements land together because they cannot be separated. The cross-cut revival branch was the only user of cut_revive_sim, so retiring that raw cosine forces the pool collapse, and collapsing the pool removes the only caller of the constant. Splitting them would have produced an intermediate commit whose only purpose was to be split. AR-008 — FaceTrackerFunc no longer keeps its own tracks_/inactive_ maps; it holds a shared_ptr<TrackRegistry> and operates on it directly. Two parallel copies of track state could disagree, and every divergence would surface as a wrong presence window with nothing to indicate it. There is now ONE candidate pool: last_seen alone says whether IoU is meaningful. The park/revive path is deleted outright — matching a dormant track is ordinary inter-frame association, and continuity falls out of the embedding comparison the tracker already did rather than being a mechanism of its own. AR-007 — track_alpha becomes the base weight for ordinary frames only. Association drops to embedding-only when position carries no information: on is_cut or is_scene_boundary, because the viewpoint changed, and for a dormant track, because time has passed since its box was last valid. The second case matters as much as the first and had no equivalent before. AR-024 — association cost is a calibrated probability, never a raw cosine. The tracker takes the calibration belonging to the active embedder, the same function object EvidenceDiscounter uses. track_max_embed_dist becomes track_assoc_min_prob, which means the same thing for every model, gallery and face size, where a bare cosine threshold did not. Retired: track_max_embed_dist, cut_revive_sim, cut_inactive_max_frames, and track_max_frames_missing — the last superseded by the registry's extinction window. That one is worth naming: a frame count silently changed meaning with sample_fps, so the same configuration behaved differently at 1 fps and 5 fps. Extinction is in seconds and lives in one place. Tests rewritten rather than deleted. The old cases asserted revival by raw cosine; the same behaviours are now asserted through the registry — a face lost across a cut and re-associated is the SAME track, one unbroken window, and a face returning past the extinction window is not. Added the case AR-007 exists for: two people swap screen positions across a cut while keeping their faces, and identity must follow the embedding rather than the box. Suite: 80 cases, 3250 assertions. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> TRACES: AR-007, AR-008, AR-024 | SR-002
This commit is contained in:
+18
-14
@@ -94,21 +94,25 @@ struct Config {
|
||||
float dense_scale{1.0f}; // dense-mode frame downscale (1 = off)
|
||||
|
||||
// ── Face tracking (frame-to-frame) ───────────────────────────────────────
|
||||
float track_alpha{0.4f}; // cost weight: 0=embedding only, 1=spatial only
|
||||
/// TRACES: AR-007, AR-008, AR-024 | SR-002
|
||||
// track_alpha is the *base* weight, used on ordinary frames. It is
|
||||
// frame-dependent (AR-007): on is_cut / is_scene_boundary, and for any track
|
||||
// that is no longer on screen, it drops to 0 (embedding only), because
|
||||
// position carries no information across a viewpoint change or a gap.
|
||||
float track_alpha{0.4f}; // base cost weight: 0=embedding only, 1=spatial only
|
||||
float track_min_iou{0.1f}; // IoU below which spatial link alone is rejected
|
||||
float track_max_embed_dist{0.7f}; // cosine dist above which embedding link alone is rejected
|
||||
int track_max_frames_missing{5}; // expire track after N consecutive missed frames
|
||||
|
||||
// ── Cross-cut track re-association ────────────────────────────────────────
|
||||
// A camera-angle change (Frame::is_cut) breaks spatial (IoU) continuity but
|
||||
// not identity: the same people are usually still on screen from a new angle.
|
||||
// Instead of destroying tracks on a cut, the tracker parks them in an
|
||||
// inactive pool. A post-cut detection whose raw cosine similarity to a parked
|
||||
// track's last-frame embedding is ≥ cut_revive_sim revives that track_id
|
||||
// (identity continuity survives the cut); otherwise it starts a fresh track.
|
||||
// Parked tracks that go unrevived for cut_inactive_max_frames are dropped.
|
||||
float cut_revive_sim{0.50f}; // min raw cosine sim (last-frame emb) to revive across a cut
|
||||
int cut_inactive_max_frames{5}; // drop a parked track after N frames without revival
|
||||
// Minimum P(same person) for an association to be admissible on appearance
|
||||
// alone. This replaces track_max_embed_dist (a raw cosine distance, AR-024).
|
||||
// 0.5 is not a tuned constant: it is the decision boundary. Below it the pair
|
||||
// is more likely two people than one, and no amount of IoU makes that a link
|
||||
// worth asserting on identity grounds.
|
||||
float track_assoc_min_prob{0.5f};
|
||||
// How long a track that has gone off screen stays available for association
|
||||
// before the registry reaps it and emits its presence claim (AR-013).
|
||||
// Replaces track_max_frames_missing: a frame count silently changed meaning
|
||||
// with sample_fps, and the same number had to be guessed twice (once for an
|
||||
// ordinary miss, once for a cut). Seconds mean one thing at any sample rate.
|
||||
double track_extinction_sec{5.0};
|
||||
|
||||
// ── Scene tracking ────────────────────────────────────────────────────────
|
||||
// extinction_sec re-tuned by DE against X-Ray per-second presence, 4-film rep4
|
||||
|
||||
Reference in New Issue
Block a user