File size: 5,894 Bytes
4c75661
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
116
117
118
119
120
121
"""๋‚ฎ ๋งต ์žฌ๊ตฌ์„ฑ ์ง„ํ–‰๋„ ๊ทธ๋ฆผ โ€” ์ง€์—ญ 3๊ณณ์˜ ์ฃผํ–‰๊ฐ€๋Šฅ์˜์—ญ ์œ„์— ํ•™์Šต๋œ ๊ตฌ๊ฐ„(์ •์  PSNR ์ƒ‰)๊ณผ ์•„์ง ์•ˆ ๋œ ๋‚ฎ ์”ฌ(ํšŒ์ƒ‰) ๊ถค์ .

๋„๋กœ ์ปค๋ฒ„๋ฆฌ์ง€๋Š” recon.batch.coverage_order ์™€ ๊ฐ™์€ 10 m ์นธ ๊ธฐ์ค€ (๋‚ฎ ์”ฌ ์ž์ฐจ ๊ถค์ ์ด ์ง€๋‚˜๊ฐ„ ์นธ ์ค‘ ํ•™์Šต๋œ ๊ตฌ๊ฐ„์ด ๋งก๋Š” ์นธ).
GPU ๋ฅผ ์“ฐ์ง€ ์•Š๋Š”๋‹ค โ€” ํ•™์Šต์ด ๋„๋Š” ์ค‘์—๋„ ๋Œ๋ ค๋„ ๋œ๋‹ค.
์‹คํ–‰: source scripts/local_env.sh && python scripts/map_coverage.py [์ถœ๋ ฅ.png]   (๊ธฐ๋ณธ outputs/coverage/map_coverage_<๋‚ ์งœ>.png)
"""
import json
import sys
import time
from pathlib import Path

import matplotlib

matplotlib.use("Agg")
import matplotlib.pyplot as plt
import numpy as np
from matplotlib import font_manager
from matplotlib.collections import LineCollection
from matplotlib.patches import Polygon

from nusim.data.index import load_scene
from nusim.maps.expansion import MapExpansion
from nusim.paths import output_dir
from nusim.recon.batch import COVER_CELL_M, day_scenes, segment_dirs

ROOT = output_dir() / "gs_day"
OUT = Path(sys.argv[1]) if len(sys.argv) > 1 else output_dir() / "coverage" / f"map_coverage_{time.strftime('%Y%m%d')}.png"
LOCS = [("singapore-onenorth", "One-North"), ("singapore-queenstown", "Queenstown"),
        ("singapore-hollandvillage", "Holland Village")]
FONT = "/usr/share/fonts/opentype/noto/NotoSansCJK-Regular.ttc"
if Path(FONT).exists():
    font_manager.fontManager.addfont(FONT)
    plt.rcParams["font.family"] = font_manager.FontProperties(fname=FONT).get_name()
PSNR_LO, PSNR_HI = 20.0, 28.0


def cells(xy: np.ndarray) -> set:
    return set(map(tuple, np.floor(xy / COVER_CELL_M).astype(int)))


def scene_track(name: str) -> tuple[np.ndarray, np.ndarray]:
    """์ •๋ฉด ์นด๋ฉ”๋ผ ์ž์ฐจ ์œ„์น˜ (n,2) ์™€ ์”ฌ ์‹œ์ž‘๋ถ€ํ„ฐ์˜ ์ดˆ."""
    fr = load_scene(name).frames["CAM_FRONT"]
    xy = np.array([f.ego_translation[:2] for f in fr])
    t = (np.array([f.timestamp for f in fr]) - fr[0].timestamp) / 1e6
    return xy, t


def seg_psnr(d: Path) -> float | None:
    p = d / "eval.json"
    return json.loads(p.read_text()).get("psnr_static") if p.exists() else None


