Blender  V3.3
COM_BilateralBlurOperation.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2011 Blender Foundation. */
3 
5 
6 namespace blender::compositor {
7 
9 {
13  flags_.complex = true;
14 
15  input_color_program_ = nullptr;
16  input_determinator_program_ = nullptr;
17 }
18 
20 {
21  input_color_program_ = get_input_socket_reader(0);
22  input_determinator_program_ = get_input_socket_reader(1);
24 }
25 
26 void BilateralBlurOperation::execute_pixel(float output[4], int x, int y, void *data)
27 {
28  /* Read the determinator color at x, y,
29  * this will be used as the reference color for the determinator. */
30  float determinator_reference_color[4];
31  float determinator[4];
32  float temp_color[4];
33  float blur_color[4];
34  float blur_divider;
35  float space = space_;
36  float sigmacolor = data_->sigma_color;
37  int minx = floor(x - space);
38  int maxx = ceil(x + space);
39  int miny = floor(y - space);
40  int maxy = ceil(y + space);
41  float delta_color;
42  input_determinator_program_->read(determinator_reference_color, x, y, data);
43 
44  zero_v4(blur_color);
45  blur_divider = 0.0f;
46  /* TODO(sergey): This isn't really good bilateral filter, it should be
47  * using gaussian bell for weights. Also sigma_color doesn't seem to be
48  * used correct at all.
49  */
50  for (int yi = miny; yi < maxy; yi += QualityStepHelper::get_step()) {
51  for (int xi = minx; xi < maxx; xi += QualityStepHelper::get_step()) {
52  /* Read determinator. */
53  input_determinator_program_->read(determinator, xi, yi, data);
54  delta_color = (fabsf(determinator_reference_color[0] - determinator[0]) +
55  fabsf(determinator_reference_color[1] - determinator[1]) +
56  /* Do not take the alpha channel into account. */
57  fabsf(determinator_reference_color[2] - determinator[2]));
58  if (delta_color < sigmacolor) {
59  /* Add this to the blur. */
60  input_color_program_->read(temp_color, xi, yi, data);
61  add_v4_v4(blur_color, temp_color);
62  blur_divider += 1.0f;
63  }
64  }
65  }
66 
67  if (blur_divider > 0.0f) {
68  mul_v4_v4fl(output, blur_color, 1.0f / blur_divider);
69  }
70  else {
71  output[0] = 0.0f;
72  output[1] = 0.0f;
73  output[2] = 0.0f;
74  output[3] = 1.0f;
75  }
76 }
77 
79 {
80  input_color_program_ = nullptr;
81  input_determinator_program_ = nullptr;
82 }
83 
85  rcti *input, ReadBufferOperation *read_operation, rcti *output)
86 {
87  rcti new_input;
88  int add = ceil(space_) + 1;
89 
90  new_input.xmax = input->xmax + (add);
91  new_input.xmin = input->xmin - (add);
92  new_input.ymax = input->ymax + (add);
93  new_input.ymin = input->ymin - (add);
94 
95  return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
96 }
97 
99  const rcti &output_area,
100  rcti &r_input_area)
101 {
102  const int add = ceil(space_) + 1;
103 
104  r_input_area.xmax = output_area.xmax + (add);
105  r_input_area.xmin = output_area.xmin - (add);
106  r_input_area.ymax = output_area.ymax + (add);
107  r_input_area.ymin = output_area.ymin - (add);
108 }
109 
110 struct PixelCursor {
113  int step;
114  float sigma_color;
116  float temp_color[4];
117  float *out;
118  int min_x, max_x;
119  int min_y, max_y;
120 };
121 
122 static void blur_pixel(PixelCursor &p)
123 {
124  float blur_divider = 0.0f;
125  zero_v4(p.out);
126 
127  /* TODO(sergey): This isn't really good bilateral filter, it should be
128  * using gaussian bell for weights. Also sigma_color doesn't seem to be
129  * used correct at all.
130  */
131  for (int yi = p.min_y; yi < p.max_y; yi += p.step) {
132  for (int xi = p.min_x; xi < p.max_x; xi += p.step) {
133  p.input_determinator->read(p.temp_color, xi, yi);
134  /* Do not take the alpha channel into account. */
135  const float delta_color = (fabsf(p.determ_reference_color[0] - p.temp_color[0]) +
138  if (delta_color < p.sigma_color) {
139  /* Add this to the blur. */
140  p.input_color->read(p.temp_color, xi, yi);
141  add_v4_v4(p.out, p.temp_color);
142  blur_divider += 1.0f;
143  }
144  }
145  }
146 
147  if (blur_divider > 0.0f) {
148  mul_v4_fl(p.out, 1.0f / blur_divider);
149  }
150  else {
152  }
153 }
154 
156  const rcti &area,
158 {
159  PixelCursor p = {};
161  p.sigma_color = data_->sigma_color;
162  p.input_color = inputs[0];
163  p.input_determinator = inputs[1];
164  const float space = space_;
165  for (int y = area.ymin; y < area.ymax; y++) {
166  p.out = output->get_elem(area.xmin, y);
167  /* This will be used as the reference color for the determinator. */
169  p.min_y = floor(y - space);
170  p.max_y = ceil(y + space);
171  for (int x = area.xmin; x < area.xmax; x++) {
172  p.min_x = floor(x - space);
173  p.max_x = ceil(x + space);
174 
175  blur_pixel(p);
176 
178  p.out += output->elem_stride;
179  }
180  }
181 }
182 
183 } // namespace blender::compositor
MINLINE void mul_v4_fl(float r[4], float f)
MINLINE void add_v4_v4(float r[4], const float a[4])
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void mul_v4_v4fl(float r[4], const float a[4], float f)
MINLINE void zero_v4(float r[4])
#define UNUSED(x)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint y
bool determine_depending_area_of_interest(rcti *input, ReadBufferOperation *read_operation, rcti *output) override
void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) override
void execute_pixel(float output[4], int x, int y, void *data) override
void get_area_of_interest(int input_idx, const rcti &output_area, rcti &r_input_area) override
Get input operation area being read by this operation on rendering given output area.
a MemoryBuffer contains access to the data of a chunk
void read(float *result, int x, int y, MemoryBufferExtend extend_x=MemoryBufferExtend::Clip, MemoryBufferExtend extend_y=MemoryBufferExtend::Clip)
void add_output_socket(DataType datatype)
SocketReader * get_input_socket_reader(unsigned int index)
void read(float result[4], int x, int y, void *chunk_data)
virtual bool determine_depending_area_of_interest(rcti *input, ReadBufferOperation *read_operation, rcti *output)
void add_input_socket(DataType datatype, ResizeMode resize_mode=ResizeMode::Center)
ccl_global KernelShaderEvalInput ccl_global float * output
ccl_global KernelShaderEvalInput * input
ccl_device_inline float3 ceil(const float3 &a)
Definition: math_float3.h:363
#define fabsf(x)
Definition: metal/compat.h:219
bool add(void *owner, const AttributeIDRef &attribute_id, eAttrDomain domain, eCustomDataType data_type, const AttributeInit &initializer)
static void area(int d1, int d2, int e1, int e2, float weights[2])
static void blur_pixel(PixelCursor &p)
constexpr float COM_COLOR_BLACK[4]
Definition: COM_defines.h:66
T floor(const T &a)
static bNodeSocketTemplate inputs[]
int ymin
Definition: DNA_vec_types.h:64
int ymax
Definition: DNA_vec_types.h:64
int xmin
Definition: DNA_vec_types.h:63
int xmax
Definition: DNA_vec_types.h:63