mirrash7 commited on
Commit
e46d29d
Β·
verified Β·
1 Parent(s): d4681a7

README: link Roboflow blog; refresh pipeline/detectors/deploy/accuracy

Browse files
Files changed (1) hide show
  1. README.md +81 -41
README.md CHANGED
@@ -1,7 +1,7 @@
1
  ---
2
  title: VAR Offside Visualizer
3
  emoji: πŸ₯…
4
- colorFrom: green
5
  colorTo: blue
6
  sdk: docker
7
  app_port: 7860
@@ -10,62 +10,102 @@ pinned: false
10
 
11
  # VAR-style Offside Visualizer
12
 
13
- Upload a match clip, scrub to the moment the ball is played, reconstruct selected
14
- players in 3D with SAM 3D Body, and place them on a virtual pitch with a draggable
15
- offside plane.
16
 
17
- ## Pipeline
 
18
 
19
- 1. **Upload** a video clip.
20
- 2. **Scrub** to the offside frame (slider + prev/next, frames seeked on demand).
21
- 3. **Detect** players on that frame β€” the only GPU step, cached per (video, frame, threshold).
22
- 4. **Select** the players to analyze and mark the defenders (incl. GK).
23
- 5. **Click two goal-parallel lines** (4 points) on the detected frame to fix the offside axis.
24
- 6. **Build** the 3D scene; drag the offside plane and read the OFFSIDE / NO-OFFSIDE verdict.
25
 
26
- The GPU runs once per frame (`pipeline/gpu.py`). Scrubbing, line geometry,
27
- placement, plotting, and the draggable plane are all CPU on the cached result.
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
28
 
29
  ## Code layout
30
 
31
  ```
32
  app.py Gradio UI + event wiring (CPU)
33
  pipeline/
34
- video.py frame seek/probe (CPU)
35
- gpu.py model load + reconstruct_frame ← the ONLY GPU code
36
- geometry.py vanishing point, ground fit, field frame, scene (CPU)
37
- overlay.py detection boxes + line-click drawing (CPU)
 
 
38
  ```
39
 
40
- Isolating the GPU in `pipeline/gpu.py` means moving inference to a serverless
41
- backend (Modal / ZeroGPU) later only touches `reconstruct_frame`.
42
-
43
- ## Deploy
44
 
45
- This is a **Docker SDK** Space for **dedicated GPU hardware** (A100 recommended):
 
 
 
 
 
 
46
 
47
- 1. Set hardware to an A100 tier.
48
- 2. Add a secret `HF_TOKEN` β€” a read token for an account with approved access to
49
- the gated **`facebook/sam-3d-body-dinov3`**. (Override the repo with the
50
- `SAM3D_REPO_ID` env var if you use a different checkpoint.)
51
- 3. First boot builds the image and downloads ~7 GB of weights β€” give it time.
52
- After that, the model stays warm until you pause the Space.
53
 
54
- **Cost control:** dedicated GPU bills while the Space is running, with no
55
- auto-shutoff. Pause the Space from its settings when you are not using it.
56
 
57
  ### Why not ZeroGPU?
58
 
59
- ZeroGPU allocates the GPU per call, caps call duration, enforces a daily quota,
60
- and cold-loads the ~7 GB model stack on each allocation β€” a poor fit for an
61
- interactive video-scrubbing session, and it requires the Gradio SDK (not Docker).
 
 
 
 
 
 
 
 
 
62
 
63
- ## Notes / limits
64
 
65
- - Scale comes from the reconstructed body height, so positions are approximate
66
- metres β€” good for relative offside ordering, **not** sub-10 cm officiating calls.
67
- The verdict surfaces a "too close to call" band rather than implying false precision.
68
- - The offside point currently uses the forward-most body vertex **including arms**;
69
- excluding arms (via MHR body-part labels) is planned β€” see `TODO.md`.
70
- - "Find the offside moment" is manual scrubbing; automatic pass-instant detection
71
- (ball tracking) is future work.
 
1
  ---
2
  title: VAR Offside Visualizer
3
  emoji: πŸ₯…
4
+ colorFrom: purple
5
  colorTo: blue
6
  sdk: docker
7
  app_port: 7860
 
10
 
11
  # VAR-style Offside Visualizer
12
 
13
+ Reconstruct selected players in 3D from a **single broadcast clip** and draw a
14
+ VAR-style offside line you can rotate and inspect β€” no multi-camera rig, no pitch
15
+ calibration.
16
 
17
+ <img width="600" height="338" alt="EgyptIran (1)" src="https://github.com/user-attachments/assets/b5a096dc-6085-4f6a-b586-7bbb5150e11e" />
18
+ <img width="600" height="338" alt="Iran Belg" src="https://github.com/user-attachments/assets/9090e30e-32d7-43cc-b6eb-c0b1a1b8a53a" />
19
 
