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.
Files changed (23) hide show
  1. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/CMakeLists.txt +20 -1
  2. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/PKG-INFO +3 -1
  3. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/README.md +2 -0
  4. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/_version.py +3 -3
  5. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/csrc/inpaint.cpp +24 -21
  6. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/csrc/inpaint.h +3 -1
  7. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/csrc/masked_image.cpp +4 -1
  8. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/csrc/masked_image.h +14 -5
  9. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/csrc/nnf.cpp +18 -16
  10. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/csrc/nnf.h +20 -7
  11. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/csrc/pyinterface.cpp +14 -10
  12. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/csrc/pyinterface.h +4 -3
  13. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/scripts/build_opencv.py +4 -1
  14. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/scripts/evaluate_inpainting.py +16 -19
  15. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/LICENSE +0 -0
  16. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/examples/images/forest_pruned.bmp +0 -0
  17. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/__init__.py +0 -0
  18. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/_lib.py +0 -0
  19. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/patch_match.py +0 -0
  20. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/patchmatch/py.typed +0 -0
  21. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/pyproject.toml +0 -0
  22. {pypatchmatch-2.0.0rc3 → pypatchmatch-2.0.0rc4}/tests/test_e2e.py +0 -0
  23. {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.0rc3
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
+ [![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)
33
35
  [![License: MIT](https://img.shields.io/badge/License-MIT-blueviolet.svg)](https://github.com/mauwii/PyPatchMatch/blob/main/LICENSE)
34
36
  [![PyPI](https://img.shields.io/pypi/v/PyPatchMatch)](https://pypi.org/project/PyPatchMatch/)
35
37
  [![Downloads](https://static.pepy.tech/badge/pypatchmatch)](https://pepy.tech/projects/pypatchmatch)
@@ -1,5 +1,7 @@
1
1
  # PatchMatch based Inpainting
2
2
 
3
+ [![CI](https://github.com/mauwii/PyPatchMatch/actions/workflows/ci.yml/badge.svg?branch=main)](https://github.com/mauwii/PyPatchMatch/actions/workflows/ci.yml)
4
+ [![Quality Gate](https://sonarcloud.io/api/project_badges/measure?project=mauwii_PyPatchMatch&metric=alert_status)](https://sonarcloud.io/summary/new_code?id=mauwii_PyPatchMatch)
3
5
  [![License: MIT](https://img.shields.io/badge/License-MIT-blueviolet.svg)](https://github.com/mauwii/PyPatchMatch/blob/main/LICENSE)
4
6
  [![PyPI](https://img.shields.io/pypi/v/PyPatchMatch)](https://pypi.org/project/PyPatchMatch/)
5
7
  [![Downloads](https://static.pepy.tech/badge/pypatchmatch)](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.0rc3'
22
- __version_tuple__ = version_tuple = (2, 0, 0, 'rc3')
21
+ __version__ = version = '2.0.0rc4'
22
+ __version_tuple__ = version_tuple = (2, 0, 0, 'rc4')
23
23
 
24
- __commit_id__ = commit_id = 'g70cf3a861'
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 base[11] = {1.0, 0.99, 0.96, 0.83, 0.38, 0.11, 0.02, 0.005, 0.0006, 0.0001, 0};
15
- int length = (PatchDistanceMetric::kDistanceScale + 1);
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 (int i = 0; i < length; ++i)
18
+ for (std::size_t i = 0; i < length; ++i)
18
19
  {
19
- double t = (double)i / length;
20
- int j = (int)(100 * t);
21
- int k = j + 1;
22
- double vj = (j < 11) ? base[j] : 0;
23
- double vk = (k < 11) ? base[k] : 0;
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(const MaskedImage &source, int ys, int xs, cv::Mat &target, int yt, int xt, double weight)
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 algorithme uses a version proposed by Xavier Philippeau.
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() && source.size().width > 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 int nr_levels = m_pyramid.size();
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 = target.upsample(new_source.size().width, new_source.size().height, m_pyramid[level - 1].global_mask());
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
- cv::Mat &vote, const MaskedImage &source, bool upscaled, bool best_only)
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(MaskedImage &target, const cv::Mat &vote, const MaskedImage &source, bool keep_known) const
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(const NearestNeighborField &nnf, bool source2target, cv::Mat &vote, const MaskedImage &source, bool upscaled, bool best_only);
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, target_ptr[1] = g, target_ptr[2] = b;
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) : m_image(image), m_mask(mask), m_global_mask(global_mask), m_image_grad_computed(false)
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) : m_image(image), m_mask(mask), m_global_mask(global_mask),
22
- m_image_grady(grady), m_image_gradx(gradx), m_image_grad_computed(grad_computed)
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
- m_image_grady.clone(), m_image_gradx.clone(), m_image_grad_computed);
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 algorithme uses a version proposed by Xavier Philippeau.
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 distance = 0;
207
- long double wsum = 0;
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 += (long double)(PatchSSDDistanceMetric::kSSDScale) * (2 * patch_size + 1);
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
- distance /= (long double)(PatchSSDDistanceMetric::kSSDScale);
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()(const MaskedImage &source, int source_y, int source_x, const MaskedImage &target, int target_y, int target_x) const
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()(const MaskedImage &source, int source_y, int source_x, const MaskedImage &target, int target_y, int target_x) const
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 { return m_patch_size; }
14
- virtual int operator()(const MaskedImage &source, int source_y, int source_x, const MaskedImage &target, int target_y, int target_x) const = 0;
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(const MaskedImage &source, const MaskedImage &target, const PatchDistanceMetric *metric, int max_retry = 20)
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(const MaskedImage &source, const MaskedImage &target, const PatchDistanceMetric *metric, const NearestNeighborField &other, int max_retry = 20)
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()(const MaskedImage &source, int source_y, int source_x, const MaskedImage &target, int target_y, int target_x) const;
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()(const MaskedImage &source, int source_y, int source_x, const MaskedImage &target, int target_y, int target_x) const;
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
- // Takes back the ownership of the buffer that _cv2_to_py released. The buffer
89
- // crosses the C interface as a plain pointer, so it cannot be a std::vector
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(PM_mat_t source_py, PM_mat_t mask_py, PM_mat_t ijmap_py, int patch_size, float guide_weight)
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 = Inpainting(source, mask, global_mask, &metric).run(verbose().load(), false, random_seed().load());
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(PM_mat_t source_py, PM_mat_t mask_py, PM_mat_t global_mask_py, PM_mat_t ijmap_py, int patch_size, float guide_weight)
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 = Inpainting(source, mask, global_mask, &metric).run(verbose().load(), false, random_seed().load());
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(PM_mat_t image, PM_mat_t mask, PM_mat_t global_mask, PM_mat_t ijmap, int patch_size, float guide_weight);
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"], check=True
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
- # SonarCloud's path traversal rule for command line arguments (pythonsecurity:S8707)
386
- # flags the patch size, the seeds and the library paths in the content. The path is
387
- # fixed, and they only appear as escaped text, so the issue is suppressed.
388
- REPORT.write_text( # NOSONAR
389
- "<!doctype html>\n"
390
- '<html lang="en"><head><meta charset="utf-8">'
391
- '<meta name="viewport" content="width=device-width, initial-scale=1">'
392
- f"<title>patchmatch evaluation</title><style>{STYLE}</style></head><body>"
393
- f"<main><header><h1>patchmatch evaluation</h1>{meta}</header>"
394
- '<div class="controls">'
395
- '<label><input type="checkbox" id="whole"> whole images</label>'
396
- '<label><input type="checkbox" id="pixels"> show pixels</label>'
397
- '<p class="hint">Click an image to enlarge it; click it, &larr; or &rarr; '
398
- "switches between the versions, Esc closes.</p></div>"
399
- f"<table><thead><tr>{head}</tr></thead><tbody>{body}</tbody></table>"
400
- f'{sections}</main><div id="viewer" hidden><div class="slot"></div><p></p>'
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, &larr; or &rarr; '
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