This commit is contained in:
knso committed 2026-09-15 21:05:18 +02:00
1 parent 6a056262a8
commit a55dca5fb6
11 files changed
+132 -25

No files matched your search

+18 -4
View File
@@ -90,12 +90,14 @@ def is_thin(mask: np.ndarray) -> bool:
return float(ndi.distance_transform_edt(np.pad(mask, 1)).max()) <= THIN_DEPTH
def rebuild(labels: np.ndarray, mask: np.ndarray, blocked: np.ndarray | None = None) -> RebuildResult:
def rebuild(labels: np.ndarray, mask: np.ndarray, blocked: np.ndarray | None = None,
add: bool = True) -> RebuildResult:
"""Baut das Klassenbild unter einer zusammenhängenden Maske wieder auf.
blocked sind alle Pixel, die nicht als Quelle taugen — alle Beschriftungsmasken; ohne
Angabe nur diese Maske. Reihenfolge wie in der Spec: Straßen und Wege, Flächen,
Gebäude schließen, Gebäude ergänzen.
Gebäude schließen, Gebäude ergänzen. Mit add=False endet der Aufbau nach dem Schließen;
ergänzt wird dann über add_buildings, sobald alle Masken aufgebaut sind.
"""
blocked = mask if blocked is None else blocked
stats = RebuildStats()
@@ -107,6 +109,14 @@ def rebuild(labels: np.ndarray, mask: np.ndarray, blocked: np.ndarray | None = N
_stamp(L, M, painted, road, points, halves)
_fill_areas(L, M & ~painted, B)
_close_buildings(L, M, B, painted, stats)
corners = _add_buildings(labels, mask, blocked, stats) if add else []
return RebuildResult(stats, corners)
def add_buildings(labels: np.ndarray, mask: np.ndarray, blocked: np.ndarray | None = None) -> RebuildResult:
"""Ergänzt Gebäude unter einer schon aufgebauten Maske; die Statistik trägt nur added und note."""
blocked = mask if blocked is None else blocked
stats = RebuildStats()
corners = _add_buildings(labels, mask, blocked, stats)
return RebuildResult(stats, corners)
@@ -535,13 +545,17 @@ def _window(mask, margin):
def _rectangle(rows, cols) -> Polygon:
"""Gedrehtes Hüllrechteck um Pixel (Zeilen, Spalten) als Polygon in (Spalte, Zeile), mit Pixelkante."""
"""Gedrehtes Hüllrechteck um Pixel (Zeilen, Spalten) als Polygon in (Spalte, Zeile), mit Pixelkante.
Liegen die Pixel auf einer Linie, ist das Hüllrechteck eine Linie; eckige Enden machen daraus
wieder ein Rechteck mit vier Ecken statt einer Kapsel.
"""
points = MultiPoint(np.column_stack([cols, rows]).astype(float))
with warnings.catch_warnings():
# Siehe buildings.regularize(): harmlose GEOS-Warnung bei achsenparallelen Formen.
warnings.filterwarnings("ignore", message=r".*oriented_envelope.*", category=RuntimeWarning)
envelope = points.minimum_rotated_rectangle
return envelope.buffer(0.5, join_style="mitre")
return envelope.buffer(0.5, cap_style="square", join_style="mitre")
def _sides(rect: Polygon) -> tuple[float, float]: