PyPatchMatch 2.0.0rc3__tar.gz → 2.0.0rc4__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.0.0rc3 → pypatchmatch-2.0.0rc4}/CMakeLists.txt +20 -1
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/PKG-INFO +3 -1
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/README.md +2 -0
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/_version.py +3 -3
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/csrc/inpaint.cpp +24 -21
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/csrc/inpaint.h +3 -1
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/csrc/masked_image.cpp +4 -1
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/csrc/masked_image.h +14 -5
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/csrc/nnf.cpp +18 -16
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/csrc/nnf.h +20 -7
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/csrc/pyinterface.cpp +14 -10
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/csrc/pyinterface.h +4 -3
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/scripts/build_opencv.py +4 -1
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/scripts/evaluate_inpainting.py +16 -19
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/LICENSE +0 -0
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/examples/images/forest_pruned.bmp +0 -0
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/__init__.py +0 -0
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/_lib.py +0 -0
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/patch_match.py +0 -0
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/py.typed +0 -0
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/pyproject.toml +0 -0
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/tests/test_e2e.py +0 -0
- {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/tests/test_patch_match.py +0 -0
|
@@ -4,6 +4,7 @@ project(patchmatch LANGUAGES CXX)
|
|
|
4
4
|
option(PATCHMATCH_BUILD_EXAMPLES "Build the C++ example (requires OpenCV imgcodecs)" OFF)
|
|
5
5
|
option(PATCHMATCH_WITH_HIGHGUI "Enable the debug visualization of Inpainting::run (requires OpenCV highgui)" OFF)
|
|
6
6
|
option(PATCHMATCH_FAST_MATH "Compile with fast-math optimizations" ON)
|
|
7
|
+
option(PATCHMATCH_SANITIZE "Build with AddressSanitizer and UndefinedBehaviorSanitizer, without fast math (GCC, Clang)" OFF)
|
|
7
8
|
|
|
8
9
|
if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
|
9
10
|
set(CMAKE_BUILD_TYPE Release CACHE STRING "Build type" FORCE)
|
|
@@ -32,13 +33,20 @@ add_library(patchmatch SHARED
|
|
|
32
33
|
target_include_directories(patchmatch PUBLIC patchmatch/csrc)
|
|
33
34
|
target_link_libraries(patchmatch PUBLIC opencv_core)
|
|
34
35
|
|
|
36
|
+
# CI adds CMAKE_COMPILE_WARNING_AS_ERROR; the OpenCV headers are system headers
|
|
37
|
+
if(MSVC)
|
|
38
|
+
target_compile_options(patchmatch PRIVATE /W4)
|
|
39
|
+
else()
|
|
40
|
+
target_compile_options(patchmatch PRIVATE -Wall -Wextra -Wpedantic -Wshadow)
|
|
41
|
+
endif()
|
|
42
|
+
|
|
35
43
|
if(MSVC AND NOT OpenCV_SHARED)
|
|
36
44
|
# A static OpenCV (as built by scripts/build_opencv.py) uses the static MSVC runtime.
|
|
37
45
|
set_property(TARGET patchmatch PROPERTY
|
|
38
46
|
MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
|
|
39
47
|
endif()
|
|
40
48
|
|
|
41
|
-
if(PATCHMATCH_FAST_MATH)
|
|
49
|
+
if(PATCHMATCH_FAST_MATH AND NOT PATCHMATCH_SANITIZE)
|
|
42
50
|
if(MSVC)
|
|
43
51
|
target_compile_options(patchmatch PRIVATE /fp:fast)
|
|
44
52
|
else()
|
|
@@ -46,6 +54,17 @@ if(PATCHMATCH_FAST_MATH)
|
|
|
46
54
|
endif()
|
|
47
55
|
endif()
|
|
48
56
|
|
|
57
|
+
if(PATCHMATCH_SANITIZE)
|
|
58
|
+
if(MSVC)
|
|
59
|
+
message(FATAL_ERROR "PATCHMATCH_SANITIZE needs GCC or Clang")
|
|
60
|
+
endif()
|
|
61
|
+
# GCC's -fsanitize=undefined leaves out float-cast-overflow
|
|
62
|
+
set(PATCHMATCH_SANITIZERS -fsanitize=address,undefined,float-cast-overflow)
|
|
63
|
+
target_compile_options(patchmatch PRIVATE ${PATCHMATCH_SANITIZERS}
|
|
64
|
+
-fno-sanitize-recover=all -fno-omit-frame-pointer -g)
|
|
65
|
+
target_link_options(patchmatch PRIVATE ${PATCHMATCH_SANITIZERS})
|
|
66
|
+
endif()
|
|
67
|
+
|
|
49
68
|
if(PATCHMATCH_WITH_HIGHGUI)
|
|
50
69
|
target_compile_definitions(patchmatch PRIVATE PATCHMATCH_WITH_HIGHGUI)
|
|
51
70
|
target_link_libraries(patchmatch PRIVATE opencv_imgproc opencv_highgui)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: PyPatchMatch
|
|
3
|
-
Version: 2.0.
|
|
3
|
+
Version: 2.0.0rc4
|
|
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>
|
|
@@ -30,6 +30,8 @@ Description-Content-Type: text/markdown
|
|
|
30
30
|
|
|
31
31
|
# PatchMatch based Inpainting
|
|
32
32
|
|
|
33
|
+
[](https://github.com/mauwii/PyPatchMatch/actions/workflows/ci.yml)
|
|
34
|
+
[](https://sonarcloud.io/summary/new_code?id=mauwii_PyPatchMatch)
|
|
33
35
|
[](https://github.com/mauwii/PyPatchMatch/blob/main/LICENSE)
|
|
34
36
|
[](https://pypi.org/project/PyPatchMatch/)
|
|
35
37
|
[](https://pepy.tech/projects/pypatchmatch)
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# PatchMatch based Inpainting
|
|
2
2
|
|
|
3
|
+
[](https://github.com/mauwii/PyPatchMatch/actions/workflows/ci.yml)
|
|
4
|
+
[](https://sonarcloud.io/summary/new_code?id=mauwii_PyPatchMatch)
|
|
3
5
|
[](https://github.com/mauwii/PyPatchMatch/blob/main/LICENSE)
|
|
4
6
|
[](https://pypi.org/project/PyPatchMatch/)
|
|
5
7
|
[](https://pepy.tech/projects/pypatchmatch)
|
|
@@ -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.
|
|
22
|
-
__version_tuple__ = version_tuple = (2, 0, 0, '
|
|
21
|
+
__version__ = version = '2.0.0rc4'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 0, 0, 'rc4')
|
|
23
23
|
|
|
24
|
-
__commit_id__ = commit_id = '
|
|
24
|
+
__commit_id__ = commit_id = 'g6f35e1d41'
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
#include <algorithm>
|
|
2
|
+
#include <array>
|
|
2
3
|
#include <iostream>
|
|
3
4
|
#ifdef PATCHMATCH_WITH_HIGHGUI
|
|
4
|
-
#include <opencv2/imgproc.hpp>
|
|
5
5
|
#include <opencv2/highgui.hpp>
|
|
6
|
+
#include <opencv2/imgproc.hpp>
|
|
6
7
|
#endif
|
|
7
8
|
|
|
8
9
|
#include "inpaint.h"
|
|
@@ -11,17 +12,16 @@ namespace
|
|
|
11
12
|
{
|
|
12
13
|
std::vector<double> make_distance2similarity()
|
|
13
14
|
{
|
|
14
|
-
double
|
|
15
|
-
|
|
15
|
+
constexpr std::array<double, 11> base = {1.0, 0.99, 0.96, 0.83, 0.38, 0.11, 0.02, 0.005, 0.0006, 0.0001, 0};
|
|
16
|
+
const std::size_t length = static_cast<std::size_t>(PatchDistanceMetric::kDistanceScale) + 1;
|
|
16
17
|
std::vector<double> table(length);
|
|
17
|
-
for (
|
|
18
|
+
for (std::size_t i = 0; i < length; ++i)
|
|
18
19
|
{
|
|
19
|
-
double t = (
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
table[i] = vj + (100 * t - j) * (vk - vj);
|
|
20
|
+
const double t = static_cast<double>(i) / static_cast<double>(length);
|
|
21
|
+
const auto j = static_cast<std::size_t>(100 * t);
|
|
22
|
+
if (j >= base.size() - 1)
|
|
23
|
+
continue; // the table is zero from here on
|
|
24
|
+
table[i] = base[j] + (100 * t - static_cast<double>(j)) * (base[j + 1] - base[j]);
|
|
25
25
|
}
|
|
26
26
|
return table;
|
|
27
27
|
}
|
|
@@ -34,7 +34,8 @@ namespace
|
|
|
34
34
|
return table;
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
inline void _weighted_copy(
|
|
37
|
+
inline void _weighted_copy(
|
|
38
|
+
const MaskedImage &source, int ys, int xs, cv::Mat &target, int yt, int xt, double weight)
|
|
38
39
|
{
|
|
39
40
|
if (source.is_masked(ys, xs))
|
|
40
41
|
return;
|
|
@@ -67,10 +68,10 @@ namespace
|
|
|
67
68
|
target_ptr[c] = static_cast<double>(source_ptr[c]) * weight;
|
|
68
69
|
target_ptr[3] = weight;
|
|
69
70
|
}
|
|
70
|
-
}
|
|
71
|
+
} // namespace
|
|
71
72
|
|
|
72
73
|
/**
|
|
73
|
-
* This
|
|
74
|
+
* This algorithm uses a version proposed by Xavier Philippeau.
|
|
74
75
|
*/
|
|
75
76
|
|
|
76
77
|
Inpainting::Inpainting(cv::Mat image, cv::Mat mask, const PatchDistanceMetric *metric)
|
|
@@ -89,7 +90,8 @@ void Inpainting::_initialize_pyramid()
|
|
|
89
90
|
{
|
|
90
91
|
auto source = m_initial;
|
|
91
92
|
m_pyramid.push_back(source);
|
|
92
|
-
while (source.size().height > m_distance_metric->patch_size() &&
|
|
93
|
+
while (source.size().height > m_distance_metric->patch_size() &&
|
|
94
|
+
source.size().width > m_distance_metric->patch_size())
|
|
93
95
|
{
|
|
94
96
|
source = source.downsample();
|
|
95
97
|
m_pyramid.push_back(source);
|
|
@@ -99,7 +101,7 @@ void Inpainting::_initialize_pyramid()
|
|
|
99
101
|
cv::Mat Inpainting::run(bool verbose, bool verbose_visualize, unsigned int random_seed)
|
|
100
102
|
{
|
|
101
103
|
NearestNeighborField::seed_random(random_seed);
|
|
102
|
-
const
|
|
104
|
+
const auto nr_levels = static_cast<int>(m_pyramid.size());
|
|
103
105
|
|
|
104
106
|
MaskedImage source, target;
|
|
105
107
|
for (int level = nr_levels - 1; level >= 0; --level)
|
|
@@ -210,7 +212,8 @@ MaskedImage Inpainting::_expectation_maximization(MaskedImage source, MaskedImag
|
|
|
210
212
|
if (level >= 1 && iter_em == nr_iters_em - 1)
|
|
211
213
|
{
|
|
212
214
|
new_source = m_pyramid[level - 1];
|
|
213
|
-
new_target =
|
|
215
|
+
new_target =
|
|
216
|
+
target.upsample(new_source.size().width, new_source.size().height, m_pyramid[level - 1].global_mask());
|
|
214
217
|
upscaled = true;
|
|
215
218
|
}
|
|
216
219
|
else
|
|
@@ -253,8 +256,8 @@ MaskedImage Inpainting::_expectation_maximization(MaskedImage source, MaskedImag
|
|
|
253
256
|
|
|
254
257
|
// Expectation step: vote for best estimations of each pixel.
|
|
255
258
|
void Inpainting::_expectation_step(
|
|
256
|
-
const NearestNeighborField &nnf, bool source2target,
|
|
257
|
-
|
|
259
|
+
const NearestNeighborField &nnf, bool source2target, cv::Mat &vote, const MaskedImage &source, bool upscaled,
|
|
260
|
+
bool best_only)
|
|
258
261
|
{
|
|
259
262
|
auto source_size = nnf.source_size();
|
|
260
263
|
auto target_size = nnf.target_size();
|
|
@@ -262,8 +265,7 @@ void Inpainting::_expectation_step(
|
|
|
262
265
|
const auto &kDistance2Similarity = distance2similarity();
|
|
263
266
|
|
|
264
267
|
double w = 0;
|
|
265
|
-
auto copy = [&](int ys, int xs, int yt, int xt)
|
|
266
|
-
{
|
|
268
|
+
auto copy = [&](int ys, int xs, int yt, int xt) {
|
|
267
269
|
if (best_only)
|
|
268
270
|
_best_copy(source, ys, xs, vote, yt, xt, w);
|
|
269
271
|
else
|
|
@@ -320,7 +322,8 @@ void Inpainting::_expectation_step(
|
|
|
320
322
|
}
|
|
321
323
|
|
|
322
324
|
// Maximization Step: maximum likelihood of target pixel.
|
|
323
|
-
void Inpainting::_maximization_step(
|
|
325
|
+
void Inpainting::_maximization_step(
|
|
326
|
+
MaskedImage &target, const cv::Mat &vote, const MaskedImage &source, bool keep_known) const
|
|
324
327
|
{
|
|
325
328
|
auto target_size = target.size();
|
|
326
329
|
for (int i = 0; i < target_size.height; ++i)
|
|
@@ -15,7 +15,9 @@ public:
|
|
|
15
15
|
private:
|
|
16
16
|
void _initialize_pyramid(void);
|
|
17
17
|
MaskedImage _expectation_maximization(MaskedImage source, MaskedImage target, int level, bool verbose);
|
|
18
|
-
void _expectation_step(
|
|
18
|
+
void _expectation_step(
|
|
19
|
+
const NearestNeighborField &nnf, bool source2target, cv::Mat &vote, const MaskedImage &source, bool upscaled,
|
|
20
|
+
bool best_only);
|
|
19
21
|
void _maximization_step(MaskedImage &target, const cv::Mat &vote, const MaskedImage &source, bool keep_known) const;
|
|
20
22
|
|
|
21
23
|
MaskedImage m_initial;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
#include "masked_image.h"
|
|
2
|
+
|
|
2
3
|
#include <algorithm>
|
|
3
4
|
#include <iostream>
|
|
4
5
|
|
|
@@ -73,7 +74,9 @@ MaskedImage MaskedImage::downsample() const
|
|
|
73
74
|
if (ksum > 0)
|
|
74
75
|
{
|
|
75
76
|
auto target_ptr = ret.get_mutable_image(y / 2, x / 2);
|
|
76
|
-
target_ptr[0] = r
|
|
77
|
+
target_ptr[0] = static_cast<unsigned char>(r);
|
|
78
|
+
target_ptr[1] = static_cast<unsigned char>(g);
|
|
79
|
+
target_ptr[2] = static_cast<unsigned char>(b);
|
|
77
80
|
ret.set_mask(y / 2, x / 2, 0);
|
|
78
81
|
}
|
|
79
82
|
else
|
|
@@ -14,12 +14,14 @@ public:
|
|
|
14
14
|
{
|
|
15
15
|
// pass
|
|
16
16
|
}
|
|
17
|
-
MaskedImage(cv::Mat image, cv::Mat mask, cv::Mat global_mask)
|
|
17
|
+
MaskedImage(cv::Mat image, cv::Mat mask, cv::Mat global_mask)
|
|
18
|
+
: m_image(image), m_mask(mask), m_global_mask(global_mask), m_image_grad_computed(false)
|
|
18
19
|
{
|
|
19
20
|
// pass
|
|
20
21
|
}
|
|
21
|
-
MaskedImage(cv::Mat image, cv::Mat mask, cv::Mat global_mask, cv::Mat grady, cv::Mat gradx, bool grad_computed)
|
|
22
|
-
|
|
22
|
+
MaskedImage(cv::Mat image, cv::Mat mask, cv::Mat global_mask, cv::Mat grady, cv::Mat gradx, bool grad_computed)
|
|
23
|
+
: m_image(image), m_mask(mask), m_global_mask(global_mask), m_image_grady(grady), m_image_gradx(gradx),
|
|
24
|
+
m_image_grad_computed(grad_computed)
|
|
23
25
|
{
|
|
24
26
|
// pass
|
|
25
27
|
}
|
|
@@ -31,11 +33,18 @@ public:
|
|
|
31
33
|
m_mask = cv::Mat(cv::Size(width, height), CV_8U);
|
|
32
34
|
m_mask = cv::Scalar::all(0);
|
|
33
35
|
}
|
|
36
|
+
// cv::Mat's move assignment is not noexcept, so the implicit one would not be
|
|
37
|
+
MaskedImage(const MaskedImage &) = default;
|
|
38
|
+
MaskedImage(MaskedImage &&) noexcept = default;
|
|
39
|
+
MaskedImage &operator=(const MaskedImage &) = default;
|
|
40
|
+
MaskedImage &operator=(MaskedImage &&) noexcept = default;
|
|
41
|
+
~MaskedImage() = default;
|
|
42
|
+
|
|
34
43
|
inline MaskedImage clone()
|
|
35
44
|
{
|
|
36
45
|
return MaskedImage(
|
|
37
|
-
m_image.clone(), m_mask.clone(), m_global_mask.clone(),
|
|
38
|
-
|
|
46
|
+
m_image.clone(), m_mask.clone(), m_global_mask.clone(), m_image_grady.clone(), m_image_gradx.clone(),
|
|
47
|
+
m_image_grad_computed);
|
|
39
48
|
}
|
|
40
49
|
|
|
41
50
|
inline cv::Size size() const
|
|
@@ -1,14 +1,16 @@
|
|
|
1
|
+
#include "nnf.h"
|
|
2
|
+
|
|
1
3
|
#include <algorithm>
|
|
2
|
-
#include <iostream>
|
|
3
4
|
#include <cmath>
|
|
5
|
+
#include <cstdint>
|
|
6
|
+
#include <iostream>
|
|
4
7
|
#include <random>
|
|
5
8
|
|
|
6
9
|
#include "masked_image.h"
|
|
7
|
-
#include "nnf.h"
|
|
8
10
|
|
|
9
11
|
/**
|
|
10
12
|
* Nearest-Neighbor Field (see PatchMatch algorithm).
|
|
11
|
-
* This
|
|
13
|
+
* This algorithm uses a version proposed by Xavier Philippeau.
|
|
12
14
|
*
|
|
13
15
|
*/
|
|
14
16
|
|
|
@@ -36,7 +38,7 @@ namespace
|
|
|
36
38
|
{
|
|
37
39
|
return static_cast<int>(random_engine()() % static_cast<unsigned int>(n));
|
|
38
40
|
}
|
|
39
|
-
}
|
|
41
|
+
} // namespace
|
|
40
42
|
|
|
41
43
|
void NearestNeighborField::seed_random(unsigned int seed)
|
|
42
44
|
{
|
|
@@ -199,12 +201,11 @@ namespace
|
|
|
199
201
|
}
|
|
200
202
|
|
|
201
203
|
int distance_masked_images(
|
|
202
|
-
const MaskedImage &source, int ys, int xs,
|
|
203
|
-
const MaskedImage &target, int yt, int xt,
|
|
204
|
-
int patch_size)
|
|
204
|
+
const MaskedImage &source, int ys, int xs, const MaskedImage &target, int yt, int xt, int patch_size)
|
|
205
205
|
{
|
|
206
|
-
long double
|
|
207
|
-
|
|
206
|
+
// Exact integer sums: long double is emulated in software on Linux aarch64
|
|
207
|
+
std::int64_t distance = 0;
|
|
208
|
+
std::int64_t wsum = 0;
|
|
208
209
|
|
|
209
210
|
source.compute_image_gradients();
|
|
210
211
|
target.compute_image_gradients();
|
|
@@ -218,7 +219,7 @@ namespace
|
|
|
218
219
|
|
|
219
220
|
if (yys <= 0 || yys >= source_size.height - 1 || yyt <= 0 || yyt >= target_size.height - 1)
|
|
220
221
|
{
|
|
221
|
-
distance +=
|
|
222
|
+
distance += std::int64_t{PatchSSDDistanceMetric::kSSDScale} * (2 * patch_size + 1);
|
|
222
223
|
wsum += 2 * patch_size + 1;
|
|
223
224
|
continue;
|
|
224
225
|
}
|
|
@@ -275,22 +276,23 @@ namespace
|
|
|
275
276
|
}
|
|
276
277
|
}
|
|
277
278
|
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
int res = int(PatchDistanceMetric::kDistanceScale * distance / wsum);
|
|
279
|
+
const double scaled = static_cast<double>(distance) / PatchSSDDistanceMetric::kSSDScale;
|
|
280
|
+
const auto res = static_cast<int>(PatchDistanceMetric::kDistanceScale * scaled / static_cast<double>(wsum));
|
|
281
281
|
if (res < 0 || res > PatchDistanceMetric::kDistanceScale)
|
|
282
282
|
return PatchDistanceMetric::kDistanceScale;
|
|
283
283
|
return res;
|
|
284
284
|
}
|
|
285
285
|
|
|
286
|
-
}
|
|
286
|
+
} // namespace
|
|
287
287
|
|
|
288
|
-
int PatchSSDDistanceMetric::operator()(
|
|
288
|
+
int PatchSSDDistanceMetric::operator()(
|
|
289
|
+
const MaskedImage &source, int source_y, int source_x, const MaskedImage &target, int target_y, int target_x) const
|
|
289
290
|
{
|
|
290
291
|
return distance_masked_images(source, source_y, source_x, target, target_y, target_x, m_patch_size);
|
|
291
292
|
}
|
|
292
293
|
|
|
293
|
-
int RegularityGuidedPatchDistanceMetricV2::operator()(
|
|
294
|
+
int RegularityGuidedPatchDistanceMetricV2::operator()(
|
|
295
|
+
const MaskedImage &source, int source_y, int source_x, const MaskedImage &target, int target_y, int target_x) const
|
|
294
296
|
{
|
|
295
297
|
if (target_y < 0 || target_y >= target.size().height || target_x < 0 || target_x >= target.size().width)
|
|
296
298
|
return PatchDistanceMetric::kDistanceScale;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
-
#include <stdexcept>
|
|
4
3
|
#include <opencv2/core.hpp>
|
|
4
|
+
#include <stdexcept>
|
|
5
|
+
|
|
5
6
|
#include "masked_image.h"
|
|
6
7
|
|
|
7
8
|
class PatchDistanceMetric
|
|
@@ -10,8 +11,13 @@ public:
|
|
|
10
11
|
PatchDistanceMetric(int patch_size) : m_patch_size(patch_size) {}
|
|
11
12
|
virtual ~PatchDistanceMetric() = default;
|
|
12
13
|
|
|
13
|
-
inline int patch_size() const
|
|
14
|
-
|
|
14
|
+
inline int patch_size() const
|
|
15
|
+
{
|
|
16
|
+
return m_patch_size;
|
|
17
|
+
}
|
|
18
|
+
virtual int operator()(
|
|
19
|
+
const MaskedImage &source, int source_y, int source_x, const MaskedImage &target, int target_y,
|
|
20
|
+
int target_x) const = 0;
|
|
15
21
|
static const int kDistanceScale;
|
|
16
22
|
|
|
17
23
|
protected:
|
|
@@ -25,13 +31,16 @@ public:
|
|
|
25
31
|
{
|
|
26
32
|
// pass
|
|
27
33
|
}
|
|
28
|
-
NearestNeighborField(
|
|
34
|
+
NearestNeighborField(
|
|
35
|
+
const MaskedImage &source, const MaskedImage &target, const PatchDistanceMetric *metric, int max_retry = 20)
|
|
29
36
|
: m_source(source), m_target(target), m_distance_metric(metric)
|
|
30
37
|
{
|
|
31
38
|
m_field = cv::Mat(m_source.size(), CV_32SC3);
|
|
32
39
|
_randomize_field(max_retry);
|
|
33
40
|
}
|
|
34
|
-
NearestNeighborField(
|
|
41
|
+
NearestNeighborField(
|
|
42
|
+
const MaskedImage &source, const MaskedImage &target, const PatchDistanceMetric *metric,
|
|
43
|
+
const NearestNeighborField &other, int max_retry = 20)
|
|
35
44
|
: m_source(source), m_target(target), m_distance_metric(metric)
|
|
36
45
|
{
|
|
37
46
|
m_field = cv::Mat(m_source.size(), CV_32SC3);
|
|
@@ -111,7 +120,9 @@ class PatchSSDDistanceMetric : public PatchDistanceMetric
|
|
|
111
120
|
{
|
|
112
121
|
public:
|
|
113
122
|
using PatchDistanceMetric::PatchDistanceMetric;
|
|
114
|
-
virtual int operator()(
|
|
123
|
+
virtual int operator()(
|
|
124
|
+
const MaskedImage &source, int source_y, int source_x, const MaskedImage &target, int target_y,
|
|
125
|
+
int target_x) const;
|
|
115
126
|
static const int kSSDScale;
|
|
116
127
|
};
|
|
117
128
|
|
|
@@ -125,7 +136,9 @@ public:
|
|
|
125
136
|
if (!(weight >= 0))
|
|
126
137
|
throw std::invalid_argument("the guide weight must be >= 0");
|
|
127
138
|
}
|
|
128
|
-
virtual int operator()(
|
|
139
|
+
virtual int operator()(
|
|
140
|
+
const MaskedImage &source, int source_y, int source_x, const MaskedImage &target, int target_y,
|
|
141
|
+
int target_x) const;
|
|
129
142
|
|
|
130
143
|
protected:
|
|
131
144
|
cv::Mat m_ijmap;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
|
+
#include "pyinterface.h"
|
|
2
|
+
|
|
1
3
|
#include <atomic>
|
|
2
4
|
#include <cstring>
|
|
3
5
|
#include <exception>
|
|
4
6
|
#include <memory>
|
|
5
7
|
#include <string>
|
|
6
8
|
|
|
7
|
-
#include "pyinterface.h"
|
|
8
9
|
#include "inpaint.h"
|
|
9
10
|
|
|
10
11
|
int _dtype_py_to_cv(int dtype_py);
|
|
@@ -66,7 +67,7 @@ namespace
|
|
|
66
67
|
}
|
|
67
68
|
return PM_mat_t{nullptr, {0, 0, 0}, 0};
|
|
68
69
|
}
|
|
69
|
-
}
|
|
70
|
+
} // namespace
|
|
70
71
|
|
|
71
72
|
const char *PM_last_error()
|
|
72
73
|
{
|
|
@@ -85,10 +86,8 @@ void PM_set_verbose(int value)
|
|
|
85
86
|
|
|
86
87
|
void PM_free_pymat(PM_mat_t pymat)
|
|
87
88
|
{
|
|
88
|
-
//
|
|
89
|
-
|
|
90
|
-
// (SonarCloud cpp:S5945).
|
|
91
|
-
std::unique_ptr<unsigned char[]> data(static_cast<unsigned char *>(pymat.data_ptr)); // NOSONAR
|
|
89
|
+
// Frees the buffer that _cv2_to_py released.
|
|
90
|
+
std::default_delete<unsigned char[]>()(static_cast<unsigned char *>(pymat.data_ptr));
|
|
92
91
|
}
|
|
93
92
|
|
|
94
93
|
PM_mat_t PM_inpaint(PM_mat_t source_py, PM_mat_t mask_py, int patch_size)
|
|
@@ -102,7 +101,8 @@ PM_mat_t PM_inpaint(PM_mat_t source_py, PM_mat_t mask_py, int patch_size)
|
|
|
102
101
|
});
|
|
103
102
|
}
|
|
104
103
|
|
|
105
|
-
PM_mat_t PM_inpaint_regularity(
|
|
104
|
+
PM_mat_t PM_inpaint_regularity(
|
|
105
|
+
PM_mat_t source_py, PM_mat_t mask_py, PM_mat_t ijmap_py, int patch_size, float guide_weight)
|
|
106
106
|
{
|
|
107
107
|
return guarded([source_py, mask_py, ijmap_py, patch_size, guide_weight] {
|
|
108
108
|
cv::Mat source = _py_to_cv2(source_py);
|
|
@@ -123,12 +123,15 @@ PM_mat_t PM_inpaint2(PM_mat_t source_py, PM_mat_t mask_py, PM_mat_t global_mask_
|
|
|
123
123
|
cv::Mat global_mask = _py_to_cv2(global_mask_py);
|
|
124
124
|
|
|
125
125
|
auto metric = PatchSSDDistanceMetric(patch_size);
|
|
126
|
-
cv::Mat result =
|
|
126
|
+
cv::Mat result =
|
|
127
|
+
Inpainting(source, mask, global_mask, &metric).run(verbose().load(), false, random_seed().load());
|
|
127
128
|
return _cv2_to_py(result);
|
|
128
129
|
});
|
|
129
130
|
}
|
|
130
131
|
|
|
131
|
-
PM_mat_t PM_inpaint2_regularity(
|
|
132
|
+
PM_mat_t PM_inpaint2_regularity(
|
|
133
|
+
PM_mat_t source_py, PM_mat_t mask_py, PM_mat_t global_mask_py, PM_mat_t ijmap_py, int patch_size,
|
|
134
|
+
float guide_weight)
|
|
132
135
|
{
|
|
133
136
|
return guarded([source_py, mask_py, global_mask_py, ijmap_py, patch_size, guide_weight] {
|
|
134
137
|
cv::Mat source = _py_to_cv2(source_py);
|
|
@@ -137,7 +140,8 @@ PM_mat_t PM_inpaint2_regularity(PM_mat_t source_py, PM_mat_t mask_py, PM_mat_t g
|
|
|
137
140
|
cv::Mat ijmap = _py_to_cv2(ijmap_py);
|
|
138
141
|
|
|
139
142
|
auto metric = RegularityGuidedPatchDistanceMetricV2(patch_size, ijmap, guide_weight);
|
|
140
|
-
cv::Mat result =
|
|
143
|
+
cv::Mat result =
|
|
144
|
+
Inpainting(source, mask, global_mask, &metric).run(verbose().load(), false, random_seed().load());
|
|
141
145
|
return _cv2_to_py(result);
|
|
142
146
|
});
|
|
143
147
|
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
#pragma once
|
|
2
2
|
|
|
3
|
-
#include <opencv2/core.hpp>
|
|
4
|
-
#include <cstdlib>
|
|
5
3
|
#include <cstdio>
|
|
4
|
+
#include <cstdlib>
|
|
6
5
|
#include <cstring>
|
|
6
|
+
#include <opencv2/core.hpp>
|
|
7
7
|
|
|
8
8
|
extern "C"
|
|
9
9
|
{
|
|
@@ -42,6 +42,7 @@ extern "C"
|
|
|
42
42
|
PM_mat_t PM_inpaint(PM_mat_t image, PM_mat_t mask, int patch_size);
|
|
43
43
|
PM_mat_t PM_inpaint_regularity(PM_mat_t image, PM_mat_t mask, PM_mat_t ijmap, int patch_size, float guide_weight);
|
|
44
44
|
PM_mat_t PM_inpaint2(PM_mat_t image, PM_mat_t mask, PM_mat_t global_mask, int patch_size);
|
|
45
|
-
PM_mat_t PM_inpaint2_regularity(
|
|
45
|
+
PM_mat_t PM_inpaint2_regularity(
|
|
46
|
+
PM_mat_t image, PM_mat_t mask, PM_mat_t global_mask, PM_mat_t ijmap, int patch_size, float guide_weight);
|
|
46
47
|
|
|
47
48
|
} /* extern "C" */
|
|
@@ -134,8 +134,11 @@ def main() -> None:
|
|
|
134
134
|
options.update(WINDOWS_CMAKE_OPTIONS)
|
|
135
135
|
defines = [f"-D{key}={value}" for key, value in options.items()]
|
|
136
136
|
subprocess.run([cmake, "-S", source, "-B", build, *defines], check=True)
|
|
137
|
+
# without a count, `make -j` starts all compilations at once
|
|
138
|
+
jobs = str(os.cpu_count() or 1)
|
|
137
139
|
subprocess.run(
|
|
138
|
-
[cmake, "--build", build, "--config", "Release", "--parallel"],
|
|
140
|
+
[cmake, "--build", build, "--config", "Release", "--parallel", jobs],
|
|
141
|
+
check=True,
|
|
139
142
|
)
|
|
140
143
|
subprocess.run([cmake, "--install", build, "--config", "Release"], check=True)
|
|
141
144
|
|
|
@@ -382,25 +382,22 @@ def write_report(
|
|
|
382
382
|
for case, results in rows
|
|
383
383
|
)
|
|
384
384
|
sections = "".join(section(case, results, labels) for case, results in rows)
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
f"</div><script>{SCRIPT}</script></body></html>\n",
|
|
402
|
-
encoding="utf-8",
|
|
403
|
-
)
|
|
385
|
+
with REPORT.open("w", encoding="utf-8") as report:
|
|
386
|
+
report.write(
|
|
387
|
+
"<!doctype html>\n"
|
|
388
|
+
'<html lang="en"><head><meta charset="utf-8">'
|
|
389
|
+
'<meta name="viewport" content="width=device-width, initial-scale=1">'
|
|
390
|
+
f"<title>patchmatch evaluation</title><style>{STYLE}</style></head><body>"
|
|
391
|
+
f"<main><header><h1>patchmatch evaluation</h1>{meta}</header>"
|
|
392
|
+
'<div class="controls">'
|
|
393
|
+
'<label><input type="checkbox" id="whole"> whole images</label>'
|
|
394
|
+
'<label><input type="checkbox" id="pixels"> show pixels</label>'
|
|
395
|
+
'<p class="hint">Click an image to enlarge it; click it, ← or → '
|
|
396
|
+
"switches between the versions, Esc closes.</p></div>"
|
|
397
|
+
f"<table><thead><tr>{head}</tr></thead><tbody>{body}</tbody></table>"
|
|
398
|
+
f'{sections}</main><div id="viewer" hidden><div class="slot"></div><p></p>'
|
|
399
|
+
f"</div><script>{SCRIPT}</script></body></html>\n"
|
|
400
|
+
)
|
|
404
401
|
|
|
405
402
|
|
|
406
403
|
def describe(args: argparse.Namespace, labels: list[str], paths: list[str]) -> str:
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|