PyPatchMatch 2.0.0b1__py3-none-macosx_11_0_arm64.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,124 @@
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 = [
37
+ np.dtype(np.uint8),
38
+ np.dtype(np.int8),
39
+ np.dtype(np.uint16),
40
+ np.dtype(np.int16),
41
+ np.dtype(np.int32),
42
+ np.dtype(np.float32),
43
+ np.dtype(np.float64),
44
+ ]
45
+ _PYMAT_DTYPE_IDS = {dtype: i for i, dtype in enumerate(_PYMAT_DTYPES)}
46
+
47
+
48
+ def np_to_pymat(npmat: np.ndarray) -> CMatT:
49
+ """Wrap a contiguous HxWxC array without copying it."""
50
+ if npmat.ndim != 3:
51
+ raise ValueError(f"expected a 3-dimensional array, got {npmat.ndim} dims")
52
+ if not npmat.flags.c_contiguous:
53
+ raise ValueError("expected a C-contiguous array")
54
+ try:
55
+ dtype_id = _PYMAT_DTYPE_IDS[npmat.dtype]
56
+ except KeyError:
57
+ raise TypeError(f"unsupported dtype {npmat.dtype}") from None
58
+ height, width, channels = npmat.shape
59
+ return CMatT(
60
+ ctypes.c_void_p(npmat.ctypes.data),
61
+ CShapeT(width, height, channels),
62
+ dtype_id,
63
+ )
64
+
65
+
66
+ def pymat_to_np(pymat: CMatT) -> np.ndarray:
67
+ """Copy the data referenced by ``pymat`` into a new numpy array."""
68
+ dtype = _PYMAT_DTYPES[pymat.dtype]
69
+ shape = (pymat.shape.height, pymat.shape.width, pymat.shape.channels)
70
+ buffer = (ctypes.c_byte * (int(np.prod(shape)) * dtype.itemsize)).from_address(
71
+ pymat.data_ptr
72
+ )
73
+ return np.frombuffer(buffer, dtype=dtype).reshape(shape).copy()
74
+
75
+
76
+ def find_library() -> Path:
77
+ """Locate the shared library that is installed next to this package."""
78
+ package = sys.modules[__package__]
79
+ for directory in package.__path__:
80
+ candidate = Path(directory) / LIBRARY_NAME
81
+ if candidate.is_file():
82
+ return candidate
83
+ raise OSError(
84
+ f"{LIBRARY_NAME} not found in {list(package.__path__)}; "
85
+ "reinstall PyPatchMatch or build it from source with OpenCV available"
86
+ )
87
+
88
+
89
+ def load_library() -> ctypes.CDLL:
90
+ lib = ctypes.CDLL(str(find_library()))
91
+
92
+ lib.PM_set_random_seed.argtypes = [ctypes.c_uint]
93
+ lib.PM_set_random_seed.restype = None
94
+ lib.PM_set_verbose.argtypes = [ctypes.c_int]
95
+ lib.PM_set_verbose.restype = None
96
+ lib.PM_free_pymat.argtypes = [CMatT]
97
+ lib.PM_free_pymat.restype = None
98
+
99
+ lib.PM_inpaint.argtypes = [CMatT, CMatT, ctypes.c_int]
100
+ lib.PM_inpaint2.argtypes = [CMatT, CMatT, CMatT, ctypes.c_int]
101
+ lib.PM_inpaint_regularity.argtypes = [
102
+ CMatT,
103
+ CMatT,
104
+ CMatT,
105
+ ctypes.c_int,
106
+ ctypes.c_float,
107
+ ]
108
+ lib.PM_inpaint2_regularity.argtypes = [
109
+ CMatT,
110
+ CMatT,
111
+ CMatT,
112
+ CMatT,
113
+ ctypes.c_int,
114
+ ctypes.c_float,
115
+ ]
116
+ for func in (
117
+ lib.PM_inpaint,
118
+ lib.PM_inpaint2,
119
+ lib.PM_inpaint_regularity,
120
+ lib.PM_inpaint2_regularity,
121
+ ):
122
+ func.restype = CMatT
123
+
124
+ 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.0b1'
22
+ __version_tuple__ = version_tuple = (2, 0, 0, 'b1')
23
+
24
+ __commit_id__ = commit_id = None
Binary file
@@ -0,0 +1,183 @@
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
+ from collections.abc import Callable
21
+ from typing import TypeAlias
22
+
23
+ import numpy as np
24
+ from PIL import Image
25
+
26
+ from ._lib import CMatT, load_library, np_to_pymat, pymat_to_np
27
+ from ._lib import CShapeT as CShapeT # re-exported for backwards compatibility
28
+
29
+ __all__ = [
30
+ "inpaint",
31
+ "inpaint_regularity",
32
+ "patchmatch_available",
33
+ "set_random_seed",
34
+ "set_verbose",
35
+ ]
36
+
37
+ logger = logging.getLogger(__name__)
38
+
39
+ ImageLike: TypeAlias = np.ndarray | Image.Image
40
+
41
+ try:
42
+ _lib: ctypes.CDLL | None = load_library()
43
+ except OSError as e:
44
+ _lib = None
45
+ logger.warning("patchmatch failed to load: %s", e)
46
+
47
+ # True if the native library was loaded successfully.
48
+ patchmatch_available = _lib is not None
49
+
50
+
51
+ def _get_lib() -> ctypes.CDLL:
52
+ if _lib is None:
53
+ raise RuntimeError("the patchmatch native library is not available")
54
+ return _lib
55
+
56
+
57
+ def set_random_seed(seed: int) -> None:
58
+ _get_lib().PM_set_random_seed(ctypes.c_uint(seed))
59
+
60
+
61
+ def set_verbose(verbose: bool) -> None:
62
+ _get_lib().PM_set_verbose(ctypes.c_int(verbose))
63
+
64
+
65
+ def inpaint(
66
+ image: ImageLike,
67
+ mask: ImageLike | None = None,
68
+ *,
69
+ global_mask: ImageLike | None = None,
70
+ patch_size: int = 15,
71
+ ) -> np.ndarray:
72
+ """Fill the masked regions of ``image`` using PatchMatch.
73
+
74
+ Args:
75
+ image: 3-channel uint8 RGB/BGR image.
76
+ mask: 1-channel uint8 or bool mask of the hole(s) to fill (non-zero = hole),
77
+ with the same height and width as ``image``. If ``None``, all pure
78
+ white pixels (255, 255, 255) are treated as holes.
79
+ global_mask: mask like ``mask`` of pixels that must not be used as a source.
80
+ patch_size: patch size for the inpainting algorithm.
81
+
82
+ Returns:
83
+ The repaired image, with the same shape as ``image``.
84
+ """
85
+ lib = _get_lib()
86
+ image, mask, global_mask = _prepare_inputs(image, mask, global_mask)
87
+
88
+ if global_mask is None:
89
+ return _call(lib.PM_inpaint, image, mask, ctypes.c_int(patch_size))
90
+ return _call(lib.PM_inpaint2, image, mask, global_mask, ctypes.c_int(patch_size))
91
+
92
+
93
+ def inpaint_regularity(
94
+ image: ImageLike,
95
+ mask: ImageLike | None,
96
+ ijmap: np.ndarray,
97
+ *,
98
+ global_mask: ImageLike | None = None,
99
+ patch_size: int = 15,
100
+ guide_weight: float = 0.25,
101
+ ) -> np.ndarray:
102
+ """Like :func:`inpaint`, additionally guided by a regularity map.
103
+
104
+ Args:
105
+ ijmap: HxWx3 float32 array with the regularity coordinates of each pixel;
106
+ a map of a different size is scaled to the image.
107
+ guide_weight: weight of the regularity term relative to the patch distance.
108
+ """
109
+ lib = _get_lib()
110
+ image, mask, global_mask = _prepare_inputs(image, mask, global_mask)
111
+
112
+ if not (
113
+ isinstance(ijmap, np.ndarray)
114
+ and ijmap.ndim == 3
115
+ and ijmap.shape[2] == 3
116
+ and ijmap.dtype == np.float32
117
+ ):
118
+ raise ValueError("ijmap must be an HxWx3 float32 array")
119
+ ijmap = np.ascontiguousarray(ijmap)
120
+
121
+ args = (ijmap, ctypes.c_int(patch_size), ctypes.c_float(guide_weight))
122
+ if global_mask is None:
123
+ return _call(lib.PM_inpaint_regularity, image, mask, *args)
124
+ return _call(lib.PM_inpaint2_regularity, image, mask, global_mask, *args)
125
+
126
+
127
+ def _prepare_inputs(
128
+ image: ImageLike, mask: ImageLike | None, global_mask: ImageLike | None
129
+ ) -> tuple[np.ndarray, np.ndarray, np.ndarray | None]:
130
+ """Validate the inputs and convert them to contiguous arrays."""
131
+ image = _canonize_image_array(image)
132
+ mask = _default_mask(image) if mask is None else _canonize_mask_array(mask)
133
+ if global_mask is not None:
134
+ global_mask = _canonize_mask_array(global_mask)
135
+
136
+ # the native code indexes the masks with the image coordinates
137
+ for name, m in (("mask", mask), ("global_mask", global_mask)):
138
+ if m is not None and m.shape[:2] != image.shape[:2]:
139
+ raise ValueError(
140
+ f"{name} must have the same height and width as the image, "
141
+ f"got {m.shape[:2]} for an image of {image.shape[:2]}"
142
+ )
143
+ return image, mask, global_mask
144
+
145
+
146
+ def _call(func: Callable[..., CMatT], *args: object) -> np.ndarray:
147
+ """Call ``func`` with arrays converted to pymats and copy the result."""
148
+ c_args = [np_to_pymat(a) if isinstance(a, np.ndarray) else a for a in args]
149
+ ret = func(*c_args)
150
+ try:
151
+ return pymat_to_np(ret)
152
+ finally:
153
+ _get_lib().PM_free_pymat(ret)
154
+
155
+
156
+ def _canonize_image_array(image: ImageLike) -> np.ndarray:
157
+ image = np.asarray(image)
158
+ if not (image.ndim == 3 and image.shape[2] == 3 and image.dtype == np.uint8):
159
+ raise ValueError(
160
+ "image must be an HxWx3 uint8 array, "
161
+ f"got shape {image.shape} and dtype {image.dtype}"
162
+ )
163
+ return np.ascontiguousarray(image)
164
+
165
+
166
+ def _canonize_mask_array(mask: ImageLike) -> np.ndarray:
167
+ mask = np.asarray(mask)
168
+ if mask.dtype == np.bool_: # e.g. boolean arrays or PIL images in mode "1"
169
+ mask = mask.astype(np.uint8)
170
+ if mask.ndim == 2:
171
+ mask = mask[..., np.newaxis]
172
+ if not (mask.ndim == 3 and mask.shape[2] == 1 and mask.dtype == np.uint8):
173
+ raise ValueError(
174
+ "mask must be an HxW or HxWx1 uint8 array, "
175
+ f"got shape {mask.shape} and dtype {mask.dtype}"
176
+ )
177
+ return np.ascontiguousarray(mask)
178
+
179
+
180
+ def _default_mask(image: np.ndarray) -> np.ndarray:
181
+ """Treat all pure white pixels as holes."""
182
+ mask = (image == 255).all(axis=2, keepdims=True).astype(np.uint8)
183
+ return np.ascontiguousarray(mask)
patchmatch/py.typed ADDED
File without changes
@@ -0,0 +1,118 @@
1
+ Metadata-Version: 2.4
2
+ Name: PyPatchMatch
3
+ Version: 2.0.0b1
4
+ Summary: This library implements the PatchMatch based inpainting algorithm.
5
+ Author-Email: The InvokeAI Project <lincoln.stein@gmail.com>, Kyle Schouviller <kyle0654@hotmail.com>, Matthias Wild <mauwii@outlook.de>, Younesse ANDAM <younesse.andam@gmail.com>
6
+ License-Expression: MIT
7
+ License-File: LICENSE
8
+ Classifier: Programming Language :: C++
9
+ Classifier: Programming Language :: Python :: 3
10
+ Classifier: Programming Language :: Python :: 3.10
11
+ Classifier: Programming Language :: Python :: 3.11
12
+ Classifier: Programming Language :: Python :: 3.12
13
+ Classifier: Programming Language :: Python :: 3.13
14
+ Classifier: Programming Language :: Python :: 3.14
15
+ Classifier: Topic :: Multimedia :: Graphics
16
+ Classifier: Topic :: Scientific/Engineering :: Image Processing
17
+ Project-URL: Source Code, https://github.com/mauwii/PyPatchMatch
18
+ Requires-Python: >=3.10
19
+ Requires-Dist: numpy
20
+ Requires-Dist: pillow
21
+ Description-Content-Type: text/markdown
22
+
23
+ # PatchMatch based Inpainting
24
+
25
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blueviolet.svg)](https://github.com/mauwii/PyPatchMatch/blob/main/LICENSE)
26
+ [![PyPI](https://img.shields.io/pypi/v/PyPatchMatch)](https://pypi.org/project/PyPatchMatch/)
27
+ [![Downloads](https://static.pepy.tech/badge/pypatchmatch)](https://pepy.tech/project/pypatchmatch)
28
+ [![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)
29
+
30
+ This library implements the PatchMatch based inpainting algorithm. It provides both C++
31
+ and Python interfaces. This implementation is heavily based on the implementation by
32
+ Younesse ANDAM: [younesse-cv/PatchMatch](https://github.com/younesse-cv/PatchMatch),
33
+ with some bug fixes, and updates.
34
+
35
+ ## Installation
36
+
37
+ ```sh
38
+ pip install PyPatchMatch
39
+ ```
40
+
41
+ Wheels for Linux, macOS and Windows ship the compiled library including the required
42
+ OpenCV runtime, so no compiler or OpenCV installation is needed. On other platforms pip
43
+ builds from the source distribution, which requires a C++17 compiler, CMake and the
44
+ OpenCV development files (e.g. `apt install libopencv-dev` or `brew install opencv`).
45
+
46
+ ## Usage
47
+
48
+ Python (see [examples/py_example.py](examples/py_example.py)):
49
+
50
+ ```python
51
+ import patchmatch
52
+
53
+ image = ... # HxWx3 uint8 numpy array or PIL image
54
+ mask = ... # HxW uint8 or bool numpy array or PIL image, non-zero marks the holes
55
+ result = patchmatch.inpaint(image, mask, patch_size=3)
56
+ ```
57
+
58
+ The mask must have the same height and width as the image. If `mask` is omitted, all
59
+ pure white pixels are treated as holes.
60
+ `patchmatch.patchmatch_available` tells whether the native library could be loaded.
61
+ The previous import path `from patchmatch import patch_match` keeps working.
62
+
63
+ C++ (see [examples/cpp_example.cpp](examples/cpp_example.cpp), build and run it with
64
+ [examples/cpp_example_run.sh](examples/cpp_example_run.sh)):
65
+
66
+ ```cpp
67
+ #include "inpaint.h"
68
+
69
+ int main() {
70
+ cv::Mat image = ...;
71
+ cv::Mat mask = ...;
72
+
73
+ auto metric = PatchSSDDistanceMetric(5);
74
+ cv::Mat result = Inpainting(image, mask, &metric).run();
75
+ }
76
+ ```
77
+
78
+ The library is built with CMake; `PATCHMATCH_BUILD_EXAMPLES` builds the example and
79
+ `PATCHMATCH_WITH_HIGHGUI` enables the debug visualization of `Inpainting::run`.
80
+
81
+ ## Development
82
+
83
+ The project is managed with [uv](https://docs.astral.sh/uv/):
84
+
85
+ ```sh
86
+ uv sync # create .venv, build the library, install dev deps
87
+ uv run pre-commit install # enable ruff and the other hooks on commit
88
+ uv run pytest # run the test suite
89
+ uv run pytest -m "not e2e" # only the fast unit tests
90
+ ```
91
+
92
+ Releases are published to PyPI by creating a GitHub release; the version is taken from
93
+ its tag (e.g. `v1.1.0`).
94
+
95
+ ## README and COPYRIGHT by Younesse ANDAM
96
+
97
+ @Author: Younesse ANDAM
98
+
99
+ @Contact: younesse.andam@gmail.com
100
+
101
+ Description:
102
+
103
+ This project is a personal implementation of an algorithm called PATCHMATCH
104
+ that restores missing areas in an image. The algorithm is presented in the following
105
+ paper PatchMatch A Randomized Correspondence Algorithm for Structural Image Editing by
106
+ C.Barnes, E.Shechtman, A.Finkelstein and Dan B.Goldman ACM Transactions on Graphics
107
+ (Proc. SIGGRAPH), vol.28, aug-2009
108
+
109
+ For more information please refer to
110
+ http://www.cs.princeton.edu/gfx/pubs/Barnes_2009_PAR/index.php
111
+
112
+ Copyright (c) 2010-2011
113
+
114
+ ## Requirements
115
+
116
+ To run the project you need to install Opencv library and link it to your project.
117
+ Opencv can be download it here
118
+ http://opencv.org/downloads.html
@@ -0,0 +1,10 @@
1
+ patchmatch/_version.py,sha256=5Mjj8BHQfkFMFCymzp7wS1ihg7-kJNbFLOz8wmyJ-mY,528
2
+ patchmatch/__init__.py,sha256=Xg_AyDjCY9obrk95tzu6h0ox1fttEczi_OKu3ycsSvM,345
3
+ patchmatch/libpatchmatch.dylib,sha256=E-eoa7S9iNra1JAUtNyoOQW8ayILHoABPyhZLtSwTq8,2809024
4
+ patchmatch/patch_match.py,sha256=774tjbBg1HVEfyrf4V9fMYr4KBrRDPUtdJL4aG926Vw,5998
5
+ patchmatch/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
6
+ patchmatch/_lib.py,sha256=1DayYVBWlQ2b8AB_4fCL4Cyxicue77_eURyVhTX1mGU,3448
7
+ pypatchmatch-2.0.0b1.dist-info/RECORD,,
8
+ pypatchmatch-2.0.0b1.dist-info/WHEEL,sha256=1Big0Cn6LCpgYnkzxn-ESHZfABrxq9SG62kfQRLXJmA,137
9
+ pypatchmatch-2.0.0b1.dist-info/METADATA,sha256=-PEXUIFHHlgbC4J_bkwdLjraBWsrI599MqUTS7PwvKM,4539
10
+ pypatchmatch-2.0.0b1.dist-info/licenses/LICENSE,sha256=6VGSBzoFC-2RWaUpfSom3IlBW3AZfOwDuZrVzOmfN_E,1101
@@ -0,0 +1,6 @@
1
+ Wheel-Version: 1.0
2
+ Generator: scikit-build-core 1.0.3
3
+ Root-Is-Purelib: false
4
+ Tag: py3-none-macosx_11_0_arm64
5
+ Generator: delocate 0.13.0
6
+
@@ -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.