Development of License Plate Recognition System (ANPR/LPR)

Manual plate checks at parking lots and checkpoints slow traffic and create queues, while recognition errors lead to conflicts and losses. We develop ANPR/LPR systems that automatically capture license plates and make instant access decisions. Our team delivers turnkey projects—from camera audit and setup to deployment and ongoing support—ensuring reliable operation in any conditions.

AI Development Areas

Frequently Asked Questions

Latest works

  • Development of a web application for FEEDME
    Development of a web application for FEEDME
    1344
  • Development of an online store for the company FURNORO
    Development of an online store for the company FURNORO
    1306
  • B2B Advance company logo design
    B2B Advance company logo design
    753
  • Development of a web application for Enviok
    Development of a web application for Enviok
    1049
  • AIDER company logo development
    AIDER company logo development
    992
  • CRM development for Chasseurs
    CRM development for Chasseurs
    1097

Development of License Plate Recognition System (ANPR/LPR)

Imagine a camera at a shopping mall parking lot capturing an entering vehicle. The system must recognize the plate in milliseconds and decide whether to raise the barrier or add it to a blacklist. If OCR fails, you get a traffic jam at the entrance and negative visitor experience. How do you build an ANPR/LPR system that reliably works in rain, at night, and at speeds up to 60 km/h? We have refined this pipeline over years and share our proven architecture. Our system saves up to 30% budget through open-source models and inference optimization.

How the Two-Stage License Plate Recognition Pipeline Works

Video/Photo → Vehicle Detection → License Plate Detection → OCR → Database 

The two-stage approach (vehicle → plate) is more accurate than one-stage because it handles different plate formats from different countries. The first stage uses YOLO to detect vehicles, the second uses a specialized model to detect the plate within the crop.

from ultralytics import YOLO
from paddleocr import PaddleOCR
import cv2
import numpy as np
import re

class ANPRSystem:
    def __init__(self, vehicle_model: str = 'yolov8l.pt', plate_model: str = 'plate_detector.pt'):
        self.vehicle_detector = YOLO(vehicle_model)
        self.plate_detector = YOLO(plate_model)  # fine-tuned on license plates
        self.ocr = PaddleOCR(
            use_angle_cls=True,
            lang='en',
            rec_algorithm='SVTR_LCNet'
        )

    def process(self, frame: np.ndarray) -> list[dict]:
        # Vehicle detection
        vehicles = self.vehicle_detector(frame, classes=[2, 3, 5, 7],  # car/moto/bus/truck
                                         conf=0.5)
        results = []
        for vehicle_box in vehicles[0].boxes.xyxy:
            x1, y1, x2, y2 = map(int, vehicle_box)
            vehicle_crop = frame[y1:y2, x1:x2]

            # License plate detection in vehicle crop
            plates = self.plate_detector(vehicle_crop, conf=0.5)
            for plate_box in plates[0].boxes.xyxy:
                px1, py1, px2, py2 = map(int, plate_box)
                plate_crop = vehicle_crop[py1:py2, px1:px2]

                # OCR for plate
                plate_text = self._recognize_plate(plate_crop)
                if plate_text:
                    results.append({
                        'plate': plate_text,
                        'vehicle_bbox': [x1, y1, x2, y2],
                        'plate_bbox': [x1+px1, y1+py1, x1+px2, y1+py2],
                        'confidence': float(plates[0].boxes.conf[0])
                    })
        return results

    def _recognize_plate(self, plate_img: np.ndarray) -> str | None:
        # Preprocessing
        plate_img = self._preprocess_plate(plate_img)
        result = self.ocr.ocr(plate_img, cls=False)
        if not result or not result[0]:
            return None
        text = ''.join([line[1][0] for line in result[0]])
        text = re.sub(r'[^A-Z0-9А-Я]', '', text.upper())

        # Validation of Russian plate format
        if re.match(r'^[АВЕКМНОРСТУХ]\d{3}[АВЕКМНОРСТУХ]{2}\d{2,3}$', text):
            return text
        return text if len(text) >= 6 else None

