PyPatchMatch 2.1.0__tar.gz → 2.2.0b3__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.
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/CLAUDE.md +15 -21
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/CMakeLists.txt +2 -1
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/PKG-INFO +17 -4
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/README.md +15 -2
- pypatchmatch-2.2.0b3/examples/images/camera_damaged.png +0 -0
- pypatchmatch-2.2.0b3/examples/images/camera_damaged_mask.png +0 -0
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/patchmatch/_lib.py +3 -2
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/patchmatch/_version.py +3 -3
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/patchmatch/csrc/inpaint.cpp +399 -42
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/patchmatch/csrc/inpaint.h +11 -0
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/patchmatch/csrc/masked_image.cpp +34 -18
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/patchmatch/csrc/masked_image.h +49 -21
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/patchmatch/csrc/nnf.cpp +212 -126
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/patchmatch/csrc/nnf.h +59 -28
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/patchmatch/csrc/pyinterface.cpp +35 -42
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/pyproject.toml +5 -2
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/scripts/evaluate_inpainting.py +60 -49
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/tests/test_e2e.py +95 -34
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/tests/test_patch_match.py +67 -25
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/LICENSE +0 -0
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/SECURITY.md +0 -0
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/examples/images/chelsea.png +0 -0
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/examples/images/forest_pruned.bmp +0 -0
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/patchmatch/__init__.py +0 -0
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/patchmatch/csrc/pyinterface.h +0 -0
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/patchmatch/patch_match.py +0 -0
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/patchmatch/py.typed +0 -0
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/scripts/build_opencv.py +0 -0
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/scripts/render_readme_example.py +0 -0
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/tests/conftest.py +0 -0
- {pypatchmatch-2.1.0 → pypatchmatch-2.2.0b3}/tests/test_properties.py +0 -0
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
# CLAUDE.md
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
coverage and fill-quality runs are skills in `.claude/skills/`.
|
|
3
|
+
The details of the native code, the C interface, packaging and CI are path-scoped rules
|
|
4
|
+
in `.claude/rules/`, which load when a matching file is read or edited; read the rule
|
|
5
|
+
before changing such a file through Bash. The sanitizer, C++ coverage and fill-quality
|
|
6
|
+
runs are skills in `.claude/skills/`.
|
|
8
7
|
|
|
9
8
|
## Project
|
|
10
9
|
|
|
@@ -27,24 +26,18 @@ uv run pre-commit install
|
|
|
27
26
|
uv run pytest # all tests, with the coverage gate
|
|
28
27
|
uv run pytest -m "not e2e" # fast unit tests only
|
|
29
28
|
uv run pytest -m e2e --no-cov # end-to-end tests only
|
|
30
|
-
uv run pytest tests/test_patch_match.py::test_inpaint_global_mask --no-cov
|
|
31
|
-
uv run pytest -k regularity --no-cov
|
|
32
29
|
uv run mypy # strict, also a pre-commit hook
|
|
33
30
|
uv run pre-commit run --all-files # what the CI lint job runs
|
|
34
|
-
uv run ruff check --fix . && uv run ruff format .
|
|
35
31
|
uv build # sdist and wheel into dist/
|
|
36
32
|
```
|
|
37
33
|
|
|
38
34
|
- Pass `--no-cov` for any partial run: `addopts` always enables coverage, and
|
|
39
35
|
`fail_under = 95` (branch coverage, subprocesses included through
|
|
40
36
|
`patch = ["subprocess"]`) fails the run otherwise.
|
|
41
|
-
-
|
|
42
|
-
`
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
- `--cov=patchmatch` measures the source tree, so coverage only works with the editable
|
|
46
|
-
install that `uv sync` creates. With a non-editable install (`uv sync --no-editable`,
|
|
47
|
-
`uv pip install .`) it reports 0 % and the gate fails.
|
|
37
|
+
- Keep the editable install that `uv sync` creates. With a non-editable one
|
|
38
|
+
(`uv sync --no-editable`, `uv pip install .`), `--cov=patchmatch` measures the unused
|
|
39
|
+
source tree and reports 0 %, and `python -m pytest` imports the source tree from the
|
|
40
|
+
repository root, without the compiled library.
|
|
48
41
|
- `uv sync` rebuilds the library only when a `tool.uv.cache-keys` entry changes
|
|
49
42
|
(`CMakeLists.txt`, `patchmatch/csrc/*`, `pyproject.toml`, git commit or tags). Force it
|
|
50
43
|
with `uv sync --reinstall-package pypatchmatch`.
|
|
@@ -69,11 +62,11 @@ Other entry points:
|
|
|
69
62
|
- `uv run python scripts/render_readme_example.py` runs `py_example.py` and renders the
|
|
70
63
|
picture at the top of the README, `examples/images/readme_example.jpg`; rerun it and
|
|
71
64
|
commit the picture after changes that affect the fills.
|
|
72
|
-
-
|
|
73
|
-
|
|
74
|
-
`
|
|
75
|
-
|
|
76
|
-
|
|
65
|
+
- `uv run --group gui gui/app.py` starts the Gradio GUI (paint holes, compare the fill).
|
|
66
|
+
No CI job installs gradio, so after API changes run its test with
|
|
67
|
+
`uv run --group gui pytest gui --no-cov` and try the GUI by hand.
|
|
68
|
+
- CMake options: the `option()` lines of `CMakeLists.txt`. `PATCHMATCH_SANITIZE` turns
|
|
69
|
+
off fast math, which lets the compiler drop checks.
|
|
77
70
|
|
|
78
71
|
## Architecture
|
|
79
72
|
|
|
@@ -114,7 +107,8 @@ CMake installs the shared library into the package directory.
|
|
|
114
107
|
goes through a test parameter instead of a `# type: ignore`.
|
|
115
108
|
- Backwards compatibility: `from patchmatch import patch_match` and
|
|
116
109
|
`patch_match.CShapeT`/`CMatT` keep working (tested).
|
|
117
|
-
- Comments explain why
|
|
110
|
+
- Comments explain why, in one short line where the code would otherwise be misread or
|
|
111
|
+
wrongly simplified; details and measurements go into the commit message.
|
|
118
112
|
- No `NOSONAR` markers: change the code so that the SonarCloud rule is satisfied, and ask
|
|
119
113
|
when that seems impossible. The only exception is `nnf.cpp`: cpp:S2245 flags every
|
|
120
114
|
declaration of `std::mt19937`, which only drives the randomized search.
|
|
@@ -57,8 +57,9 @@ if(PATCHMATCH_SANITIZE)
|
|
|
57
57
|
endif()
|
|
58
58
|
# GCC's -fsanitize=undefined leaves out float-cast-overflow
|
|
59
59
|
set(PATCHMATCH_SANITIZERS -fsanitize=address,undefined,float-cast-overflow)
|
|
60
|
+
# -UNDEBUG keeps the asserts, which check the incremental distances of the propagation
|
|
60
61
|
target_compile_options(patchmatch PRIVATE ${PATCHMATCH_SANITIZERS}
|
|
61
|
-
-fno-sanitize-recover=all -fno-omit-frame-pointer -g)
|
|
62
|
+
-fno-sanitize-recover=all -fno-omit-frame-pointer -g -UNDEBUG)
|
|
62
63
|
target_link_options(patchmatch PRIVATE ${PATCHMATCH_SANITIZERS})
|
|
63
64
|
endif()
|
|
64
65
|
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyPatchMatch
|
|
3
|
-
Version: 2.
|
|
3
|
+
Version: 2.2.0b3
|
|
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>
|
|
@@ -41,9 +41,12 @@ Description-Content-Type: text/markdown
|
|
|
41
41
|
This library implements the PatchMatch based inpainting algorithm. It provides both C++
|
|
42
42
|
and Python interfaces. This implementation is heavily based on the implementation by
|
|
43
43
|
Younesse ANDAM: [younesse-cv/PatchMatch](https://github.com/younesse-cv/PatchMatch),
|
|
44
|
-
with some bug fixes, and updates.
|
|
44
|
+
with some bug fixes, and updates. This repository continues
|
|
45
|
+
[vacancy/PyPatchMatch](https://github.com/vacancy/PyPatchMatch) by Jiayuan Mao, through
|
|
46
|
+
the forks [lkwq007/PyPatchMatch](https://github.com/lkwq007/PyPatchMatch) and
|
|
47
|
+
[invoke-ai/PyPatchMatch](https://github.com/invoke-ai/PyPatchMatch).
|
|
45
48
|
|
|
46
|
-

|
|
47
50
|
|
|
48
51
|
From left to right: the photo, the input of
|
|
49
52
|
[examples/py_example.py](https://github.com/mauwii/PyPatchMatch/blob/main/examples/py_example.py)
|
|
@@ -98,7 +101,11 @@ The previous import path `from patchmatch import patch_match` keeps working.
|
|
|
98
101
|
|
|
99
102
|
`patch_size` is the radius of the compared patches, which span `2 * patch_size + 1`
|
|
100
103
|
pixels in each direction. Larger patches follow larger structures but are much slower;
|
|
101
|
-
the default of 15 compares 31x31 patches, the examples use 3.
|
|
104
|
+
the default of 15 compares 31x31 patches, the examples use 3. Below 5, the coarse levels
|
|
105
|
+
that lay out the fill are also tried with a radius of 5, which is kept where it fits
|
|
106
|
+
the surroundings better, so that repeating patterns continue across larger holes. Above
|
|
107
|
+
7, coarse levels narrower than six patches use the largest radius that fits, but at
|
|
108
|
+
least 7: larger patches found no sources there and left the fill flat.
|
|
102
109
|
|
|
103
110
|
`patchmatch.set_random_seed(seed)` sets the seed of the randomized search, modulo
|
|
104
111
|
`2**32`, and `patchmatch.set_verbose(True)` prints the progress of the native code to
|
|
@@ -136,8 +143,14 @@ uv run pre-commit install # enable ruff and the other hooks on commit
|
|
|
136
143
|
uv run pytest # run the test suite
|
|
137
144
|
uv run pytest -m "not e2e" # only the fast unit tests
|
|
138
145
|
uv run python scripts/evaluate_inpainting.py # measure the fill quality
|
|
146
|
+
uv run --group gui gui/app.py # draw masks in the browser, http://127.0.0.1:7860
|
|
139
147
|
```
|
|
140
148
|
|
|
149
|
+
The GUI tries new images quickly, without writing a script for each one, e.g. to pick
|
|
150
|
+
new examples or to verify edge cases: load an image, paint the holes (every painted
|
|
151
|
+
pixel is one) and compare the original with the fill. Its test runs with
|
|
152
|
+
`uv run --group gui pytest gui --no-cov`.
|
|
153
|
+
|
|
141
154
|
The evaluation cuts holes into the images of `examples/images`, compares the fills with
|
|
142
155
|
the original content and writes `examples/images/evaluation.html`, which shows them side
|
|
143
156
|
by side. `--baseline` evaluates another build of the library as well, e.g. of the main
|
|
@@ -11,7 +11,10 @@
|
|
|
11
11
|
This library implements the PatchMatch based inpainting algorithm. It provides both C++
|
|
12
12
|
and Python interfaces. This implementation is heavily based on the implementation by
|
|
13
13
|
Younesse ANDAM: [younesse-cv/PatchMatch](https://github.com/younesse-cv/PatchMatch),
|
|
14
|
-
with some bug fixes, and updates.
|
|
14
|
+
with some bug fixes, and updates. This repository continues
|
|
15
|
+
[vacancy/PyPatchMatch](https://github.com/vacancy/PyPatchMatch) by Jiayuan Mao, through
|
|
16
|
+
the forks [lkwq007/PyPatchMatch](https://github.com/lkwq007/PyPatchMatch) and
|
|
17
|
+
[invoke-ai/PyPatchMatch](https://github.com/invoke-ai/PyPatchMatch).
|
|
15
18
|
|
|
16
19
|

|
|
17
20
|
|
|
@@ -68,7 +71,11 @@ The previous import path `from patchmatch import patch_match` keeps working.
|
|
|
68
71
|
|
|
69
72
|
`patch_size` is the radius of the compared patches, which span `2 * patch_size + 1`
|
|
70
73
|
pixels in each direction. Larger patches follow larger structures but are much slower;
|
|
71
|
-
the default of 15 compares 31x31 patches, the examples use 3.
|
|
74
|
+
the default of 15 compares 31x31 patches, the examples use 3. Below 5, the coarse levels
|
|
75
|
+
that lay out the fill are also tried with a radius of 5, which is kept where it fits
|
|
76
|
+
the surroundings better, so that repeating patterns continue across larger holes. Above
|
|
77
|
+
7, coarse levels narrower than six patches use the largest radius that fits, but at
|
|
78
|
+
least 7: larger patches found no sources there and left the fill flat.
|
|
72
79
|
|
|
73
80
|
`patchmatch.set_random_seed(seed)` sets the seed of the randomized search, modulo
|
|
74
81
|
`2**32`, and `patchmatch.set_verbose(True)` prints the progress of the native code to
|
|
@@ -106,8 +113,14 @@ uv run pre-commit install # enable ruff and the other hooks on commit
|
|
|
106
113
|
uv run pytest # run the test suite
|
|
107
114
|
uv run pytest -m "not e2e" # only the fast unit tests
|
|
108
115
|
uv run python scripts/evaluate_inpainting.py # measure the fill quality
|
|
116
|
+
uv run --group gui gui/app.py # draw masks in the browser, http://127.0.0.1:7860
|
|
109
117
|
```
|
|
110
118
|
|
|
119
|
+
The GUI tries new images quickly, without writing a script for each one, e.g. to pick
|
|
120
|
+
new examples or to verify edge cases: load an image, paint the holes (every painted
|
|
121
|
+
pixel is one) and compare the original with the fill. Its test runs with
|
|
122
|
+
`uv run --group gui pytest gui --no-cov`.
|
|
123
|
+
|
|
111
124
|
The evaluation cuts holes into the images of `examples/images`, compares the fills with
|
|
112
125
|
the original content and writes `examples/images/evaluation.html`, which shows them side
|
|
113
126
|
by side. `--baseline` evaluates another build of the library as well, e.g. of the main
|
|
Binary file
|
|
Binary file
|
|
@@ -82,8 +82,9 @@ def find_library() -> Path:
|
|
|
82
82
|
)
|
|
83
83
|
|
|
84
84
|
|
|
85
|
-
def load_library() -> ctypes.CDLL:
|
|
86
|
-
|
|
85
|
+
def load_library(path: Path | None = None) -> ctypes.CDLL:
|
|
86
|
+
"""Load the installed library, or the build at ``path``."""
|
|
87
|
+
lib = ctypes.CDLL(str(path or find_library()))
|
|
87
88
|
|
|
88
89
|
lib.PM_set_random_seed.argtypes = [ctypes.c_uint]
|
|
89
90
|
lib.PM_set_random_seed.restype = None
|
|
@@ -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.
|
|
22
|
-
__version_tuple__ = version_tuple = (2,
|
|
21
|
+
__version__ = version = '2.2.0b3'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 2, 0, 'b3')
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'gc0f3bbfe6'
|