AI & Computer Vision, lesson 28 of 52

Field Trip 1: Capturing Football Data on a Real Pitch

intermediate24 min read

Introduction

Today the classroom becomes a football field. With your Field Collection Brief from lesson 15, your team sets up a laptop and webcam beside a real pitch and collects a dataset of players, the ball, goals and the empty pitch. The skill isn't just pressing record: it's noticing what's going wrong and fixing it while you're still there.

By the end of this trip you'll be able to:

  • Carry out a data collection plan they wrote themselves, in real conditions
  • Work in the roles from the field brief (Operator, Class Manager, Spotter, Logger and Reviewer)
  • Change camera positions to create several sessions per class
  • Use field_check.py to find what is missing while they are still at the field
  • Follow the consent and privacy rules they wrote (lesson 14)
  • Adapt when something goes wrong, and record what happened
  • Back up the data and write a short trip report

Working principle

The plan is the plan, until it isn't

The approved brief says what to do. At the field the sun, the wind and the players will change things. The skill today is to notice (the on-screen blur number, the accept rate, the log) and adjust (a different angle, a lower threshold, a break in the shade) while keeping the rules you wrote.

Sessions make the dataset useful

Each time you change the camera position, press N to start a new session. In lesson 13 we will keep whole sessions together in one split, so we need several sessions per class. A target of 80 ball frames from a single position is much less useful than 80 from four positions.

Check while you can still fix it

The most expensive discovery is "we have no goal photos" back in the classroom. So at the halfway point, and again at the end, the Logger runs field_check.py and the team reacts.

The consent rules from lesson 14 apply at the field. Signed forms for every child in frame. The camera points at the pitch and not the stands. If anyone objects, stop, delete their frames and move. Your teacher or team leader carries the list.

What you'll need

  • Your approved Field Collection Brief (lesson 15)
  • A charged laptop, a webcam on a stand, and capture.py set to your field settings
  • field_check.py (below)
  • Water, a hat and sunscreen

Preparation

Team checklist (the day before)

DoneItem
☐Laptop fully charged, charger packed
☐capture.py runs. CAMERA_INDEX tested with the webcam you will use.
☐Settings changed to the field configuration in the brief (blur threshold, interval, minimum difference, targets, DATASET_ROOT)
☐Webcam fixed to a stand, with a long USB cable if needed
☐A phone or tablet to watch the log, and to take photos of camera positions
☐field_check.py on the laptop, with the TARGETS edited to match the brief
☐Brief printed. Role cards printed. Names written on them.
☐Spare storage space: at least 2 GB free
☐Water bottle, hat, sunscreen, comfortable shoes

Plan for the day

A suggested 2-hour schedule. Adjust to your pitch and light.

TimeWhat happensWho
0:00 to 0:10Arrive, safety talk, agree where you may stand. Re-read the privacy rules.Everyone
0:10 to 0:25Set up at Position A. Test the camera. Check the blur number on a still scene. Confirm roles.Teams
0:25 to 0:50Position A: capture player and goal. Press N at the start.Teams
0:50 to 1:00Move to Position B (a different angle and distance). Press N.Teams
1:00 to 1:15Checkpoint 1: run field_check.py. Decide what the second half must fix. Rotate roles. Water and shade.Logger
1:15 to 1:35Position B or C: ball-focused capture during set pieces, close range. Press N at each move.Teams
1:35 to 1:45Background: empty pitch sections, no players. Press C to change class.Teams
1:45 to 1:55Checkpoint 2: run field_check.py again. Fill in any gaps. Back up.Logger
1:55 to 2:10Pack up, copy the dataset folder to a second place, count equipment, head count, leave no litter.All

Roles (from lesson 15)

RoleAt the field
OperatorRuns capture.py. Watches the blur score. Presses SPACE. Says when a class target is reached.
Class ManagerOwns every class change. Checks the class name in the banner before each burst.
SpotterWatches the action and calls moments ("corner kick, get the ball!"). Keeps people out of the way of the camera.
Logger and ReviewerRuns field_check.py, photographs each position, keeps the consent list, notes problems and weather.

Rotate roles at Checkpoint 1 so everyone has a turn at the laptop.

Field tools

field_check.py: are we on track?

Put this in the folder that contains your DATASET_ROOT. Edit TARGETS to match your brief. Run it with python field_check.py field_trip_1, using the root folder name from capture.py. It reads the CSV log that capture.py writes (lesson 11), so it needs no camera.

import csv
import os
import sys
from collections import Counter, defaultdict
 
ROOT = sys.argv[1] if len(sys.argv) > 1 else "field_trip_1"        # DATASET_ROOT in capture.py
TARGETS = {"player": 80, "ball": 80, "goal": 40, "background": 40}   # copy these from your approved brief
MIN_ACCEPT_RATE = 0.40
MIN_SESSIONS_PER_CLASS = 3
 
log_path = os.path.join(ROOT, "capture_log.csv")
if not os.path.exists(log_path):
    raise SystemExit(f"No log at {log_path}. Is DATASET_ROOT right?")
 
with open(log_path) as f:
    rows = list(csv.DictReader(f))
 
tries = len(rows)
kept = [r for r in rows if r["accepted"] == "True"]
print(f"Attempts: {tries}   Kept: {len(kept)}   Accept rate: {len(kept) / max(tries, 1):.0%}")
 
