Vehicle Detection & Traffic Analysis System
Vehicle detection and traffic monitoring built from classical image processing — CLAHE contrast enhancement and morphological operations, no neural network.
- Approach
- Classical CV
- Enhancement
- CLAHE
- Segmentation
- Morphological ops
Overview
An image-processing pipeline for vehicle detection and traffic monitoring, built in MATLAB using CLAHE contrast enhancement and morphological operations to isolate and count vehicles in road scenes.
Problem
Traffic footage is hostile input. Lighting shifts across the frame, shadows read as solid objects, vehicles overlap and occlude each other, and the road surface changes brightness with weather and time of day. A fixed global threshold that works on one frame fails on the next. The constraint here was to solve it with classical techniques — no training data, no model — which means every stage has to earn its place.
Solution
A staged pipeline where each step removes one specific kind of noise. CLAHE equalises contrast locally rather than globally, so a shaded region and a sunlit region are both usable instead of one being crushed. Segmentation then separates candidate vehicles from the road, and morphological operations — opening to erase speckle, closing to seal fragmented vehicle bodies — clean the binary mask into coherent regions. Connected components become vehicle candidates, filtered by geometric properties like area and aspect ratio to discard shadows and debris before counting.
Architecture
Linear pipeline, one responsibility per stage. Tuning happens at stage boundaries, which is what makes a classical approach debuggable.
- Layer 01
Input
Frame acquisition
Road scene image / video frame
Grayscale conversion
Colour is not the signal here
- Layer 02
Enhancement
CLAHE
Local contrast, clip-limited
Noise reduction
Smoothing before thresholding
- Layer 03
Segmentation
Threshold to binary
Vehicle vs. road surface
Morphological opening
Remove speckle
Morphological closing
Fill vehicle bodies
- Layer 04
Analysis
Connected components
Candidate regions
Geometric filtering
Area + aspect ratio
Count & annotate
Bounding boxes, density
Tech Stack
Screenshots
Screenshot slot 1
Screenshot slot 2
Interface captures for Vehicle Detection & Traffic Analysis System aren’t published here yet — the architecture and decisions above are the substance. Available on request, or in the repository.
Challenges
- 01
Global contrast destroys real scenes
Standard histogram equalisation improved the frame on average and ruined it locally — blowing out sunlit asphalt while leaving shadowed vehicles unusable. CLAHE was the fix: equalise in tiles with a clip limit, so local detail survives instead of being averaged away.
- 02
Shadows look exactly like cars
A dark region attached to a vehicle is, to a threshold, part of the vehicle. Separating them meant leaning on geometry rather than intensity — filtering candidate regions by area and aspect ratio, since a shadow rarely has a vehicle’s proportions.
- 03
One vehicle, many fragments
Thresholding broke single vehicles into several blobs — windscreen, roof and bonnet segmented separately — which inflated the count. Morphological closing sealed those gaps, but tuning the structuring element was a genuine trade-off: too small and vehicles stayed fragmented, too large and adjacent vehicles merged into one.
- 04
Tuning without overfitting to one frame
Every parameter that fixed one image degraded another. The discipline was to validate each stage across varied frames rather than optimising the pipeline against a single favourable example.
Lessons Learned
- 01
Classical CV forces you to understand your data. There’s no model to absorb the messiness for you.
- 02
Local beats global almost every time — CLAHE over plain histogram equalisation is the whole lesson in one substitution.
- 03
When intensity is ambiguous, switch features. Geometry solved the shadow problem that no threshold could.
- 04
Every parameter is a trade-off with a cost on both sides. Naming that cost out loud is how you stop guessing.
Live Demo & Repository
Live demo
Not publicly hosted. Happy to walk through it live or share a recording.
Source code
View on GitHub
Want the deeper version of this?
I’m happy to walk through the code, the trade-offs, or the parts that didn’t make the write-up.