Spaces:
Sleeping
Sleeping
perf: O(pieces*H*W) -> Theta(H*W) piece extraction via find_objects (103x at 190 pieces)
Browse files- src/tearing.py +13 -8
src/tearing.py
CHANGED
|
@@ -19,6 +19,7 @@ from __future__ import annotations
|
|
| 19 |
from dataclasses import dataclass
|
| 20 |
|
| 21 |
import numpy as np
|
|
|
|
| 22 |
from scipy.spatial import cKDTree
|
| 23 |
|
| 24 |
from .noise import value_noise
|
|
@@ -111,19 +112,23 @@ def tear_page(
|
|
| 111 |
_, flat_labels = tree.query(query, k=1, workers=-1)
|
| 112 |
labels = flat_labels.reshape(H, W).astype(np.int32)
|
| 113 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 114 |
pieces: list[Piece] = []
|
| 115 |
-
for lbl in
|
| 116 |
-
|
| 117 |
-
ys_idx, xs_idx = np.nonzero(mask)
|
| 118 |
-
if ys_idx.size == 0:
|
| 119 |
continue
|
| 120 |
-
y0, y1 =
|
| 121 |
-
x0, x1 =
|
| 122 |
-
sub_mask =
|
| 123 |
rgb = np.zeros((y1 - y0, x1 - x0, 3), dtype=np.uint8) # black background
|
| 124 |
rgb[sub_mask] = page_rgb[y0:y1, x0:x1][sub_mask]
|
| 125 |
pieces.append(
|
| 126 |
-
Piece(label=int(lbl), x=x0, y=y0, rgb=rgb, mask=sub_mask)
|
| 127 |
)
|
| 128 |
|
| 129 |
# Piece-index <-> raw-label map from the pieces we actually emitted, so
|
|
|
|
| 19 |
from dataclasses import dataclass
|
| 20 |
|
| 21 |
import numpy as np
|
| 22 |
+
from scipy.ndimage import find_objects
|
| 23 |
from scipy.spatial import cKDTree
|
| 24 |
|
| 25 |
from .noise import value_noise
|
|
|
|
| 112 |
_, flat_labels = tree.query(query, k=1, workers=-1)
|
| 113 |
labels = flat_labels.reshape(H, W).astype(np.int32)
|
| 114 |
|
| 115 |
+
# Bounding boxes for every label in ONE pass (Theta(H*W)) instead of a
|
| 116 |
+
# full-array `labels == lbl` scan per piece (O(pieces*H*W) -> the old hot
|
| 117 |
+
# spot at high DPI / many pieces). find_objects indexes by label value, so
|
| 118 |
+
# shift +1 (0 is its "background" sentinel; our labels are 0-based).
|
| 119 |
+
slices = find_objects(labels + 1)
|
| 120 |
+
|
| 121 |
pieces: list[Piece] = []
|
| 122 |
+
for lbl, sl in enumerate(slices):
|
| 123 |
+
if sl is None: # label value absent from the map
|
|
|
|
|
|
|
| 124 |
continue
|
| 125 |
+
y0, y1 = sl[0].start, sl[0].stop
|
| 126 |
+
x0, x1 = sl[1].start, sl[1].stop
|
| 127 |
+
sub_mask = labels[y0:y1, x0:x1] == lbl # mask only over the bbox
|
| 128 |
rgb = np.zeros((y1 - y0, x1 - x0, 3), dtype=np.uint8) # black background
|
| 129 |
rgb[sub_mask] = page_rgb[y0:y1, x0:x1][sub_mask]
|
| 130 |
pieces.append(
|
| 131 |
+
Piece(label=int(lbl), x=int(x0), y=int(y0), rgb=rgb, mask=sub_mask)
|
| 132 |
)
|
| 133 |
|
| 134 |
# Piece-index <-> raw-label map from the pieces we actually emitted, so
|