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