patchmatch-cython 0.1.5__tar.gz → 0.2.0__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.
- {patchmatch_cython-0.1.5/src/patchmatch_cython.egg-info → patchmatch_cython-0.2.0}/PKG-INFO +72 -26
- patchmatch_cython-0.2.0/README.md +184 -0
- {patchmatch_cython-0.1.5 → patchmatch_cython-0.2.0}/pyproject.toml +1 -1
- {patchmatch_cython-0.1.5 → patchmatch_cython-0.2.0}/setup.py +6 -5
- {patchmatch_cython-0.1.5 → patchmatch_cython-0.2.0}/src/patchmatch_cython/__init__.py +1 -1
- {patchmatch_cython-0.1.5 → patchmatch_cython-0.2.0}/src/patchmatch_cython/cython_solver.py +33 -8
- {patchmatch_cython-0.1.5 → patchmatch_cython-0.2.0}/src/patchmatch_cython/cython_solver_impl.cpp +9720 -2900
- patchmatch_cython-0.2.0/src/patchmatch_cython/cython_solver_impl.pyx +628 -0
- patchmatch_cython-0.2.0/src/patchmatch_cython/imageops.py +719 -0
- patchmatch_cython-0.2.0/src/patchmatch_cython/inpaint.py +368 -0
- patchmatch_cython-0.2.0/src/patchmatch_cython/python_solver.py +402 -0
- {patchmatch_cython-0.1.5 → patchmatch_cython-0.2.0}/src/patchmatch_cython/solver.py +13 -2
- {patchmatch_cython-0.1.5 → patchmatch_cython-0.2.0/src/patchmatch_cython.egg-info}/PKG-INFO +72 -26
- {patchmatch_cython-0.1.5 → patchmatch_cython-0.2.0}/src/patchmatch_cython.egg-info/SOURCES.txt +7 -1
- patchmatch_cython-0.2.0/tests/test_basic_functionality.py +29 -0
- patchmatch_cython-0.2.0/tests/test_imageops.py +300 -0
- patchmatch_cython-0.2.0/tests/test_inpaint_api.py +137 -0
- patchmatch_cython-0.2.0/tests/test_quality_options.py +263 -0
- patchmatch_cython-0.2.0/tests/test_questionable_behaviors.py +241 -0
- patchmatch_cython-0.2.0/tests/test_solvers.py +137 -0
- patchmatch_cython-0.2.0/tests/test_validation.py +75 -0
- patchmatch_cython-0.1.5/README.md +0 -138
- patchmatch_cython-0.1.5/src/patchmatch_cython/cython_solver_impl.pyx +0 -297
- patchmatch_cython-0.1.5/src/patchmatch_cython/imageops.py +0 -200
- patchmatch_cython-0.1.5/src/patchmatch_cython/inpaint.py +0 -139
- patchmatch_cython-0.1.5/src/patchmatch_cython/python_solver.py +0 -318
- patchmatch_cython-0.1.5/tests/test_basic_functionality.py +0 -71
- {patchmatch_cython-0.1.5 → patchmatch_cython-0.2.0}/LICENSE +0 -0
- {patchmatch_cython-0.1.5 → patchmatch_cython-0.2.0}/MANIFEST.in +0 -0
- {patchmatch_cython-0.1.5 → patchmatch_cython-0.2.0}/local_build.py +0 -0
- {patchmatch_cython-0.1.5 → patchmatch_cython-0.2.0}/setup.cfg +0 -0
- {patchmatch_cython-0.1.5 → patchmatch_cython-0.2.0}/src/patchmatch_cython.egg-info/dependency_links.txt +0 -0
- {patchmatch_cython-0.1.5 → patchmatch_cython-0.2.0}/src/patchmatch_cython.egg-info/not-zip-safe +0 -0
- {patchmatch_cython-0.1.5 → patchmatch_cython-0.2.0}/src/patchmatch_cython.egg-info/requires.txt +0 -0
- {patchmatch_cython-0.1.5 → patchmatch_cython-0.2.0}/src/patchmatch_cython.egg-info/top_level.txt +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: patchmatch-cython
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.2.0
|
|
4
4
|
Summary: High-performance PatchMatch implementation for image inpainting using Cython
|
|
5
5
|
Home-page: https://github.com/Teriks/patchmatch-cython
|
|
6
6
|
Author: Teriks
|
|
@@ -70,16 +70,11 @@ Dynamic: requires-python
|
|
|
70
70
|
|
|
71
71
|
# PatchMatch Cython
|
|
72
72
|
|
|
73
|
-
High-performance PatchMatch implementation for pyramidical image inpainting in
|
|
73
|
+
High-performance PatchMatch implementation for pyramidical image inpainting in Cython.
|
|
74
74
|
|
|
75
|
-
This package can function without `python
|
|
75
|
+
This package can function without OpenCV (`opencv-python` / `opencv-python-headless`) with only slightly reduced quality and speed in a few helpers. When OpenCV is installed it is used for resize (`INTER_LINEAR` / `INTER_AREA`), morphology for valid/query centers, and distance transforms for seam feathering.
|
|
76
76
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
When OpenCV is not installed, an implementation of bilinear upscaling using numpy will be used.
|
|
80
|
-
|
|
81
|
-
This package provides a pure python solver and a cython solver, the cython solver is
|
|
82
|
-
around 30 to 50 times faster than the python solver depending on patch size.
|
|
77
|
+
The package provides a pure Python solver and a Cython solver; the Cython solver is typically about 30–50× faster depending on patch size.
|
|
83
78
|
|
|
84
79
|
## Installation
|
|
85
80
|
|
|
@@ -102,13 +97,10 @@ pip install .
|
|
|
102
97
|
import cv2
|
|
103
98
|
from patchmatch_cython import inpaint_pyramid
|
|
104
99
|
|
|
105
|
-
# Load image and mask
|
|
106
100
|
image = cv2.imread('image.jpg')
|
|
107
|
-
mask = cv2.imread('mask.png', 0) > 128
|
|
101
|
+
mask = cv2.imread('mask.png', 0) > 128 # True = hole to fill
|
|
108
102
|
|
|
109
|
-
# Inpaint
|
|
110
103
|
result = inpaint_pyramid(image, mask)
|
|
111
|
-
|
|
112
104
|
cv2.imwrite('result.jpg', result)
|
|
113
105
|
```
|
|
114
106
|
|
|
@@ -119,27 +111,84 @@ import numpy as np
|
|
|
119
111
|
from PIL import Image
|
|
120
112
|
from patchmatch_cython import inpaint_pyramid
|
|
121
113
|
|
|
122
|
-
# Load image and mask
|
|
123
114
|
image = np.array(Image.open('image.jpg'))
|
|
124
115
|
mask = np.array(Image.open('mask.png').convert('L')) > 128
|
|
125
116
|
|
|
126
|
-
|
|
127
|
-
result = inpaint_pyramid(image, mask)
|
|
128
|
-
|
|
117
|
+
result = inpaint_pyramid(image, mask) # auto-selects fastest available solver
|
|
129
118
|
Image.fromarray(result).save('result.jpg')
|
|
130
119
|
```
|
|
131
120
|
|
|
132
|
-
### Explicit
|
|
121
|
+
### Explicit solver selection
|
|
133
122
|
|
|
134
123
|
```python
|
|
135
124
|
from patchmatch_cython import PythonSolver, CythonSolver, inpaint_pyramid
|
|
136
125
|
|
|
137
|
-
# Force specific solver
|
|
138
126
|
result = inpaint_pyramid(image, mask, solver_class=CythonSolver) # Fast
|
|
139
127
|
result = inpaint_pyramid(image, mask, solver_class=PythonSolver) # Fallback
|
|
140
128
|
```
|
|
141
129
|
|
|
142
|
-
|
|
130
|
+
### Quality / compose options
|
|
131
|
+
|
|
132
|
+
Both `inpaint_pyramid` and `inpaint_single` accept the same optional knobs.
|
|
133
|
+
Defaults preserve a sensible baseline; turn options on when you need more structure,
|
|
134
|
+
completeness, or softer seams.
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from patchmatch_cython import inpaint_pyramid
|
|
138
|
+
|
|
139
|
+
result = inpaint_pyramid(
|
|
140
|
+
image,
|
|
141
|
+
mask,
|
|
142
|
+
patch_size=5, # odd int; square patch side
|
|
143
|
+
seed=0, # reproducible RNG (optional)
|
|
144
|
+
em_loops=2, # coarse match→vote→rematch loops (pyramid: coarse levels only)
|
|
145
|
+
edge_weighted=True, # structure-aware distance (boosted gradients)
|
|
146
|
+
reverse_search=True, # source→query completeness pass + stronger usage penalty
|
|
147
|
+
poisson_blend=True, # harmonic seam soften (default ~8px band)
|
|
148
|
+
hole_refine=3, # extra full-res PatchMatch iterations after the main solve
|
|
149
|
+
mask_feather=6.0, # soft compose width in px from the hole boundary
|
|
150
|
+
)
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
| Parameter | Default | Description |
|
|
154
|
+
|---|---|---|
|
|
155
|
+
| `patch_size` | `5` | Odd positive int; square patch size for matching / voting. |
|
|
156
|
+
| `seed` | `None` | RNG seed for reproducible NNF init / search. |
|
|
157
|
+
| `em_loops` | `1` | Outer match→paint→rematch loops. On pyramids, applied at coarse levels only (finest stays `1`). |
|
|
158
|
+
| `edge_weighted` | `False` | `False` = color-only matching. `True` = color + boosted gradient channels. Hole-touching gradients are suppressed so zeroed holes do not create fake edges. |
|
|
159
|
+
| `reverse_search` | `False` | After each EM loop, try assigning underused near-hole sources to better queries (completeness). |
|
|
160
|
+
| `poisson_blend` | `True` | Soften seams by blending the PatchMatch fill with a harmonic membrane near the hole rim. Ignored when `mask_feather > 0` (feather supplies the band). |
|
|
161
|
+
| `hole_refine` | `0` | Extra full-resolution PatchMatch iterations after the main solve (`0` disables). Only hole pixels are painted; the user mask is not modified. |
|
|
162
|
+
| `mask_feather` | `0.0` | Soft compose width in pixels from the hole boundary. Uses a distance ramp toward a harmonic rim pull (not the original hole content). Does **not** change the mask used for matching. |
|
|
163
|
+
|
|
164
|
+
`inpaint_single` is the same API plus `iterations` (PatchMatch passes at one scale):
|
|
165
|
+
|
|
166
|
+
```python
|
|
167
|
+
from patchmatch_cython import inpaint_single
|
|
168
|
+
|
|
169
|
+
result = inpaint_single(
|
|
170
|
+
image,
|
|
171
|
+
mask,
|
|
172
|
+
iterations=7,
|
|
173
|
+
em_loops=2,
|
|
174
|
+
reverse_search=True,
|
|
175
|
+
hole_refine=2,
|
|
176
|
+
mask_feather=4.0,
|
|
177
|
+
poisson_blend=False, # feather handles seams when mask_feather > 0
|
|
178
|
+
)
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
**Masks:** accept `bool`, `{0,1}`, or `{0,255}`. `True` / non-zero = region to inpaint. Known (unmasked) pixels are preserved in the output. The library never dilates/erodes the user mask for matching; `mask_feather` only affects final compositing.
|
|
182
|
+
|
|
183
|
+
**OpenCV runtime toggle** (optional):
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
from patchmatch_cython.imageops import set_use_opencv, opencv_available
|
|
187
|
+
|
|
188
|
+
set_use_opencv(False) # force NumPy fallbacks even if OpenCV is installed
|
|
189
|
+
```
|
|
190
|
+
|
|
191
|
+
## Package extras
|
|
143
192
|
|
|
144
193
|
**For examples:**
|
|
145
194
|
|
|
@@ -163,15 +212,13 @@ To build wheels locally for distribution or development:
|
|
|
163
212
|
|
|
164
213
|
### Prerequisites
|
|
165
214
|
|
|
166
|
-
Install build dependencies:
|
|
167
|
-
|
|
168
215
|
```bash
|
|
169
216
|
pip install cibuildwheel
|
|
170
217
|
```
|
|
171
218
|
|
|
172
|
-
### Build
|
|
219
|
+
### Build wheels
|
|
173
220
|
|
|
174
|
-
Use the included `local_build.py` script
|
|
221
|
+
Use the included `local_build.py` script:
|
|
175
222
|
|
|
176
223
|
```bash
|
|
177
224
|
# Build for all supported Python versions (3.10-3.14)
|
|
@@ -193,14 +240,13 @@ python local_build.py --no-clean
|
|
|
193
240
|
python local_build.py --help
|
|
194
241
|
```
|
|
195
242
|
|
|
196
|
-
### Build
|
|
243
|
+
### Build options
|
|
197
244
|
|
|
198
245
|
- `--python`: Specify Python versions to build for (e.g., `3.11 3.12`)
|
|
199
246
|
- `--platform`: Target platform (`auto`, `linux`, `macos`, `windows`)
|
|
200
247
|
- `--test`: Test wheel installation after building
|
|
201
248
|
- `--no-clean`: Skip cleaning build artifacts before building
|
|
202
249
|
|
|
203
|
-
|
|
204
250
|
## Requirements
|
|
205
251
|
|
|
206
252
|
- Python 3.10+
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
# PatchMatch Cython
|
|
2
|
+
|
|
3
|
+
High-performance PatchMatch implementation for pyramidical image inpainting in Cython.
|
|
4
|
+
|
|
5
|
+
This package can function without OpenCV (`opencv-python` / `opencv-python-headless`) with only slightly reduced quality and speed in a few helpers. When OpenCV is installed it is used for resize (`INTER_LINEAR` / `INTER_AREA`), morphology for valid/query centers, and distance transforms for seam feathering.
|
|
6
|
+
|
|
7
|
+
The package provides a pure Python solver and a Cython solver; the Cython solver is typically about 30–50× faster depending on patch size.
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
pip install patchmatch-cython
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
**From source:**
|
|
16
|
+
```bash
|
|
17
|
+
git clone <repository-url>
|
|
18
|
+
cd patchmatch-cython
|
|
19
|
+
pip install .
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
## Usage
|
|
23
|
+
|
|
24
|
+
### With OpenCV
|
|
25
|
+
|
|
26
|
+
```python
|
|
27
|
+
import cv2
|
|
28
|
+
from patchmatch_cython import inpaint_pyramid
|
|
29
|
+
|
|
30
|
+
image = cv2.imread('image.jpg')
|
|
31
|
+
mask = cv2.imread('mask.png', 0) > 128 # True = hole to fill
|
|
32
|
+
|
|
33
|
+
result = inpaint_pyramid(image, mask)
|
|
34
|
+
cv2.imwrite('result.jpg', result)
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### With Pillow
|
|
38
|
+
|
|
39
|
+
```python
|
|
40
|
+
import numpy as np
|
|
41
|
+
from PIL import Image
|
|
42
|
+
from patchmatch_cython import inpaint_pyramid
|
|
43
|
+
|
|
44
|
+
image = np.array(Image.open('image.jpg'))
|
|
45
|
+
mask = np.array(Image.open('mask.png').convert('L')) > 128
|
|
46
|
+
|
|
47
|
+
result = inpaint_pyramid(image, mask) # auto-selects fastest available solver
|
|
48
|
+
Image.fromarray(result).save('result.jpg')
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
### Explicit solver selection
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from patchmatch_cython import PythonSolver, CythonSolver, inpaint_pyramid
|
|
55
|
+
|
|
56
|
+
result = inpaint_pyramid(image, mask, solver_class=CythonSolver) # Fast
|
|
57
|
+
result = inpaint_pyramid(image, mask, solver_class=PythonSolver) # Fallback
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
### Quality / compose options
|
|
61
|
+
|
|
62
|
+
Both `inpaint_pyramid` and `inpaint_single` accept the same optional knobs.
|
|
63
|
+
Defaults preserve a sensible baseline; turn options on when you need more structure,
|
|
64
|
+
completeness, or softer seams.
|
|
65
|
+
|
|
66
|
+
```python
|
|
67
|
+
from patchmatch_cython import inpaint_pyramid
|
|
68
|
+
|
|
69
|
+
result = inpaint_pyramid(
|
|
70
|
+
image,
|
|
71
|
+
mask,
|
|
72
|
+
patch_size=5, # odd int; square patch side
|
|
73
|
+
seed=0, # reproducible RNG (optional)
|
|
74
|
+
em_loops=2, # coarse match→vote→rematch loops (pyramid: coarse levels only)
|
|
75
|
+
edge_weighted=True, # structure-aware distance (boosted gradients)
|
|
76
|
+
reverse_search=True, # source→query completeness pass + stronger usage penalty
|
|
77
|
+
poisson_blend=True, # harmonic seam soften (default ~8px band)
|
|
78
|
+
hole_refine=3, # extra full-res PatchMatch iterations after the main solve
|
|
79
|
+
mask_feather=6.0, # soft compose width in px from the hole boundary
|
|
80
|
+
)
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
| Parameter | Default | Description |
|
|
84
|
+
|---|---|---|
|
|
85
|
+
| `patch_size` | `5` | Odd positive int; square patch size for matching / voting. |
|
|
86
|
+
| `seed` | `None` | RNG seed for reproducible NNF init / search. |
|
|
87
|
+
| `em_loops` | `1` | Outer match→paint→rematch loops. On pyramids, applied at coarse levels only (finest stays `1`). |
|
|
88
|
+
| `edge_weighted` | `False` | `False` = color-only matching. `True` = color + boosted gradient channels. Hole-touching gradients are suppressed so zeroed holes do not create fake edges. |
|
|
89
|
+
| `reverse_search` | `False` | After each EM loop, try assigning underused near-hole sources to better queries (completeness). |
|
|
90
|
+
| `poisson_blend` | `True` | Soften seams by blending the PatchMatch fill with a harmonic membrane near the hole rim. Ignored when `mask_feather > 0` (feather supplies the band). |
|
|
91
|
+
| `hole_refine` | `0` | Extra full-resolution PatchMatch iterations after the main solve (`0` disables). Only hole pixels are painted; the user mask is not modified. |
|
|
92
|
+
| `mask_feather` | `0.0` | Soft compose width in pixels from the hole boundary. Uses a distance ramp toward a harmonic rim pull (not the original hole content). Does **not** change the mask used for matching. |
|
|
93
|
+
|
|
94
|
+
`inpaint_single` is the same API plus `iterations` (PatchMatch passes at one scale):
|
|
95
|
+
|
|
96
|
+
```python
|
|
97
|
+
from patchmatch_cython import inpaint_single
|
|
98
|
+
|
|
99
|
+
result = inpaint_single(
|
|
100
|
+
image,
|
|
101
|
+
mask,
|
|
102
|
+
iterations=7,
|
|
103
|
+
em_loops=2,
|
|
104
|
+
reverse_search=True,
|
|
105
|
+
hole_refine=2,
|
|
106
|
+
mask_feather=4.0,
|
|
107
|
+
poisson_blend=False, # feather handles seams when mask_feather > 0
|
|
108
|
+
)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
**Masks:** accept `bool`, `{0,1}`, or `{0,255}`. `True` / non-zero = region to inpaint. Known (unmasked) pixels are preserved in the output. The library never dilates/erodes the user mask for matching; `mask_feather` only affects final compositing.
|
|
112
|
+
|
|
113
|
+
**OpenCV runtime toggle** (optional):
|
|
114
|
+
|
|
115
|
+
```python
|
|
116
|
+
from patchmatch_cython.imageops import set_use_opencv, opencv_available
|
|
117
|
+
|
|
118
|
+
set_use_opencv(False) # force NumPy fallbacks even if OpenCV is installed
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Package extras
|
|
122
|
+
|
|
123
|
+
**For examples:**
|
|
124
|
+
|
|
125
|
+
```bash
|
|
126
|
+
pip install patchmatch-cython[visualization]
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
Adds: `matplotlib`, `Pillow`
|
|
130
|
+
|
|
131
|
+
**For development:**
|
|
132
|
+
|
|
133
|
+
```bash
|
|
134
|
+
pip install patchmatch-cython[dev]
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
Adds: `pytest`, `build`, `cibuildwheel`, `setuptools`, `wheel`
|
|
138
|
+
|
|
139
|
+
## Building
|
|
140
|
+
|
|
141
|
+
To build wheels locally for distribution or development:
|
|
142
|
+
|
|
143
|
+
### Prerequisites
|
|
144
|
+
|
|
145
|
+
```bash
|
|
146
|
+
pip install cibuildwheel
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
### Build wheels
|
|
150
|
+
|
|
151
|
+
Use the included `local_build.py` script:
|
|
152
|
+
|
|
153
|
+
```bash
|
|
154
|
+
# Build for all supported Python versions (3.10-3.14)
|
|
155
|
+
python local_build.py
|
|
156
|
+
|
|
157
|
+
# Build for specific Python versions
|
|
158
|
+
python local_build.py --python 3.11 3.12
|
|
159
|
+
|
|
160
|
+
# Build for specific platform
|
|
161
|
+
python local_build.py --platform linux
|
|
162
|
+
|
|
163
|
+
# Build and test wheel installation
|
|
164
|
+
python local_build.py --test
|
|
165
|
+
|
|
166
|
+
# Build without cleaning previous artifacts
|
|
167
|
+
python local_build.py --no-clean
|
|
168
|
+
|
|
169
|
+
# View all options
|
|
170
|
+
python local_build.py --help
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
### Build options
|
|
174
|
+
|
|
175
|
+
- `--python`: Specify Python versions to build for (e.g., `3.11 3.12`)
|
|
176
|
+
- `--platform`: Target platform (`auto`, `linux`, `macos`, `windows`)
|
|
177
|
+
- `--test`: Test wheel installation after building
|
|
178
|
+
- `--no-clean`: Skip cleaning build artifacts before building
|
|
179
|
+
|
|
180
|
+
## Requirements
|
|
181
|
+
|
|
182
|
+
- Python 3.10+
|
|
183
|
+
- NumPy (auto-installed)
|
|
184
|
+
- C++ compiler (for building from source)
|
|
@@ -47,12 +47,13 @@ def get_compiler_args():
|
|
|
47
47
|
# with "unsupported option '-mcpu='".
|
|
48
48
|
if archs == ["arm64"]:
|
|
49
49
|
return ["-O3", "-mcpu=apple-m1"]
|
|
50
|
-
# -march=native
|
|
51
|
-
if archs == ["x86_64"] and platform.machine().lower() in ("x86_64", "amd64"):
|
|
52
|
-
return ["-O3", "-march=native"]
|
|
50
|
+
# Avoid -march=native so wheels remain portable across CPUs.
|
|
53
51
|
return ["-O3"]
|
|
54
52
|
else: # Linux and other Unix-like
|
|
55
|
-
|
|
53
|
+
# Portable default; set PATCHMATCH_NATIVE=1 for local native builds.
|
|
54
|
+
if os.environ.get("PATCHMATCH_NATIVE") == "1":
|
|
55
|
+
return ["-O3", "-march=native"]
|
|
56
|
+
return ["-O3"]
|
|
56
57
|
|
|
57
58
|
# Build from Cython source only
|
|
58
59
|
extensions = [
|
|
@@ -82,7 +83,7 @@ with open("README.md", "r", encoding="utf-8") as fh:
|
|
|
82
83
|
|
|
83
84
|
setup(
|
|
84
85
|
name="patchmatch-cython",
|
|
85
|
-
version="0.
|
|
86
|
+
version="0.2.0",
|
|
86
87
|
author="Teriks",
|
|
87
88
|
author_email="Teriks999@gmail.com",
|
|
88
89
|
description="High-performance PatchMatch implementation for image inpainting using Cython",
|
|
@@ -41,14 +41,22 @@ class CythonSolver(Solver):
|
|
|
41
41
|
self,
|
|
42
42
|
image: np.ndarray,
|
|
43
43
|
mask: np.ndarray,
|
|
44
|
-
patch_size: int
|
|
44
|
+
patch_size: int,
|
|
45
|
+
edge_weighted: bool = False,
|
|
45
46
|
) -> None:
|
|
46
|
-
|
|
47
|
+
# Normalize mask to {0,1} uint8. Plain astype(uint8) leaves {0,255} masks
|
|
48
|
+
# unchanged; boolean indexing bugs are avoided by going through != 0.
|
|
49
|
+
image_f32 = np.ascontiguousarray(image, dtype=np.float32)
|
|
50
|
+
mask_u8 = (np.asarray(mask) != 0).astype(np.uint8)
|
|
51
|
+
super().__init__(
|
|
52
|
+
image_f32, mask_u8.astype(bool), patch_size, edge_weighted=edge_weighted
|
|
53
|
+
)
|
|
47
54
|
|
|
48
55
|
self._solver: typing.Any = CythonSolverImpl(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
patch_size
|
|
56
|
+
image_f32,
|
|
57
|
+
np.ascontiguousarray(mask_u8),
|
|
58
|
+
patch_size,
|
|
59
|
+
edge_weighted=bool(edge_weighted),
|
|
52
60
|
)
|
|
53
61
|
|
|
54
62
|
@property
|
|
@@ -64,7 +72,9 @@ class CythonSolver(Solver):
|
|
|
64
72
|
iterations: int = 5,
|
|
65
73
|
randomize_nnf: bool = True,
|
|
66
74
|
nnf: typing.Optional[np.ndarray] = None,
|
|
67
|
-
seed: typing.Optional[int] = None
|
|
75
|
+
seed: typing.Optional[int] = None,
|
|
76
|
+
em_loops: int = 1,
|
|
77
|
+
reverse_search: bool = False,
|
|
68
78
|
) -> np.ndarray:
|
|
69
79
|
"""
|
|
70
80
|
Run the PatchMatch algorithm using Cython acceleration.
|
|
@@ -85,8 +95,23 @@ class CythonSolver(Solver):
|
|
|
85
95
|
:type nnf: numpy.ndarray or None
|
|
86
96
|
:param seed: Random seed for this specific run (overrides instance seed)
|
|
87
97
|
:type seed: int or None
|
|
88
|
-
:
|
|
98
|
+
:param em_loops: Outer match→vote→rematch loops (1 preserves prior behavior)
|
|
99
|
+
:type em_loops: int
|
|
100
|
+
:param reverse_search: Enable reverse/completeness search after each EM loop
|
|
101
|
+
:type reverse_search: bool
|
|
102
|
+
:return: Inpainted image with masked regions filled (float32)
|
|
89
103
|
:rtype: numpy.ndarray
|
|
90
104
|
"""
|
|
91
105
|
|
|
92
|
-
|
|
106
|
+
# Keep float32 here so callers (and inpaint_*) can round/saturate once.
|
|
107
|
+
return np.asarray(
|
|
108
|
+
self._solver(
|
|
109
|
+
iterations,
|
|
110
|
+
randomize_nnf,
|
|
111
|
+
nnf,
|
|
112
|
+
seed,
|
|
113
|
+
em_loops,
|
|
114
|
+
reverse_search,
|
|
115
|
+
),
|
|
116
|
+
dtype=np.float32,
|
|
117
|
+
)
|