CSC Helmet CD — Development Log

Retuning a motorcycle-helmet compliance pipeline for a gate camera where the road — and the riders on it — are often forty pixels tall.

Camera
Fixed entrance gate, CAMERA03
Source clip
1280×720 · 60 fps · 2:43
Stack
YOLOv8 · ByteTrack · OpenCV

The workflow

10 changes, in the order they were made

Config-only, in-place tuning of the existing detect → track → associate → count loop — no architecture rewrite, no retraining. Each step is an .env knob, reversible on its own.

01

Track the motorcycle first — everything else is conditional pipeline

A rider or helmet only ever matters here as an attribute of a motorcycle — never tracked as its own object. Splitting detection into motorcycle-first, rider-second, helmet-third means a frame with no motorcycle at all skips two entire inference calls, not just their results.

02

Restrict inference to the half of the frame that matters zone

On a fixed gate camera, half the view is often sky, building, or the wrong side of the road. DETECTION_ZONE crops inference to one half before the model ever sees the rest, cutting cost roughly in half and removing a source of false positives outright — drawn on-screen as a red boundary line.

03

Don't let a missed rider erase a violation counting

A motorcycle on screen is, definitionally, being ridden. If the person detector missed the rider in every frame of a track's life, the count previously read 0 riders, 0 helmets, 0 violations — silently correct-looking, and silently wrong. Flooring the rider count to at least one fixes it.

moto #2, before: riders=0 helmets=0 no_helmet=0 moto #2, after: riders=1 helmets=0 no_helmet=1

How a frame gets analyzed

Step 01's gating, drawn as the decision it actually is — the branch that determines whether two more model calls happen at all.

Frame video source Track motorcycle ByteTrack · moto class only moto found? found ≥1 Detect riders untracked pass, same model Detect helmets separate model, untracked Counted toward this motorcycle found 0 Skip entirely no rider/helmet inference cost paid
Motorcycle detection runs on every frame; rider and helmet detection only run — as two further, separate model calls — on the frames where it actually found something. A frame with no motorcycle at all never pays for either.

Input & Process

Hardware

An Example of the Configuration

Every default that changed from V5 to V6 — the rest of the pipeline (storage, upload, tracking lifecycle) is unchanged.
SettingV5V6
Modelyolov8n.ptyolov8s.pt
Inference size640px960px
Confidence / IoU0.35 / 0.500.25 / 0.45
Helmet confidence0.350.20
ByteTrack high / low / new0.50 / 0.10 / 0.600.40 / 0.05 / 0.50
Min frames to count53
Rider/helmet overlap floor0.25 (hardcoded)0.15
Min detection box area— none —9px²
Contrast preprocessing— none —CLAHE
Rider/helmet tracked by IDyes, with motorcycleno — motorcycle only
Detection regionfull framefull / half-left / half-right
Min rider assumption— none —1 per motorcycle
Dev-machine throughputn/a4.8 → 12.1 FPS (cpu → mps)