Development of License Plate Recognition System (ANPR/LPR)

We design and deploy artificial intelligence systems: from prototype to production-ready solutions. Our team combines expertise in machine learning, data engineering and MLOps to make AI work not in the lab, but in real business.
Showing 1 of 1All 1566 services
Development of License Plate Recognition System (ANPR/LPR)
Medium
~3-5 days
Frequently Asked Questions

AI Development Areas

AI Solution Development Stages

Latest works

  • image_website-b2b-advance_0.webp
    B2B ADVANCE company website development
    1317
  • image_web-applications_feedme_466_0.webp
    Development of a web application for FEEDME
    1226
  • image_websites_belfingroup_462_0.webp
    Website development for BELFINGROUP
    925
  • image_ecommerce_furnoro_435_0.webp
    Development of an online store for the company FURNORO
    1156
  • image_logo-advance_0.webp
    B2B Advance company logo design
    620
  • image_crm_enviok_479_0.webp
    Development of a web application for Enviok
    894

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 free 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.