← All projects

Padel Video Tracker

Upload a padel match filmed from behind the court and get back an annotated video, player heatmaps, distance, speed, time at the net and rally stats, from a GPU computer-vision pipeline.

Match insights with active play, rallies and rally length, then Team 1's net dominance, side balance and two player heatmaps with distance, speed, shots and errors
Match insights and heatmaps · the video frame is left out

The short version

pipeline stages
9
ball recall, badged on every figure
47–56%
total GPU spend while building it
£0.48

What it is

You give it a match filmed from a fixed camera behind the court and it gives you back a video with every player marked in their team colour, a fading ball trail and a live minimap, plus the stats: distance, speed, heatmaps, time at the net, rallies and shots.

It runs end to end on real footage. The results page groups players by team and shows where each one actually stood.

What I had to steer

Two rules: keep GPU spend tiny, and never present a number as more certain than it is. Every run was a short clip with a cost estimate first, against a £10 cap. When top speed came back at exactly 36 km/h for two players, that was the speed clamp in the code, not a measurement, so the page says so.

The ball tracker misses about half the frames, so every figure that depends on the ball carries a badge.

What I wired together

Next.js on Vercel with Neon Postgres and Cloudflare R2 for multipart video uploads. The pipeline is Python on Modal T4 GPUs: YOLO11 and ByteTrack for players, a tennis-trained TrackNet for the ball, an OpenCV homography from pixels to court metres, and a calibration screen where you click the court corners. Webhooks report progress back to the app.

Where I pushed it

Measuring instead of assuming. The plan for better ball tracking was to zoom in at full resolution so the ball looked bigger. I tested it on 398 missed frames and it recovered 3. A modest 1.5 to 1.75 times zoom recovered 54, so that's what shipped. The measurement overturned the plan, which was the point of measuring.

The build log

From footage to heatmaps

Most padel clubs now record matches on a fixed camera behind the court. I wanted to know what you could pull out of that footage with off-the-shelf computer vision and a small budget.

The pipeline runs in stages on a rented GPU: ingest the clip, skip the dead time between points, calibrate the court, track the players, track the ball, fuse it all into court coordinates, detect events, work out the stats and render the annotated video. The web app handles uploads, starts the job and shows progress as each stage reports back.

The first real run took a 77-second clip, found 7,308 player positions, collapsed 15 tracker IDs into the four real players and rendered the video for about 2p of GPU time. Automatic court detection declined to guess on broadcast footage, which was the right call, so I added a screen where you click the court corners. Once calibrated, the stats looked physically sensible: 65 to 135 metres covered in 77 seconds.

Then the ball. TrackNet was trained on tennis and found the padel ball in about half the frames. The plan was to crop in at full resolution so the ball would look twice as big. I measured it on 398 missed frames: the planned setting recovered 3, the worst of six options. A modest zoom recovered far more, because the network had learned the ball at one size. Running two zoom levels and a ballistic gap-filler is what shipped.

Ball recall is still the limit, between 47% and 56% across three test clips, and the results page badges every shot-based figure. The screenshots show the stats and heatmaps only. The test clips include professional broadcast footage, so I’ve left the video frames out.