arrow_back Back to Projects
Production Live

Automatic Number Plate Recognition System

Real-Time ANPR for Chiang Mai Provincial Office

location_on Chiang Mai Provincial Office

Python FastAPI YOLOv8 EasyOCR OpenCV SQLite WebSocket CUDA Tailwind CSS

This project is an AI-powered system for real-time vehicle license plate recognition, developed for Chiang Mai Provincial Office. The system accepts simultaneous feeds from multiple cameras, detects vehicles, reads license plates, stores records, and streams live results to a web dashboard — all running on-premises with no external cloud dependency.

The system is specifically designed for Thai license plates, covering all 77 provinces including special plate formats such as taxi plates, with an intelligent OCR correction engine that understands the unique characteristics of Thai characters and digits that are commonly confused.

videocam

Multi-Camera Real-Time

Supports multiple simultaneous cameras — RTSP, USB, Screen Capture — with Auto-Reconnect.

smart_toy

Two-Stage AI Detection

YOLOv8m detects vehicles → YOLOv8m locates the license plate, accelerated with NVIDIA CUDA.

document_scanner

Two-Zone OCR

Splits each plate into 2 zones: letters + digits (top) and province (bottom), with Multi-Pass Preprocessing.

spellcheck

Thai Plate Validator

Regex + Fuzzy Matching for all 77 provinces + 8-rule character correction table.

palette

Vehicle Color Detection

Detects 9 vehicle colors using OpenCV HSV Histogram Analysis.

filter_list

Smart Deduplication

TTLCache with 500 entries prevents the same plate from being recorded twice within 30 seconds.

notifications

Discord Webhook

Instant alerts with image attachments on every detection, sent via Async HTTP.

schedule

Auto Data Retention

APScheduler automatically purges old records every night at 02:00 (configurable).

Backend
Python FastAPI Uvicorn APScheduler
Database
SQLite SQLAlchemy 2.0 aiosqlite
AI / CV
YOLOv8m EasyOCR PyTorch + CUDA OpenCV Pillow NumPy
Frontend
Jinja2 Tailwind CSS WebSocket JavaScript
Networking
httpx websockets python-multipart huggingface-hub

10-Step Detection Pipeline

  1. 1 Detect vehicles using YOLO (Vehicle Model — COCO)
  2. 2 Detect vehicle color via HSV Histogram Analysis
  3. 3 Detect license plate within the vehicle bounding box
  4. 4 Crop the license plate region from the frame
  5. 5 Read characters with EasyOCR Two-Zone + Multi-Pass preprocessing
  6. 6 Validate and correct result with Thai Plate Validator
  7. 7 Check Deduplication Cache
  8. 8 Save plate crop image and full frame snapshot
  9. 9 Write record to SQLite Database
  10. 10 Broadcast via WebSocket + send Discord Webhook

Threading Model

The system uses a Producer-Consumer Multi-Threading model: one Camera Thread per camera → Frame Queue → Frame Router → Shared Detection Queue → Detection Workers × 2 → FastAPI Async Event Loop (DB + WebSocket Broadcast)

Parameter Default Value Unit
OCR Confidence 60 %
Plate Confidence 50 %
Frame Skip 5 frames
Dedup TTL 30 seconds
Data Retention 30 days
Detection Workers 2 threads
Province Database 77 provinces
OCR was inaccurate on Thai license plates expand_more
Built a Thai Plate Validator with an 8-rule character correction table + Regex patterns that understand Thai plate structure + Fuzzy Matching for province names.
Thai province text is too small for OCR to read reliably expand_more
Isolated the bottom zone clearly, applied aggressive upscaling, and ran 8 preprocessing variants — selecting the result with the highest confidence score.
Multiple simultaneous cameras blocked the async event loop expand_more
Designed a threading architecture that offloads Camera Threads and Detection Workers from the Event Loop, connected via Thread-safe Queues.
Thai text could not be rendered on images with OpenCV expand_more
Used Pillow + THSarabunNew.ttf to render Thai text onto a NumPy array, then converted it back to OpenCV BGR format.
The same plate was being recorded hundreds of times per minute expand_more
Implemented a TTLCache keyed on (camera_id, plate_text_clean) with a 30-second TTL — skipping duplicate records immediately.