Skip to content

Read number plates, keep no plate text

anpr-pipeline finds a plate in an image or a video stream, reads it, checks it against the Turkish plate format and stores only a keyed hash of it. One pip install gives you a CLI and an HTTP and WebSocket service.

The detector finds the plate, the OCR model reads 34ABC1Z34, and the parser knows that the last block of a Turkish plate is digits, so the Z becomes a 2. The result is checked against the 81 province codes:

TR34 ABC 1234

{
"raw_text": "34ABC1Z34",
"normalized_text": "34ABC1234",
"parsed": {
"province_code": "34",
"province_name": "İstanbul",
"letters": "ABC",
"digits": "1234",
"canonical": "34 ABC 1234"
}
}

On a video stream the same plate is read on many frames. A per-character vote over the best reads settles it, and only then is it stored, as an HMAC-SHA256 hash.

Detection

A YOLOv9-t ONNX model from fast-alpr, trained on plates from more than 65 countries. Runs on a plain CPU.

OCR with confidences

fast-plate-ocr reads the cropped plate and gives a confidence for every character. It can also run on CUDA or OpenVINO.

Turkish plate rules

All 81 province codes and the NN L{1-3} N{2-4} shape. Characters that look alike, such as 0 and O, 1 and I, or 8 and B, are fixed by position.

Tracking and voting

An IoU tracker follows each plate across frames, and a majority vote per character position decides the final reading.

Privacy by default

The database holds a keyed hash, never the plate text, and old rows are deleted after 30 days. See Privacy.

Ready to run

pip install, Docker or uv. REST and WebSocket endpoints, a small web page with webcam support, Prometheus metrics and optional OpenTelemetry.

anpr-pipeline is free software under the MIT License. It started in 2022 as a YOLOv5, EasyOCR and Flask project and was rewritten in 2026. The old code is still in the repository’s legacy/ folder.