AI license plate recognition ANPR/LPR in mobile app

BLACKSPARC.TECH is engaged in the development, support and maintenance of iOS, Android, PWA mobile applications. We have extensive experience and expertise in publishing mobile applications in popular markets like Google Play, App Store, Amazon, AppGallery and others.

Development and support of all types of mobile applications:

Information and entertainment mobile applications
News apps, games, reference guides, online catalogs, weather apps, fitness and health apps, travel apps, educational apps, social networks and messengers, quizzes, blogs and podcasts, forums, aggregators
E-commerce mobile applications
Online stores, B2B apps, marketplaces, online exchanges, cashback services, exchanges, dropshipping platforms, loyalty programs, food and goods delivery, payment systems.
Business process management mobile applications
CRM systems, ERP systems, project management, sales team tools, financial management, production management, logistics and delivery management, HR management, data monitoring systems
Electronic services mobile applications
Classified ads platforms, online schools, online cinemas, electronic service platforms, cashback platforms, video hosting, thematic portals, online booking and scheduling platforms, online trading platforms

These are just some of the types of mobile applications we work with, and each of them may have its own specific features and functionality, tailored to the specific needs and goals of the client.

Showing 1 of 1All 1735 services
AI license plate recognition ANPR/LPR in mobile app
Complex
~1-2 weeks
Frequently Asked Questions

Our competencies:

Development stages

Latest works

  • image_mobile-applications_feedme_467_0.webp
    Development of a mobile application for FEEDME
    792
  • image_mobile-applications_xoomer_471_0.webp
    Development of a mobile application for XOOMER
    671
  • image_mobile-applications_rhl_428_0.webp
    Development of a mobile application for RHL
    1097
  • image_mobile-applications_zippy_411_0.webp
    Development of a mobile application for ZIPPY
    969
  • image_mobile-applications_affhome_429_0.webp
    Development of a mobile application for Affhome
    914
  • image_mobile-applications_flavors_409_0.webp
    Development of a mobile application for the FLAVORS company
    495

ANPR/LPR License Plate Recognition in Mobile Applications

Automatic Number Plate Recognition on mobile—mature task with clear tools. Main engineering problem isn't OCR itself but the pipeline from frame capture to reliable read number: plate detection in real conditions (night, dirt, reflections, CIS non-standard fonts).

Approach Selection

Two paths by requirements:

On-device—for high-frequency scanning (parking, checkpoints) or no guaranteed internet. Models: OpenALPR (open source, supports 60+ countries including RU/BY/UA), Plate Recognizer Edge SDK, Google ML Kit Text Recognition v2 (simple standard plates).

Cloud API—Plate Recognizer API, OpenALPR Cloud, AWS Rekognition. More accurate on complex cases (non-standard angle, unclear font), better handles various CIS regions.

// iOS: on-device ANPR via Vision + custom YOLOv8 for plate detection
class LicensePlateRecognizer {

    // Step 1: plate detection via CoreML (YOLOv8n—fast variant)
    private let plateDetector: VNCoreMLModel

    // Step 2: OCR via Vision Text Recognition
    private func recognizeText(in croppedImage: CGImage,
                               completion: @escaping (String?) -> Void) {
        let request = VNRecognizeTextRequest { request, _ in
            let text = (request.results as? [VNRecognizedTextObservation])?
                .compactMap { $0.topCandidates(1).first?.string }
                .joined()
            completion(text)
        }
        request.recognitionLevel = .accurate
        request.usesLanguageCorrection = false  // disable—plates aren't words
        request.minimumTextHeight = 0.1

        try? VNImageRequestHandler(cgImage: croppedImage).perform([request])
    }

    func recognize(sampleBuffer: CMSampleBuffer) async -> PlateResult? {
        guard let pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer) else { return nil }

        // Detect plate
        let plateBBox = await detectPlate(in: pixelBuffer)
        guard let bbox = plateBBox else { return nil }

        // Crop and OCR
        let croppedCGImage = cropCGImage(pixelBuffer: pixelBuffer, rect: bbox)
        let rawText = await recognizeTextAsync(croppedCGImage)

        // Normalize and validate
        return normalizePlate(rawText)
    }
}

CIS License Plate Normalization

OCR produces raw text. For CIS plates, post-processing is critical:

struct PlateNormalizer {

    // Replace visually similar characters (typical OCR errors)
    static let ocrCorrections: [Character: Character] = [
        "0": "O",   // sometimes reversed
        "1": "I",
        "8": "B",
    ]

    // Patterns for different countries
    static let patterns: [(country: String, regex: String)] = [
        ("RU", #"^[АВЕКМНОРСТУХ]{1}\d{3}[АВЕКМНОРСТУХ]{2}\d{2,3}$"#),
        ("BY", #"^\d{4}[ABCEHIKMOPTX]{2}-\d{1}$"#),
        ("UA", #"^[АВСЕКМНРОТХBCEKMNOPTX]{2}\d{4}[АВСЕКМНРОТХBCEKMNOPTX]{2}$"#),
        ("KZ", #"^\d{3}[A-Z]{3}\d{2}$"#)
    ]

    func normalize(_ rawText: String) -> PlateResult? {
        let cleaned = rawText.uppercased()
            .replacingOccurrences(of: " ", with: "")
            .replacingOccurrences(of: "-", with: "")

        for (country, pattern) in Self.patterns {
            if cleaned.range(of: pattern, options: .regularExpression) != nil {
                return PlateResult(text: cleaned, country: country, confidence: .high)
            }
        }

        // No pattern match—low confidence, return as-is
        return PlateResult(text: cleaned, country: nil, confidence: .low)
    }
}

Continuous Video Stream Mode

For parking or checkpoint—continuous frame scanning without button tap:

// Android: CameraX + continuous analysis via ImageAnalysis
class ContinuousPlateAnalyzer(
    private val onPlateDetected: (PlateResult) -> Unit
) : ImageAnalysis.Analyzer {

    private val frameThrottler = FrameThrottler(maxFps = 5) // 5 fps sufficient
    private val consecutiveMatchThreshold = 3               // 3 consecutive same

    private val recentResults = ArrayDeque<String>(maxOf = 5)

    override fun analyze(image: ImageProxy) {
        if (!frameThrottler.shouldProcess()) { image.close(); return }

        val bitmap = image.toBitmap()
        val result = plateRecognizer.recognize(bitmap)
        image.close()

        result?.let { plate ->
            recentResults.add(plate.text)
            if (recentResults.size >= consecutiveMatchThreshold &&
                recentResults.takeLast(consecutiveMatchThreshold).all { it == plate.text }) {
                onPlateDetected(plate)
                recentResults.clear()
            }
        }
    }
}

Threshold of 3 consecutive identical results eliminates false positives on random objects resembling plates.

Timeline Estimates

On-device ANPR with Vision/ML Kit, normalization for one country, basic UI—3–5 days. Multi-country system with RU/BY/UA/KZ support, continuous video analysis, scan history, external database integration (stolen cars, clients), iOS + Android—1–2 weeks.