Blender  V3.3
COM_InpaintOperation.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2011 Blender Foundation. */
3 
4 #include "MEM_guardedalloc.h"
5 
6 #include "COM_InpaintOperation.h"
7 
8 namespace blender::compositor {
9 
10 #define ASSERT_XY_RANGE(x, y) \
11  BLI_assert(x >= 0 && x < this->get_width() && y >= 0 && y < this->get_height())
12 
14 {
17  flags_.complex = true;
18  input_image_program_ = nullptr;
19  pixelorder_ = nullptr;
20  manhattan_distance_ = nullptr;
21  cached_buffer_ = nullptr;
22  cached_buffer_ready_ = false;
24 }
26 {
28 
29  pixelorder_ = nullptr;
30  manhattan_distance_ = nullptr;
31  cached_buffer_ = nullptr;
32  cached_buffer_ready_ = false;
33 
34  this->init_mutex();
35 }
36 
37 void InpaintSimpleOperation::clamp_xy(int &x, int &y)
38 {
39  int width = this->get_width();
40  int height = this->get_height();
41 
42  if (x < 0) {
43  x = 0;
44  }
45  else if (x >= width) {
46  x = width - 1;
47  }
48 
49  if (y < 0) {
50  y = 0;
51  }
52  else if (y >= height) {
53  y = height - 1;
54  }
55 }
56 
57 float *InpaintSimpleOperation::get_pixel(int x, int y)
58 {
59  int width = this->get_width();
60 
61  ASSERT_XY_RANGE(x, y);
62 
65 }
66 
67 int InpaintSimpleOperation::mdist(int x, int y)
68 {
69  int width = this->get_width();
70 
71  ASSERT_XY_RANGE(x, y);
72 
73  return manhattan_distance_[y * width + x];
74 }
75 
76 bool InpaintSimpleOperation::next_pixel(int &x, int &y, int &curr, int iters)
77 {
78  int width = this->get_width();
79 
80  if (curr >= area_size_) {
81  return false;
82  }
83 
84  int r = pixelorder_[curr++];
85 
86  x = r % width;
87  y = r / width;
88 
89  if (this->mdist(x, y) > iters) {
90  return false;
91  }
92 
93  return true;
94 }
95 
96 void InpaintSimpleOperation::calc_manhattan_distance()
97 {
98  int width = this->get_width();
99  int height = this->get_height();
100  short *m = manhattan_distance_ = (short *)MEM_mallocN(sizeof(short) * width * height, __func__);
101  int *offsets;
102 
103  offsets = (int *)MEM_callocN(sizeof(int) * (width + height + 1),
104  "InpaintSimpleOperation offsets");
105 
106  for (int j = 0; j < height; j++) {
107  for (int i = 0; i < width; i++) {
108  int r = 0;
109  /* no need to clamp here */
110  if (this->get_pixel(i, j)[3] < 1.0f) {
111  r = width + height;
112  if (i > 0) {
113  r = min_ii(r, m[j * width + i - 1] + 1);
114  }
115  if (j > 0) {
116  r = min_ii(r, m[(j - 1) * width + i] + 1);
117  }
118  }
119  m[j * width + i] = r;
120  }
121  }
122 
123  for (int j = height - 1; j >= 0; j--) {
124  for (int i = width - 1; i >= 0; i--) {
125  int r = m[j * width + i];
126 
127  if (i + 1 < width) {
128  r = min_ii(r, m[j * width + i + 1] + 1);
129  }
130  if (j + 1 < height) {
131  r = min_ii(r, m[(j + 1) * width + i] + 1);
132  }
133 
134  m[j * width + i] = r;
135 
136  offsets[r]++;
137  }
138  }
139 
140  offsets[0] = 0;
141 
142  for (int i = 1; i < width + height + 1; i++) {
143  offsets[i] += offsets[i - 1];
144  }
145 
146  area_size_ = offsets[width + height];
147  pixelorder_ = (int *)MEM_mallocN(sizeof(int) * area_size_, __func__);
148 
149  for (int i = 0; i < width * height; i++) {
150  if (m[i] > 0) {
151  pixelorder_[offsets[m[i] - 1]++] = i;
152  }
153  }
154 
155  MEM_freeN(offsets);
156 }
157 
158 void InpaintSimpleOperation::pix_step(int x, int y)
159 {
160  const int d = this->mdist(x, y);
161  float pix[3] = {0.0f, 0.0f, 0.0f};
162  float pix_divider = 0.0f;
163 
164  for (int dx = -1; dx <= 1; dx++) {
165  for (int dy = -1; dy <= 1; dy++) {
166  /* changing to both != 0 gives dithering artifacts */
167  if (dx != 0 || dy != 0) {
168  int x_ofs = x + dx;
169  int y_ofs = y + dy;
170 
171  this->clamp_xy(x_ofs, y_ofs);
172 
173  if (this->mdist(x_ofs, y_ofs) < d) {
174 
175  float weight;
176 
177  if (dx == 0 || dy == 0) {
178  weight = 1.0f;
179  }
180  else {
181  weight = M_SQRT1_2; /* 1.0f / sqrt(2) */
182  }
183 
184  madd_v3_v3fl(pix, this->get_pixel(x_ofs, y_ofs), weight);
185  pix_divider += weight;
186  }
187  }
188  }
189  }
190 
191  float *output = this->get_pixel(x, y);
192  if (pix_divider != 0.0f) {
193  mul_v3_fl(pix, 1.0f / pix_divider);
194  /* use existing pixels alpha to blend into */
195  interp_v3_v3v3(output, pix, output, output[3]);
196  output[3] = 1.0f;
197  }
198 }
199 
201 {
202  if (cached_buffer_ready_) {
203  return cached_buffer_;
204  }
205  lock_mutex();
206  if (!cached_buffer_ready_) {
208  cached_buffer_ = (float *)MEM_dupallocN(buf->get_buffer());
209 
210  this->calc_manhattan_distance();
211 
212  int curr = 0;
213  int x, y;
214 
215  while (this->next_pixel(x, y, curr, iterations_)) {
216  this->pix_step(x, y);
217  }
218  cached_buffer_ready_ = true;
219  }
220 
221  unlock_mutex();
222  return cached_buffer_;
223 }
224 
225 void InpaintSimpleOperation::execute_pixel(float output[4], int x, int y, void * /*data*/)
226 {
227  this->clamp_xy(x, y);
228  copy_v4_v4(output, this->get_pixel(x, y));
229 }
230 
232 {
233  input_image_program_ = nullptr;
234  this->deinit_mutex();
235  if (cached_buffer_) {
237  cached_buffer_ = nullptr;
238  }
239 
240  if (pixelorder_) {
242  pixelorder_ = nullptr;
243  }
244 
245  if (manhattan_distance_) {
247  manhattan_distance_ = nullptr;
248  }
249  cached_buffer_ready_ = false;
250 }
251 
253  rcti * /*input*/, ReadBufferOperation *read_operation, rcti *output)
254 {
255  if (cached_buffer_ready_) {
256  return false;
257  }
258 
259  rcti new_input;
260 
261  new_input.xmax = get_width();
262  new_input.xmin = 0;
263  new_input.ymax = get_height();
264  new_input.ymin = 0;
265 
266  return NodeOperation::determine_depending_area_of_interest(&new_input, read_operation, output);
267 }
268 
270  const rcti &UNUSED(output_area),
271  rcti &r_input_area)
272 {
273  BLI_assert(input_idx == 0);
274  UNUSED_VARS_NDEBUG(input_idx);
275  r_input_area = this->get_canvas();
276 }
277 
279  const rcti &area,
281 {
282  /* TODO(manzanilla): once tiled implementation is removed, run multi-threaded where possible. */
283  MemoryBuffer *input = inputs[0];
284  if (!cached_buffer_ready_) {
285  if (input->is_a_single_elem()) {
286  MemoryBuffer *tmp = input->inflate();
288  delete tmp;
289  }
290  else {
291  cached_buffer_ = (float *)MEM_dupallocN(input->get_buffer());
292  }
293 
294  this->calc_manhattan_distance();
295 
296  int curr = 0;
297  int x, y;
298  while (this->next_pixel(x, y, curr, iterations_)) {
299  this->pix_step(x, y);
300  }
301  cached_buffer_ready_ = true;
302  }
303 
304  const int num_channels = COM_data_type_num_channels(get_output_socket()->get_data_type());
305  MemoryBuffer buf(cached_buffer_, num_channels, input->get_width(), input->get_height());
306  output->copy_from(&buf, area);
307 }
308 
309 } // namespace blender::compositor
#define BLI_assert(a)
Definition: BLI_assert.h:46
MINLINE int min_ii(int a, int b)
#define M_SQRT1_2
Definition: BLI_math_base.h:32
MINLINE void copy_v4_v4(float r[4], const float a[4])
MINLINE void madd_v3_v3fl(float r[3], const float a[3], float f)
MINLINE void mul_v3_fl(float r[3], float f)
void interp_v3_v3v3(float r[3], const float a[3], const float b[3], float t)
Definition: math_vector.c:29
#define UNUSED_VARS_NDEBUG(...)
#define UNUSED(x)
#define ASSERT_XY_RANGE(x, 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 GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble GLdouble r _GL_VOID_RET _GL_VOID GLfloat GLfloat r _GL_VOID_RET _GL_VOID GLint GLint r _GL_VOID_RET _GL_VOID GLshort GLshort r _GL_VOID_RET _GL_VOID GLdouble GLdouble r
_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
Read Guarded memory(de)allocation.
void update_memory_buffer(MemoryBuffer *output, const rcti &area, Span< MemoryBuffer * > inputs) override
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
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
float * get_buffer()
get the data of this MemoryBuffer
void add_output_socket(DataType datatype)
SocketReader * get_input_socket_reader(unsigned int index)
NodeOperationOutput * get_output_socket(unsigned int index=0)
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 *)
ccl_global KernelShaderEvalInput ccl_global float * output
ccl_global KernelShaderEvalInput * input
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_dupallocN)(const void *vmemh)
Definition: mallocn.c:28
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
static void area(int d1, int d2, int e1, int e2, float weights[2])
constexpr int COM_DATA_TYPE_COLOR_CHANNELS
Definition: COM_defines.h:62
constexpr int COM_data_type_num_channels(const DataType datatype)
Definition: COM_defines.h:42
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