
Ball tracking
Follow the ball
to understand the play.
I've always been a proponent of the eye-test: watching games tells you more about plays and players than paper stats. At any real scale it's very expensive to watch and parse that much footage, so EyeBall automates it. It starts by following the ball. A Kalman filter stitches noisy detections into a smooth trajectory, and the shape of that trajectory tells you when passes happen. Layer in dribbles, player position, and clock state and you get actions, and from actions, plays. The same tracking also drives a synthetic broadcast camera for amateur footage, no operator required.
Case 01 -- Tight tracking
Jordan, drive to the rim.
A classic crossover-and-finish. The ball changes direction and speed twice per second and briefly disappears behind MJ's body at the rim. The system holds the trajectory through all of it. That's the starting point for any downstream analytics: if you can't follow the ball, you can't measure the play.
Case 02 -- Possession breakdown
Spurs at Houston, half-court.
One half-court possession. The system watches the ball move between players and stamps a timestamp every time the trajectory changes direction sharply enough to register as a pass. It also over-counts here -- classical CV has no way to distinguish a real pass from a crisp dribble reversal. That's the natural limitation of a ball-only signal.
Passes are a starting point, not the answer. Combine them with dribble detection, player position, and shot-clock state and you get action detection -- pick-and-roll, hand-off, off-ball screen, isolation -- and from there, play detection. That's what I'm building toward: the box score never tells you which actions actually got run.
Under the hood, no training data required: HSV + contour detection, Kalman smoothing, outlier rejection, and an angle-based pass detector with a cooldown gate.
Detection
HSV + contours
Smoothing
Two-pass Savgol + outlier rejection
Events
Angle-based pass detection
Output -- Houston half-court run
Passes detected
7
Detection rate
70%
294 / 420 frames
Clip duration
14.0s
Trajectory
4,796px
total path length
Pass timeline (seconds)
Downstream application
Broadcast amateur games
without a camera operator.
Amateur clubs and leagues don't have an efficient, cost-effective way to broadcast their games professionally. An amateur club coach in Spain reached out to me about exactly this, and the system was installed at his facility. A fixed panoramic camera records the whole court, EyeBall tracks the action and renders a synthetic 16:9 pan over it, and parents, players, and fans get professional-looking film with no human involved beyond pressing start. Motion inside a court ROI drives the pan target; Savitzky-Golay keeps the crop from jittering.
Source
Output
Engineering note
No training data? Generate it with NBA 2K.
Good labelled basketball film -- with the ball picked out on every frame -- is rare. Before classical CV got the current pipeline running, I trained the early ball-detection models on synthetic data generated from NBA 2K: realistic geometry, controllable camera, and a game engine I could produce labelled frames from on demand. Not a shortcut to production, but a legitimate proof of concept and a reliable test bed wherever a real labelled set doesn't exist yet.
Under the hood
Stack.
- DetectionHSV + contours (live); YOLO (production upgrade)
- State estimationKalman filter with outlier rejection on a speed gate
- SmoothingTwo-pass Savitzky-Golay with linear interpolation through gaps
- EventsAngle-based pass detection with cooldown + min-motion gate
- BroadcastingCourt-ROI motion envelope, Savgol-smoothed 16:9 crop
- StackPython 3.12, OpenCV 4.10, NumPy, SciPy, imutils