File size: 3,116 Bytes
1a12965
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
"""Unit tests for src.analysis.geometry_analyzer."""

from __future__ import annotations

import numpy as np

from src.analysis.geometry_analyzer import GeometryAnalyzer


def _blank_page(w: int = 400, h: int = 300) -> np.ndarray:
    return np.full((h, w, 3), 250, dtype=np.uint8)


def _draw_ink_blob(image: np.ndarray, box) -> np.ndarray:
    out = image.copy()
    x1, y1, x2, y2 = box
    out[y1:y2, x1:x2] = 30  # dark ink blob
    return out


def test_geometry_analyzer_detects_ink_inside_target_box():
    page = _blank_page()
    target_box = (100, 100, 200, 150)
    page = _draw_ink_blob(page, (120, 115, 180, 135))

    analyzer = GeometryAnalyzer()
    result = analyzer.analyze(page, target_box=target_box, canvas_size=(400, 300))

    assert result.found is True
    assert result.ink_pixels > 0
    assert result.box_coverage_pct > 0
    assert result.containment_pct > 0


def test_geometry_analyzer_reports_not_found_on_blank_box():
    page = _blank_page()
    target_box = (100, 100, 200, 150)

    analyzer = GeometryAnalyzer()
    result = analyzer.analyze(page, target_box=target_box, canvas_size=(400, 300))

    assert result.found is False
    assert result.ink_pixels == 0
    assert result.box_coverage_pct == 0.0
    assert result.polygon_overlap_proxy == 0.0


def test_geometry_analyzer_ignores_printed_rule_line():
    """A thin, wide, solid horizontal line (a printed field rule) should not register as ink."""
    page = _blank_page()
    target_box = (50, 50, 350, 70)
    page[64:66, 60:340] = 40  # printed underline: 2px tall, very wide, solid

    analyzer = GeometryAnalyzer()
    result = analyzer.analyze(page, target_box=target_box, canvas_size=(400, 300))

    assert result.found is False


def test_geometry_analyzer_full_coverage_signature():
    page = _blank_page()
    target_box = (100, 100, 200, 150)
    page = _draw_ink_blob(page, (100, 100, 200, 150))  # fills the entire box

    analyzer = GeometryAnalyzer()
    result = analyzer.analyze(page, target_box=target_box, canvas_size=(400, 300))

    assert result.found is True
    assert result.box_coverage_pct > 95.0


def test_geometry_analyzer_widens_search_with_placement_hint():
    page = _blank_page()
    target_box = (100, 100, 150, 120)
    # Ink is well outside the tight target box (simulating a misplaced signature)
    # but within the placement hint bbox used to widen the search.
    hint_bbox = (250, 100, 320, 150)
    page = _draw_ink_blob(page, (260, 110, 300, 140))

    analyzer = GeometryAnalyzer()
    result = analyzer.analyze(page, target_box=target_box, canvas_size=(400, 300), placement_hint_bbox=hint_bbox)

    assert result.found is True
    # Detected ink should be near the hint location, not the empty target box.
    assert result.signature_bbox_px[0] > 200


def test_geometry_result_no_nan_when_not_found():
    import math
    page = _blank_page()
    analyzer = GeometryAnalyzer()
    result = analyzer.analyze(page, target_box=(10, 10, 50, 30), canvas_size=(400, 300))
    assert not math.isnan(result.mean_dark_intensity)
    assert not math.isnan(result.gray_stddev)