| """ |
| License plate OCR using EasyOCR. |
| Accepts a cropped plate image (numpy array) and returns extracted text. |
| """ |
|
|
| import re |
| import numpy as np |
| import easyocr |
|
|
| |
| _reader = None |
|
|
|
|
| def get_reader() -> easyocr.Reader: |
| global _reader |
| if _reader is None: |
| _reader = easyocr.Reader(["en"], gpu=False, verbose=False) |
| print("[OCR] EasyOCR reader initialised") |
| return _reader |
|
|
|
|
| def read_plate(crop: np.ndarray) -> str: |
| """ |
| Extract license plate text from a BGR/RGB crop. |
| |
| Returns: |
| Cleaned plate string (e.g. "KA05MN1234") or "" if nothing detected. |
| """ |
| if crop is None or crop.size == 0: |
| return "" |
|
|
| reader = get_reader() |
| results = reader.readtext(crop, detail=1, paragraph=False) |
|
|
| if not results: |
| return "" |
|
|
| |
| best = max(results, key=lambda r: r[2]) |
| raw_text = best[1] |
|
|
| return _clean_plate(raw_text) |
|
|
|
|
| def _clean_plate(text: str) -> str: |
| """ |
| Normalise OCR output to uppercase alphanumeric only. |
| Common OCR confusions corrected: O↔0, I↔1, S↔5. |
| """ |
| text = text.upper().strip() |
| text = re.sub(r"[^A-Z0-9]", "", text) |
| return text |
|
|