Blender  V3.3
COM_KeyingNode.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2012 Blender Foundation. */
3 
4 #include "COM_KeyingNode.h"
5 
9 #include "COM_KeyingOperation.h"
10 
11 #include "COM_MathBaseOperation.h"
12 
13 #include "COM_ConvertOperation.h"
14 #include "COM_SetValueOperation.h"
15 
17 
19 
22 
23 namespace blender::compositor {
24 
25 KeyingNode::KeyingNode(bNode *editor_node) : Node(editor_node)
26 {
27  /* pass */
28 }
29 
31  NodeInput *input_image,
32  int size) const
33 {
34  ConvertRGBToYCCOperation *convertRGBToYCCOperation = new ConvertRGBToYCCOperation();
35  convertRGBToYCCOperation->set_mode(BLI_YCC_ITU_BT709);
36  converter.add_operation(convertRGBToYCCOperation);
37 
38  converter.map_input_socket(input_image, convertRGBToYCCOperation->get_input_socket(0));
39 
40  CombineChannelsOperation *combine_operation = new CombineChannelsOperation();
41  converter.add_operation(combine_operation);
42 
43  for (int channel = 0; channel < 4; channel++) {
44  SeparateChannelOperation *separate_operation = new SeparateChannelOperation();
45  separate_operation->set_channel(channel);
46  converter.add_operation(separate_operation);
47 
48  converter.add_link(convertRGBToYCCOperation->get_output_socket(0),
49  separate_operation->get_input_socket(0));
50 
51  if (ELEM(channel, 0, 3)) {
52  converter.add_link(separate_operation->get_output_socket(0),
53  combine_operation->get_input_socket(channel));
54  }
55  else {
56  KeyingBlurOperation *blur_xoperation = new KeyingBlurOperation();
57  blur_xoperation->set_size(size);
59  converter.add_operation(blur_xoperation);
60 
61  KeyingBlurOperation *blur_yoperation = new KeyingBlurOperation();
62  blur_yoperation->set_size(size);
64  converter.add_operation(blur_yoperation);
65 
66  converter.add_link(separate_operation->get_output_socket(),
67  blur_xoperation->get_input_socket(0));
68  converter.add_link(blur_xoperation->get_output_socket(),
69  blur_yoperation->get_input_socket(0));
70  converter.add_link(blur_yoperation->get_output_socket(0),
71  combine_operation->get_input_socket(channel));
72  }
73  }
74 
75  ConvertYCCToRGBOperation *convertYCCToRGBOperation = new ConvertYCCToRGBOperation();
76  convertYCCToRGBOperation->set_mode(BLI_YCC_ITU_BT709);
77  converter.add_operation(convertYCCToRGBOperation);
78 
79  converter.add_link(combine_operation->get_output_socket(0),
80  convertYCCToRGBOperation->get_input_socket(0));
81 
82  return convertYCCToRGBOperation->get_output_socket(0);
83 }
84 
86  NodeOperationOutput *post_blur_input,
87  int size) const
88 {
89  KeyingBlurOperation *blur_xoperation = new KeyingBlurOperation();
90  blur_xoperation->set_size(size);
92  converter.add_operation(blur_xoperation);
93 
94  KeyingBlurOperation *blur_yoperation = new KeyingBlurOperation();
95  blur_yoperation->set_size(size);
97  converter.add_operation(blur_yoperation);
98 
99  converter.add_link(post_blur_input, blur_xoperation->get_input_socket(0));
100  converter.add_link(blur_xoperation->get_output_socket(), blur_yoperation->get_input_socket(0));
101 
102  return blur_yoperation->get_output_socket();
103 }
104 
106  NodeOperationOutput *dilate_erode_input,
107  int distance) const
108 {
109  DilateDistanceOperation *dilate_erode_operation;
110  if (distance > 0) {
111  dilate_erode_operation = new DilateDistanceOperation();
112  dilate_erode_operation->set_distance(distance);
113  }
114  else {
115  dilate_erode_operation = new ErodeDistanceOperation();
116  dilate_erode_operation->set_distance(-distance);
117  }
118  converter.add_operation(dilate_erode_operation);
119 
120  converter.add_link(dilate_erode_input, dilate_erode_operation->get_input_socket(0));
121 
122  return dilate_erode_operation->get_output_socket(0);
123 }
124 
126  const CompositorContext &context,
127  NodeOperationOutput *feather_input,
128  int falloff,
129  int distance) const
130 {
131  /* this uses a modified gaussian blur function otherwise its far too slow */
132  eCompositorQuality quality = context.get_quality();
133 
134  /* initialize node data */
136  memset(&data, 0, sizeof(NodeBlurData));
137  data.filtertype = R_FILTER_GAUSS;
138  if (distance > 0) {
139  data.sizex = data.sizey = distance;
140  }
141  else {
142  data.sizex = data.sizey = -distance;
143  }
144 
146  operationx->set_data(&data);
147  operationx->set_quality(quality);
148  operationx->set_size(1.0f);
149  operationx->set_subtract(distance < 0);
150  operationx->set_falloff(falloff);
151  converter.add_operation(operationx);
152 
154  operationy->set_data(&data);
155  operationy->set_quality(quality);
156  operationy->set_size(1.0f);
157  operationy->set_subtract(distance < 0);
158  operationy->set_falloff(falloff);
159  converter.add_operation(operationy);
160 
161  converter.add_link(feather_input, operationx->get_input_socket(0));
162  converter.add_link(operationx->get_output_socket(), operationy->get_input_socket(0));
163 
164  return operationy->get_output_socket();
165 }
166 
168  NodeOperationOutput *despill_input,
169  NodeInput *input_screen,
170  float factor,
171  float color_balance) const
172 {
173  KeyingDespillOperation *despill_operation = new KeyingDespillOperation();
174  despill_operation->set_despill_factor(factor);
175  despill_operation->set_color_balance(color_balance);
176  converter.add_operation(despill_operation);
177 
178  converter.add_link(despill_input, despill_operation->get_input_socket(0));
179  converter.map_input_socket(input_screen, despill_operation->get_input_socket(1));
180 
181  return despill_operation->get_output_socket(0);
182 }
183 
185  NodeOperationOutput *clip_input,
186  int kernel_radius,
187  float kernel_tolerance,
188  float clip_black,
189  float clip_white,
190  bool edge_matte) const
191 {
192  KeyingClipOperation *clip_operation = new KeyingClipOperation();
193  clip_operation->set_kernel_radius(kernel_radius);
194  clip_operation->set_kernel_tolerance(kernel_tolerance);
195  clip_operation->set_clip_black(clip_black);
196  clip_operation->set_clip_white(clip_white);
197  clip_operation->set_is_edge_matte(edge_matte);
198  converter.add_operation(clip_operation);
199 
200  converter.add_link(clip_input, clip_operation->get_input_socket(0));
201 
202  return clip_operation->get_output_socket(0);
203 }
204 
206  const CompositorContext &context) const
207 {
208  bNode *editor_node = this->get_bnode();
209  NodeKeyingData *keying_data = (NodeKeyingData *)editor_node->storage;
210 
211  NodeInput *input_image = this->get_input_socket(0);
212  NodeInput *input_screen = this->get_input_socket(1);
213  NodeInput *input_garbage_matte = this->get_input_socket(2);
214  NodeInput *input_core_matte = this->get_input_socket(3);
215  NodeOutput *output_image = this->get_output_socket(0);
216  NodeOutput *output_matte = this->get_output_socket(1);
217  NodeOutput *output_edges = this->get_output_socket(2);
218  NodeOperationOutput *postprocessed_matte = nullptr, *postprocessed_image = nullptr,
219  *edges_matte = nullptr;
220 
221  /* keying operation */
222  KeyingOperation *keying_operation = new KeyingOperation();
223  keying_operation->set_screen_balance(keying_data->screen_balance);
224  converter.add_operation(keying_operation);
225 
226  converter.map_input_socket(input_screen, keying_operation->get_input_socket(1));
227 
228  if (keying_data->blur_pre) {
229  /* Chroma pre-blur operation for input of keying operation. */
230  NodeOperationOutput *pre_blurred_image = setup_pre_blur(
231  converter, input_image, keying_data->blur_pre);
232  converter.add_link(pre_blurred_image, keying_operation->get_input_socket(0));
233  }
234  else {
235  converter.map_input_socket(input_image, keying_operation->get_input_socket(0));
236  }
237 
238  postprocessed_matte = keying_operation->get_output_socket();
239 
240  /* black / white clipping */
241  if (keying_data->clip_black > 0.0f || keying_data->clip_white < 1.0f) {
242  postprocessed_matte = setup_clip(converter,
243  postprocessed_matte,
244  keying_data->edge_kernel_radius,
245  keying_data->edge_kernel_tolerance,
246  keying_data->clip_black,
247  keying_data->clip_white,
248  false);
249  }
250 
251  /* output edge matte */
252  edges_matte = setup_clip(converter,
253  postprocessed_matte,
254  keying_data->edge_kernel_radius,
255  keying_data->edge_kernel_tolerance,
256  keying_data->clip_black,
257  keying_data->clip_white,
258  true);
259 
260  /* apply garbage matte */
261  if (input_garbage_matte->is_linked()) {
262  SetValueOperation *value_operation = new SetValueOperation();
263  value_operation->set_value(1.0f);
264  converter.add_operation(value_operation);
265 
266  MathSubtractOperation *subtract_operation = new MathSubtractOperation();
267  converter.add_operation(subtract_operation);
268 
269  MathMinimumOperation *min_operation = new MathMinimumOperation();
270  converter.add_operation(min_operation);
271 
272  converter.add_link(value_operation->get_output_socket(),
273  subtract_operation->get_input_socket(0));
274  converter.map_input_socket(input_garbage_matte, subtract_operation->get_input_socket(1));
275 
276  converter.add_link(subtract_operation->get_output_socket(),
277  min_operation->get_input_socket(0));
278  converter.add_link(postprocessed_matte, min_operation->get_input_socket(1));
279 
280  postprocessed_matte = min_operation->get_output_socket();
281  }
282 
283  /* apply core matte */
284  if (input_core_matte->is_linked()) {
285  MathMaximumOperation *max_operation = new MathMaximumOperation();
286  converter.add_operation(max_operation);
287 
288  converter.map_input_socket(input_core_matte, max_operation->get_input_socket(0));
289  converter.add_link(postprocessed_matte, max_operation->get_input_socket(1));
290 
291  postprocessed_matte = max_operation->get_output_socket();
292  }
293 
294  /* apply blur on matte if needed */
295  if (keying_data->blur_post) {
296  postprocessed_matte = setup_post_blur(converter, postprocessed_matte, keying_data->blur_post);
297  }
298 
299  /* matte dilate/erode */
300  if (keying_data->dilate_distance != 0) {
301  postprocessed_matte = setup_dilate_erode(
302  converter, postprocessed_matte, keying_data->dilate_distance);
303  }
304 
305  /* matte feather */
306  if (keying_data->feather_distance != 0) {
307  postprocessed_matte = setup_feather(converter,
308  context,
309  postprocessed_matte,
310  keying_data->feather_falloff,
311  keying_data->feather_distance);
312  }
313 
314  /* set alpha channel to output image */
315  SetAlphaMultiplyOperation *alpha_operation = new SetAlphaMultiplyOperation();
316  converter.add_operation(alpha_operation);
317 
318  converter.map_input_socket(input_image, alpha_operation->get_input_socket(0));
319  converter.add_link(postprocessed_matte, alpha_operation->get_input_socket(1));
320 
321  postprocessed_image = alpha_operation->get_output_socket();
322 
323  /* despill output image */
324  if (keying_data->despill_factor > 0.0f) {
325  postprocessed_image = setup_despill(converter,
326  postprocessed_image,
327  input_screen,
328  keying_data->despill_factor,
329  keying_data->despill_balance);
330  }
331 
332  /* connect result to output sockets */
333  converter.map_output_socket(output_image, postprocessed_image);
334  converter.map_output_socket(output_matte, postprocessed_matte);
335 
336  if (edges_matte) {
337  converter.map_output_socket(output_edges, edges_matte);
338  }
339 }
340 
341 } // namespace blender::compositor
#define BLI_YCC_ITU_BT709
#define ELEM(...)
#define R_FILTER_GAUSS
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
void set_data(const NodeBlurData *data)
Overall context of the compositor.
NodeOperationOutput * setup_pre_blur(NodeConverter &converter, NodeInput *input_image, int size) const
NodeOperationOutput * setup_dilate_erode(NodeConverter &converter, NodeOperationOutput *dilate_erode_input, int distance) const
NodeOperationOutput * setup_clip(NodeConverter &converter, NodeOperationOutput *clip_input, int kernel_radius, float kernel_tolerance, float clip_black, float clip_white, bool edge_matte) const
NodeOperationOutput * setup_despill(NodeConverter &converter, NodeOperationOutput *despill_input, NodeInput *input_screen, float factor, float color_balance) const
NodeOperationOutput * setup_post_blur(NodeConverter &converter, NodeOperationOutput *post_blur_input, int size) const
KeyingNode(bNode *editor_node)
NodeOperationOutput * setup_feather(NodeConverter &converter, const CompositorContext &context, NodeOperationOutput *feather_input, int falloff, int distance) const
void convert_to_operations(NodeConverter &converter, const CompositorContext &context) const override
convert node to operation
void add_link(NodeOperationOutput *from, NodeOperationInput *to)
void map_output_socket(NodeOutput *node_socket, NodeOperationOutput *operation_socket)
void add_operation(NodeOperation *operation)
void map_input_socket(NodeInput *node_socket, NodeOperationInput *operation_socket)
NodeInput are sockets that can receive data/input.
Definition: COM_Node.h:190
NodeOperationOutput * get_output_socket(unsigned int index=0)
NodeOperationInput * get_input_socket(unsigned int index)
NodeOutput are sockets that can send data/input.
Definition: COM_Node.h:238
NodeOutput * get_output_socket(unsigned int index=0) const
Definition: COM_Node.cc:84
bNode * get_bnode() const
get the reference to the SDNA bNode struct
Definition: COM_Node.h:64
NodeInput * get_input_socket(unsigned int index) const
Definition: COM_Node.cc:89
void set_quality(eCompositorQuality quality)
eCompositorQuality
Possible quality settings.
Definition: COM_Enums.h:19
T distance(const T &a, const T &b)
float edge_kernel_tolerance
void * storage