PyPatchMatch 2.0.0__py3-none-win_amd64.whl

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/__init__.py ADDED
@@ -0,0 +1,19 @@
1
+ """PatchMatch based inpainting."""
2
+
3
+ from ._version import __version__
4
+ from .patch_match import (
5
+ inpaint,
6
+ inpaint_regularity,
7
+ patchmatch_available,
8
+ set_random_seed,
9
+ set_verbose,
10
+ )
11
+
12
+ __all__ = [
13
+ "__version__",
14
+ "inpaint",
15
+ "inpaint_regularity",
16
+ "patchmatch_available",
17
+ "set_random_seed",
18
+ "set_verbose",
19
+ ]
patchmatch/_lib.py ADDED
@@ -0,0 +1,122 @@
1
+ """ctypes bindings for the native patchmatch library."""
2
+
3
+ from __future__ import annotations
4
+
5
+ import ctypes
6
+ import sys
7
+ from pathlib import Path
8
+
9
+ import numpy as np
10
+
11
+ if sys.platform == "win32":
12
+ LIBRARY_NAME = "patchmatch.dll"
13
+ elif sys.platform == "darwin":
14
+ LIBRARY_NAME = "libpatchmatch.dylib"
15
+ else:
16
+ LIBRARY_NAME = "libpatchmatch.so"
17
+
18
+
19
+ class CShapeT(ctypes.Structure):
20
+ _fields_ = [
21
+ ("width", ctypes.c_int),
22
+ ("height", ctypes.c_int),
23
+ ("channels", ctypes.c_int),
24
+ ]
25
+
26
+
27
+ class CMatT(ctypes.Structure):
28
+ _fields_ = [
29
+ ("data_ptr", ctypes.c_void_p),
30
+ ("shape", CShapeT),
31
+ ("dtype", ctypes.c_int),
32
+ ]
33
+
34
+
35
+ # Order matches the PM_dtype_e enum in csrc/pyinterface.h.
36
+ _PYMAT_DTYPES = [np.dtype(np.uint8), np.dtype(np.float32)]
37
+ _PYMAT_DTYPE_IDS = {dtype: i for i, dtype in enumerate(_PYMAT_DTYPES)}
38
+
39
+
40
+ def np_to_pymat(npmat: np.ndarray) -> CMatT:
41
+ """Wrap a contiguous HxWxC array without copying it."""
42
+ if npmat.ndim != 3:
43
+ raise ValueError(f"expected a 3-dimensional array, got {npmat.ndim} dims")
44
+ if not npmat.flags.c_contiguous:
45
+ raise ValueError("expected a C-contiguous array")
46
+ try:
47
+ dtype_id = _PYMAT_DTYPE_IDS[npmat.dtype]
48
+ except KeyError:
49
+ raise TypeError(f"unsupported dtype {npmat.dtype}") from None
50
+ height, width, channels = npmat.shape
51
+ return CMatT(
52
+ ctypes.c_void_p(npmat.ctypes.data),
53
+ CShapeT(width, height, channels),
54
+ dtype_id,
55
+ )
56
+
57
+
58
+ def pymat_to_np(pymat: CMatT) -> np.ndarray:
59
+ """Copy the data referenced by ``pymat`` into a new numpy array."""
60
+ dtype = _PYMAT_DTYPES[pymat.dtype]
61
+ shape = (pymat.shape.height, pymat.shape.width, pymat.shape.channels)
62
+ buffer = (ctypes.c_byte * (int(np.prod(shape)) * dtype.itemsize)).from_address(
63
+ pymat.data_ptr
64
+ )
65
+ return np.frombuffer(buffer, dtype=dtype).reshape(shape).copy()
66
+
67
+
68
+ def find_library() -> Path:
69
+ """Locate the shared library that is installed next to this package."""
70
+ package = sys.modules[__package__]
71
+ for directory in package.__path__:
72
+ candidate = Path(directory) / LIBRARY_NAME
73
+ if candidate.is_file():
74
+ return candidate
75
+ # Without a wheel for the platform, a failed build from the sdist installs the
76
+ # package without the library, see the overrides in pyproject.toml.
77
+ raise OSError(
78
+ f"{LIBRARY_NAME} not found in {list(package.__path__)}. Without a wheel for "
79
+ "this platform, PyPatchMatch is built from source, which needs a C++ "
80
+ "compiler, CMake and OpenCV. Install them and reinstall it without the "
81
+ "cache: pip install --force-reinstall --no-deps --no-cache-dir pypatchmatch"
82
+ )
83
+
84
+
85
+ def load_library() -> ctypes.CDLL:
86
+ lib = ctypes.CDLL(str(find_library()))
87
+
88
+ lib.PM_set_random_seed.argtypes = [ctypes.c_uint]
89
+ lib.PM_set_random_seed.restype = None
90
+ lib.PM_set_verbose.argtypes = [ctypes.c_int]
91
+ lib.PM_set_verbose.restype = None
92
+ lib.PM_free_pymat.argtypes = [CMatT]
93
+ lib.PM_free_pymat.restype = None
94
+ lib.PM_last_error.argtypes = []
95
+ lib.PM_last_error.restype = ctypes.c_char_p
96
+
97
+ lib.PM_inpaint.argtypes = [CMatT, CMatT, ctypes.c_int]
98
+ lib.PM_inpaint2.argtypes = [CMatT, CMatT, CMatT, ctypes.c_int]
99
+ lib.PM_inpaint_regularity.argtypes = [
100
+ CMatT,
101
+ CMatT,
102
+ CMatT,
103
+ ctypes.c_int,
104
+ ctypes.c_float,
105
+ ]
106
+ lib.PM_inpaint2_regularity.argtypes = [
107
+ CMatT,
108
+ CMatT,
109
+ CMatT,
110
+ CMatT,
111
+ ctypes.c_int,
112
+ ctypes.c_float,
113
+ ]
114
+ for func in (
115
+ lib.PM_inpaint,
116
+ lib.PM_inpaint2,
117
+ lib.PM_inpaint_regularity,
118
+ lib.PM_inpaint2_regularity,
119
+ ):
120
+ func.restype = CMatT
121
+
122
+ return lib
patchmatch/_version.py ADDED
@@ -0,0 +1,24 @@
1
+ # file generated by vcs-versioning
2
+ # don't change, don't track in version control
3
+ from __future__ import annotations
4
+
5
+ __all__ = [
6
+ "__version__",
7
+ "__version_tuple__",
8
+ "version",
9
+ "version_tuple",
10
+ "__commit_id__",
11
+ "commit_id",
12
+ ]
13
+
14
+ version: str
15
+ __version__: str
16
+ __version_tuple__: tuple[int | str, ...]
17
+ version_tuple: tuple[int | str, ...]
18
+ commit_id: str | None
19
+ __commit_id__: str | None
20
+
21
+ __version__ = version = '2.0.0'
22
+ __version_tuple__ = version_tuple = (2, 0, 0)
23
+
24
+ __commit_id__ = commit_id = None
@@ -0,0 +1,239 @@
1
+ # File : patch_match.py
2
+ # Author : Jiayuan Mao
3
+ # Email : maojiayuan@gmail.com
4
+ # Date : 01/09/2020
5
+ #
6
+ # Distributed under terms of the MIT license.
7
+ #
8
+ # Additional modifications by Kyle Schouviller and Matthias Wild
9
+
10
+ """PatchMatch based inpainting.
11
+
12
+ PatchMatch: A Randomized Correspondence Algorithm for Structural Image Editing.
13
+ C. Barnes, E. Shechtman, A. Finkelstein and Dan B. Goldman. SIGGRAPH 2009.
14
+ """
15
+
16
+ from __future__ import annotations
17
+
18
+ import ctypes
19
+ import logging
20
+ import math
21
+ import operator
22
+ from collections.abc import Callable
23
+ from typing import SupportsIndex, TypeAlias
24
+
25
+ import numpy as np
26
+ from PIL import Image
27
+
28
+ # CMatT and CShapeT are re-exported for backwards compatibility
29
+ from ._lib import CMatT as CMatT
30
+ from ._lib import CShapeT as CShapeT
31
+ from ._lib import load_library, np_to_pymat, pymat_to_np
32
+
33
+ __all__ = [
34
+ "inpaint",
35
+ "inpaint_regularity",
36
+ "patchmatch_available",
37
+ "set_random_seed",
38
+ "set_verbose",
39
+ ]
40
+
41
+ logger = logging.getLogger(__name__)
42
+
43
+ ImageLike: TypeAlias = np.ndarray | Image.Image
44
+
45
+ try:
46
+ _lib: ctypes.CDLL | None = load_library()
47
+ except OSError as e:
48
+ _lib = None
49
+ logger.warning("patchmatch failed to load: %s", e)
50
+
51
+ # True if the native library was loaded successfully.
52
+ patchmatch_available = _lib is not None
53
+
54
+ # The native code computes 2 * patch_size + 1 as a C int.
55
+ _MAX_PATCH_SIZE = (2**31 - 2) // 2
56
+
57
+
58
+ def _get_lib() -> ctypes.CDLL:
59
+ if _lib is None:
60
+ raise RuntimeError("the patchmatch native library is not available")
61
+ return _lib
62
+
63
+
64
+ def set_random_seed(seed: int) -> None:
65
+ _get_lib().PM_set_random_seed(ctypes.c_uint(seed))
66
+
67
+
68
+ def set_verbose(verbose: bool) -> None:
69
+ _get_lib().PM_set_verbose(ctypes.c_int(verbose))
70
+
71
+
72
+ def inpaint(
73
+ image: ImageLike,
74
+ mask: ImageLike | None = None,
75
+ *,
76
+ global_mask: ImageLike | None = None,
77
+ patch_size: SupportsIndex = 15,
78
+ ) -> np.ndarray:
79
+ """Fill the masked regions of ``image`` using PatchMatch.
80
+
81
+ Args:
82
+ image: 3-channel uint8 RGB/BGR image.
83
+ mask: 1-channel uint8 or bool mask of the hole(s) to fill (non-zero = hole),
84
+ with the same height and width as ``image``. If ``None``, all pure
85
+ white pixels (255, 255, 255) are treated as holes.
86
+ global_mask: mask like ``mask`` of pixels that are neither filled nor used as
87
+ a source; they keep their values from ``image``.
88
+ patch_size: radius of the compared patches, which span
89
+ ``(2 * patch_size + 1) ** 2`` pixels. Larger patches follow larger
90
+ structures but are much slower; the examples use 3.
91
+
92
+ Returns:
93
+ The repaired image, with the same shape as ``image``. Only the holes are
94
+ filled; all other pixels keep their values from ``image``.
95
+ """
96
+ lib = _get_lib()
97
+ patch_size = _check_patch_size(patch_size)
98
+ image, mask, global_mask = _prepare_inputs(image, mask, global_mask)
99
+ # OpenCV 4.6 turns an empty image into one of shape (0, 0, 1)
100
+ if image.size == 0:
101
+ return image.copy()
102
+
103
+ if global_mask is None:
104
+ return _call(lib.PM_inpaint, image, mask, ctypes.c_int(patch_size))
105
+ return _call(lib.PM_inpaint2, image, mask, global_mask, ctypes.c_int(patch_size))
106
+
107
+
108
+ def inpaint_regularity(
109
+ image: ImageLike,
110
+ mask: ImageLike | None,
111
+ ijmap: np.ndarray,
112
+ *,
113
+ global_mask: ImageLike | None = None,
114
+ patch_size: SupportsIndex = 15,
115
+ guide_weight: float = 0.25,
116
+ ) -> np.ndarray:
117
+ """Like :func:`inpaint`, additionally guided by a regularity map.
118
+
119
+ Args:
120
+ ijmap: HxWx3 float32 array of finite values with the regularity coordinates
121
+ of each pixel in the first two channels; the third channel is unused.
122
+ A map of a different size is scaled to the image.
123
+ guide_weight: non-negative weight of the regularity term relative to the
124
+ patch distance.
125
+ """
126
+ lib = _get_lib()
127
+ patch_size = _check_patch_size(patch_size)
128
+ image, mask, global_mask = _prepare_inputs(image, mask, global_mask)
129
+
130
+ if not (
131
+ isinstance(ijmap, np.ndarray)
132
+ and ijmap.ndim == 3
133
+ and ijmap.shape[2] == 3
134
+ and ijmap.dtype == np.float32
135
+ and ijmap.size > 0
136
+ ):
137
+ raise ValueError("ijmap must be a non-empty HxWx3 float32 array")
138
+ # NaN and infinity turn into out-of-range patch distances in the native code
139
+ if not np.isfinite(ijmap).all():
140
+ raise ValueError("ijmap must only contain finite values")
141
+ ijmap = np.ascontiguousarray(ijmap)
142
+
143
+ # the native code divides by 1 + guide_weight and indexes a table with the result
144
+ guide_weight = float(guide_weight)
145
+ if not (math.isfinite(guide_weight) and guide_weight >= 0):
146
+ raise ValueError(
147
+ f"guide_weight must be a finite number >= 0, got {guide_weight}"
148
+ )
149
+
150
+ # OpenCV 4.6 turns an empty image into one of shape (0, 0, 1)
151
+ if image.size == 0:
152
+ return image.copy()
153
+
154
+ args = (ijmap, ctypes.c_int(patch_size), ctypes.c_float(guide_weight))
155
+ if global_mask is None:
156
+ return _call(lib.PM_inpaint_regularity, image, mask, *args)
157
+ return _call(lib.PM_inpaint2_regularity, image, mask, global_mask, *args)
158
+
159
+
160
+ def _check_patch_size(patch_size: SupportsIndex) -> int:
161
+ try:
162
+ patch_size = operator.index(patch_size)
163
+ except TypeError:
164
+ raise TypeError(
165
+ f"patch_size must be an integer, got {type(patch_size).__name__}"
166
+ ) from None
167
+ # The native code crashes for 0 and never terminates for negative sizes. ctypes
168
+ # silently wraps larger values into the C int range, e.g. 2**31 to a negative size.
169
+ if not 1 <= patch_size <= _MAX_PATCH_SIZE:
170
+ raise ValueError(
171
+ f"patch_size must be between 1 and {_MAX_PATCH_SIZE}, got {patch_size}"
172
+ )
173
+ return patch_size
174
+
175
+
176
+ def _prepare_inputs(
177
+ image: ImageLike,
178
+ mask: ImageLike | None,
179
+ global_mask: ImageLike | None,
180
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray | None]:
181
+ """Validate the inputs and convert them to contiguous arrays."""
182
+ image = _canonize_image_array(image)
183
+ mask = _default_mask(image) if mask is None else _canonize_mask_array(mask)
184
+ if global_mask is not None:
185
+ global_mask = _canonize_mask_array(global_mask)
186
+
187
+ # the native code indexes the masks with the image coordinates
188
+ for name, m in (("mask", mask), ("global_mask", global_mask)):
189
+ if m is not None and m.shape[:2] != image.shape[:2]:
190
+ raise ValueError(
191
+ f"{name} must have the same height and width as the image, "
192
+ f"got {m.shape[:2]} for an image of {image.shape[:2]}"
193
+ )
194
+ return image, mask, global_mask
195
+
196
+
197
+ def _call(func: Callable[..., CMatT], *args: object) -> np.ndarray:
198
+ """Call ``func`` with arrays converted to pymats and copy the result."""
199
+ lib = _get_lib()
200
+ c_args = [np_to_pymat(a) if isinstance(a, np.ndarray) else a for a in args]
201
+ ret = func(*c_args)
202
+ if not ret.data_ptr:
203
+ # the error message is kept per thread, like the call itself
204
+ message = lib.PM_last_error().decode(errors="replace").strip()
205
+ raise RuntimeError(f"patchmatch failed: {message}")
206
+ try:
207
+ return pymat_to_np(ret)
208
+ finally:
209
+ lib.PM_free_pymat(ret)
210
+
211
+
212
+ def _canonize_image_array(image: ImageLike) -> np.ndarray:
213
+ image = np.asarray(image)
214
+ if not (image.ndim == 3 and image.shape[2] == 3 and image.dtype == np.uint8):
215
+ raise ValueError(
216
+ "image must be an HxWx3 uint8 array, "
217
+ f"got shape {image.shape} and dtype {image.dtype}"
218
+ )
219
+ return np.ascontiguousarray(image)
220
+
221
+
222
+ def _canonize_mask_array(mask: ImageLike) -> np.ndarray:
223
+ mask = np.asarray(mask)
224
+ if mask.dtype == np.bool_: # e.g. boolean arrays or PIL images in mode "1"
225
+ mask = mask.astype(np.uint8)
226
+ if mask.ndim == 2:
227
+ mask = mask[..., np.newaxis]
228
+ if not (mask.ndim == 3 and mask.shape[2] == 1 and mask.dtype == np.uint8):
229
+ raise ValueError(
230
+ "mask must be an HxW or HxWx1 uint8 array, "
231
+ f"got shape {mask.shape} and dtype {mask.dtype}"
232
+ )
233
+ return np.ascontiguousarray(mask)
234
+
235
+
236
+ def _default_mask(image: np.ndarray) -> np.ndarray:
237
+ """Treat all pure white pixels as holes."""
238
+ mask = (image == 255).all(axis=2, keepdims=True).astype(np.uint8)
239
+ return np.ascontiguousarray(mask)
Binary file
patchmatch/py.typed ADDED
File without changes
@@ -0,0 +1,176 @@
1
+ Metadata-Version: 2.4
2
+ Name: PyPatchMatch
3
+ Version: 2.0.0
4
+ Summary: This library implements the PatchMatch based inpainting algorithm.
5
+ Keywords: inpainting,patchmatch,image-processing,opencv
6
+ Author-Email: The InvokeAI Project <lincoln.stein@gmail.com>, Jiayuan Mao <maojiayuan@gmail.com>, Kyle Schouviller <kyle0654@hotmail.com>, Matthias Wild <mauwii@outlook.de>, Younesse ANDAM <younesse.andam@gmail.com>
7
+ License-Expression: MIT
8
+ License-File: LICENSE
9
+ Classifier: Development Status :: 5 - Production/Stable
10
+ Classifier: Operating System :: MacOS
11
+ Classifier: Operating System :: Microsoft :: Windows
12
+ Classifier: Operating System :: POSIX :: Linux
13
+ Classifier: Programming Language :: C++
14
+ Classifier: Programming Language :: Python :: 3
15
+ Classifier: Programming Language :: Python :: 3.11
16
+ Classifier: Programming Language :: Python :: 3.12
17
+ Classifier: Programming Language :: Python :: 3.13
18
+ Classifier: Programming Language :: Python :: 3.14
19
+ Classifier: Programming Language :: Python :: 3.15
20
+ Classifier: Topic :: Multimedia :: Graphics
21
+ Classifier: Topic :: Scientific/Engineering :: Image Processing
22
+ Classifier: Typing :: Typed
23
+ Project-URL: Source Code, https://github.com/mauwii/PyPatchMatch
24
+ Project-URL: Issues, https://github.com/mauwii/PyPatchMatch/issues
25
+ Project-URL: Release Notes, https://github.com/mauwii/PyPatchMatch/releases
26
+ Requires-Python: >=3.11
27
+ Requires-Dist: numpy>=1.23.2
28
+ Requires-Dist: pillow>=9.2.0
29
+ Description-Content-Type: text/markdown
30
+
31
+ # PatchMatch based Inpainting
32
+
33
+ [![CI](https://github.com/mauwii/PyPatchMatch/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mauwii/PyPatchMatch/actions/workflows/ci.yml)
34
+ [![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=mauwii_PyPatchMatch&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=mauwii_PyPatchMatch)
35
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blueviolet.svg)](https://github.com/mauwii/PyPatchMatch/blob/main/LICENSE)
36
+ [![PyPI](https://img.shields.io/pypi/v/PyPatchMatch)](https://pypi.org/project/PyPatchMatch/)
37
+ [![Downloads](https://static.pepy.tech/badge/pypatchmatch)](https://pepy.tech/projects/pypatchmatch)
38
+ [![Ruff](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/ruff/main/assets/badge/v2.json)](https://github.com/astral-sh/ruff)
39
+
40
+ This library implements the PatchMatch based inpainting algorithm. It provides both C++
41
+ and Python interfaces. This implementation is heavily based on the implementation by
42
+ Younesse ANDAM: [younesse-cv/PatchMatch](https://github.com/younesse-cv/PatchMatch),
43
+ with some bug fixes, and updates.
44
+
45
+ ![Birdhouses removed from a photo by patchmatch.inpaint](https://raw.githubusercontent.com/mauwii/PyPatchMatch/v2.0.0/examples/images/readme_example.jpg)
46
+
47
+ From left to right: the photo, the input of
48
+ [examples/py_example.py](https://github.com/mauwii/PyPatchMatch/blob/main/examples/py_example.py)
49
+ with the birdhouses painted out in white, and its result.
50
+
51
+ ## Installation
52
+
53
+ ```sh
54
+ pip install PyPatchMatch
55
+ ```
56
+
57
+ Wheels for Linux (glibc, x86_64 and aarch64), macOS 11+ (arm64 and x86_64) and Windows
58
+ (x64) ship the compiled library with a statically linked OpenCV, so no compiler or
59
+ OpenCV installation is needed. On other platforms, e.g. Alpine Linux or Windows on ARM,
60
+ pip builds from the source distribution, which requires a C++17 compiler, CMake and the
61
+ OpenCV development files (e.g. `apt install libopencv-dev` or `brew install opencv`).
62
+
63
+ If that build fails, PyPatchMatch is installed without the native library instead of
64
+ blocking the installation: `patchmatch.patchmatch_available` is `False` and the
65
+ inpainting functions raise `RuntimeError`. After installing the missing tools, reinstall
66
+ it without the cached build:
67
+
68
+ ```sh
69
+ pip install --force-reinstall --no-deps --no-cache-dir PyPatchMatch
70
+ ```
71
+
72
+ ## Usage
73
+
74
+ Python (see
75
+ [examples/py_example.py](https://github.com/mauwii/PyPatchMatch/blob/main/examples/py_example.py)):
76
+
77
+ ```python
78
+ import patchmatch
79
+
80
+ image = ... # HxWx3 uint8 numpy array or PIL image
81
+ mask = ... # HxW uint8 or bool numpy array or PIL image, non-zero marks the holes
82
+ result = patchmatch.inpaint(image, mask, patch_size=3)
83
+ ```
84
+
85
+ The mask must have the same height and width as the image. If `mask` is omitted, all
86
+ pure white pixels are treated as holes. Only the holes are filled; all other pixels keep
87
+ their values, and the colors under the holes have no influence on the fill. Holes need
88
+ hard edges: an anti-aliased brush leaves light pixels along the edge of its strokes that
89
+ are not pure white, so they count as known and the fill continues them. Paint without
90
+ anti-aliasing or pass a mask that covers those pixels as well. The optional keyword
91
+ argument `global_mask`, in the same format, marks pixels that are neither filled nor
92
+ used as a source; they keep their values as well, and their colors have no influence on
93
+ the fill (see
94
+ [examples/py_example_global_mask.py](https://github.com/mauwii/PyPatchMatch/blob/main/examples/py_example_global_mask.py)).
95
+ `patchmatch.patchmatch_available` tells whether the native library could be loaded.
96
+ The previous import path `from patchmatch import patch_match` keeps working.
97
+
98
+ `patch_size` is the radius of the compared patches, which span `2 * patch_size + 1`
99
+ pixels in each direction. Larger patches follow larger structures but are much slower;
100
+ the default of 15 compares 31x31 patches, the examples use 3.
101
+
102
+ `patchmatch.set_random_seed(seed)` sets the seed of the randomized search and
103
+ `patchmatch.set_verbose(True)` prints the progress of the native code to stderr.
104
+ `patchmatch.inpaint_regularity(image, mask, ijmap)` additionally guides the search with
105
+ a regularity map, an HxWx3 float32 array with the regularity coordinates of each pixel
106
+ in its first two channels. Its `guide_weight` must be at least 0.
107
+
108
+ C++ (see
109
+ [examples/cpp_example.cpp](https://github.com/mauwii/PyPatchMatch/blob/main/examples/cpp_example.cpp),
110
+ build and run it with
111
+ [examples/cpp_example_run.sh](https://github.com/mauwii/PyPatchMatch/blob/main/examples/cpp_example_run.sh)):
112
+
113
+ ```cpp
114
+ #include "inpaint.h"
115
+
116
+ int main() {
117
+ cv::Mat image = ...;
118
+ cv::Mat mask = ...;
119
+
120
+ auto metric = PatchSSDDistanceMetric(5);
121
+ cv::Mat result = Inpainting(image, mask, &metric).run();
122
+ }
123
+ ```
124
+
125
+ The library is built with CMake; `PATCHMATCH_BUILD_EXAMPLES` builds the example.
126
+
127
+ ## Development
128
+
129
+ The project is managed with [uv](https://docs.astral.sh/uv/):
130
+
131
+ ```sh
132
+ uv sync # create .venv, build the library, install dev deps
133
+ uv run pre-commit install # enable ruff and the other hooks on commit
134
+ uv run pytest # run the test suite
135
+ uv run pytest -m "not e2e" # only the fast unit tests
136
+ uv run python scripts/evaluate_inpainting.py # measure the fill quality
137
+ ```
138
+
139
+ The evaluation cuts holes into the images of `examples/images`, compares the fills with
140
+ the original content and writes `examples/images/evaluation.html`, which shows them side
141
+ by side. `--baseline` evaluates another build of the library as well, e.g. of the main
142
+ branch; the docstring of the script explains the columns.
143
+ Pull requests that change the C++ code get this comparison with their base commit in the
144
+ summary of the workflow "Fill quality", and the HTML report as its artifact.
145
+
146
+ Releases are published to PyPI by creating a GitHub release; the version is taken from
147
+ its tag (e.g. `v2.0.0`). Every released wheel and sdist carries a build provenance
148
+ attestation: `gh attestation verify <file> -R mauwii/PyPatchMatch`.
149
+
150
+ ## License
151
+
152
+ PyPatchMatch is released under the
153
+ [MIT License](https://github.com/mauwii/PyPatchMatch/blob/main/LICENSE). The wheels
154
+ contain a statically linked build of OpenCV core (Apache-2.0) and its bundled
155
+ third-party code; their licenses are included in the `licenses/opencv` directory of the
156
+ wheel's `.dist-info`, and a CycloneDX SBOM of OpenCV (PEP 770) in
157
+ `sboms/opencv.cdx.json`, so that vulnerability scanners can find it.
158
+
159
+ ## README and COPYRIGHT by Younesse ANDAM
160
+
161
+ @Author: Younesse ANDAM
162
+
163
+ @Contact: <younesse.andam@gmail.com>
164
+
165
+ Description:
166
+
167
+ This project is a personal implementation of an algorithm called PATCHMATCH
168
+ that restores missing areas in an image. The algorithm is presented in the following
169
+ paper PatchMatch A Randomized Correspondence Algorithm for Structural Image Editing by
170
+ C.Barnes, E.Shechtman, A.Finkelstein and Dan B.Goldman ACM Transactions on Graphics
171
+ (Proc. SIGGRAPH), vol.28, aug-2009
172
+
173
+ For more information please refer to
174
+ <https://gfx.cs.princeton.edu/pubs/Barnes_2009_PAR/>
175
+
176
+ Copyright (c) 2010-2011
@@ -0,0 +1,16 @@
1
+ patchmatch/__init__.py,sha256=Xg_AyDjCY9obrk95tzu6h0ox1fttEczi_OKu3ycsSvM,345
2
+ patchmatch/_lib.py,sha256=KKEeHtn4I0IcRdG49FQV_xpezcar9LqlGD-kvf-pZiM,3740
3
+ patchmatch/_version.py,sha256=VSe8z1c-2znHD5SwdS66oTYzIMMZBTNvCi8rZuxkhq4,544
4
+ patchmatch/patch_match.py,sha256=WgStWyICUp97keT5CROxC1o-FjwlzhawcNUVst_Uolo,8328
5
+ patchmatch/patchmatch.dll,sha256=c0BfCKC4xV9lqYCyiuXrNLLtgIaVDFZyAPTda126sA4,900096
6
+ patchmatch/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ pypatchmatch-2.0.0.dist-info/METADATA,sha256=CkaOl9wKKoQDTMOZfViWYW1UcjniBZNYQk1lVau4KR0,8510
8
+ pypatchmatch-2.0.0.dist-info/WHEEL,sha256=QOQSSLDAidk39OMVpTfE4kjgcxpaKg4ohhjJQ7vAJpA,102
9
+ pypatchmatch-2.0.0.dist-info/licenses/LICENSE,sha256=6VGSBzoFC-2RWaUpfSom3IlBW3AZfOwDuZrVzOmfN_E,1101
10
+ pypatchmatch-2.0.0.dist-info/licenses/opencv/dlpack-LICENSE,sha256=Po9rw5J2pYbWDIxars4v-YkmIYHPKz0qEo21j5epMAw,11345
11
+ pypatchmatch-2.0.0.dist-info/licenses/opencv/flatbuffers-LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
12
+ pypatchmatch-2.0.0.dist-info/licenses/opencv/opencv-LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
13
+ pypatchmatch-2.0.0.dist-info/licenses/opencv/SoftFloat-COPYING.txt,sha256=DFsINlE22lJjnXd_Hr_AOYiwFp2AZVyQxZ8bP6PlJqI,1732
14
+ pypatchmatch-2.0.0.dist-info/licenses/opencv/zlib-LICENSE,sha256=4y_04A2dlJMFN2NSkdo55-YScDM0v2_ejH8Whv6KRaI,1002
15
+ pypatchmatch-2.0.0.dist-info/sboms/opencv.cdx.json,sha256=v6wP7Xzl-ZayAiWt7P8EKiCkygzvUEDVVAkG47ZHEls,870
16
+ pypatchmatch-2.0.0.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: scikit-build-core 1.1.0
3
+ Root-Is-Purelib: false
4
+ Tag: py3-none-win_amd64
5
+
@@ -0,0 +1,22 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2023 Matthias Wild
4
+ Copyright (c) 2020 Jiayuan Mao
5
+
6
+ Permission is hereby granted, free of charge, to any person obtaining a copy
7
+ of this software and associated documentation files (the "Software"), to deal
8
+ in the Software without restriction, including without limitation the rights
9
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
+ copies of the Software, and to permit persons to whom the Software is
11
+ furnished to do so, subject to the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be included in all
14
+ copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
+ SOFTWARE.
@@ -0,0 +1,36 @@
1
+
2
+ License for Berkeley SoftFloat Release 3c
3
+
4
+ John R. Hauser
5
+ 2017 February 10
6
+
7
+ The following applies to the whole of SoftFloat Release 3c as well as to
8
+ each source file individually.
9
+
10
+ Copyright 2011, 2012, 2013, 2014, 2015, 2016, 2017 The Regents of the
11
+ University of California. All rights reserved.
12
+
13
+ Redistribution and use in source and binary forms, with or without
14
+ modification, are permitted provided that the following conditions are met:
15
+
16
+ 1. Redistributions of source code must retain the above copyright notice,
17
+ this list of conditions, and the following disclaimer.
18
+
19
+ 2. Redistributions in binary form must reproduce the above copyright
20
+ notice, this list of conditions, and the following disclaimer in the
21
+ documentation and/or other materials provided with the distribution.
22
+
23
+ 3. Neither the name of the University nor the names of its contributors
24
+ may be used to endorse or promote products derived from this software
25
+ without specific prior written permission.
26
+
27
+ THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS "AS IS", AND ANY
28
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
29
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ARE
30
+ DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR ANY
31
+ DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
32
+ (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
33
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
34
+ ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36
+ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.