4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5 * Copyright (C) 2003-2016 Cinelerra CV contributors
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include "denoisevideo.h"
42 REGISTER_PLUGIN(DenoiseVideo)
49 DenoiseVideoConfig::DenoiseVideoConfig()
60 int DenoiseVideoConfig::equivalent(DenoiseVideoConfig &that)
62 return frames == that.frames &&
63 EQUIV(threshold, that.threshold) &&
68 count_changed == that.count_changed;
71 void DenoiseVideoConfig::copy_from(DenoiseVideoConfig &that)
74 threshold = that.threshold;
75 count_changed = that.count_changed;
82 void DenoiseVideoConfig::interpolate(DenoiseVideoConfig &prev,
83 DenoiseVideoConfig &next,
88 double next_scale = (double)(current_frame - prev_frame) / (next_frame - prev_frame);
89 double prev_scale = (double)(next_frame - current_frame) / (next_frame - prev_frame);
91 this->frames = (int)(prev.frames * prev_scale + next.frames * next_scale);
92 this->threshold = prev.threshold * prev_scale + next.threshold * next_scale;
97 count_changed = prev.count_changed;
105 DenoiseVideoFrames::DenoiseVideoFrames(DenoiseVideo *plugin, int x, int y)
113 plugin->config.frames)
115 this->plugin = plugin;
118 int DenoiseVideoFrames::handle_event()
120 int result = get_value();
121 if(result < 1 || result > 256) result = 256;
122 plugin->config.frames = result;
123 plugin->send_configure_change();
133 DenoiseVideoThreshold::DenoiseVideoThreshold(DenoiseVideo *plugin,
134 DenoiseVideoWindow *gui,
137 : BC_TumbleTextBox(gui,
138 plugin->config.threshold,
145 this->plugin = plugin;
150 int DenoiseVideoThreshold::handle_event()
152 plugin->config.threshold = atof(get_text());
153 plugin->send_configure_change();
161 DenoiseVideoToggle::DenoiseVideoToggle(DenoiseVideo *plugin,
162 DenoiseVideoWindow *gui,
167 : BC_CheckBox(x, y, *output, text)
169 this->plugin = plugin;
170 this->output = output;
173 int DenoiseVideoToggle::handle_event()
175 *output = get_value();
176 plugin->send_configure_change();
181 DenoiseVideoCountChanged::DenoiseVideoCountChanged(DenoiseVideo *plugin,
182 DenoiseVideoWindow *gui,
187 plugin->config.count_changed,
188 _("Average changing pixels"))
190 this->plugin = plugin;
194 int DenoiseVideoCountChanged::handle_event()
196 plugin->config.count_changed = 1;
197 gui->count_same->update(0);
198 plugin->send_configure_change();
206 DenoiseVideoCountSame::DenoiseVideoCountSame(DenoiseVideo *plugin,
207 DenoiseVideoWindow *gui,
212 !plugin->config.count_changed,
213 _("Average similar pixels"))
215 this->plugin = plugin;
219 int DenoiseVideoCountSame::handle_event()
221 plugin->config.count_changed = 0;
222 gui->count_changed->update(0);
223 plugin->send_configure_change();
236 DenoiseVideoWindow::DenoiseVideoWindow(DenoiseVideo *plugin)
237 : PluginClientWindow(plugin,
244 this->plugin = plugin;
248 void DenoiseVideoWindow::create_objects()
251 int ys5 = yS(5), ys10 = yS(10), ys30 = yS(30);
252 int x = xs10, y = ys10;
255 add_subwindow(new BC_Title(x, y, _("Frames to accumulate:")));
257 add_subwindow(frames = new DenoiseVideoFrames(plugin, x, y));
258 y += frames->get_h() + ys5;
259 add_subwindow(title = new BC_Title(x, y, _("Threshold:")));
260 y += title->get_h() + ys5;
261 threshold = new DenoiseVideoThreshold(plugin, this, x, y);
262 threshold->create_objects();
263 y += threshold->get_h() + ys5;
264 add_subwindow(bar = new BC_Bar(x, y, get_w() - x * 2));
265 y += bar->get_h() + ys5;
266 add_subwindow(count_changed = new DenoiseVideoCountChanged(plugin,
270 y += count_changed->get_h() + ys5;
271 add_subwindow(count_same = new DenoiseVideoCountSame(plugin,
275 y += count_same->get_h() + ys5;
276 add_subwindow(bar = new BC_Bar(x, y, get_w() - x * 2));
277 y += bar->get_h() + ys5;
278 add_subwindow(do_r = new DenoiseVideoToggle(plugin, this, x, y, &plugin->config.do_r, _("Red")));
280 add_subwindow(do_g = new DenoiseVideoToggle(plugin, this, x, y, &plugin->config.do_g, _("Green")));
282 add_subwindow(do_b = new DenoiseVideoToggle(plugin, this, x, y, &plugin->config.do_b, _("Blue")));
284 add_subwindow(do_a = new DenoiseVideoToggle(plugin, this, x, y, &plugin->config.do_a, _("Alpha")));
303 DenoiseVideo::DenoiseVideo(PluginServer *server)
304 : PluginVClient(server)
311 DenoiseVideo::~DenoiseVideo()
315 if(accumulation) delete [] accumulation;
318 int DenoiseVideo::process_realtime(VFrame *input, VFrame *output)
320 load_configuration();
322 int h = input->get_h();
323 int w = input->get_w();
324 int color_model = input->get_color_model();
328 accumulation = new float[w * h * BC_CModels::components(color_model)];
329 bzero(accumulation, sizeof(float) * w * h * BC_CModels::components(color_model));
332 float *accumulation_ptr = accumulation;
333 float opacity = (float)1.0 / config.frames;
334 float transparency = 1 - opacity;
335 float threshold = (float)config.threshold *
336 BC_CModels::calculate_max(color_model);
337 int do_it[4] = { config.do_r, config.do_g, config.do_b, config.do_a };
339 #define DENOISE_MACRO(type, components, max) \
341 for(int i = 0; i < h; i++) \
343 type *output_row = (type*)output->get_rows()[i]; \
344 type *input_row = (type*)input->get_rows()[i]; \
346 for(int k = 0; k < w * components; k++) \
348 if( do_it[k % components] ) \
350 float input_pixel = *input_row; \
351 (*accumulation_ptr) = \
352 transparency * (*accumulation_ptr) + \
353 opacity * input_pixel; \
355 float difference = fabs((*accumulation_ptr) - input_pixel); \
356 if( !config.count_changed ? \
357 difference > threshold : difference < threshold) \
359 (*accumulation_ptr) = input_pixel; \
360 *output_row = (type)(*accumulation_ptr); \
363 if(sizeof(type) < 4) \
364 *output_row = (type)CLIP((*accumulation_ptr), 0, max); \
368 *output_row = *input_row; \
373 accumulation_ptr++; \
387 DENOISE_MACRO(unsigned char, 3, 0xff);
391 DENOISE_MACRO(float, 3, 1.0);
396 DENOISE_MACRO(unsigned char, 4, 0xff);
400 DENOISE_MACRO(float, 4, 1.0);
405 DENOISE_MACRO(uint16_t, 3, 0xffff);
408 case BC_RGBA16161616:
409 case BC_YUVA16161616:
410 DENOISE_MACRO(uint16_t, 4, 0xffff);
417 const char* DenoiseVideo::plugin_title() { return N_("Denoise video"); }
418 int DenoiseVideo::is_realtime() { return 1; }
421 NEW_WINDOW_MACRO(DenoiseVideo, DenoiseVideoWindow)
423 LOAD_CONFIGURATION_MACRO(DenoiseVideo, DenoiseVideoConfig)
425 void DenoiseVideo::update_gui()
429 load_configuration();
430 ((DenoiseVideoWindow*)thread->window)->lock_window();
431 ((DenoiseVideoWindow*)thread->window)->frames->update(config.frames);
432 ((DenoiseVideoWindow*)thread->window)->threshold->update(config.threshold);
433 ((DenoiseVideoWindow*)thread->window)->count_changed->update(config.count_changed);
434 ((DenoiseVideoWindow*)thread->window)->count_same->update(!config.count_changed);
435 ((DenoiseVideoWindow*)thread->window)->unlock_window();
442 void DenoiseVideo::save_data(KeyFrame *keyframe)
446 // cause data to be stored directly in text
447 output.set_shared_output(keyframe->xbuf);
448 output.tag.set_title("DENOISE_VIDEO");
449 output.tag.set_property("FRAMES", config.frames);
450 output.tag.set_property("THRESHOLD", config.threshold);
451 output.tag.set_property("DO_R", config.do_r);
452 output.tag.set_property("DO_G", config.do_g);
453 output.tag.set_property("DO_B", config.do_b);
454 output.tag.set_property("DO_A", config.do_a);
455 output.tag.set_property("COUNT_CHANGED", config.count_changed);
457 output.tag.set_title("/DENOISE_VIDEO");
459 output.append_newline();
460 output.terminate_string();
463 void DenoiseVideo::read_data(KeyFrame *keyframe)
467 input.set_shared_input(keyframe->xbuf);
469 while(!input.read_tag())
471 if(input.tag.title_is("DENOISE_VIDEO"))
473 config.frames = input.tag.get_property("FRAMES", config.frames);
474 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
475 config.do_r = input.tag.get_property("DO_R", config.do_r);
476 config.do_g = input.tag.get_property("DO_G", config.do_g);
477 config.do_b = input.tag.get_property("DO_B", config.do_b);
478 config.do_a = input.tag.get_property("DO_A", config.do_a);
479 config.count_changed = input.tag.get_property("COUNT_CHANGED", config.count_changed);