Blender  V3.3
COM_KeyingClipOperation.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2012 Blender Foundation. */
3 
5 
6 namespace blender::compositor {
7 
9 {
12 
13  kernel_radius_ = 3;
14  kernel_tolerance_ = 0.1f;
15 
16  clip_black_ = 0.0f;
17  clip_white_ = 1.0f;
18 
19  is_edge_matte_ = false;
20 
21  flags_.complex = true;
22 }
23 
25 {
27 
28  return buffer;
29 }
30 
31 void KeyingClipOperation::execute_pixel(float output[4], int x, int y, void *data)
32 {
33  const int delta = kernel_radius_;
34  const float tolerance = kernel_tolerance_;
35 
36  MemoryBuffer *input_buffer = (MemoryBuffer *)data;
37  float *buffer = input_buffer->get_buffer();
38 
39  int buffer_width = input_buffer->get_width();
40  int buffer_height = input_buffer->get_height();
41 
42  float value = buffer[(y * buffer_width + x)];
43 
44  bool ok = false;
45  int start_x = max_ff(0, x - delta + 1), start_y = max_ff(0, y - delta + 1),
46  end_x = min_ff(x + delta - 1, buffer_width - 1),
47  end_y = min_ff(y + delta - 1, buffer_height - 1);
48 
49  int count = 0, total_count = (end_x - start_x + 1) * (end_y - start_y + 1) - 1;
50  int threshold_count = ceil((float)total_count * 0.9f);
51 
52  if (delta == 0) {
53  ok = true;
54  }
55 
56  for (int cx = start_x; ok == false && cx <= end_x; cx++) {
57  for (int cy = start_y; ok == false && cy <= end_y; cy++) {
58  if (UNLIKELY(cx == x && cy == y)) {
59  continue;
60  }
61 
62  int buffer_index = (cy * buffer_width + cx);
63  float current_value = buffer[buffer_index];
64 
65  if (fabsf(current_value - value) < tolerance) {
66  count++;
67  if (count >= threshold_count) {
68  ok = true;
69  }
70  }
71  }
72  }
73 
74  if (is_edge_matte_) {
75  if (ok) {
76  output[0] = 0.0f;
77  }
78  else {
79  output[0] = 1.0f;
80  }
81  }
82  else {
83  output[0] = value;
84 
85  if (ok) {
86  if (output[0] < clip_black_) {
87  output[0] = 0.0f;
88  }
89  else if (output[0] >= clip_white_) {
90  output[0] = 1.0f;
91  }
92  else {
94  }
95  }
96  }
97 }
98 
100  ReadBufferOperation *read_operation,
101  rcti *output)
102 {
103  rcti new_input;
104 
105  new_input.xmin = input->xmin - kernel_radius_;
106  new_input.ymin = input->ymin - kernel_radius_;
107  new_input.xmax = input->xmax + kernel_radius_;
108  new_input.ymax = input->ymax + kernel_radius_;
109 
110  return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
111 }
112 
114  const rcti &output_area,
115  rcti &r_input_area)
116 {
117  BLI_assert(input_idx == 0);
118  UNUSED_VARS_NDEBUG(input_idx);
119  r_input_area.xmin = output_area.xmin - kernel_radius_;
120  r_input_area.xmax = output_area.xmax + kernel_radius_;
121  r_input_area.ymin = output_area.ymin - kernel_radius_;
122  r_input_area.ymax = output_area.ymax + kernel_radius_;
123 }
124 
126  const rcti &area,
128 {
129  const MemoryBuffer *input = inputs[0];
130  BuffersIterator<float> it = output->iterate_with(inputs, area);
131 
132  const int delta = kernel_radius_;
133  const float tolerance = kernel_tolerance_;
134  const int width = this->get_width();
135  const int height = this->get_height();
136  const int row_stride = input->row_stride;
137  const int elem_stride = input->elem_stride;
138  for (; !it.is_end(); ++it) {
139  const int x = it.x;
140  const int y = it.y;
141 
142  const int start_x = MAX2(0, x - delta + 1);
143  const int start_y = MAX2(0, y - delta + 1);
144  const int end_x = MIN2(x + delta, width);
145  const int end_y = MIN2(y + delta, height);
146  const int x_len = end_x - start_x;
147  const int y_len = end_y - start_y;
148 
149  const int total_count = x_len * y_len - 1;
150  const int threshold_count = ceil((float)total_count * 0.9f);
151  bool ok = false;
152  if (delta == 0) {
153  ok = true;
154  }
155 
156  const float *main_elem = it.in(0);
157  const float value = *main_elem;
158  const float *row = input->get_elem(start_x, start_y);
159  const float *end_row = row + y_len * row_stride;
160  int count = 0;
161  for (; ok == false && row < end_row; row += row_stride) {
162  const float *end_elem = row + x_len * elem_stride;
163  for (const float *elem = row; ok == false && elem < end_elem; elem += elem_stride) {
164  if (UNLIKELY(elem == main_elem)) {
165  continue;
166  }
167 
168  const float current_value = *elem;
169  if (fabsf(current_value - value) < tolerance) {
170  count++;
171  if (count >= threshold_count) {
172  ok = true;
173  }
174  }
175  }
176  }
177 
178  if (is_edge_matte_) {
179  *it.out = ok ? 0.0f : 1.0f;
180  }
181  else {
182  if (!ok) {
183  *it.out = value;
184  }
185  else if (value < clip_black_) {
186  *it.out = 0.0f;
187  }
188  else if (value >= clip_white_) {
189  *it.out = 1.0f;
190  }
191  else {
192  *it.out = (value - clip_black_) / (clip_white_ - clip_black_);
193  }
194  }
195  }
196 }
197 
198 } // namespace blender::compositor
#define BLI_assert(a)
Definition: BLI_assert.h:46
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
#define UNUSED_VARS_NDEBUG(...)
#define MAX2(a, b)
#define UNLIKELY(x)
#define MIN2(a, b)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei height
_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
_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 GLsizei width
bool determine_depending_area_of_interest(rcti *input, ReadBufferOperation *read_operation, rcti *output) override
void execute_pixel(float output[4], int x, int y, void *data) override
calculate a single pixel
void update_memory_buffer_partial(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) 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
const int get_width() const
get the width of this MemoryBuffer
const int get_height() const
get the height of this MemoryBuffer
float * get_buffer()
get the data of this MemoryBuffer
void add_output_socket(DataType datatype)
NodeOperation * get_input_operation(int index)
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)
virtual void * initialize_tile_data(rcti *)
int count
ccl_global float * buffer
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
static void area(int d1, int d2, int e1, int e2, float weights[2])
typename BuffersIteratorBuilder< T >::Iterator BuffersIterator
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