Year
2025
Role
System design, API and database layer, deployment
Stack
- YOLOv5
- OCR
- FastAPI
- PostgreSQL
- React
- Docker
Applied computer vision
License Plate Recognition System
A fine-tuned YOLOv5 detector coupled with OCR, wrapped in a FastAPI service and a React frontend so citizens can look up their own traffic violations. Runs at ~12 FPS.
- Developed a real-time license plate recognition system by integrating a fine-tuned YOLOv5 model with OCR for text extraction.
- Focused on system development: designed the pipeline, built REST APIs with FastAPI, managed data in PostgreSQL, and created a ReactJS-based frontend. Deployed the system with Docker for scalability and ease of integration.
- Achieved real-time processing at ~12 FPS with reliable recognition accuracy.
- Enhanced traffic management efficiency and enabled citizens to conveniently check their traffic violation records online.

- Throughput
- ~12 FPS
- end-to-end
- Pipeline stages
- 4
- detect
The problem
Vietnam's traffic enforcement runs on phạt nguội — violations recorded by camera and mailed out later. The gap is that a driver has no convenient way to find out whether a violation exists against their plate until the notice arrives. The lookup exists; the interface does not.
Pipeline
The system is four stages, each one a place where the previous stage's errors compound:
- Detection — a YOLOv5 model fine-tuned on Vietnamese plates, which differ enough from the Western plates in public datasets (two-line motorcycle plates, distinct fonts and aspect ratios) that an off-the-shelf detector underperforms badly.
- Crop and rectify — plates are photographed at an angle far more often than head-on.
- OCR — text extraction from the rectified crop.
- Lookup — normalise the string and query PostgreSQL for violation records.
My part: making it a system
The modelling was the smaller half. What I owned was turning a notebook into something deployable:
- FastAPI for the inference service, so detection and OCR sit behind one typed HTTP contract rather than being called from a script.
- PostgreSQL for the violation records, with the plate string normalised on write so that lookup is an index hit and not a fuzzy scan.
- React frontend — the public-facing half; a citizen types or photographs a plate and gets an answer.
- Docker for the whole thing, which is what makes it reproducible on a machine that is not mine.
Performance
The pipeline sustains ~12 FPS end to end, detection and OCR included. That is the number that matters for the use case: fast enough to run against a live camera feed rather than only against uploaded stills, which is the difference between a demo and a deployment.
What I took from it
The accuracy of the detector was never the bottleneck for usefulness — the interface was. A model at 95% behind a REST API that a frontend can call beats a model at 98% that lives in a notebook. Most of the engineering effort went into the boring layers, and that is where the value was.