Skip to content
brorn
No. 003 · Sports & video

video-campo

Stitches 2 phone cameras into a pitch panorama and renders a virtual camera that follows the ball, on the GPU.

Live
Period
2026-10 → now
Platforms
Command line · Local GPU
Role
Solo: design, build, ship
Tech
Fig. 1 · Two views, one panorama · Video: SoccerTrack v2 (CC BY 4.0)
Fig. 2 · Players and ball trail · Video: SoccerTrack v2 (CC BY 4.0)
Fig. 3 · Ball-following camera · Video: SoccerTrack v2 (CC BY 4.0)

§1The problem

One phone can't capture the whole pitch. With two, you have to align them in time and in image, stitch them without a visible seam, and still decide where to point the camera with nobody operating it.

§2What I built

  • SyncThe two phones are synchronised by sound.
  • StitchingLens and angle calibration from the image, stitched into a cylindrical panorama with colour correction.
  • Virtual cameraBall detection with YOLO and a ball track; a virtual camera with zoom and smoothing that looks ahead.
  • CLIResumable stages (each stage writes its own file) and JSON progress for the apps to follow.
  • Re-renderA command to redo only the camera with a different zoom.

§3The hard parts

5 entries
  1. 01

    Speed

    The panorama went from 37-46 to about 120 frames per second; the bottleneck was the loop waiting for the GPU on every frame.

  2. 02

    Sync drift between the phones' clocks

    About 140 ppm, corrected with windows measured across the game.

  3. 03

    Parallax and seam

    Measuring the difference in the overlap band and correcting only near the seam.

  4. 04

    Numerical traps

    A lens inversion that folds over, and infinite values turning into NaN in the black bands.

  5. 05

    Orientation and encoder limits

    Each phone's orientation comes from the app's marker, not just the grass; the GPU's 4096 px H.264 limit was solved with HEVC.

§4Result

frames/s for the panorama (was 37-46)
~120
clock drift corrected between phones
~140 ppm
detection processing per game
~1h10

Runs on my own computer's GPU: the 2-camera panorama at about 120 frames/s, and detection takes about 1h10 of processing per game. Other apps call it the same way they would call ffmpeg.

§5Stack

  • Python
  • PyTorch (CUDA)
  • YOLO11 (ultralytics)
  • OpenCV (SIFT)
  • ffmpeg with NVENC
  • HEVC