I live on a narrow residential road where two vehicles physically can't pass each other — and an awful lot of trucks use it anyway. Everyone on the street knows it's bad, but "everyone knows" isn't data. So I pointed a Raspberry Pi 5 and a £17 webcam out of the window and built an AI traffic counter in a day. It watches the road 24/7, counts every vehicle, and photographs every truck — the same 7-days-including-a-weekend evidence format official traffic surveys use.
A YOLOv8-nano neural network (exported to NCNN, which is ARM-optimised — roughly 15 FPS on the Pi 5's CPU alone, no AI accelerator needed) detects vehicles in every frame. ByteTrack gives each vehicle a persistent identity from frame to frame, and the first time its centre crosses a virtual red line it's counted — once, even if the detection flickers. Every crossing lands in a SQLite database with class, direction, and confidence; trucks and buses also get a JPEG snapshot as an evidence trail. A small Flask dashboard on port 8080 shows a live annotated camera view, today's totals, an hourly heavy-vs-other chart, and the snapshot gallery. Two systemd services keep it all running for weeks unattended.
USB webcam in the window
│
▼
┌─────────────────┐
│ detect.py │ YOLOv8n · ByteTrack
│ (trafficmonitor│ counts line crossings
│ service) │
└───┬─────────┬───┘
│ │
▼ ▼
traffic.db snapshots/
(SQLite) (truck JPEGs)
│ │
▼ ▼
┌─────────────────┐
│ webui.py │ live view · charts
│ (trafficweb) │ gallery · :8080
└─────────────────┘
Everything below is in the download — no cloud, no subscriptions, nothing leaves your Pi.
Detects car / truck / bus / motorcycle / bicycle (and pedestrians, counted separately). One vehicle = one count with direction of travel, logged to SQLite with a timestamp — plus a dedup guard so tracker glitches can't double-count on a single-file road.
Open http://<your-pi>:8080 from any device on your network: live annotated camera frame, today's totals, hourly heavy-vs-other bar chart, recent events, truck snapshot gallery, disk space, and a plain-English help page explaining what the categories mean.
Every truck and bus crossing gets a full-frame JPEG saved with the timestamp in the filename. After a week you have a browsable gallery of exactly what came down the road, when — the thing that turns a complaint into a case.
report.py gives daily totals per class, hourly breakdowns for any day, and a raw CSV export for spreadsheets — handy for putting a proper chart in front of the council.
A daft bonus: if a person in hi-vis dwells in view for 25+ seconds, it logs a "warden sighting" and can ping your phone. Expect false positives from builders, binmen and couriers — it's a heuristic, and it's honest about that.
Optional alerts via a Telegram bot, or via WhatsApp using the included wa-bridge — a tiny Node service you pair to a spare number by scanning a QR code straight off the dashboard. Both entirely optional; the counter doesn't care.
Because a project page that pretends the AI is perfect is worse than useless:
Big vans count as "truck". The model is trained on COCO, where a
Sprinter-sized van and an artic are both "truck", and small vans often land in "car".
For a heavy-traffic argument that's actually conservative-ish, but a proper van/HGV
split is planned — every crossing already logs the vehicle's bounding-box size, so once
there's a week of data I can calibrate a length-based classification.
It's a daylight tool with a cheap webcam — fine for the 7am–7pm window
official surveys care about, but don't expect miracles at midnight without a better camera.
The warden spotter is a beta heuristic, not a promise. And on privacy:
pedestrians are counted but never photographed, snapshots are only taken of trucks and
buses, and everything stays on the Pi.
Official automatic traffic counts (the rubber-tube ones the council does) run for at least 7 consecutive days including a weekend, so that's the bar this is built to meet: it runs unattended for weeks via systemd, restarts itself after power cuts, writes the live preview frame to RAM to spare the SD card, and every single count is backed by a timestamped database row — with a photo for every heavy vehicle. You're not saying "it feels like a lot of lorries"; you're handing over a spreadsheet and a gallery.
No AI accelerator, no fancy camera. The Pi 5's CPU is enough for a 20–30 mph road.
| Item | Notes | Approx price |
|---|---|---|
| Raspberry Pi 5 (4GB+) | The brains. 8GB works too, 4GB is plenty. | ~£55 |
| 1080p USB webcam | Any UVC webcam. I use a ~£17 Trust TANOR from Argos — genuinely fine. | ~£17 |
| Official 27W USB-C PSU | Don't cheap out here — weak supplies brown out the Pi under AI load. | ~£12 |
| 32GB+ microSD | Weeks of events + snapshots. An SSD is nicer but not needed. | ~£8 |
| Window mount / mini tripod | Anything stable. Lens right against the glass to kill reflections. | ~£10 |
The zip contains the full source plus a bootstrap script that does the boring bits.
Use Raspberry Pi Imager, enable SSH in the imager's settings, boot the Pi and make sure you can SSH in. No desktop needed — the dashboard is how you'll look at it.
Download trafficmonitor.zip, unzip it, and copy the trafficMonitor folder to the Pi's home directory (scp -r trafficMonitor pi@<your-pi>: — or use the included deploy/push.ps1 if you're on Windows).
bash ~/trafficMonitor/scripts/bootstrap.sh — installs the apt packages (OpenCV, picamera2, sqlite3), creates a Python venv, pip-installs the requirements, and sets up the two systemd services (trafficmonitor + trafficweb). One command, go make tea.
~/traffic-venv/bin/python scripts/export_ncnn.py — downloads YOLOv8-nano and converts it to NCNN, which roughly doubles the frame rate on the Pi's ARM CPU. Do this once.
Upstairs window, looking along or across the road, lens right up against the glass. Run python src/detect.py --source 0 --show with a screen attached, or just start the service and use the dashboard's live view to aim. Tune the red count line with --line 0.6 (fraction of frame width). Frame it so vehicles take about a second to cross the view.
sudo systemctl start trafficmonitor trafficweb, then open http://<your-pi>:8080. Leave it for 7+ consecutive days including a weekend, review the first day's truck snapshots to sanity-check the classifications, then export the CSV and go be a nuisance to your council.
Full Python source, dashboard, bootstrap script, reports, and the optional WhatsApp bridge. No accounts, no telemetry, MIT-spirited — if it helps you win a traffic argument, I'd love to hear about it.