File size: 4,378 Bytes
d70361b
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
"""Ablate report-75 improvements: ribbon strip + soft DL close on before6/after6."""
from __future__ import annotations

import sys
from pathlib import Path

import cv2
import numpy as np
from dotenv import load_dotenv
from PIL import Image

ROOT = Path(__file__).resolve().parents[1]
sys.path.insert(0, str(ROOT))
load_dotenv(ROOT / ".env", override=True)

from app.detection_engine import (  # noqa: E402
    _alignment_ncc,
    _is_alignment_edge_ribbon,
    ai_deep_learning_method,
    analyze_change_regions,
    get_detection_max_size,
    normalize_radiometry,
    preprocess_image,
    recover_chromatic_roof_construction,
    recover_dark_roof_construction,
    strip_alignment_edge_ribbons_from_mask,
    split_weakly_bridged_change_blobs,
    strip_parking_cluster_from_mask,
    strip_shadow_fragments_from_mask,
    strip_shadow_only_from_mask,
    strip_transient_from_mask,
    strip_weak_seasonal_veg_from_mask,
    visualize_changes,
)


def main():
    before_p = ROOT / "data/library_sources/central_delhi/Images/before6.tif"
    after_p = ROOT / "data/library_sources/central_delhi/Images/after6.tif"
    b_pil = Image.open(before_p).convert("RGB")
    a_pil = Image.open(after_p).convert("RGB")
    if a_pil.size != b_pil.size:
        a_pil = a_pil.resize(b_pil.size, Image.Resampling.LANCZOS)
    ms = get_detection_max_size()
    b0 = preprocess_image(b_pil, max_size=ms)
    a0 = preprocess_image(a_pil, max_size=ms)
    ncc = float(_alignment_ncc(b0, a0))
    registration_ok = ncc >= 0.55
    print("ncc", round(ncc, 4), "registration_ok", registration_ok, "ms", ms)

    b_chr, a_chr = b0.copy(), a0.copy()
    b, a = normalize_radiometry(b0, a0)

    # Match UI job: sensitivity 0.45
    change_mask, debug = ai_deep_learning_method(
        b, a, sensitivity=0.45, registration_ok=registration_ok
    )
    print("dl", {k: debug.get(k) for k in (
        "threshold_score", "model_changed_px", "combined_changed_px")})

    def count(m):
        return int(np.sum(m > 127))

    steps = [("raw_clean+chroma", change_mask.copy())]
    change_mask = strip_transient_from_mask(change_mask, b, a)
    steps.append(("transient", change_mask.copy()))
    change_mask = strip_shadow_only_from_mask(
        change_mask, b, a, registration_ok=registration_ok)
    steps.append(("shadow_only", change_mask.copy()))
    change_mask = strip_shadow_fragments_from_mask(
        change_mask, b, a, registration_ok=registration_ok)
    steps.append(("fragments", change_mask.copy()))
    change_mask = strip_alignment_edge_ribbons_from_mask(change_mask)
    steps.append(("ribbons", change_mask.copy()))
    change_mask = strip_parking_cluster_from_mask(change_mask, b, a)
    change_mask = strip_weak_seasonal_veg_from_mask(change_mask, b, a)
    change_mask = recover_chromatic_roof_construction(change_mask, b_chr, a_chr)
    change_mask = recover_dark_roof_construction(
        change_mask, b_chr, a_chr, registration_ok=registration_ok)
    steps.append(("recover", change_mask.copy()))
    change_mask = strip_shadow_fragments_from_mask(
        change_mask, b, a, registration_ok=False)
    change_mask = strip_alignment_edge_ribbons_from_mask(change_mask)
    change_mask = split_weakly_bridged_change_blobs(change_mask)
    steps.append(("final", change_mask.copy()))

    prev = None
    for name, m in steps:
        px = count(m)
        delta = None if prev is None else px - prev
        print(f"{name:18s} px={px:7d} delta={delta} pct={100*px/m.size:.2f}%")
        prev = px

    regs = analyze_change_regions(
        change_mask, a_chr, min_area=150, use_ensemble=False,
        before_img=b_chr, registration_ok=False,
    )
    print("regions", len(regs), "top", [
        (r["id"], r["area"], r["bbox"][2], r["bbox"][3],
         round(max(r["bbox"][2], r["bbox"][3]) / max(min(r["bbox"][2], r["bbox"][3]), 1), 1),
         _is_alignment_edge_ribbon(r["area"], r["bbox"][2], r["bbox"][3], r.get("fill_ratio")))
        for r in regs[:15]
    ])

    out = ROOT / "data/delhi_cd/friday_drone_report_fix/report75_improve"
    out.mkdir(parents=True, exist_ok=True)
    overlay = visualize_changes(
        b_chr, a_chr, change_mask, regions=regs, shape_mode="polygon")
    cv2.imwrite(str(out / "overlay_bgr.png"), cv2.cvtColor(overlay, cv2.COLOR_RGB2BGR))
    print("wrote", out / "overlay_bgr.png")


if __name__ == "__main__":
    main()