Skip to content

feat: identify the court camera from the video instead of the filename - #91

Merged
brianle423 merged 1 commit into
mainfrom
feat/court-auto-detect
Sep 14, 2026
Merged

brianle423 merged 1 commit into
mainfrom
feat/court-auto-detect

Conversation

@brianle423

Copy link
Copy Markdown
Collaborator

Summary

Replaces the Court2 filename convention with automatic camera identification. Implemented by Codex (xhigh) from docs/superpowers/plans/2026-09-14-court-auto-detect.md, revised after real-model validation, reviewed by Claude.

  • Signal: normalized correlation of a 96x54 grayscale thumbnail of sampled startup frames against each calibration frame in backend/calibration_frames/camera_fingerprints.json (courts 2, 4, 6). Gates: best ≥ 0.75 and margin over the runner-up ≥ 0.12, both in PipelineConfig.
  • Cross-check: the court-line detector's own keypoints on the calibration frames, compared to its keypoints on the video; recorded as keypoint_agrees, never overrides the decision. (Hand-marked calibration keypoints turned out unusable as fingerprints: the detector sits ~110 px from them with the same ranking on every input.)
  • Fallback order: explicit config.camera_id → auto-identify → filename hint → detected homography. Nothing is worse than today on unknown footage.
  • Stored: matches.camera_id, matches.camera_match (migration 20260914_add_camera_id.sql; a missing column only logs) and returned as cameraId / cameraMatch by GET /api/recordings/[id].
  • Tooling: python3 -m backend.tools.identify_camera <video|image>... prints both signal tables. backend/README.md documents the gates and how to register a new court.

Validation (real model, CPU)

input decision NCC per court keypoint cross-check
court2.png / court4.png / court6.png itself 1.00 vs ≤ 0.66 agrees
St Mary's court-2 clip court 2 0.93 / 0.65 / 0.49 agrees (18 px vs 29)
calibration_frames/videos/test2.mov court 2 0.84 / 0.64 / 0.41 agrees (16 px vs 34)
calibration_frames/videos/test3.mp4 none (too_low) 0.42 / 0.34 / 0.27 n/a

Test plan

  • 112 backend tests pass with the project requirements (camera identify, rallies, storage upload, reaper)
  • tsc clean
  • Apply supabase/migrations/20260914_add_camera_id.sql in the SQL editor (optional; code tolerates its absence)
  • modal deploy backend/app.py from a checkout that has backend/weights/, then reprocess one recording and check the [Camera] identified= log line

Courts 2, 4, and 6 are recognized by normalized correlation of a 96x54 grayscale
thumbnail against each calibration frame (gates 0.75 absolute, 0.12 margin), with the
court-line detector's own keypoints on those frames as a recorded cross-check. Fallback
order: explicit config.camera_id, auto-identify, filename hint, detected homography.
The decision is stored on matches.camera_id / camera_match (migration included; a
missing column only logs) and returned by the recording API.

Validated with the real model on CPU: the three calibration frames identify themselves at
1.00, the St Mary's court-2 clip scores 0.93 vs 0.65, test2.mov resolves to court 2 at
0.84, and off-court footage is rejected at 0.42.
@vercel

vercel Bot commented Sep 14, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
courtcheck Ready Ready Preview Sep 14, 2026 11:08pm UTC

@brianle423
brianle423 merged commit 79b3203 into main Sep 14, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant