Downloads · 30 days
0
xmichael/lpr-ocr-costa-rica
lpr-ocr-costa-rica is a image-to-text model from xmichael. Use it when you need a caption or text from an image. It is set up for onnxruntime. The card lists the license as cc-by-4.0.
<div align="center" <img src="https://www.wink.co/img/winklogo.png" width="200" alt="WINK Streaming"
Downloads · 30 days
0
Access
Public
Updated Apr 17, 2026
Repo size
4.6 MB
Likes
0
Public
Click a slice to open those files.
.onnx4.6 MB · 100%
From the Hugging Face model README
98.4% plate accuracy · 4.4MB ONNX · CTC architecture · Real-time inference
</div>A high-accuracy OCR model for reading Costa Rica license plates, developed by WINK Streaming as part of a production LPR (License Plate Recognition) system.
The model reads cropped plate images and outputs the plate text. It handles both daytime color and nighttime IR/grayscale camera feeds.
| Property | Value |
|---|---|
| Architecture | CNN (5 conv blocks) + BiLSTM (128 hidden × 2 layers) + CTC decoder |
| Parameters | 1,117,170 |
| Input | [batch, 96, 192, 1] — grayscale, NHWC, uint8 (0-255) |
| Output | [batch, 48, 38] — 48 CTC timesteps, 38 classes |
| Alphabet | 0-9, A-Z, _ (pad) + CTC blank (index 37) |
| ONNX size | 4.4 MB |
| ONNX opset | 18 (IR version 8) |
| Inference | ~5ms CPU, ~2ms GPU |
| Metric | Score |
|---|---|
| Plate accuracy (exact match) | 98.4% |
| Character accuracy | 97.8% |
| Validation set | 9,074 crops |
| Training set | 81,666 crops from 9,727 labeled detections |
Evaluated on held-out 10% split of production data from Axis & Hikvision cameras (2304×1296, color day / IR night).
AAP096)672625)O)import numpy as np
import cv2
import onnxruntime as ort
ALPHABET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ_"
BLANK = 37 # CTC blank token
def load_and_preprocess(image_path, h=96, w=192):
"""Load image, convert to grayscale, resize with aspect-preserving padding."""
img = cv2.imread(image_path, cv2.IMREAD_GRAYSCALE)
src_h, src_w = img.shape[:2]
scale = min(h / src_h, w / src_w)
new_h, new_w = int(src_h * scale), int(src_w * scale)
resized = cv2.resize(img, (new_w, new_h), interpolation=cv2.INTER_AREA)
canvas = np.full((h, w), 128, dtype=np.uint8)
y_off, x_off = (h - new_h) // 2, (w - new_w) // 2
canvas[y_off:y_off+new_h, x_off:x_off+new_w] = resized
return canvas
def ctc_decode(logits):
"""Greedy CTC decode: collapse repeats, remove blanks."""
indices = np.argmax(logits, axis=-1)
chars = []
prev = -1
for idx in indices:
if idx != prev and idx != BLANK and idx < len(ALPHABET):
chars.append(ALPHABET[idx])
prev = idx
return ''.join(chars)
def predict(session, image_path):
"""Run OCR on a plate crop image."""
gray = load_and_preprocess(image_path)
blob = gray.reshape(1, 96, 192, 1).astype(np.uint8)
logits = session.run(None, {"input": blob})[0][0] # [48, 38]
return ctc_decode(logits)
# Usage
session = ort.InferenceSession("wink-lpr-ocr-cr.onnx")
plate_text = predict(session, "plate_crop.jpg")
print(f"Plate: {plate_text}")
[batch, 96, 192, 1] NHWC format — no normalization needed, the model handles it internallyThe model outputs [batch, 48, 38] logits — 48 CTC timesteps over 38 classes:
0-9A-Z_Greedy CTC decode: Take argmax per timestep, collapse consecutive identical indices, remove blank tokens.
The model was trained from scratch on hard labels (no knowledge distillation). Training data includes both positive examples (verified plate crops) and negative examples (non-plate crops like logos, signs) to teach the model to abstain on non-plate input.
If you use this model, please cite:
@misc{wink-lpr-ocr-cr-2026,
title={WINK LPR OCR — Costa Rica License Plate Recognition},
author={WINK Streaming},
year={2026},
url={https://www.wink.co},
note={98.4\% plate accuracy CTC-CRNN model}
}
CC-BY-4.0 — free for commercial and non-commercial use with attribution.
WINK Streaming builds intelligent video infrastructure — from camera ingestion and AI-powered analytics to archival and playback. This model is part of our production LPR system.