Blender V5.0
morphological_distance.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include <limits>
6
7#include "BLI_math_base.hh"
9
10#include "GPU_shader.hh"
11
12#include "COM_context.hh"
13#include "COM_result.hh"
14#include "COM_utilities.hh"
15
17
18namespace blender::compositor {
19
20static const char *get_shader_name(const int distance)
21{
22 if (distance > 0) {
23 return "compositor_morphological_distance_dilate";
24 }
25 return "compositor_morphological_distance_erode";
26}
27
29 const Result &input,
31 const int distance)
32{
33 gpu::Shader *shader = context.get_shader(get_shader_name(distance));
34 GPU_shader_bind(shader);
35
36 /* Pass the absolute value of the distance. We have specialized shaders for each sign. */
37 GPU_shader_uniform_1i(shader, "radius", math::abs(distance));
38
39 input.bind_as_texture(shader, "input_tx");
40
41 output.allocate_texture(input.domain());
42 output.bind_as_image(shader, "output_img");
43
44 compute_dispatch_threads_at_least(shader, input.domain().size);
45
47 output.unbind_as_image();
48 input.unbind_as_texture();
49}
50
51template<bool IsDilate>
54 const int structuring_element_radius)
55{
56 output.allocate_texture(input.domain());
57
58 const float limit = IsDilate ? std::numeric_limits<float>::lowest() :
59 std::numeric_limits<float>::max();
60 const auto morphology_operator = [](const float a, const float b) {
61 if constexpr (IsDilate) {
62 return math::max(a, b);
63 }
64 else {
65 return math::min(a, b);
66 }
67 };
68
69 const int2 image_size = input.domain().size;
70
71 const int radius_squared = math::square(structuring_element_radius);
72
73 /* Find the minimum/maximum value in the circular window of the given radius around the pixel.
74 * By circular window, we mean that pixels in the window whose distance to the center of window
75 * is larger than the given radius are skipped and not considered. Consequently, the dilation
76 * or erosion that take place produces round results as opposed to squarish ones. This is
77 * essentially a morphological operator with a circular structuring element. */
78 parallel_for(image_size, [&](const int2 texel) {
79 /* Compute the start and end bounds of the window such that no out-of-bounds processing happen
80 * in the loops. */
81 const int2 start = math::max(texel - structuring_element_radius, int2(0)) - texel;
82 const int2 end = math::min(texel + structuring_element_radius + 1, image_size) - texel;
83
84 float value = limit;
85 for (int y = start.y; y < end.y; y++) {
86 const int yy = y * y;
87 for (int x = start.x; x < end.x; x++) {
88 if (x * x + yy > radius_squared) {
89 continue;
90 }
91 value = morphology_operator(value, input.load_pixel<float>(texel + int2(x, y)));
92 }
93 }
94
95 output.store_pixel(texel, value);
96 });
97}
98
100 const Result &input,
101 Result &output,
102 const int distance)
103{
104 if (context.use_gpu()) {
106 }
107 else {
108 if (distance > 0) {
110 }
111 else {
113 }
114 }
115}
116
117} // namespace blender::compositor
void GPU_shader_bind(blender::gpu::Shader *shader, const blender::gpu::shader::SpecializationConstants *constants_state=nullptr)
void GPU_shader_uniform_1i(blender::gpu::Shader *sh, const char *name, int value)
void GPU_shader_unbind()
#define input
#define output
float distance(VecOp< float, D >, VecOp< float, D >) RET
void compute_dispatch_threads_at_least(gpu::Shader *shader, int2 threads_range, int2 local_size=int2(16))
Definition utilities.cc:196
static void morphological_distance_cpu(const Result &input, Result &output, const int structuring_element_radius)
void morphological_distance(Context &context, const Result &input, Result &output, const int distance)
static void morphological_distance_gpu(Context &context, const Result &input, Result &output, const int distance)
void parallel_for(const int2 range, const Function &function)
static const char * get_shader_name(const int distance)
T min(const T &a, const T &b)
T square(const T &a)
T max(const T &a, const T &b)
T abs(const T &a)
VecBase< int32_t, 2 > int2