Real‑time, end‑to‑end detection and recognition of Iranian vehicle license‑plate characters using a single YOLOv11 model.
- Key Features
- Project Structure
- Quick Start
- Dataset
- Training & Validation
- Results
- Inference
- Deployment
- Benchmarks
- Troubleshooting & FAQ
- Contributing
- License
- Citation
- Contact
- One‑shot OCR – detects every plate and individual characters in one forward pass
- 5‑Fold cross‑validation ready (see
fold*.yaml) - Git LFS integrated to handle large datasets/weights (
*.pt,.npy) - Training & inference scripts for CPU/GPU and edge devices
- Supports export to ONNX, TensorRT, Core ML
- Extensive visualizations: PR curves, confusion matrices, animated demos
- MIT‑licensed – free for personal & commercial use
.
├── datasets/ # raw images + labels (not in Git) ─┐
│ └── README_DATA.md # download instructions ─┘ managed via LFS / external link
├── OCR_YOLO/ # custom YOLOv11 model cfg & anchors
├── runs/ # training logs, weights, TensorBoard
├── figs/ # result images, gif demos, PR plots
├── scripts/ # helper utilities (dataset split, download)
├── *.yaml # data configs (full + five folds)
├── Training.py # single‑split training
├── Training_fold.py # k‑fold driver
├── Test.py # inference CLI
├── requirements.txt
└── README.md # ← this file
Large archives (My Project.rar, .pt weights) have been removed from Git history – see Removing Large Files.
git lfs install
git clone https://github.com/your‑user/iranian‑lpr‑yolov11.git
cd iranian‑lpr‑yolov11python -m venv .venv
# Windows:
.venv\Scripts\activate
# Linux / macOS:
source .venv/bin/activate
pip install -r requirements.txtWe provide a helper script (needs a free Roboflow API key):
python scripts/download_dataset.py --dest datasets/Or download manually from Roboflow Universe and extract to datasets/.
# baseline (single split)
python Training.py --model yolo11n.pt --epochs 150 --imgsz 640
# 5‑fold CV
python Training_fold.py --epochs 120Training logs are written to TensorBoard (runs/exp*/)—open with:
tensorboard --logdir runs --port 6006| Item | Value |
|---|---|
| Source | Persian Plate Characters (Roboflow) |
| Images | 3 684 (3300 train / 231 val / 153 test) |
| Classes | 26 (0‑9, Persian letters) |
| Annotation | YOLO txt (xc, yc, w, h) |
| License | CC BY 4.0 |
- HSV/brightness shift
- Mosaic × 4, MixUp
- Random perspective (translate ±10%, rotate ±5°)
- Label‑smoothing = 0.0 (per class)
Augmentations are configured in OCR_YOLO/hyp.scratch.yaml.
All hyper‑parameters can be overridden via CLI:
python Training.py --batch 16 --epochs 200 --lr 0.01 --weights yolo11s.ptTraining_fold.py automatically creates an aggregated CSV (runs/folds_metrics.csv) for easy comparison.
| Component | Description |
|---|---|
| box_loss | IoU‑aware bounding‑box regression (CIoU) |
| cls_loss | BCE / focal loss on class logits |
| dfl_loss | Distribution Focal Loss – anchors width/height |
| Fold | Precision | Recall | [email protected] | [email protected]‑0.95 |
|---|---|---|---|---|
| 0 | 0.982 | 0.996 | 0.994 | 0.752 |
| 1 | 0.985 | 0.997 | 0.996 | 0.748 |
| 2 | 0.980 | 0.995 | 0.993 | 0.736 |
| 3 | 0.984 | 0.996 | 0.995 | 0.740 |
| 4 | 0.981 | 0.995 | 0.992 | 0.737 |
| Mean | 0.982 | 0.996 | 0.994 | 0.743 |
Full logs and plots live in runs/.
python Test.py --source imgs/demo_plate.jpg --conf 0.55 --save-txt --showOutputs annotated images to runs/predict/.
from ultralytics import YOLO
model = YOLO("weights/best.pt")
results = model("imgs/demo_plate.jpg", conf=0.5)
for r in results:
print(r.boxes.cls, r.boxes.xyxy) # class ids + boxes
print(r.names) # class‑id → label map| Target | Tool | Command |
|---|---|---|
| ONNX | Ultralytics | yolo export --format onnx |
| TensorRT | onnx-tensorrt |
see script in scripts/export_tensorrt.py |
| Core ML | coremltools | yolo export --format coreml |
| Raspberry Pi 5 | NNPACK / TFLite | quantize to INT8, see docs |
| Model | Size | FPS* | [email protected] | Device |
|---|---|---|---|---|
| YOLOv11‑n (ours) | 7.5 M | 94 | 0.994 | RTX 3070 |
| YOLOv5‑s | 14.2 M | 82 | 0.982 | RTX 3070 |
| LPRNet | 5.4 M | 65 | 0.903 | RTX 3070 |
* inference on 640×640 batch‑1, PyTorch 2.2
Large files exceed 100 MB – push rejected
GitHub blocks files > 100 MB. We use Git LFS. Install LFS and recommit:
git lfs install
git lfs track "*.pt" "*.npy"
git add .gitattributes
git add path/to/large_file.pt
git commit -m "track with LFS"
git pushCUDA out of memory
- Reduce
--batchsize - Use
--imgsz 416 - Enable
--cache ramonly if memory allows
Prediction string has wrong order of characters
Ensure label_map.py matches your dataset’s character order. The default map is included.
Pull requests are welcome! Please:
- Open an issue describing your feature/bug.
- Create a branch (
git checkout -b fix/bug‑foo). - Commit with conventional messages (
feat:,fix:). - Run unit tests (
pytest). - Submit a PR, filling the template.
We follow the Contributor Covenant Code of Conduct.
This project is licensed under the MIT License.
See LICENSE for full text.
If you use this repository, please cite:
@misc{najar2025persianlpr,
author = {Abolfazl Najar},
title = {Persian License‑Plate Recognition with YOLOv11},
year = {2025},
howpublished = {GitHub},
url = {https://github.com/your‑user/iranian‑lpr‑yolov11}
}| Author | Abolfazl Najar |
| [email protected] | |
| https://www.linkedin.com/in/abolfazl-najar | |
| Lab | Intelligent Power Electronics & Electric Machine Laboratory, University of Georgia |
Feel free to reach out for collaboration or questions!