reasons = Counter(r["reason"] for r in rows if r["accepted"] != "True")
if reasons:
    print("Rejected because:", ", ".join(f"{k} {v}" for k, v in reasons.most_common()))
 
sessions = defaultdict(set)
per_class = Counter()
for r in kept:
    per_class[r["class"]] += 1
    sessions[r["class"]].add(r["session"])
 
print(f"\n{'class':<12}{'kept':>6}{'target':>8}{'sessions':>10}   status")
warnings = []
for cls, target in TARGETS.items():
    n, s = per_class[cls], len(sessions[cls])
    status = "OK"
    if n < target:
        status = f"NEED {target - n} MORE"
        warnings.append(f"{cls}: {n}/{target} frames")
    if s < MIN_SESSIONS_PER_CLASS:
        status += f"  (only {s} session{'s' if s != 1 else ''}: change position!)"
        warnings.append(f"{cls}: only {s} session(s), the lesson 13 split needs variety")
    print(f"{cls:<12}{n:>6}{target:>8}{s:>10}   {status}")
 
# Do the files on disk match the log?
on_disk = Counter()
for cls in TARGETS:
    folder = os.path.join(ROOT, cls)
    if os.path.isdir(folder):
        on_disk[cls] = len([x for x in os.listdir(folder) if x.endswith(".jpg")])
mismatch = [c for c in TARGETS if on_disk[c] != per_class[c]]
if mismatch:
    warnings.append("files and log disagree for: " + ", ".join(mismatch))
 
if len(kept) / max(tries, 1) < MIN_ACCEPT_RATE:
    warnings.append(f"accept rate below {MIN_ACCEPT_RATE:.0%}: check blur number, camera shake, MIN_DIFF")
 
print("\nTOTAL KEPT:", len(kept), "(goal: 200 or more across the 4 classes)")
print("ALL CLEAR" if not warnings else "FIX BEFORE LEAVING THE FIELD:")
for w in warnings:
    print("  -", w)

It tells you, for each class: how many frames you kept, your target, and in how many sessions. It flags classes with too few frames or too few positions, and any mismatch between the files and the log.

Quality rules of thumb at the field

RuleWhy
Watch the on-screen blur number. If it is red most of the time, steady the camera or lower the threshold a little.Motion blur wastes your time
Accept rate below about 40%? Stop and change something.Otherwise you collect a lot of nothing
Press N every time the camera movesSessions are needed for the lesson 13 split
Do the ball in short, close bursts around set piecesThe ball is small and quickly gone
Capture background tooEmpty pitch teaches what "nothing" looks like
Pause (P) during stoppagesNo point saving a still scene

After the field

Data handling (same day)

  1. Copy the DATASET_ROOT folder to a second location (a USB drive, or the school drive). Do this before anything else.
  2. Run field_check.py one last time and save its output.
  3. Do not post raw images in group chats or public places (lesson 14).
  4. Upload to the labelling tool only if your charter allows it, and only with consent in place.
  5. Write the deletion date from the consent form on the folder.

Trip report: template

Each team submits one page in the the next lesson.

SectionWhat to write
1. NumbersFrames kept per class (from field_check.py), accept rate, number of sessions
2. Versus the briefWhich targets we met, and which we missed. Why?
3. What workedTwo things in our plan that helped
4. What surprised usTwo things that the brief did not predict
5. Settings we changedWhich capture.py settings we changed at the field, and why
6. ProblemsTechnical, people, or weather. What we did.
7. Consent and privacyDid any issue come up? What did we do?
8. Next timeThree changes for Field Trip 2 (lesson 39)

If it goes wrong

ErrorCauseFix
Accept rate very lowCamera shaking, strong sun, low threshold mismatchUse the stand. Check the blur number. Lower BLUR_THRESHOLD a little, as agreed in the brief.
Wrong class folderForgot to press CClass Manager checks the banner each time. Fix by moving files, then rerun the checker.
Laptop overheatsDirect sunWork in shade. Close other apps. Restart capture.py (counts rebuild from files).
Webcam not foundIndex changed, cable looseTry index 1 or 2. Reseat the cable. Check the OS camera permission.
Only one session loggedForgot NPress N now, move the camera, continue. Mention it in the report.
Frames of people who did not consentThe camera drifted into the standsDelete the frames. Reframe. Add a note to the report.
field_check.py says "No log"Wrong root folder nameUse the same DATASET_ROOT as capture.py
Out of disk spaceLarge JPEG quality, many framesLower SAVE_QUALITY a little, or free space before leaving

Try it

  • Plot a histogram of blur scores per position from the log and bring it to the report
  • Propose a better position by sketching the pitch with the camera's field of view
  • Time how long each class took to reach its target

Check what you learnt

  1. When should you press N in capture.py?

  2. Why run field_check.py halfway through the trip?

  3. A spectator objects to being filmed. What do you do?

  4. Why rotate roles at the checkpoint?

  5. What's the last thing to do before leaving?

Conclusion

In the field, the plan meets reality. Change position and start a new session often, watch the blur score and accept rate, check your class counts halfway with field_check.py, keep to the consent rules, and back the dataset up before you leave.

What next?

Next: Clean the field data & retrain. Back in the classroom, you'll clean the catch and retrain on real field data.