20
+ πŸ“ **The story, the concept, and a walkthrough:**
21
+ [*Build a 3D Soccer Offside (VAR) System* β€” Roboflow blog](https://blog.roboflow.com/build-a-3d-soccer-offside-var-system/).
22
+ This README covers the setup, architecture, configuration, and technical detail the
23
+ blog intentionally leaves out.
 
 
24
 
25
+ ---
26
+
27
+ ## Pipeline (what each step actually does)
28
+
29
+ 1. **Upload** a clip (`gr.Video`).
30
+ 2. **Scrub** to the frame the ball is played β€” frames are seeked on demand (no bulk extract).
31
+ 3. **Goal-parallel lines** on that frame: **✨ Auto-detect** (OpenCV: grass/white-line
32
+ masks β†’ Hough β†’ vanishing-point RANSAC, proposes the two families; **↔ Flip** swaps
33
+ them) or click 4 points by hand. These fix the offside axis via the vanishing point.
34
+ 4. **Detect players (GPU)** with the selected detector β€” boxes + masks, cached per frame.
35
+ 5. **Select** players by clicking their box/silhouette (click again to deselect).
36
+ 6. **Mark defenders** (incl. GK). The offside line is drawn at the *furthest-forward*
37
+ marked defender's furthest body point, **arms/hands excluded** (via MHR keypoints).
38
+ 7. **Build** β†’ reconstruct only the selected players, place them on a shared field frame,
39
+ and render a Plotly scene with a draggable offside plane + OFFSIDE / NO-OFFSIDE verdict.
40
+ Optionally **πŸŽ₯ Generate a clean three.js scene** (gridlines, goal-direction arrow,
41
+ in-scene verdict, **Save PNG**).
42
+
43
+ ## Detectors (toggle in the UI)
44
+
45
+ | Option | Backend | Notes |
46
+ |---|---|---|
47
+ | **ViTDet (boxes)** | ViTDet-H Cascade Mask R-CNN (detectron2) | most accurate on broadcast footage; heavier |
48
+ | **RF-DETR (boxes)** | RF-DETR-Seg (Roboflow) | fast, Roboflow-native |
49
+ | **RF-DETR (segments)** | RF-DETR-Seg (Roboflow) | click silhouettes instead of boxes |
50
+
51
+ Each backend loads **lazily** β€” you only pay VRAM for the one you use. 3D reconstruction
52
+ is always **SAM 3D Body** (`facebook/sam-3d-body-dinov3`; DINOv3 backbone + MHR body model
53
+ + MoGe2 FOV estimator).
54
+
55
+ ## GPU / CPU boundary (the cost design)
56
+
57
+ The GPU is touched in **exactly two places** β€” detection and reconstruction β€” both in
58
+ `pipeline/gpu.py`, both cached per frame. Detection runs on the whole frame; the heavy
59
+ mesh reconstruction runs **only on the players you selected** (~3, not ~30). Everything
60
+ else (scrubbing, line geometry, placement, both renderers, the draggable plane) is pure
61
+ CPU on cached NumPy, so a dedicated GPU only ever does the heavy lifting.
62
 
63
  ## Code layout
64
 
65
  ```
66
  app.py Gradio UI + event wiring (CPU)
67
  pipeline/
68
+ video.py frame seek / probe (CPU)
69
+ gpu.py detectors + SAM-3D reconstruction ← the ONLY GPU code
70
+ autolines.py pitch-line detection + VP-RANSAC proposal (CPU, OpenCV)
71
+ overlay.py detection boxes / masks + line-click drawing (CPU)
72
+ geometry.py vanishing point, ground/up fit, field frame, offside, Plotly scene (CPU)
73
+ threed.py self-contained three.js scene (iframe srcdoc, CPU)
74
  ```
75
 
76
+ ## Deploy (Docker SDK Space)
 
 
 
77
 
78
+ 1. **Hardware:** a **GPU tier is required** (CPU fails at `.to("cuda")`). Comfortable
79
+ minimum β‰ˆ **L4 / A10G (24 GB)**; tested on **A100 (40 GB)**. VRAM is the limiter
80
+ (detector + SAM-3D held together) β€” using RF-DETR and selecting few players lowers it.
81
+ 2. **Secret `HF_TOKEN`:** a token for an account with **approved access to the gated
82
+ `facebook/sam-3d-body-dinov3`**. Without it the weight download 401s.
83
+ 3. First boot builds the image (compiles detectron2) and downloads ~7 GB of weights β€”
84
+ give it time. The model then stays warm until you pause the Space.
85
 
86
+ **Cost control:** dedicated GPU bills continuously with no auto-shutoff β€” **pause the
87
+ Space** when not in use.
 
 
 
 
88
 
89
+ **Config env vars:** `HF_TOKEN` (required secret) Β· `SAM3D_REPO_ID`
90
+ (default `facebook/sam-3d-body-dinov3`) Β· `RFDETR_SIZE` (default `large`; `nano/small/medium`).
91
 
92
  ### Why not ZeroGPU?
93
 
94
+ ZeroGPU allocates the GPU per call, caps duration, enforces a daily quota, cold-loads the
95
+ ~7 GB stack each time, and requires the Gradio SDK (not Docker) β€” all a poor fit for an
96
+ interactive scrubbing session.
97
+
98
+ ## Accuracy & honesty
99
+
100
+ - Scale comes from **reconstructed body height**, so positions are approximate metres β€”
101
+ good for relative offside ordering and a convincing visual, **not** sub-10 cm calls.
102
+ - **Level is onside** (offside law): any positive margin flags OFFSIDE, tagged **"(tight)"**
103
+ when within the Β±0.30 m band; orange = level / too-close-to-call on the onside side.
104
+ - Line detection **proposes** β€” you confirm/flip/redraw. A full metric homography was
105
+ tried and rejected as the default (it can be confidently wrong on sparse frames).
106
 
107
+ ## Explicitly later (see `TODO.md`)
108
 
109
+ Automatic pass-instant detection (ball tracking) Β· jersey/team auto-coloring Β· a
110
+ soccer-trained detector + field-keypoint homography (Roboflow) Β· three.js realism
111
+ (shadows / HDRI / GLB export).