# Using OpenCV camera-motion compensation to track a basketball and keep it in vertical video crops

**URL:** <https://forum.opencv.org/t/using-opencv-camera-motion-compensation-to-track-a-basketball-and-keep-it-in-vertical-video-crops/24773>\
**Category:** Projects\
**Created:** [October 21, 2026, 8:15pm UTC](https://forum.opencv.org/t/using-opencv-camera-motion-compensation-to-track-a-basketball-and-keep-it-in-vertical-video-crops/24773 "2026-10-21T20:15:01Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![ColinGPT9](https://avatars.discourse-cdn.com/v4/letter/c/9e8a1a/32.png) [@ColinGPT9](https://forum.opencv.org/u/ColinGPT9)\
**Post date:** [October 21, 2026, 8:15pm UTC](https://forum.opencv.org/t/using-opencv-camera-motion-compensation-to-track-a-basketball-and-keep-it-in-vertical-video-crops/24773/1 "2026-10-21T20:15:01Z")

</div>

I’m building Clips Kitty, a free, open-source Python application that turns basketball broadcasts into vertical highlights. I recently added a basketball pipeline and tested it on highlights from the 2026 NBA Finals.

One of the challenges was turning ball detections into a stable crop. A basketball broadcast has camera pans, fast movement, cuts and frequent false detections, so following every detected ball independently doesn’t work well.

The pipeline uses OpenCV’s `cv2.phaseCorrelate` on downscaled frames to estimate camera movement. I compensate for the camera pan before linking ball candidates into tracks, then select a plausible trajectory for each camera shot. The crop planner uses the resulting tracks and shot phases to plan the framing for the entire clip without zooming in and out.

For basketball detection, I integrated E-BARD’s YOLOv8n detector, used unmodified under CC BY 4.0:

I also implemented a fallback rim finder using HSV thresholds and morphological operations.

On a small test of 256 frames from one NBA Finals highlights package, 172 had a visible ball. Using a presence-based detection check at confidence 0.10, E-BARD found the ball in 86% of those frames at 960 px input resolution. This metric is different from the model card’s reported recall, so the results aren’t directly comparable.

More importantly, I measured the finished 9:16 renders:

- Ball inside the crop: 85/172 frames (49%) in the first version, versus 162/172 (94%) now.

- Rim visible as the ball arrived: 20/47 moments (43%) versus 46/47 (98%).

The frames were labelled by Claude vision agents. This is a small evaluation using one broadcaster, not a general benchmark, and the pipeline still struggles with certain close-ups and camera angles.

I’d be interested in feedback on the camera-motion compensation, tracking and fallback rim detection, particularly how to handle closer camera views and false positives.

Source code (AGPL-3.0): [GitHub - ColinGPT9/clips-studio: Clips Kitty: Free open-source AI video clipper. Local Opus Clip alternative (also Klap & Vizard) that turns Twitch, Kick & YouTube streams into auto-captioned Shorts, Reels, and TikToks, and can auto-post them 24/7 from a mini PC. Local AI (Ollama, Whisper): no usage or subscription fees. Or OpenRouter: a 2-hour VOD cost 11 cents in my testing. · GitHub](https://github.com/ColinGPT9/clips-studio)

The basketball feature is available in Clips Kitty 2.1.
