PyPatchMatch 2.0.1__py3-none-win_amd64.whl → 2.0.2__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/_version.py CHANGED
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
18
18
  commit_id: str | None
19
19
  __commit_id__: str | None
20
20
 
21
- __version__ = version = '2.0.1'
22
- __version_tuple__ = version_tuple = (2, 0, 1)
21
+ __version__ = version = '2.0.2'
22
+ __version_tuple__ = version_tuple = (2, 0, 2)
23
23
 
24
24
  __commit_id__ = commit_id = None
patchmatch/patch_match.py CHANGED
@@ -17,7 +17,6 @@ from __future__ import annotations
17
17
 
18
18
  import ctypes
19
19
  import logging
20
- import math
21
20
  import operator
22
21
  from collections.abc import Callable
23
22
  from typing import SupportsIndex, TypeAlias
@@ -44,7 +43,9 @@ ImageLike: TypeAlias = np.ndarray | Image.Image
44
43
 
45
44
  try:
46
45
  _lib: ctypes.CDLL | None = load_library()
47
- except OSError as e:
46
+ except (OSError, AttributeError) as e:
47
+ # AttributeError: a library without the PM_* functions, e.g. one that 1.x
48
+ # compiled into the package directory and that pip does not remove on upgrade
48
49
  _lib = None
49
50
  logger.warning("patchmatch failed to load: %s", e)
50
51
 
@@ -54,6 +55,9 @@ patchmatch_available = _lib is not None
54
55
  # The native code computes 2 * patch_size + 1 as a C int.
55
56
  _MAX_PATCH_SIZE = (2**31 - 2) // 2
56
57
 
58
+ # The native code takes a C float, which turns larger weights into infinity.
59
+ _MAX_GUIDE_WEIGHT = float(np.finfo(np.float32).max)
60
+
57
61
 
58
62
  def _get_lib() -> ctypes.CDLL:
59
63
  if _lib is None:
@@ -62,10 +66,17 @@ def _get_lib() -> ctypes.CDLL:
62
66
 
63
67
 
64
68
  def set_random_seed(seed: int) -> None:
69
+ """Set the seed of the randomized search of all following inpaintings.
70
+
71
+ Every inpainting starts from this seed, so equal inputs give equal results. The
72
+ native code keeps it as a 32-bit unsigned int, so ``seed`` is taken modulo
73
+ ``2**32``: ``2**32`` behaves like 0 and -1 like ``2**32 - 1``.
74
+ """
65
75
  _get_lib().PM_set_random_seed(ctypes.c_uint(seed))
66
76
 
67
77
 
68
78
  def set_verbose(verbose: bool) -> None:
79
+ """Print the progress of all following inpaintings to stderr if ``verbose``."""
69
80
  _get_lib().PM_set_verbose(ctypes.c_int(verbose))
70
81
 
71
82
 
