File size: 2,275 Bytes
1c0c94d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
"""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"