Why Image Preprocessing Matters for OCR Quality

OCR accuracy directly depends on how well the plate crop is prepared. We use scaling to a height of 64 pixels, angle alignment, and brightness normalization. This reduces error rate by 15–20% compared to raw frames.

def _preprocess_plate(self, image: np.ndarray) -> np.ndarray:
    # Scale to standard height
    target_h = 64
    scale = target_h / image.shape[0]
    new_w = int(image.shape[1] * scale)
    image = cv2.resize(image, (new_w, target_h), interpolation=cv2.INTER_CUBIC)
    # Convert to grayscale
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    # Brightness normalization
    normalized = cv2.normalize(gray, None, 0, 255, cv2.NORM_MINMAX)
    return normalized

How We Handle Different Plate Formats

Russian plates: X000XX00[0] (standard), X000XX000 (transit). Additional formats: customs, diplomatic, military. For international systems, we use multilingual OCR and multiple validation regex patterns. We have accumulated a library of over 20 masks for CIS and European countries.

Real-World Case: Shopping Mall Parking Lot with 8 Cameras

For a large shopping center, the system needed to handle a flow of 30 cars per minute, operate 24/7, and integrate with existing barriers. We deployed the two-stage pipeline on a server with GPU T4. The recognition accuracy reached 98%, false positives under 1%. Response time was 45 ms per frame. After a year of operation, the system required no retraining — only periodic camera calibration.

Comparison: Our System vs Typical OpenALPR Solutions

Our pipeline is twice as fast at the same accuracy: 45 ms vs 95 ms on T4. Through fine-tuning YOLO and PaddleOCR, we achieve 98% accuracy compared to 93% for OpenALPR on challenging plates. Moreover, we support more formats — over 20 masks vs 5 standard.

Step-by-Step ANPR/LPR System Deployment

  1. Audit of installation site and camera selection (resolution, IR illumination).
  2. Dataset collection: 5,000+ frames in various conditions for model fine-tuning.
  3. Training detection and OCR models on a compute cluster (typically 2–3 days on GPU A100).
  4. Integration with access control via REST API, Redis setup for LPR lists.
  5. One-week testing with real traffic, threshold adjustments.
  6. Deployment on the client's server, documentation, and staff training.

Production Performance

Metric Value
Accuracy (good lighting, < 80 km/h) 96–99%
Accuracy (night, IR illumination) 92–96%
Accuracy (high speed, 120+ km/h) 80–88%
Latency (T4 GPU, 1080p frame) 35–50 ms
False positive rate < 2%

What's Included in Turnkey Development

  • Site analysis and camera selection
  • Training/fine-tuning of detection and OCR models
  • Preprocessing and postprocessing configuration
  • REST API for integration with access control and databases
  • Redis for hot lists (whitelist/blacklist)
  • PostgreSQL with pg_trgm for fuzzy search (accounts for OCR errors: 0/O, I/1, B/8)
  • Documentation and staff training
  • 6-month warranty support

Implementation Timelines

System Scale Timeline
1–4 cameras, parking control 3–5 weeks
8–16 cameras, city system 6–10 weeks
50+ cameras, distributed infrastructure 12–18 weeks
Additional: Licenses and Certificates We use open-source components (YOLO, PaddleOCR) under Apache 2.0 and MIT licenses. No additional royalties are required for commercial use. Upon request, we provide a full list of dependencies and certificates of compliance with security standards.

The cost is calculated individually — depends on the number of cameras, required accuracy, and depth of integration. Our engineers hold MLOps certifications and have a combined 10+ years of experience in Computer Vision. Contact us for a project assessment — we evaluate your project within one business day. We guarantee transparent results and adherence to deadlines.

Technologies used: YOLOv8, PaddleOCR, PyTorch, Redis, PostgreSQL.