File size: 7,006 Bytes
4f5a43e 6ec2b63 50bdc0c 4f5a43e 50bdc0c 4f5a43e 7684c9c 4f5a43e 7684c9c 4f5a43e 7684c9c 4f5a43e 7684c9c 4f5a43e 7684c9c 4f5a43e 7684c9c 4f5a43e 7684c9c 4f5a43e 7684c9c 4f5a43e 7684c9c 4f5a43e 50bdc0c 7684c9c 4f5a43e 7684c9c 4f5a43e 7684c9c 4f5a43e 7684c9c 4f5a43e 7684c9c 65362c9 7684c9c 4f5a43e 7684c9c 4f5a43e | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | ---
license: mit
language:
- fa
library_name: onnxruntime
pipeline_tag: image-to-text
tags:
- alpr
- license-plate-recognition
- ocr
- persian
- farsi
- iranian-license-plate
- crnn
- ctc
- yolo
- onnx
- object-detection
---
<p align="center">
<img src="https://huggingface.co/Dibachain/Platrix/resolve/main/banner.png" alt="Platrix" width="100%" />
</p>
# Platrix — Iranian License-Plate Recognition Models
Production ONNX models for detecting and reading **Iranian vehicle license
plates**, powering the [**Platrix**](https://github.com/AliAkrami1375/Platrix)
real-time, self-hosted plate-surveillance system.
> 📦 **Code & full pipeline:** https://github.com/AliAkrami1375/Platrix
> 🤗 **This model repo:** https://huggingface.co/Dibachain/Platrix
The pipeline is **two-stage**: a YOLO **detector** locates the plate in the
frame, an image-quality **enhancement** step cleans the crop, then a
segmentation-free **CRNN + CTC reader** reads the whole plate at once and returns
the standard Iranian layout `DD L DDD DD` (two digits · letter · three digits ·
two-digit region), e.g. `۸۱ و ۶۳۸ ۱۳`.
All models run with **ONNX Runtime** — no PyTorch or TensorFlow needed at
inference time.
---
## 📊 Performance
Measured on **220 real Iranian surveillance photos** (grayscale gate/road
cameras — the hard, real-world domain, not staged shots).
<p align="center">
<img src="https://huggingface.co/Dibachain/Platrix/resolve/main/assets/benchmark.png" width="88%" />
</p>
A lightweight **secondary detector** runs only when the primary finds nothing.
It recovers plates the primary is blind to — trucks, night shots, small/far and
dim plates — lifting the end-to-end read rate from **95.9% → 97.7%** with **no
regression** on the easy majority (the fallback fires on only ~2% of frames).
<p align="center">
<img src="https://huggingface.co/Dibachain/Platrix/resolve/main/assets/recovery.png" width="70%" />
</p>
### Training curves
<p align="center">
<img src="https://huggingface.co/Dibachain/Platrix/resolve/main/assets/reader_training.png" width="49%" />
<img src="https://huggingface.co/Dibachain/Platrix/resolve/main/assets/detector_training.png" width="49%" />
</p>
The reader reaches ~93% whole-plate accuracy in training and **~98% on real
photos**; the detector reaches **mAP@0.5 ≈ 0.99** on held-out real frames.
---
## 📁 Files
| File | Role | Input | Output |
|------|------|-------|--------|
| `plate_yolo.onnx` | **Plate detector** (YOLOv8, primary) | `1×3×H×W` RGB, letterboxed, `/255` | `1×5×N` → `cx,cy,w,h,conf` |
| `plate_yolo_fallback.onnx` | **Secondary detector** — runs only when the primary finds nothing; recovers hard surveillance frames | `1×3×640×640` | `1×5×N` |
| `ocr_crnn.onnx` | **Whole-plate reader** (CRNN+CTC) — *recommended* | `1×1×32×128` grayscale, `/255` | `1×T×(C+1)` logits (CTC, blank = last) |
| `ocr_crnn.labels.json` | Class list for the CRNN (index → character) | — | 32 classes |
| `ocr_cnn.onnx` | Per-character classifier (lightweight fallback reader) | `1×1×32×32` grayscale | class logits |
| `ocr_cnn.labels.json` | Class list for the per-char classifier | — | — |
**Character set (32 classes):** digits `0–9` and the Persian plate letters
`ا ب ت ث ج ح د ز س ش ص ط ع ق ل م ن ه و پ ژ ی`.
---
## 🚀 Getting started
### Option A — Run the full Platrix system (recommended)
The complete app (web dashboard, multi-camera streaming, watchlists, API) lives
in the GitHub repo. It downloads these models for you.
```bash
git clone https://github.com/AliAkrami1375/Platrix.git
cd Platrix
# fetch the models from this repo into ./models
pip install -U "huggingface_hub[cli]"
huggingface-cli download Dibachain/Platrix \
plate_yolo.onnx plate_yolo_fallback.onnx \
ocr_crnn.onnx ocr_crnn.labels.json ocr_cnn.onnx ocr_cnn.labels.json \
--local-dir models/
# then either:
docker compose up --build # Docker
# — or —
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt && pip install -e .
platrix serve # dashboard at http://localhost:8080
```
### Option B — Use the models directly (ONNX Runtime)
```bash
pip install onnxruntime opencv-python-headless numpy
huggingface-cli download Dibachain/Platrix \
plate_yolo.onnx plate_yolo_fallback.onnx ocr_crnn.onnx ocr_crnn.labels.json \
--local-dir models/
```
```python
import json, cv2, numpy as np, onnxruntime as ort
# --- Reader (CRNN + CTC) ---
labels = json.load(open("models/ocr_crnn.labels.json", encoding="utf-8"))
blank = len(labels) # CTC blank is the last index
crnn = ort.InferenceSession("models/ocr_crnn.onnx", providers=["CPUExecutionProvider"])
def read_plate(plate_bgr):
g = cv2.cvtColor(plate_bgr, cv2.COLOR_BGR2GRAY)
g = cv2.resize(g, (128, 32)).astype(np.float32) / 255.0 # 1x1x32x128
logits = crnn.run(None, {"input": g[None, None]})[0][0] # T x (C+1)
ids, out, prev = logits.argmax(1), [], -1
for i in ids: # greedy CTC decode
if i != blank and i != prev:
out.append(labels[i])
prev = i
return "".join(out)
```
**Two-stage flow:** run `plate_yolo.onnx` first (standard YOLOv8 letterbox
pre-process + confidence/NMS post-process) to crop the plate, then pass the crop
to `read_plate`. If the primary detector returns nothing, run
`plate_yolo_fallback.onnx` at **640×640** as a second pass — it recovers the hard
surveillance frames the primary is blind to. A few **real test photos** ship
under [`img-test/`](./tree/main/img-test) so you can try it immediately.
---
## 🧠 How it works
1. **Detect** — YOLOv8 locates the plate; weak/non-plate boxes are ignored.
2. **Enhance** — the crop is upscaled, denoised, contrast-corrected and sharpened.
The *same* enhancement is applied during training, so there is no train/serve
mismatch — the enhancement genuinely helps instead of shifting the input.
3. **Read** — the segmentation-free CRNN reads the whole plate in one pass with a
CTC head. It is trained on **real Iranian plate-character shapes**, so
look-alike glyphs (e.g. the digit `۴` vs `۶`) are read correctly.
Splitting a plate into individual characters is fragile on real photos (shadows,
motion blur, tilt, dirt); reading the entire plate at once is far more robust.
---
## Intended use & limitations
- **Intended for** lawful applications such as parking management, access
control, gate automation and traffic analytics.
- **Optimised for** standard private Iranian plates. Very low-resolution,
heavily occluded or non-standard plates may reduce accuracy.
- You are responsible for complying with the privacy and surveillance laws that
apply to your deployment.
---
## Links
- **Project & full pipeline:** https://github.com/AliAkrami1375/Platrix
- **License:** MIT
|