File size: 2,557 Bytes
ba4abf7
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
"""
Lightweight validation for the change detection pipeline.
Run from change_detection_webapp: python scripts/validate_detection.py
"""
import sys
from pathlib import Path

import numpy as np
from PIL import Image

ROOT = Path(__file__).resolve().parent.parent
sys.path.insert(0, str(ROOT))

from app.detection_engine import (  # noqa: E402
    register_images,
    run_detection,
    fuse_dl_and_classical,
)


def test_registration_identical_pair():
    rng = np.random.default_rng(42)
    img = rng.integers(0, 255, (320, 320, 3), dtype=np.uint8)
    b, a, ok, meta = register_images(img, img.copy())
    assert meta.get("ncc", 0) >= 0.5 or ok, f"weak NCC on identical pair: {meta}"
    print("  registration identical pair:", ok, meta)


def test_registration_with_shift():
    img = np.zeros((400, 400, 3), dtype=np.uint8)
    img[80:200, 80:200] = [180, 90, 60]
    shifted = np.roll(np.roll(img, 8, axis=0), 5, axis=1)
    b, a, ok, meta = register_images(img, shifted)
    print("  registration shifted pair:", ok, "ncc=", meta.get("ncc"))


def test_fusion_shapes():
    h, w = 128, 128
    dl = np.zeros((h, w), dtype=np.float32)
    dl[40:80, 40:80] = 0.8
    cl = np.zeros((h, w), dtype=np.float32)
    cl[50:90, 50:90] = 0.7
    img = np.full((h, w, 3), 128, dtype=np.uint8)
    mask, score, dbg = fuse_dl_and_classical(dl, cl, img, img, sensitivity=0.5)
    assert mask.shape == (h, w)
    assert score.shape == (h, w)
    assert dbg.get("fused_changed_px", 0) >= 0
    print("  fusion:", dbg.get("fused_changed_px"), "px")


def test_run_detection_synthetic():
    rng = np.random.default_rng(0)
    before = rng.integers(0, 255, (256, 256, 3), dtype=np.uint8)
    after = before.copy()
    after[100:180, 100:180] = [40, 180, 40]
    mask, _, stats, regions = run_detection(
        Image.fromarray(before),
        Image.fromarray(after),
        method="AI-Based Deep Learning",
        enable_registration=True,
        enable_normalization=True,
        detection_sensitivity=0.5,
    )
    assert mask.shape[:2] == (256, 256)
    ratio = stats["change_percentage"]
    assert 0 <= ratio <= 100
    assert "params" in stats
    assert not stats.get("threshold_debug", {}).get("fallback_used", False)
    print("  run_detection: change%=", f"{ratio:.2f}", "regions=", len(regions))


def main():
    print("validate_detection.py")
    test_registration_identical_pair()
    test_registration_with_shift()
    test_fusion_shapes()
    test_run_detection_synthetic()
    print("All checks passed.")


if __name__ == "__main__":
    main()