start
This commit is contained in:
1 parent
6a056262a8
commit
a55dca5fb6
11 files changed
+132
-25
No files matched your search
@@ -24,7 +24,7 @@ from skimage.morphology import disk
|
||||
|
||||
from .classify import PALETTE
|
||||
from .coords import SLICE, chunk_for_world, chunk_name
|
||||
from .inpaint import RebuildStats, fill_nearest, is_thin, rebuild
|
||||
from .inpaint import RebuildStats, add_buildings, fill_nearest, is_thin, rebuild
|
||||
|
||||
KINDS = ("text_white", "text_red", "marker", "symbol", "street_name", "region")
|
||||
MARGIN = {"text_white": 7, "text_red": 7, "marker": 3, "symbol": 4, "street_name": 1, "region": 0}
|
||||
@@ -406,7 +406,7 @@ def remove_annotations(mosaic: np.ndarray, labels: np.ndarray, annotations: Anno
|
||||
owners.setdefault(int(cid), entry)
|
||||
touched.append(ids)
|
||||
|
||||
generated = []
|
||||
generated, rebuilt = [], []
|
||||
h, w = labels.shape
|
||||
for cid, sl in enumerate(ndi.find_objects(components), start=1):
|
||||
if sl is None:
|
||||
@@ -419,9 +419,17 @@ def remove_annotations(mosaic: np.ndarray, labels: np.ndarray, annotations: Anno
|
||||
continue
|
||||
mask = np.zeros(labels.shape, dtype=bool)
|
||||
mask[sl] = piece
|
||||
result = rebuild(labels, mask, union)
|
||||
result = rebuild(labels, mask, union, add=False)
|
||||
owner = owners[cid]
|
||||
owner.stats = result.stats if owner.stats is None else _merged(owner.stats, result.stats)
|
||||
rebuilt.append((cid, sl))
|
||||
# Ergänzt wird erst, wenn alle Masken aufgebaut sind: sonst zählten Buchstabenkonturen noch nicht
|
||||
# aufgebauter Masken als Straße und teilten Blöcke, und das Ergebnis hinge von der Reihenfolge ab.
|
||||
for cid, sl in rebuilt:
|
||||
mask = np.zeros(labels.shape, dtype=bool)
|
||||
mask[sl] = components[sl] == cid
|
||||
result = add_buildings(labels, mask, union)
|
||||
owners[cid].stats = _merged(owners[cid].stats, result.stats)
|
||||
generated += [Polygon([(SLICE["x0"] + c, SLICE["y1"] - r) for r, c in corners])
|
||||
for corners in result.buildings]
|
||||
for entry, ids in zip(entries, touched):
|
||||
|
||||
@@ -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]:
|
||||
|
||||
Reference in new issue
Block a user