object-remove 0.2.0__tar.gz → 0.2.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {object_remove-0.2.0 → object_remove-0.2.1}/PKG-INFO +3 -1
- {object_remove-0.2.0 → object_remove-0.2.1}/README.md +2 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/__init__.py +1 -1
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/cv/orb.py +46 -50
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/primary/quad_tree_index.py +13 -4
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/self_similar_shift.py +29 -11
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove.egg-info/PKG-INFO +3 -1
- {object_remove-0.2.0 → object_remove-0.2.1}/pyproject.toml +1 -1
- {object_remove-0.2.0 → object_remove-0.2.1}/LICENSE +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/cv/__init__.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/cv/box_filter.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/cv/canny.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/cv/distance_transform.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/cv/frequency_separation.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/cv/harris.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/cv/max_finder.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/cv/nearest_opaque.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/cv/symmetric_convolution.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/effects/__init__.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/effects/background_blur.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/effects/perspective_correction.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/__init__.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/clone_stamp.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/patch_comparator.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/patch_comparator_gpu.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/patchmatch/__init__.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/patchmatch/group_solver.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/patchmatch/patch.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/patchmatch/patch_scorer.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/patchmatch/patch_search_index.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/patchmatch/solver.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/patchmatch/torch_solver.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/primary/__init__.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/primary/patch_grid_solver.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/primary/patch_grid_solver_gpu.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/primary/renderer.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/primary/scoring.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/self_similar_shift_gpu.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/wire_removal.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/imageutil.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/mask/__init__.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/mask/auto_select.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/mask/brush_rasterizer.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/mask/connected_components.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/mask/polygon_selection.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/mask/selection_enhancer.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/pipeline/__init__.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/pipeline/remove_object_job.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/py.typed +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/pyramid/__init__.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/pyramid/image_pyramid.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/pyramid/scale_scheduler.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/pyramid/tile_scheduler.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/pyramid/torch_pyramid.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/render/__init__.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/render/compositor.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/render/fused_patch_blend.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/render/multiband_blender.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/render/multiband_blender_gpu.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/render/poisson_blender.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/render/poisson_blender_gpu.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/runtime/__init__.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/runtime/device.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/session/__init__.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/session/empty_session_sweeper.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove/session/undo_session_manager.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove.egg-info/SOURCES.txt +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove.egg-info/dependency_links.txt +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove.egg-info/requires.txt +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/object_remove.egg-info/top_level.txt +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/setup.cfg +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/tests/test_clone_stamp.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/tests/test_cv.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/tests/test_effects.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/tests/test_fillengines.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/tests/test_gpu.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/tests/test_mask.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/tests/test_perspective_correction.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/tests/test_pipeline.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/tests/test_primary_fill_engine.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/tests/test_pyramid.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/tests/test_render.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/tests/test_session.py +0 -0
- {object_remove-0.2.0 → object_remove-0.2.1}/tests/test_wire_removal.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: object-remove
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: From-scratch reference implementation of a tiered on-device object-removal pipeline, CPU and GPU
|
|
5
5
|
Author: shalaga44
|
|
6
6
|
License-Expression: MIT
|
|
@@ -31,6 +31,8 @@ Dynamic: license-file
|
|
|
31
31
|
|
|
32
32
|
# object_remove
|
|
33
33
|
|
|
34
|
+
[](https://pypi.org/project/object-remove/0.2.1/)
|
|
35
|
+
|
|
34
36
|
A from scratch implementation of an on device object removal pipeline (see
|
|
35
37
|
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for the full design): a
|
|
36
38
|
polygon/scanline mask layer, **four fill engines** of increasing
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# object_remove
|
|
2
2
|
|
|
3
|
+
[](https://pypi.org/project/object-remove/0.2.1/)
|
|
4
|
+
|
|
3
5
|
A from scratch implementation of an on device object removal pipeline (see
|
|
4
6
|
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for the full design): a
|
|
5
7
|
polygon/scanline mask layer, **four fill engines** of increasing
|
|
@@ -15,7 +15,7 @@ Public entry point::
|
|
|
15
15
|
import importlib
|
|
16
16
|
from typing import Any
|
|
17
17
|
|
|
18
|
-
__version__ = "0.1
|
|
18
|
+
__version__ = "0.2.1"
|
|
19
19
|
|
|
20
20
|
# Lazy attribute map: name maps to (submodule, attribute). Loaded on first access so
|
|
21
21
|
# importing any subpackage never eagerly drags in the whole tree.
|
|
@@ -31,12 +31,15 @@ def fast_corners(gray: np.ndarray, valid: np.ndarray, threshold: float = 0.06,
|
|
|
31
31
|
n_contig: int = 9, border: int = 16) -> List[Tuple[int, int]]:
|
|
32
32
|
"""FAST 9 corner detector over valid pixels only.
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
34
|
+
Both the 4 point compass quick reject and the full 16 point contiguous
|
|
35
|
+
arc test are vectorised over the whole interior at once via shifted
|
|
36
|
+
slices, rather than looping per candidate pixel in Python -- a Python
|
|
37
|
+
loop there would scale with total image area (not hole size), dominating
|
|
38
|
+
runtime on large photos. The arc test still needs a loop to walk the 16
|
|
39
|
+
(+n_contig-1 wrap-around) circle taps and accumulate the longest same
|
|
40
|
+
sign run, but that loop is a fixed ~24 iterations regardless of image
|
|
41
|
+
size, with each iteration a single vectorised array op over every
|
|
42
|
+
interior pixel at once -- identical semantics to the scalar version.
|
|
40
43
|
"""
|
|
41
44
|
H, W = gray.shape
|
|
42
45
|
circ = _FAST_CIRCLE
|
|
@@ -57,35 +60,26 @@ def fast_corners(gray: np.ndarray, valid: np.ndarray, threshold: float = 0.06,
|
|
|
57
60
|
reject += (v > hi) | (v < lo)
|
|
58
61
|
|
|
59
62
|
cand = (reject >= 3) & valid[iy0:iy1, ix0:ix1]
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
if _has_contiguous(states, n_contig):
|
|
73
|
-
pts.append((y, x))
|
|
74
|
-
return pts
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
def _has_contiguous(states: List[int], n: int) -> bool:
|
|
78
|
-
ext = states + states[:n - 1]
|
|
63
|
+
if not cand.any():
|
|
64
|
+
return []
|
|
65
|
+
|
|
66
|
+
states = np.empty((len(circ),) + center.shape, dtype=np.int8)
|
|
67
|
+
for i, (dx, dy) in enumerate(circ):
|
|
68
|
+
v = shifted(dx, dy)
|
|
69
|
+
states[i] = np.where(v > hi, 1, np.where(v < lo, -1, 0))
|
|
70
|
+
|
|
71
|
+
# circular wrap-around, same as `states + states[:n_contig - 1]` in the
|
|
72
|
+
# scalar version's per-point list
|
|
73
|
+
ext = np.concatenate([states, states[:n_contig - 1]], axis=0)
|
|
74
|
+
found = np.zeros(center.shape, dtype=bool)
|
|
79
75
|
for sgn in (1, -1):
|
|
80
|
-
run =
|
|
81
|
-
for
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
run = 0
|
|
88
|
-
return False
|
|
76
|
+
run = np.zeros(center.shape, dtype=np.int32)
|
|
77
|
+
for i in range(ext.shape[0]):
|
|
78
|
+
run = np.where(ext[i] == sgn, run + 1, 0)
|
|
79
|
+
found |= run >= n_contig
|
|
80
|
+
|
|
81
|
+
cys, cxs = np.nonzero(cand & found)
|
|
82
|
+
return [(int(cy) + iy0, int(cx) + ix0) for cy, cx in zip(cys, cxs)]
|
|
89
83
|
|
|
90
84
|
|
|
91
85
|
def _brief_pattern(patch: int = 15, n_bits: int = 256, seed: int = 42) -> np.ndarray:
|
|
@@ -97,26 +91,28 @@ _BRIEF = _brief_pattern()
|
|
|
97
91
|
|
|
98
92
|
|
|
99
93
|
def brief_descriptors(gray: np.ndarray, pts: List[Tuple[int, int]]) -> List[Keypoint]:
|
|
100
|
-
"""256 bit BRIEF on a smoothed image, packed into 32 uint8 bytes.
|
|
94
|
+
"""256 bit BRIEF on a smoothed image, packed into 32 uint8 bytes.
|
|
95
|
+
|
|
96
|
+
Bit computation is vectorised across all points *and* all 256 pattern
|
|
97
|
+
taps at once (one (N, 256) gather + compare + packbits), instead of a
|
|
98
|
+
per point Python loop each doing its own small array ops -- per call
|
|
99
|
+
overhead there dominates runtime for images with many keypoints.
|
|
100
|
+
"""
|
|
101
|
+
if not pts:
|
|
102
|
+
return []
|
|
101
103
|
sm = gaussian_blur(gray)
|
|
102
104
|
H, W = sm.shape
|
|
103
|
-
out: List[Keypoint] = []
|
|
104
105
|
pat = _BRIEF
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
# per element np.clip() call overhead (measured ~19x slower than a single
|
|
108
|
-
# array clip of the same size), which dominates runtime for images with
|
|
109
|
-
# many keypoints.
|
|
106
|
+
pys = np.asarray([p[0] for p in pts], dtype=np.int64)[:, None]
|
|
107
|
+
pxs = np.asarray([p[1] for p in pts], dtype=np.int64)[:, None]
|
|
110
108
|
pax, pay, pbx, pby = pat[:, 0], pat[:, 1], pat[:, 2], pat[:, 3]
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
out.append(Keypoint(y, x, packed))
|
|
119
|
-
return out
|
|
109
|
+
ay = np.clip(pys + pay[None, :], 0, H - 1)
|
|
110
|
+
ax = np.clip(pxs + pax[None, :], 0, W - 1)
|
|
111
|
+
by = np.clip(pys + pby[None, :], 0, H - 1)
|
|
112
|
+
bx = np.clip(pxs + pbx[None, :], 0, W - 1)
|
|
113
|
+
bits = (sm[ay, ax] < sm[by, bx]).astype(np.uint8) # (N, 256)
|
|
114
|
+
packed = np.packbits(bits, axis=1) # (N, 32)
|
|
115
|
+
return [Keypoint(y, x, packed[i]) for i, (y, x) in enumerate(pts)]
|
|
120
116
|
|
|
121
117
|
|
|
122
118
|
def hamming(a: np.ndarray, b: np.ndarray) -> np.ndarray:
|
{object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/primary/quad_tree_index.py
RENAMED
|
@@ -85,8 +85,10 @@ class QuadTreeIndex:
|
|
|
85
85
|
yield from self._iter_points(c)
|
|
86
86
|
|
|
87
87
|
def all_points(self) -> np.ndarray:
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
# every index gets inserted into exactly one leaf at construction
|
|
89
|
+
# time (see __init__/_insert), so the full point set is always just
|
|
90
|
+
# self.coords -- no need to walk the tree to reconstruct it.
|
|
91
|
+
return self.coords
|
|
90
92
|
|
|
91
93
|
def query_range(self, y0: int, x0: int, y1: int, x1: int) -> np.ndarray:
|
|
92
94
|
"""Points whose centre lies in ``[y0,y1) x [x0,x1)``, pruning whole
|
|
@@ -122,8 +124,15 @@ class QuadTreeIndex:
|
|
|
122
124
|
) -> Optional[Tuple[int, int]]:
|
|
123
125
|
coords = self.all_points()
|
|
124
126
|
if used and len(coords):
|
|
125
|
-
|
|
126
|
-
|
|
127
|
+
# linearise (y, x) -> y*W+x so the per-point dict.get in a Python
|
|
128
|
+
# loop becomes one vectorised membership test against just the
|
|
129
|
+
# (typically far smaller) set of sources that are actually
|
|
130
|
+
# over-used, rather than looping over every candidate in Python.
|
|
131
|
+
W = self.root.x1
|
|
132
|
+
overused = [k[0] * W + k[1] for k, v in used.items() if v >= max_reuse]
|
|
133
|
+
if overused:
|
|
134
|
+
coord_idx = coords[:, 0] * W + coords[:, 1]
|
|
135
|
+
coords = coords[~np.isin(coord_idx, overused)]
|
|
127
136
|
return _best_match(image, ty, tx, coords, radius, target_valid)
|
|
128
137
|
|
|
129
138
|
|
|
@@ -72,18 +72,27 @@ def _similar_far_offsets(kps: List[Keypoint], hole_bbox,
|
|
|
72
72
|
# DP seam carving + transpose trick
|
|
73
73
|
# ==========================================================================
|
|
74
74
|
def min_cost_seam(energy: np.ndarray) -> np.ndarray:
|
|
75
|
-
"""Min cost vertical seam via DP. Returns one column index per row.
|
|
75
|
+
"""Min cost vertical seam via DP. Returns one column index per row.
|
|
76
|
+
|
|
77
|
+
Row y only depends on row y-1, so the DP itself must stay a sequential
|
|
78
|
+
Python loop over rows; but within a row, each column's 3 way choice
|
|
79
|
+
(up-left/up/up-right) is independent of its neighbours' choices and is
|
|
80
|
+
vectorised across the whole row at once (edges padded with +inf so they
|
|
81
|
+
naturally fall back to the 2 candidate case), instead of an inner
|
|
82
|
+
per-column Python loop -- same argmin tie-breaking (favours the
|
|
83
|
+
lower-index candidate) as the scalar version.
|
|
84
|
+
"""
|
|
76
85
|
h, w = energy.shape
|
|
77
86
|
cost = energy.astype(np.float64).copy()
|
|
78
87
|
back = np.zeros((h, w), dtype=np.int32)
|
|
88
|
+
xs = np.arange(w)
|
|
79
89
|
for y in range(1, h):
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
cost[y, x] += choices[k]
|
|
90
|
+
prev = cost[y - 1]
|
|
91
|
+
padded = np.concatenate(([np.inf], prev, [np.inf]))
|
|
92
|
+
choices = np.stack([padded[0:w], padded[1:w + 1], padded[2:w + 2]]) # (3, w)
|
|
93
|
+
k = np.argmin(choices, axis=0)
|
|
94
|
+
back[y] = np.clip(xs + (k - 1), 0, w - 1)
|
|
95
|
+
cost[y] += choices[k, xs]
|
|
87
96
|
seam = np.zeros(h, dtype=np.int32)
|
|
88
97
|
seam[-1] = int(np.argmin(cost[-1]))
|
|
89
98
|
for y in range(h - 2, -1, -1):
|
|
@@ -267,6 +276,12 @@ class SelfSimilarShiftEngine:
|
|
|
267
276
|
ry0, ry1 = rys.min(), rys.max() + 1
|
|
268
277
|
rx0, rx1 = rxs.min(), rxs.max() + 1
|
|
269
278
|
out = np.zeros((H, W), dtype=bool)
|
|
279
|
+
# The DP always spans the same fixed row range (ry0:ry1); only the
|
|
280
|
+
# column bounds change with each row's hole extent. Rows sharing the
|
|
281
|
+
# same (strip_x0, strip_x1) -- typical for straight-ish hole edges --
|
|
282
|
+
# would otherwise resolve the identical DP from scratch once per row
|
|
283
|
+
# just to read off a single seam[yy] value, so cache by those bounds.
|
|
284
|
+
seam_cache: dict = {}
|
|
270
285
|
for y in range(ry0, ry1):
|
|
271
286
|
hx = np.nonzero(hole[y])[0]
|
|
272
287
|
if hx.size == 0:
|
|
@@ -277,9 +292,12 @@ class SelfSimilarShiftEngine:
|
|
|
277
292
|
strip_x0, strip_x1 = hx.max() + 1, rx1
|
|
278
293
|
if strip_x1 <= strip_x0:
|
|
279
294
|
continue
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
seam
|
|
295
|
+
key = (strip_x0, strip_x1)
|
|
296
|
+
seam = seam_cache.get(key)
|
|
297
|
+
if seam is None:
|
|
298
|
+
strip = diff[ry0:ry1, strip_x0:strip_x1]
|
|
299
|
+
seam = min_cost_seam(strip)
|
|
300
|
+
seam_cache[key] = seam
|
|
283
301
|
yy = y - ry0
|
|
284
302
|
cut = strip_x0 + seam[yy]
|
|
285
303
|
if axis == "left":
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: object-remove
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.1
|
|
4
4
|
Summary: From-scratch reference implementation of a tiered on-device object-removal pipeline, CPU and GPU
|
|
5
5
|
Author: shalaga44
|
|
6
6
|
License-Expression: MIT
|
|
@@ -31,6 +31,8 @@ Dynamic: license-file
|
|
|
31
31
|
|
|
32
32
|
# object_remove
|
|
33
33
|
|
|
34
|
+
[](https://pypi.org/project/object-remove/0.2.1/)
|
|
35
|
+
|
|
34
36
|
A from scratch implementation of an on device object removal pipeline (see
|
|
35
37
|
[`docs/ARCHITECTURE.md`](docs/ARCHITECTURE.md) for the full design): a
|
|
36
38
|
polygon/scanline mask layer, **four fill engines** of increasing
|
|
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "object-remove"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.1"
|
|
8
8
|
description = "From-scratch reference implementation of a tiered on-device object-removal pipeline, CPU and GPU"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
license = "MIT"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/patch_comparator_gpu.py
RENAMED
|
File without changes
|
{object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/patchmatch/__init__.py
RENAMED
|
File without changes
|
{object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/patchmatch/group_solver.py
RENAMED
|
File without changes
|
|
File without changes
|
{object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/patchmatch/patch_scorer.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/patchmatch/torch_solver.py
RENAMED
|
File without changes
|
|
File without changes
|
{object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/primary/patch_grid_solver.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{object_remove-0.2.0 → object_remove-0.2.1}/object_remove/fillengines/self_similar_shift_gpu.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|