| """Plate normalisation + attachment to the vehicle it sits inside.""" |
|
|
| from __future__ import annotations |
|
|
| from core.graph import attach_plates |
| from core.plates import ChainPlateRecognizer, _as_conf, normalize_plate |
| from core.schemas import BBox, EvidenceGraph, Plate, Vehicle |
|
|
|
|
| def _car(vid: str, box: tuple[float, float, float, float]) -> Vehicle: |
| return Vehicle( |
| id=vid, |
| type="car", |
| bbox=BBox(x1=box[0], y1=box[1], x2=box[2], y2=box[3]), |
| confidence=0.9, |
| ) |
|
|
|
|
| def test_normalize_valid_indian_plate() -> None: |
| assert normalize_plate("up 32 ab 1234") == ("UP32AB1234", True) |
|
|
|
|
| def test_normalize_rejects_garbage() -> None: |
| cleaned, ok = normalize_plate("!!??") |
| assert ok is False |
| assert cleaned == "" |
|
|
|
|
| def test_plate_attaches_to_enclosing_vehicle() -> None: |
| g = EvidenceGraph(image_id="i", vehicles=[_car("v1", (0, 0, 100, 100))]) |
| plate = Plate( |
| text="UP32AB1234", |
| regex_ok=True, |
| confidence=0.8, |
| bbox=BBox(x1=40, y1=70, x2=70, y2=85), |
| ) |
| attach_plates(g, [plate]) |
| got = g.plate_of("v1") |
| assert got is not None |
| assert got.text == "UP32AB1234" |
|
|
|
|
| def test_plate_outside_vehicle_is_not_attached() -> None: |
| g = EvidenceGraph(image_id="i", vehicles=[_car("v1", (0, 0, 50, 50))]) |
| plate = Plate( |
| text="UP32AB1234", |
| regex_ok=True, |
| confidence=0.8, |
| bbox=BBox(x1=200, y1=200, x2=230, y2=215), |
| ) |
| attach_plates(g, [plate]) |
| assert g.plate_of("v1") is None |
|
|
|
|
| def test_as_conf_collapses_list_to_mean() -> None: |
| assert _as_conf([0.8, 0.6]) == 0.7 |
| assert _as_conf(0.5) == 0.5 |
| assert _as_conf(None) == 0.0 |
|
|
|
|
| class _Fixed: |
| def __init__(self, plates: list[Plate]) -> None: |
| self._plates = plates |
|
|
| def read_all(self, image_path: str) -> list[Plate]: |
| return self._plates |
|
|
|
|
| def test_chain_uses_primary_when_it_reads_a_plate() -> None: |
| chain = ChainPlateRecognizer( |
| _Fixed([Plate(text="UP32AB1234")]), _Fixed([Plate(text="ZZ")]) |
| ) |
| assert chain.read_all("x")[0].text == "UP32AB1234" |
|
|
|
|
| def test_chain_falls_back_when_primary_is_empty() -> None: |
| chain = ChainPlateRecognizer(_Fixed([]), _Fixed([Plate(text="MH01AA1111")])) |
| assert chain.read_all("x")[0].text == "MH01AA1111" |
|
|