fig, axes = plt.subplots(1, 3, figsize=(24, 9.2), gridspec_kw={"width_ratios": [1.25, 1, 1]})
cmap = plt.get_cmap("viridis")
tot = {"scenes": 0, "done": 0, "segs": 0, "cells": 0, "cells_done": 0}
for ax, (loc, title) in zip(axes, LOCS):
    names = day_scenes(loc)
    all_xy, done_lines, done_c, todo_lines, done_cells, all_cells = [], [], [], [], set(), set()
    n_done, n_segs = 0, 0
    for s in names:
        xy, t = scene_track(s)
        all_xy.append(xy)
        all_cells |= cells(xy)
        segs = segment_dirs(ROOT, s)
        if not segs:
            todo_lines.append(xy)
            continue
        n_done += 1
        owned = np.zeros(len(t), bool)
        for info, d in segs:
            n_segs += 1
            o0 = info.get("own0") if info.get("own0") is not None else -1
            o1 = info.get("own1") if info.get("own1") is not None else 1e9
            m = (t >= o0) & (t <= o1)
            owned |= m
            if m.sum() >= 2:
                done_lines.append(xy[m])
                v = seg_psnr(d)
                done_c.append(cmap((np.clip(v, PSNR_LO, PSNR_HI) - PSNR_LO) / (PSNR_HI - PSNR_LO)) if v else (0.5, 0.5, 0.5, 1))
                done_cells |= cells(xy[m])
        if (~owned).sum() >= 2:  # ํ•™์Šต์ด ๋œ ๋๋‚œ ์”ฌ์˜ ๋‚˜๋จธ์ง€ ๊ตฌ๊ฐ„
            todo_lines.append(xy[~owned])
    pts = np.concatenate(all_xy)
    lo, hi = pts.min(0) - 80, pts.max(0) + 80
    m = MapExpansion(loc)
    for rec in m._d["drivable_area"]:
        for tok in rec["polygon_tokens"]:
            rings = m.polygon_rings(tok)
            if not rings:
                continue
            r0 = np.asarray(rings[0])
            if r0[:, 0].max() < lo[0] or r0[:, 0].min() > hi[0] or r0[:, 1].max() < lo[1] or r0[:, 1].min() > hi[1]:
                continue
            ax.add_patch(Polygon(r0, closed=True, fc="#E9ECF1", ec="none", zorder=0))
            for h in rings[1:]:
                ax.add_patch(Polygon(np.asarray(h), closed=True, fc="white", ec="none", zorder=0))
    ax.add_collection(LineCollection(todo_lines, colors="#B9BEC7", linewidths=1.2, zorder=1))
    ax.add_collection(LineCollection(done_lines, colors=done_c, linewidths=3.2, zorder=2, capstyle="round"))
    ax.set_xlim(lo[0], hi[0]); ax.set_ylim(lo[1], hi[1]); ax.set_aspect("equal")
    ax.set_xticks([]); ax.set_yticks([])
    cov = len(done_cells & all_cells) / max(len(all_cells), 1)
    ax.set_title(f"{title}\n์”ฌ {n_done}/{len(names)} ยท ๊ตฌ๊ฐ„ {n_segs}๊ฐœ ยท ๋„๋กœ ์ปค๋ฒ„๋ฆฌ์ง€ {cov:.0%}", fontsize=17)
    sb = 200.0
    ax.plot([lo[0] + 30, lo[0] + 30 + sb], [lo[1] + 30] * 2, color="k", lw=3)
    ax.text(lo[0] + 30 + sb / 2, lo[1] + 45, "200 m", ha="center", fontsize=12)
    for k, v in (("scenes", len(names)), ("done", n_done), ("segs", n_segs), ("cells", len(all_cells)),
                 ("cells_done", len(done_cells & all_cells))):
        tot[k] += v
    print(f"{loc}: ์”ฌ {n_done}/{len(names)}, ๊ตฌ๊ฐ„ {n_segs}, ๋„๋กœ ์นธ {len(done_cells & all_cells)}/{len(all_cells)} ({cov:.1%})")

sm = plt.cm.ScalarMappable(cmap=cmap, norm=plt.Normalize(PSNR_LO, PSNR_HI))
cb = fig.colorbar(sm, ax=axes, orientation="horizontal", fraction=0.035, pad=0.03, aspect=60)
cb.set_label("ํ•™์Šต๋œ ๊ตฌ๊ฐ„์˜ ์ •์  PSNR (dB) โ€” ํšŒ์ƒ‰ ์„ : ์•„์ง ํ•™์Šต ์•ˆ ๋œ ๋‚ฎ ์”ฌ ๊ถค์  ยท ๋ฐ”ํƒ•: ์ฃผํ–‰๊ฐ€๋Šฅ์˜์—ญ", fontsize=13)
fig.suptitle(f"์‹ฑ๊ฐ€ํฌ๋ฅด ๋‚ฎ ๋งต ์žฌ๊ตฌ์„ฑ ์ง„ํ–‰ โ€” {time.strftime('%Y-%m-%d %H:%M')}  ยท  ์”ฌ {tot['done']}/{tot['scenes']}  ยท  "
             f"๊ตฌ๊ฐ„ {tot['segs']}๊ฐœ  ยท  ๋„๋กœ ์ปค๋ฒ„๋ฆฌ์ง€ {tot['cells_done'] / tot['cells']:.0%} (10 m ์นธ {tot['cells_done']}/{tot['cells']})",
             fontsize=20, fontweight="bold")
OUT.parent.mkdir(parents=True, exist_ok=True)
fig.savefig(OUT, dpi=110, bbox_inches="tight")
print("saved", OUT)