feat: add SPEED mode with gated homography (PR 3) - #61
Open
AlexBodner wants to merge 17 commits into
Open
Conversation
Introduce pitch detection cache, speed badges, plain minimap, and Mode.SPEED. Sequence gating lives on fit_pitch_homography via HomographyGateState instead of a separate tracker class. Co-authored-by: Cursor <cursoragent@cursor.com>
Pitch detector options belong in PR3 where keypoint cache and homography-backed speed are wired. Co-authored-by: Cursor <cursoragent@cursor.com>
Keep m/s computation in speed.py, dedupe model and min-speed constants, reuse minimap transforms for gap-fill, drop unused homography helper, and document SPEED in the soccer README. Co-authored-by: Cursor <cursoragent@cursor.com>
fit_pitch_homography is ungated per-frame fit only. Temporal reproj and jump gating uses local locked/last_was_accept vars in the replay loop. Co-authored-by: Cursor <cursoragent@cursor.com>
Reuse DEFAULT_*_MODEL_ID in main.py, align pitch detector threshold API with player detector, document gate/sprint constants, and type _speed_by_tid transformer. Co-authored-by: Cursor <cursoragent@cursor.com>
Restore local PITCH_DETECTION_MODEL_PATH for legacy modes and use inline analytics model-id defaults instead of library constants. Co-authored-by: Cursor <cursoragent@cursor.com>
Goal-distance when minimap homography exists; centroid fallback for DIRECTION and missing frames. Single derive_clip_locks and apply_goalkeeper_teams router. Co-authored-by: Cursor <cursoragent@cursor.com>
Vote outfield team locks from player-class rows only, preserve pitch-based gk_lock instead of overwriting from shirt votes, and let relock respect gk_lock on goalkeeper rows. Set UMAP n_jobs=1 for stable classifier fit. Co-authored-by: Cursor <cursoragent@cursor.com>
Set random_state=0 so SigLIP shirt clustering is reproducible across renders and PR demos. Co-authored-by: Cursor <cursoragent@cursor.com>
Compute shirt-colour locks from unmutated player-class votes only; derive gk_lock and goal-defender shading separately with mutate=False. Restore derive_tracklet_team_lock for DIRECTION and drop fixed random_state seeds. Co-authored-by: Cursor <cursoragent@cursor.com>
Adapt fit stride when max_frames would leave too few samples, and classify from upper-torso jersey crops so green pitch no longer collapses clusters. Also drop accidental session.tracks dependency from PR3 (DISTANCE-only API). Co-authored-by: Cursor <cursoragent@cursor.com>
With denser short-clip sampling and torso crops, fixed UMAP/KMeans seeds keep demo renders reproducible without collapsing kit clusters. Co-authored-by: Cursor <cursoragent@cursor.com>
Drop jersey-crop sampling and fixed UMAP/KMeans seeds; use the original full-box crops and classifier setup that produced the working PR3 demos. Co-authored-by: Cursor <cursoragent@cursor.com>
This was referenced Jul 15, 2026
AlexBodner
marked this pull request as ready for review
July 17, 2026 02:40
Locks in the lab rule used by SPEED/radar locks: mean of the N most defensive players per side, then assign each GK to the nearer goal's team. Co-authored-by: Cursor <cursoragent@cursor.com>
Comparing signed left/right margins flipped sides when both agreed on orientation but the larger magnitude had the same sign (c01561_3). Co-authored-by: Cursor <cursoragent@cursor.com>
Session team_locks already builds TeamLocks via derive_gk_locks; the duplicate helper was never called. Co-authored-by: Cursor <cursoragent@cursor.com>
Session team_locks already derives outfield majority + GK locks; these wrappers were never called. Co-authored-by: Cursor <cursoragent@cursor.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
SPEEDanalytics mode: per-player ground-speed badges (m/s), direction dots, and a translucent radar minimap.goalkeeper.py): defensive-block goal sides + nearer-goal GK when minimap H exists, centroid fallback otherwise.derive_gk_locks/apply_goalkeeper_teamsonVideoTrackingSession.team_locksand replay.Demo
SPEEDon08fd33_0.mp4(full-clip render, truncated preview):All demos
Design notes for reviewers
replay_gated_transformsfor speed;gap_fill_speed_transformsfor badge display when a gated frame is rejected (so badges still show).Scope
In:
speed.py, pitch detect/cache, gated H, GK locks, SPEED wiring inmain.pyOut: distance traces (PR4), combo/ALL (PR5), goal shading draw (PR6), ball/pass (later)
Test plan
python main.py --source_video_path data/08fd33_0.mp4 --target_video_path data/renders/speed.mp4 --mode SPEED --tracker bytetrack--cache)c01561_3(regression covered by unit tests)