UConn AI Club / VIDEO TRAILS Updated

YOUR PROJECT / PYTHON + VIDEO + CSV

Draw the path. Own the code.

Read a ball’s coordinates from a CSV, remember its recent positions with a deque, and draw an effect on every video frame. Then change the visual design and test your version.

The default mode renders supplied positions. The optional small-CNN experiment below learns to estimate a center from image pixels. Coordinates can come from manual labels, a simple color rule, or a model. Those methods need different evidence; the same drawing loop can use any of them.

Try it directly in your browser—no notebook download needed. Choose a video, play both views, change the effect, inspect frames and edit coordinates. If you already have the complete local workshop, the Python files are in its take-home-code folder: open them there. The download links make individual copies; they do not include the matching videos and CSV data. Use the setup check below before rendering with Python.

↑ Back to the guided route

BUILD THE LOOP

Four pieces turn data into a video.

01

Read the CSV

Use Frame as a dictionary key. Rows may be out of order or missing.

positions = load_positions(csv_path)
row = positions.get(frame_index)
02

Remember a short history

A bounded deque keeps the newest eight observations. A missing position inserts None.

history = deque(maxlen=8)
history.appendleft(point_or_none)
03

Draw on each frame

Connect adjacent valid observations. Break the line at a missing row; do not invent an unseen path.

success, image = capture.read()
draw_frame(image, history, point)
04

Write the whole video

Continue until decoding ends, using the original dimensions and frame rate.

writer.write(image)
frame_index += 1
First time using Python? Check the setup before rendering.

Browser route: no Python, terminal or notebook is required for the interactive preview. Finish the first three guided steps here.

Python route: use Python 3.10 or newer and a complete local workshop copy. A terminal is the window where you type commands. Its current folder matters: open it in take-home-code, beside render_trail.py, check_setup.py and requirements.txt. Keep the neighboring take-home-football-tracker/assets folder; that is where the videos live.

  1. Run python --version to check the interpreter. On macOS, use python3 consistently if that is your command.
  2. Run python check_setup.py. This read-only check needs no extra packages. Expect the soccer video hash to match and 179 CSV rows. It does not yet check video decoding.
  3. Install the requirements using the command below, then run python check_setup.py --decode. Expect all 179 frames at 24 fps, size 960 × 540, and in-bounds positions.
  4. Run the renderer below. Open outputs/soccer-trail.mp4 in a local video player. Compare it with the original before changing the code.

If a check fails, read its exact message before proceeding. A matching file hash confirms the supplied video identity; it does not prove the coordinate labels are accurate. The setup check writes no files, installs nothing and makes no network requests.

Run the reference from this folder

python -m pip install -r requirements.txt
python render_trail.py --video ../take-home-football-tracker/assets/single-ball.mp4 --positions data/soccer.csv --output outputs/soccer-trail.mp4 --trail-length 8

On macOS, use python3. Add --effect rock --radius 105 for a rock sticker, --effect capture for the illustrated ball, or --save-frames outputs/frames to save individual images. The reference writes all decoded frames, including frames with missing CSV positions.

↑ Back to the guided route

TRY IT NOW / INTERACTIVE BROWSER DEMO

See the data move through your loop.

Your sticker

Choose an image to use your own sticker. Transparent PNG keeps the background visible.

The image stays in this browser. Uploading selects “My image sticker” automatically. Artwork radius changes its size; the selected CSV or CNN supplies its position.

Original

Your sticker / trail

Loading the supplied CSV…

Inspect or replace the coordinate data

The required columns are Frame, Visibility, X and Y. Frame numbers start at zero and coordinates use the original video’s pixel dimensions. Visibility=0 means no point should be drawn for that frame. Source is an extra provenance column.

Frame,Visibility,X,Y,Source
0,0,,,none
1,1,120,80,example_only
2,1,124,83,example_only
3,0,,,none

The four rows above illustrate the schema only. They are not measurements for either supplied video.

Matching the video, frame numbers, resolution and frame rate is part of your project. A custom video clears old positions so a previous clip’s coordinates cannot silently carry over.

TRAIN IT HERE / THREE SMALL CNNS

Can a tiny CNN move your sticker?

Train three randomly initialized networks directly in this browser on the selected video. Each takes a 32 × 18 RGB frame and predicts two normalized center coordinates. All three use the same chronological 60% training / 20% validation / 20% test split and seed 314. The best validation epoch is kept; the final test frames are used only for the comparison table.

Download Python CNNsOptional Python CNN requirements

Select a video, then train. Everything runs locally; no model download or image upload is needed.

MethodParametersTest center errorImage diagonalTrain + evaluation

Compare with the baseline. Predicting the average training position can already work well when a ball barely moves. More layers do not guarantee a better result. Tiny B has fewer parameters than Tiny A because its second pooling step shrinks the dense layer. After training, choose a CNN under Position source above to drive the rock sticker with its actual predictions. CSV trails are hidden in CNN mode; predictions update at up to about 10 Hz.

These are center regressors trained on visible frames from one clip—not pretrained object detectors. They always output a point, including when no ball is visible. The labels are supplied coordinate estimates, so the table measures agreement with held-out CSV coordinates, not verified tracking accuracy. A new clip or edited CSV clears the trained models. Neighboring frames remain related even with a chronological split; testing on a different labeled video is a separate challenge.

See the three architectures and training objective

Tiny A: Conv(4) → MaxPool → Flatten → Dense(2). Tiny B: Conv(4) → MaxPool → Conv(8) → MaxPool → Flatten → Dense(2). Tiny C: Conv(8) → MaxPool → Conv(12) → MaxPool → Flatten → Dense(2). All convolutions use 3 × 3 kernels, same padding and ReLU; the output uses sigmoid. Adam uses learning rate 0.005. Loss is the mean squared difference between predicted and supplied normalized x/y coordinates.

target = [x / video_width, y / video_height]
loss = ((prediction - target) ** 2).mean()
optimizer.zero_grad()
loss.backward()
optimizer.step()

The downloadable Python implementation uses PyTorch. The browser version uses the bundled TensorFlow.js runtime on CPU. Their architectures match; identical weights or cross-runtime results are not promised.

READ AND CHANGE THE PYTHON

Make the result yours.

Complete the notebook’s CSV/history/frame-loop exercises, then choose a change that affects the result: fade older points, vary line width with speed, draw an original object, or compare two ways to obtain coordinates.

Download shown file
Loading Python…

Optional: create coordinates with simple color rules

The orange-ball script measures colored connected components in each frame. It is useful for this clip’s color and background, but it can confuse similar colors and lose an occluded ball. It supplies estimates, not ground truth.

python measure_orange_ball.py --video ../take-home-football-tracker/assets/ping-pong.mp4 --output outputs/my-ping-pong.csv
python render_trail.py --video ../take-home-football-tracker/assets/ping-pong.mp4 --positions outputs/my-ping-pong.csv --output outputs/my-ping-pong-trail.mp4

Show the code and the evidence

Explore the separate CNN detection demo if you want to compare a learned detector with other coordinate sources.