Genz — traffic-camera event detection & accident anticipation
A two-part solution for the fixed-road-camera challenge: Part A detects and timestamps traffic events (accidents, near-misses, congestion, jaywalking, and more) in a finished video, and Part B watches a video frame-by-frame and outputs a causal, real-time accident-risk score that never looks at the future. Everything ships as a zero-training, zero-GPU, rule-based pipeline that runs on CPU out of the box, with an optional learned-detector upgrade path already wired in.
Rule-based baseline, no training data Runs on CPU Optional YOLO upgrade path 14 challenge classes, 8 implemented automaticallyTeam
Team member details below are placeholders — real names, roles, and profile links go here before submission.
[Member 1 Name]
[Member 2 Name]
[Member 3 Name]
Problem & approach
The challenge has two parts, both over the same fixed, non-moving road-camera footage:
Part A -- event detection. Given a finished video, return every
interesting event as [start_sec, end_sec, label], where the label
is one of 14 fixed classes (accidents, near-misses, wrong-way driving,
jaywalking, congestion, and so on). This is scored after the fact, so the
whole video is available at once.
Part B -- accident anticipation. Given the same video played frame by frame, output a risk score from 0 to 1 at every frame, before anything bad has necessarily happened -- and it must be causal: at frame t the model may only use frames up to and including t, never later ones. The scoring rewards catching danger a few seconds early.
or optional YOLO
dominant flow direction
in order
rebuilt frame by frame
pedestrian signalscombined with max(), then
smoothed with EMA
src/detector.py also defines an optional
YoloDetector that swaps in automatically if the
ultralytics package and a weights/yolov8n.pt
file are both present -- a learned-detector upgrade path that's wired
but not required to run.
8 classes detected automatically
Each has a concrete, per-camera-agnostic signal derived from track geometry.
- stopped_vehicle — stationary ≥10s
- congestion — ≥3 vehicle tracks mostly stationary across the road for ≥8s
- wrong_way — heading ≥135° opposed to dominant flow
- near_miss — close approach + high closing speed, then divergence, no overlap
- accident — bounding-box overlap between two tracks
- road_obstacle — static "unknown"-class blob on the road for ≥10s
- jaywalking — person-classified blob inside the road-mask polygon
- failure_to_yield — vehicle–person bounding-box overlap
6 classes not yet implemented
Documented extension points — each needs per-camera calibration data (a calibration.json) we don't have without real sample footage. They never appear in detect_events output today.
- red_light — needs a calibrated signal-state ROI
- stop_line — needs a calibrated stop-line geometry
- illegal_u_turn — needs no-U-turn zone geometry
- illegal_turn — needs lane/turn geometry
- solid_line_crossing — needs lane-marking geometry
- fire_smoke — a MOG2 motion blob carries no reliable color/texture cue for smoke
EDA of sample videos
samples/ and an EDA script (src/eda.py, to be added)
is run over them. Everything below is a structural placeholder, not
real data.
Resolution / FPS / duration per sample
| Video | Resolution | FPS | Duration |
|---|---|---|---|
| — | — | — | — |
| — | — | — | — |
| — | — | — | — |
Object count over time
Motion heatmap
Traffic density (vehicles / lane)
Results on sample videos
samples/*.mp4 and have
been run through run_submission.py. The block below is a
synthetic mockup of the intended layout only.
sample_01.mp4 — event timeline + risk curve (synthetic example)
Live demo
Runs the real solution.detect_events() from this repo's
solution.py against a video you upload, locally, on your own
machine. This is a genuine model run, not a canned animation.
Limits: .mp4 only, up to 2 minutes (120s) and 200MB. Longer or larger files are rejected with an error rather than silently truncated. This demo currently shows Part A events only — risk-curve visualization: coming soon.
| Class | Start | End | Duration |
|---|
website/demo_server.py
(a small Flask app) — see website/README.md for the two
commands to run it. Opening this file directly from disk will render the
page fine, but the "Run" button will fail to reach a server, since
there isn't one. This demo runs on your own machine; it is
not hosted anywhere publicly (see Links below).
Report
What we built
- A zero-dependency motion detector (OpenCV MOG2 + contour classification) with an optional YOLOv8 swap-in when weights are present.
- A minimal greedy IoU multi-object tracker with full per-track position history.
- A self-calibrating road model (convex hull of observed vehicle positions + circular-mean dominant flow direction), usable both offline and causally.
- A rules engine that turns finished tracks into 8 of the 14 required event classes.
- A causal risk engine (Part B) combining time-to-collision, hard-braking, and pedestrian-proximity signals with max() + EMA smoothing, calibrated so a 5s time-to-collision maps to a 0.5 score.
- This website, including a working local live-demo server.
What worked
- The zero-dependency motion detector runs entirely on CPU with no training data and no GPU.
- The causal risk engine genuinely respects the no-future-frames rule:
RiskEstimator.step()only ever sees the current frame and its own running state. run_submission.py/evaluate.pymatch the challenge's own harness and metric spec (macro F1 across IoU 0.3/0.5/0.7 for Part A; AP + alarm-F1 + mean-time-to-accident for Part B;M = 0.7*ScoreA + 0.3*ScoreB) exactly, so scoring behaves as the organizers intend.
What didn't / limitations
- No labeled data exists yet, so every threshold (stationary speed, wrong-way angle, near-miss closing speed, etc.) is hand-picked from first principles, not tuned against real ground truth.
- 6 of 14 classes (red_light, stop_line, illegal_u_turn, illegal_turn, solid_line_crossing, fire_smoke) need per-camera calibration data we don't have and are left as documented extension points rather than guessed.
- Classifying "vehicle" vs. "person" from blob size/aspect ratio alone is weak and will misclassify unusual shapes; a real detector would help a lot — the YOLO hook is already wired for exactly this upgrade.
- accident / near_miss detection relies on 2D bounding-box overlap with no depth cue, so a vehicle that merely passes close to the camera's line of sight can look like an overlap and false-positive.
Next steps
- Get real sample videos into
samples/and generate real EDA and results. - Hand-annotate a small dev set and tune thresholds against
evaluate.pyinstead of by hand. - Drop in real YOLO weights (
weights/yolov8n.pt, seeweights/download.sh) for cleaner class labels. - Calibrate stop-line / signal-state ROIs / lane geometry per camera to unlock the remaining 6 classes.
- Publicly host this demo (see Links) once the team has an account ready.
Links
- Repository TODO Team knows the URL; paste it here before submitting.
-
Model weights
The baseline ships with zero external weights (pure OpenCV + hand-written rules). An optional YOLOv8 weights file can be fetched with
weights/download.sh, but nothing in the default path requires it. - predictions_samples.json TODO Not generated yet — requires real sample videos (see EDA / Results above).