@@ -96,8 +107,7 @@ def inpaint(
96
107
  lib = _get_lib()
97
108
  patch_size = _check_patch_size(patch_size)
98
109
  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:
110
+ if not _has_holes(mask, global_mask):
101
111
  return image.copy()
102
112
 
103
113
  if global_mask is None:
@@ -140,15 +150,16 @@ def inpaint_regularity(
140
150
  raise ValueError("ijmap must only contain finite values")
141
151
  ijmap = np.ascontiguousarray(ijmap)
142
152
 
143
- # the native code divides by 1 + guide_weight and indexes a table with the result
153
+ # the native code divides by 1 + guide_weight and indexes a table with the result;
154
+ # the comparison also rejects NaN
144
155
  guide_weight = float(guide_weight)
145
- if not (math.isfinite(guide_weight) and guide_weight >= 0):
156
+ if not 0 <= guide_weight <= _MAX_GUIDE_WEIGHT:
146
157
  raise ValueError(
147
- f"guide_weight must be a finite number >= 0, got {guide_weight}"
158
+ f"guide_weight must be between 0 and {_MAX_GUIDE_WEIGHT:g}, "
159
+ f"got {guide_weight}"
148
160
  )
149
161
 
150
- # OpenCV 4.6 turns an empty image into one of shape (0, 0, 1)
151
- if image.size == 0:
162
+ if not _has_holes(mask, global_mask):
152
163
  return image.copy()
153
164
 
154
165
  args = (ijmap, ctypes.c_int(patch_size), ctypes.c_float(guide_weight))
@@ -194,6 +205,19 @@ def _prepare_inputs(
194
205
  return image, mask, global_mask
195
206
 
196
207
 
208
+ def _has_holes(mask: np.ndarray, global_mask: np.ndarray | None) -> bool:
209
+ """Whether a hole lies outside the global mask.
210
+
211
+ Otherwise the result equals the input, but the native code still runs every
212
+ level of the pyramid. This also covers empty images, which OpenCV 4.6 would
213
+ return with the shape (0, 0, 1).
214
+ """
215
+ holes = mask != 0
216
+ if global_mask is not None:
217
+ holes &= global_mask == 0
218
+ return bool(holes.any())
219
+
220
+
197
221
  def _call(func: Callable[..., CMatT], *args: object) -> np.ndarray:
198
222
  """Call ``func`` with arrays converted to pymats and copy the result."""
199
223
  lib = _get_lib()
patchmatch/patchmatch.dll CHANGED
Binary file
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: PyPatchMatch
3
- Version: 2.0.1
3
+ Version: 2.0.2
4
4
  Summary: This library implements the PatchMatch based inpainting algorithm.
5
5
  Keywords: inpainting,patchmatch,image-processing,opencv
6
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>
@@ -42,7 +42,7 @@ and Python interfaces. This implementation is heavily based on the implementatio
42
42
  Younesse ANDAM: [younesse-cv/PatchMatch](https://github.com/younesse-cv/PatchMatch),
43
43
  with some bug fixes, and updates.
44
44
 
45
- ![Birdhouses removed from a photo by patchmatch.inpaint](https://raw.githubusercontent.com/mauwii/PyPatchMatch/v2.0.1/examples/images/readme_example.jpg)
45
+ ![Birdhouses removed from a photo by patchmatch.inpaint](https://raw.githubusercontent.com/mauwii/PyPatchMatch/v2.0.2/examples/images/readme_example.jpg)
46
46
 
47
47
  From left to right: the photo, the input of
48
48
  [examples/py_example.py](https://github.com/mauwii/PyPatchMatch/blob/main/examples/py_example.py)
@@ -99,11 +99,12 @@ The previous import path `from patchmatch import patch_match` keeps working.
99
99
  pixels in each direction. Larger patches follow larger structures but are much slower;
100
100
  the default of 15 compares 31x31 patches, the examples use 3.
101
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.
102
+ `patchmatch.set_random_seed(seed)` sets the seed of the randomized search, modulo
103
+ `2**32`, and `patchmatch.set_verbose(True)` prints the progress of the native code to
104
+ stderr. `patchmatch.inpaint_regularity(image, mask, ijmap)` additionally guides the
105
+ search with a regularity map, an HxWx3 float32 array with the regularity coordinates of
106
+ each pixel in its first two channels. Its `guide_weight` must be between 0 and the
107
+ largest float32, about 3.4e38.
107
108
 
108
109
  C++ (see
109
110
  [examples/cpp_example.cpp](https://github.com/mauwii/PyPatchMatch/blob/main/examples/cpp_example.cpp),
@@ -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=ipBLbz_DzIdbN7o8rhQ_qQaSGyFnROBxzHlE8soIfNw,544
4
+ patchmatch/patch_match.py,sha256=NPTKbLRc3IzbooV_5hu_imxBEZ2gbWyKLS0XRnjIVOE,9434
5
+ patchmatch/patchmatch.dll,sha256=AQ_VgCwUpN7pisGgAOl5CtfIPWFIi3jrNwrd2-HkA90,1537024
6
+ patchmatch/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
+ pypatchmatch-2.0.2.dist-info/METADATA,sha256=_hbdKCIKVMDP-ETiQmkwRsg4moMJrsu3yEakEGygFjk,8564
8
+ pypatchmatch-2.0.2.dist-info/WHEEL,sha256=QOQSSLDAidk39OMVpTfE4kjgcxpaKg4ohhjJQ7vAJpA,102
9
+ pypatchmatch-2.0.2.dist-info/licenses/LICENSE,sha256=6VGSBzoFC-2RWaUpfSom3IlBW3AZfOwDuZrVzOmfN_E,1101
10
+ pypatchmatch-2.0.2.dist-info/licenses/opencv/dlpack-LICENSE,sha256=Po9rw5J2pYbWDIxars4v-YkmIYHPKz0qEo21j5epMAw,11345
11
+ pypatchmatch-2.0.2.dist-info/licenses/opencv/flatbuffers-LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
12
+ pypatchmatch-2.0.2.dist-info/licenses/opencv/opencv-LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
13
+ pypatchmatch-2.0.2.dist-info/licenses/opencv/SoftFloat-COPYING.txt,sha256=DFsINlE22lJjnXd_Hr_AOYiwFp2AZVyQxZ8bP6PlJqI,1732
14
+ pypatchmatch-2.0.2.dist-info/licenses/opencv/zlib-LICENSE,sha256=4y_04A2dlJMFN2NSkdo55-YScDM0v2_ejH8Whv6KRaI,1002
15
+ pypatchmatch-2.0.2.dist-info/sboms/opencv.cdx.json,sha256=ATex-BysD8SgsmzwbF8T3jwHedHA_RBYyqgJlC-Amew,866
16
+ pypatchmatch-2.0.2.dist-info/RECORD,,
@@ -1,16 +0,0 @@
1
- patchmatch/__init__.py,sha256=Xg_AyDjCY9obrk95tzu6h0ox1fttEczi_OKu3ycsSvM,345
2
- patchmatch/_lib.py,sha256=KKEeHtn4I0IcRdG49FQV_xpezcar9LqlGD-kvf-pZiM,3740
3
- patchmatch/_version.py,sha256=WnxfkVM6f3yHRZ22_TrCwE0MZX8yBFCWY5wMK7somiQ,544
4
- patchmatch/patch_match.py,sha256=WgStWyICUp97keT5CROxC1o-FjwlzhawcNUVst_Uolo,8328
5
- patchmatch/patchmatch.dll,sha256=yTDQlh4qliiHO64wdf8ec8b_jlVkf1vXkq-ajboj88E,1537024
6
- patchmatch/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
7
- pypatchmatch-2.0.1.dist-info/METADATA,sha256=N2aNBni4y1UmC4zfGZnG7V9kaUAydDgymP4cyrYvATM,8510
8
- pypatchmatch-2.0.1.dist-info/WHEEL,sha256=QOQSSLDAidk39OMVpTfE4kjgcxpaKg4ohhjJQ7vAJpA,102
9
- pypatchmatch-2.0.1.dist-info/licenses/LICENSE,sha256=6VGSBzoFC-2RWaUpfSom3IlBW3AZfOwDuZrVzOmfN_E,1101
10
- pypatchmatch-2.0.1.dist-info/licenses/opencv/dlpack-LICENSE,sha256=Po9rw5J2pYbWDIxars4v-YkmIYHPKz0qEo21j5epMAw,11345
11
- pypatchmatch-2.0.1.dist-info/licenses/opencv/flatbuffers-LICENSE.txt,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
12
- pypatchmatch-2.0.1.dist-info/licenses/opencv/opencv-LICENSE,sha256=z8d0m5b2O9McPEK1xHG_dWgUBT6EfBDz6wA0F7xSPTA,11358
13
- pypatchmatch-2.0.1.dist-info/licenses/opencv/SoftFloat-COPYING.txt,sha256=DFsINlE22lJjnXd_Hr_AOYiwFp2AZVyQxZ8bP6PlJqI,1732
14
- pypatchmatch-2.0.1.dist-info/licenses/opencv/zlib-LICENSE,sha256=4y_04A2dlJMFN2NSkdo55-YScDM0v2_ejH8Whv6KRaI,1002
15
- pypatchmatch-2.0.1.dist-info/sboms/opencv.cdx.json,sha256=ATex-BysD8SgsmzwbF8T3jwHedHA_RBYyqgJlC-Amew,866
16
- pypatchmatch-2.0.1.dist-info/RECORD,,