- 다듬기 판(classification_refine · ptd_refine)은 바탕 필터 지면점으로 외곽을 그림 — 다듬기가 지운 자리 = 외곽 안 구멍 · 외곽 자체는 안 넓힘(엔진이 바탕 마스크를 모델 짓기에 넘김 · 지면점 저장본은 안 지음) - dtm 격자: 땅 칸에서 틈 닫기(3 m) 넘게 먼 칸 + 그 둘레 빈 칸을 쌍조화(scikit-image inpaint_biharmonic · 이미 씀)로 메움 · 작은 틈은 지금처럼 가까운 칸 값 - 라플라스(막 펴기)는 버림 — 홀로 남은 땅 점마다 고깔이 생겨 용화 새 자리 튐 8.2 %(쌍조화 6.4 %) - implicit: 메운 dtm 칸을 3 m 간격 길잡이 중심점으로 더함 — 구멍 칸 튐 3.1 → 0.8 %(dtm 과 같은 면) · 중심점 뽑기 칸은 자기 외곽 넓이 그대로 - 품질 지표 ⑤ 메운 넓이 m² · % — dtm `filled_mask` · B04 값 목록 한 줄 · QUALITY_VERSION 2 - 모델 지문에 hole_fill 더함 — 다음 전처리 때 모델을 다시 지음 - 지킴 시험 test_766_2_hole_fill — 평면 · 곡면 비탈 그대로 이음 · 작은 틈 안 건드림 · 바탕 외곽 그대로 · dtm · implicit 구멍 0 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
69 lines
3.7 KiB
Python
69 lines
3.7 KiB
Python
"""766-2 외곽 안 구멍 메움 지킴 시험 — 다듬기 판은 바탕 필터 외곽 · 구멍은 막 펴기로 매끈하게.
|
|
|
|
합성 비탈(평면) 120 × 120 m · 가운데 30 × 30 m 땅 점이 다 걸러짐(다듬기가 지운 자리 흉내).
|
|
"""
|
|
|
|
import numpy as np
|
|
|
|
from B04_PreProcess.B04_PreProcess_Engine_ModelBuild import build_dtm, build_implicit
|
|
from B04_PreProcess.B04_PreProcess_Engine_ModelContext import TerrainContext, fill_holes_smooth
|
|
from B04_PreProcess.B04_PreProcess_Engine_Quality import filled_stats
|
|
from common_util.common_util_surface_sampler import build_surface_sampler
|
|
from config.config_system import build_surface_model_config
|
|
|
|
RNG = np.random.default_rng(7662)
|
|
|
|
|
|
def _scene() -> tuple[np.ndarray, np.ndarray, np.ndarray, np.ndarray]:
|
|
count = 120 * 120 * 3
|
|
x, y = RNG.uniform(0, 120, count), RNG.uniform(0, 120, count)
|
|
xyz = np.column_stack((x, y, 0.3 * x + 0.1 * y + 100.0)).astype(np.float32)
|
|
base = np.ones(count, dtype=bool)
|
|
hole = (np.abs(x - 60) < 15) & (np.abs(y - 60) < 15)
|
|
bounds = np.array([[0, 120], [0, 120], [90, 150]], dtype=np.float64)
|
|
return xyz, base, base & ~hole, bounds
|
|
|
|
|
|
def test_fill_keeps_plane_and_curved_slope() -> None:
|
|
yy, xx = np.mgrid[0:60, 0:60].astype(float)
|
|
known = np.ones(xx.shape, dtype=bool)
|
|
known[20:40, 20:40] = False
|
|
inside = np.ones(xx.shape, dtype=bool)
|
|
for truth in (0.3 * xx + 0.1 * yy, 0.004 * (xx - 25) ** 2 + 0.002 * (yy - 35) ** 2):
|
|
work = np.where(known, truth, 0.0)
|
|
filled = fill_holes_smooth(work, known, inside, 3.0)
|
|
assert filled.sum() == 14 * 14 # 땅 칸에서 3 칸 넘게 먼 자리만 메운 넓이로 셈
|
|
assert np.abs(work - truth).max() < 0.1 # 둘레 높이 · 기울기 그대로 이어짐(계단 · 혹 없음)
|
|
# 작은 틈(3 칸 안)은 메움 대상이 아님 — 지금처럼 가까운 칸 값
|
|
small = np.ones(xx.shape, dtype=bool)
|
|
small[10:13, 10:13] = False
|
|
assert not fill_holes_smooth(xx.copy(), small, inside, 3.0).any()
|
|
|
|
|
|
def test_refine_hole_inside_outer_is_filled(tmp_path) -> None:
|
|
xyz, base, refined, bounds = _scene()
|
|
config = build_surface_model_config()
|
|
plain = TerrainContext(xyz=xyz, mask=refined, bounds=bounds, config=config)
|
|
outer = TerrainContext(xyz=xyz, mask=refined, bounds=bounds, config=config, outer_mask=base)
|
|
# 외곽 = 바탕 필터 그대로(넓히지 않음) · 구멍 칸만 메움
|
|
base_ctx = TerrainContext(xyz=xyz, mask=base, bounds=bounds, config=config)
|
|
assert outer.footprint()[3].sum() == base_ctx.footprint()[3].sum()
|
|
resolution = float(config["dtm_grid_resolution_meters"])
|
|
assert outer.filled(resolution).sum() > 400
|
|
assert not base_ctx.filled(resolution).any()
|
|
build_dtm(outer, tmp_path, "dtm_ptd_refine", lambda _: None)
|
|
build_implicit(outer, tmp_path, "implicit_ptd_refine", lambda _: None)
|
|
xy = np.column_stack([np.linspace(50, 70, 21), np.full(21, 60.0)])
|
|
truth = 0.3 * xy[:, 0] + 0.1 * xy[:, 1] + 100.0
|
|
for method in ("dtm", "implicit"):
|
|
z, valid = build_surface_sampler(tmp_path, "ptd_refine", method, False).sample_xy(xy)
|
|
assert valid.all(), method # 구멍 0
|
|
# 둘레 비탈과 같은 면 — dtm 둘레 칸 = 칸 최저점(0.1~0.2 m 들쭉날쭉)이라 0.5 m 안
|
|
assert np.abs(z - truth).max() < 0.5, method
|
|
with np.load(tmp_path / "dtm_ptd_refine.npz") as data:
|
|
valid = np.asarray(data["valid_mask"], dtype=bool)
|
|
stats = filled_stats(tmp_path, "ptd_refine", valid, 1.0)
|
|
assert 400 < stats["filled_m2"] < 900 and stats["filled_pct"] > 0
|
|
# 바탕 외곽 없이(옛 길)는 구멍 자리가 외곽 밖 — 구멍이 열린 만이면 비어 있었음
|
|
assert plain.footprint()[3].sum() <= outer.footprint()[3].sum()
|