What you will build
This YOLOv8 automatic number plate recognition tutorial covers the part many quick demos skip: a complete pipeline from data preparation to usable plate text. YOLOv8 detects the number plate; an OCR engine then reads the characters inside the detected crop. Keeping detection and recognition as separate stages makes the system easier to debug, retrain, and deploy.
The examples below use the current Ultralytics package rather than outdated train.py commands. They are suitable for a first prototype on Indian road footage, but production systems need stronger validation, privacy controls, and testing across states, plate formats, weather, camera angles, and vehicle types.
ANPR architecture
A practical system has five stages:
- Capture: Read frames from an RTSP stream, CCTV camera, dashcam, or uploaded video.
- Detection: Locate each number plate with a YOLOv8 model.
- Preprocessing: Crop, enlarge, denoise, and correct the plate perspective where necessary.
- OCR: Convert the crop into text using an OCR model or service.
- Post-processing: Validate the result, remove duplicate reads, store only required metadata, and trigger an application action.
YOLOv8 is not an OCR model. A detector can confidently find a plate while still failing to read its characters. For broader computer-vision context, compare this workflow with Python-based image recognition tutorials and production-oriented machine learning applications in Python.
Set up the environment
Use Python 3.10 or 3.11 in a virtual environment. A CUDA-enabled NVIDIA GPU will substantially reduce training and inference time, but a CPU is sufficient for small experiments.
python -m venv .venv
# Linux/macOS
source .venv/bin/activate
# Windows: .venv\\Scripts\\activate
python -m pip install --upgrade pip
pip install ultralytics opencv-python easyocr numpy pandasFor a server without a display, use opencv-python-headless instead of opencv-python. Confirm that Ultralytics can import correctly:
python -c "from ultralytics import YOLO; print('Ultralytics ready')"Choose a small model such as yolov8n.pt for a fast baseline and a larger variant when accuracy matters more than latency. Benchmark on your actual camera resolution rather than relying on published model rankings.
Prepare and annotate Indian number-plate data
Generic COCO weights do not provide a reliable plate detector. You need images representing the cameras and environments where the system will operate. Include:
- Front and rear plates, motorcycles, cars, buses, trucks, and auto-rickshaws.
- Daylight, night scenes, glare, rain, shadows, dust, and motion blur.
- Close and distant vehicles, oblique angles, partial occlusion, and crowded roads.
- Different Indian plate layouts, font rendering, state codes, commercial vehicles, and temporary plates.
Do not randomly split near-identical frames from one video across train and validation sets. That creates leakage and produces misleading metrics. Split by camera, location, journey, or recording session instead.
Annotate one bounding box per visible plate using CVAT, Label Studio, or another annotation tool. Keep labels tight but do not cut off characters. A standard YOLO dataset can look like this:
data/
images/train/
images/val/
labels/train/
labels/val/
data.yamlCreate data.yaml:
path: /absolute/path/to/data
train: images/train
val: images/val
names:
0: number_plateAudit labels before training. Missing plates, boxes around the entire vehicle, and inconsistent treatment of blurred plates are common causes of poor results.
Train the YOLOv8 plate detector
Start from pretrained weights and fine-tune them on your annotated data:
yolo detect train \\
model=yolov8n.pt \\
data=data.yaml \\
epochs=80 \\
imgsz=640 \\
batch=-1 \\
device=0 \\
project=runs/anpr \\
name=plate-detectorAdjust imgsz when plates are small in the source image. Increasing it can improve recall but raises memory use and latency. Track training and validation loss, precision, recall, and mAP. Do not select a model on mAP alone: for ANPR, a missed plate and a confidently misread plate can have very different operational consequences.
Validate the best checkpoint:
yolo detect val \\
model=runs/anpr/plate-detector/weights/best.pt \\
data=data.yaml \\
imgsz=640 \\
device=0Inspect false positives and false negatives visually. Measure performance separately for day/night, vehicle type, distance, and camera. If small plates are frequently missed, improve capture resolution and annotation quality before simply increasing epochs.
Detect plates in an image or video
The following Python example runs detection and saves an annotated image:
from ultralytics import YOLO
model = YOLO("runs/anpr/plate-detector/weights/best.pt")
results = model.predict(
source="road.jpg",
conf=0.35,
imgsz=640,
save=True,
device=0,
)
for result in results:
for box in result.boxes:
x1, y1, x2, y2 = map(int, box.xyxy[0].tolist())
confidence = float(box.conf[0])
print((x1, y1, x2, y2), confidence)For a stream, use stream=True and process frames incrementally. Add a tracker such as ByteTrack if the same vehicle appears across many frames. Tracking lets you aggregate several OCR readings instead of trusting one blurry frame.
Add OCR carefully
Install and initialise EasyOCR for a baseline:
import cv2
import easyocr
from ultralytics import YOLO
detector = YOLO("runs/anpr/plate-detector/weights/best.pt")
reader = easyocr.Reader(["en"], gpu=True)
image = cv2.imread("road.jpg")
result = detector(image, conf=0.35)[0]
for box in result.boxes.xyxy.tolist():
x1, y1, x2, y2 = map(int, box)
crop = image[max(0, y1):y2, max(0, x1):x2]
crop = cv2.resize(crop, None, fx=2, fy=2, interpolation=cv2.INTER_CUBIC)
readings = reader.readtext(crop, detail=1, paragraph=False)
print(readings)Remove the accidental leading space before detector if your editor flags the code block; it should align with reader. In a real pipeline, preprocess alternatives rather than assuming one threshold works everywhere. Try grayscale conversion, contrast enhancement, mild sharpening, and perspective correction. Preserve the raw crop for audit and compare OCR confidence with plate-detector confidence.
Indian plates often include spaces or separators inconsistently in OCR output. Normalise conservatively, uppercase text, remove impossible punctuation, and validate against a domain-specific pattern without inventing missing characters. If the output is uncertain, return unknown rather than storing a plausible but incorrect registration number.
Evaluate the complete system
Detection metrics are only one layer. Create a test set that the model never sees during training and report:
- Plate detection precision, recall, mAP, and IoU.
- OCR character accuracy and full-plate exact-match rate.
- End-to-end accuracy: correct plate text linked to the correct vehicle.
- False reads per hour, latency per frame, and performance at night.
- Duplicate-read rate when one vehicle remains in view.
A useful acceptance test is a fixed video set from every deployment camera. Re-run it after changes to weights, OCR, preprocessing, camera placement, or lighting. Log confidence and anonymised error categories, not unnecessary personal data.
Production and India-specific safeguards
ANPR can expose personal information and enable tracking. Define a legitimate purpose, restrict access, encrypt data in transit and at rest, set retention limits, and document who can search or export records. Blur or discard plates when an application only needs traffic counts. Obtain appropriate permissions for camera placement and follow applicable Indian privacy, security, and sectoral requirements.
For edge deployment, export and benchmark an optimised model only after accuracy is stable. Test TensorRT or ONNX versions against the original PyTorch model, because quantisation can disproportionately affect small, low-contrast plates. Monitor camera focus, exposure, dropped frames, GPU temperature, and drift in OCR confidence.
Common failure modes
- High validation scores, poor road performance: the split leaked adjacent video frames.
- Good detection, unreadable text: the camera resolution or shutter speed is inadequate.
- Many false reads at night: add night data and use temporal consensus across frames.
- Slow inference: reduce input size, sample frames, use tracking, or deploy an edge GPU.
- Incorrect vehicle association: retain track IDs and require consistent plate readings.
A robust ANPR prototype is a measured detection-plus-OCR system, not just a webcam demo. Build the baseline, inspect errors by operating condition, and improve the camera and dataset alongside the model. Builders working on adjacent identity systems can also review the face recognition library for automated attendance tracking, while teams processing Indian-language audio may find AI speech recognition for Indian regional languages useful for a broader multimodal stack.