Predictive coast: LOST tracks follow damped pre-loss velocity#142
Merged
Conversation
LOST tracks were emitted with a frozen bbox and velocity=(0,0), so the controller lost all lead during occlusions and the first re-detection reported the whole gap as one frame of motion (40 px/frame for a 3-frame gap at 10 px/frame true motion) — the PTZ re-acquire whip. Upstream ByteTrack/BoT-SORT Kalman-predict lost tracks with positional velocity intact; the wrapper now does the same at its level: - _TrackRecord keeps an EMA velocity (~3-frame window) so one noisy detection can't dominate the coast direction. - LOST tracks coast their bbox along that velocity, damped to 10%/s so a wrong guess drifts at most ~half a second of pre-loss motion; centre clamped to frame bounds; box size preserved. - prev-centre follows the coast, and the re-acquire frame emits the smoothed velocity, so re-detection after a gap no longer spikes the feed-forward. Also gitignore /fable/ (local audit workspace). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Member
Author
|
Headless Mark A/B (M4 Pro, full profile, 8-cam cap, quiet machine):
No throughput/drop/id-switch regression. Note: occlusion-quality metrics (lost_event_count/reacquire) are 0 in BOTH legs — the current synthetic Mark scenario has no occlusion events (that's the designed-but-unbuilt M-A scenario from the Mark spec), so the coast improvement is evidenced by the RED-first unit tests (re-acquire spike 40→<25 px/frame) and needs the V1 real-camera walk-behind-occluder for camera-level confirmation. |
TCVinNYC
added a commit
that referenced
this pull request
Jul 3, 2026
…148) Reopens #143 (auto-closed when its stacked base merged as #142); identical change, rebased onto main — now just the R-1 commit. ## Summary Worker-side half of predictive tracking (tracker-side coast merged in #142): - `_maybe_track` publishes the **locked target's** LOST track (coasted bbox + decayed velocity); all other LOST tracks stay filtered. - `_drive_ptz_auto` follows a lost target iff `hypot(vx, vy) >= 1.0 px/frame` (`_COAST_FOLLOW_MIN_V`, module constant). Velocity decay makes it self-limiting: a mover is followed ≲1 s through occlusion then falls back to hold→coast→search; a stationary occluded subject is never followed. - Exactly one TrackInfo carries the target id during coast (no held-duplicate) — test-pinned. ## Evidence - 7 RED-first tests (tests/test_worker_coast_follow.py); focused suites re-run green after rebase. - Task review: Approved, 0 Critical/Important findings. - Headless Mark A/B (posted on #142/#143): no throughput/drop/id-switch regression; coast improvement quantified by unit tests (re-acquire spike 40→<25 px/frame); GUI/desktop validation session next. 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
velocity=(0,0); the first re-detection after an N-frame gap reported the whole gap as one frame of motion (measured 40 px/frame for a 3-frame gap at a true 10 px/frame) — no lead through occlusion, whip on re-acquire.autoptz/engine/pipeline/track.py):_TrackRecordcarries an EMA velocity (α=0.5, ~3-frame window); LOST tracks coast their bbox along per-frame-decayed velocity (decays to 10% after 1 s → bounded total drift ≈0.45 s of pre-loss motion), centre clamped to frame bounds,prev_c*follows the coast so re-acquire has no velocity spike, and the re-acquire frame emits the EMA instead of the gap-spanning diff. Matches upstream ByteTrack semantics (source-verified).Test plan
tests/test_track.py::TestPredictiveCoast— 7 new tests, written RED-first (the spike test failed with vx=40.0 before the fix).Validation gate (do not merge on CI alone)
Per project policy this changes tracker behavior → needs a Mark GUI 8-NDI A/B (lost_event_count / reacquire / id_switch vs main) and explicit approval. This PR isolates the tracker-side effect; the worker-side coast-follow (R-1) comes next and gets the real-camera occlusion walk.
🤖 Generated with Claude Code