4 * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "bcdisplayinfo.h"
25 #include "bcsignals.h"
30 #include "unsharpwindow.h"
36 REGISTER_PLUGIN(UnsharpMain)
40 UnsharpConfig::UnsharpConfig()
42 reset(RESET_DEFAULT_SETTINGS);
45 void UnsharpConfig::reset(int clear)
53 case RESET_RADIUS : radius = 0.1;
55 case RESET_AMOUNT : amount = 0.0;
57 case RESET_THRESHOLD : threshold = 0;
59 case RESET_DEFAULT_SETTINGS :
68 int UnsharpConfig::equivalent(UnsharpConfig &that)
70 return EQUIV(radius, that.radius) &&
71 EQUIV(amount, that.amount) &&
72 threshold == that.threshold;
75 void UnsharpConfig::copy_from(UnsharpConfig &that)
79 threshold = that.threshold;
82 void UnsharpConfig::interpolate(UnsharpConfig &prev,
86 int64_t current_frame)
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);
90 this->radius = prev.radius * prev_scale + next.radius * next_scale;
91 this->amount = prev.amount * prev_scale + next.amount * next_scale;
92 this->threshold = (int)(prev.threshold * prev_scale + next.threshold * next_scale);
113 UnsharpMain::UnsharpMain(PluginServer *server)
114 : PluginVClient(server)
120 UnsharpMain::~UnsharpMain()
126 const char* UnsharpMain::plugin_title() { return N_("Unsharp"); }
127 int UnsharpMain::is_realtime() { return 1; }
130 NEW_WINDOW_MACRO(UnsharpMain, UnsharpWindow)
132 LOAD_CONFIGURATION_MACRO(UnsharpMain, UnsharpConfig)
136 void UnsharpMain::update_gui()
140 if(load_configuration())
142 thread->window->lock_window("UnsharpMain::update_gui");
143 ((UnsharpWindow*)thread->window)->update_gui(RESET_DEFAULT_SETTINGS);
144 thread->window->unlock_window();
152 void UnsharpMain::save_data(KeyFrame *keyframe)
156 // cause data to be stored directly in text
157 output.set_shared_output(keyframe->xbuf);
158 output.tag.set_title("UNSHARP");
160 output.tag.set_property("RADIUS", config.radius);
161 output.tag.set_property("AMOUNT", config.amount);
162 output.tag.set_property("THRESHOLD", config.threshold);
164 output.tag.set_title("/UNSHARP");
166 output.append_newline();
167 output.terminate_string();
170 void UnsharpMain::read_data(KeyFrame *keyframe)
174 input.set_shared_input(keyframe->xbuf);
180 result = input.read_tag();
184 if(input.tag.title_is("UNSHARP"))
186 config.radius = input.tag.get_property("RADIUS", config.radius);
187 config.amount = input.tag.get_property("AMOUNT", config.amount);
188 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
200 int UnsharpMain::process_buffer(VFrame *frame,
201 int64_t start_position,
204 /*int need_reconfigure =*/ load_configuration();
206 if(!engine) engine = new UnsharpEngine(this,
207 get_project_smp() + 1, get_project_smp() + 1);
208 read_frame(frame, 0, get_source_position(), get_framerate(), 0);
209 engine->do_unsharp(frame);
224 UnsharpPackage::UnsharpPackage()
234 UnsharpUnit::UnsharpUnit(UnsharpEngine *server,
238 this->plugin = plugin;
239 this->server = server;
243 UnsharpUnit::~UnsharpUnit()
249 // Derived from the Gimp.
250 // In the original file it says
252 // Copyright (C) 1999 Winston Chang
253 // <winstonc@cs.wisc.edu>
254 // <winston@stdout.org>
256 // Adapted for Cinelerra by Heroine Virtual Ltd.
258 static int calculate_convolution_matrix(double radius, double **cmatrix)
260 radius = fabs(radius) + 1.0;
261 double std_dev = radius;
262 radius = std_dev * 2;
263 int matrix_length = (int)(2 * ceil(radius - 0.5) + 1);
264 matrix_length = MAX(1, matrix_length);
265 // int matrix_midpoint = matrix_length / 2 + 1;
266 (*cmatrix) = new double[matrix_length];
268 // Top right of matrix
269 for(int i = matrix_length / 2 + 1; i < matrix_length; i++)
271 double base_x = i - floor(matrix_length / 2) - 0.5;
273 for(int j = 1; j <= 50; j++)
275 if(base_x + 0.02 * j <= radius)
277 sum += exp(-(base_x + 0.02 * j) *
278 (base_x + 0.02 * j) /
279 (2 * std_dev * std_dev));
282 (*cmatrix)[i] = sum / 50;
285 // Top left of matrix
286 for(int i = 0; i < matrix_length / 2; i++)
288 (*cmatrix)[i] = (*cmatrix)[matrix_length - 1 - i];
293 for(int j = 0; j <= 50; j++)
295 sum += exp(-(0.5 + 0.02 * j) *
297 (2 * std_dev * std_dev));
299 (*cmatrix)[matrix_length / 2] = sum / 51;
303 for(int i = 0; i < matrix_length; i++)
304 sum += (*cmatrix)[i];
305 for(int i = 0; i < matrix_length; i++)
306 (*cmatrix)[i] = (*cmatrix)[i] / sum;
308 return matrix_length;
311 static double get_convolution(double *cmatrix,
315 return cmatrix[index] * input;
318 static void blur_pixels(double *cmatrix,
325 if(cmatrix_length > pixels)
327 for(int pixel = 0; pixel < pixels; pixel++)
330 for(int j = 0; j < pixels; j++)
332 if((j + cmatrix_length / 2 - pixel >= 0) &&
333 (j + cmatrix_length / 2 - pixel < cmatrix_length))
335 scale += cmatrix[j + cmatrix_length / 2 - pixel];
339 for(int i = 0; i < components; i++)
342 for(int j = 0; j < pixels; j++)
344 if((j >= pixel - cmatrix_length / 2) &&
345 (j <= pixel + cmatrix_length / 2))
347 sum += input[j * components + i] * cmatrix[i];
350 output[pixel * components + i] = sum / scale;
356 int cmatrix_middle = cmatrix_length / 2;
358 for(pixel = 0; pixel < cmatrix_middle; pixel++)
361 for(int j = cmatrix_middle - pixel; j < cmatrix_length;j++)
366 for(int i = 0; i < components; i++)
369 for(int j = cmatrix_middle - pixel; j < cmatrix_length; j++)
371 sum += input[(pixel + j - cmatrix_middle) * components + i] *
374 output[pixel * components + i] = sum / scale;
378 float *output_ptr = output + pixel * components;
379 for( ; pixel < pixels - cmatrix_middle; pixel++)
381 float *input_ptr = input + (pixel - cmatrix_middle) * components;
382 for(int i = 0; i < components; i++)
385 float *input_ptr2 = input_ptr;
386 for(int j = cmatrix_length; j > 0; j--)
388 sum += get_convolution(cmatrix,
391 input_ptr2 += components;
398 for( ; pixel < pixels; pixel++)
401 for(int j = 0; j < pixels - pixel + cmatrix_middle; j++)
406 for(int i = 0; i < components; i++)
409 for(int j = 0; j < pixels - pixel + cmatrix_middle; j++)
411 sum += input[(pixel + j - cmatrix_middle) * components + i] *
414 output[pixel * components + i] = sum / scale;
420 #define GET_ROW(type, components) \
422 type *in_row = (type*)src->get_rows()[row]; \
423 int pixels = src->get_w() * components; \
424 for(int i = 0; i < pixels; i++) \
426 dst[i] = in_row[i]; \
430 static void get_row(float *dst, VFrame *src, int row)
432 switch(src->get_color_model())
436 GET_ROW(unsigned char, 3);
443 GET_ROW(unsigned char, 4);
449 GET_ROW(uint16_t, 3);
451 case BC_YUVA16161616:
452 GET_ROW(uint16_t, 4);
457 static void get_column(float *dst, VFrame *src, int column)
459 int components = BC_CModels::components(src->get_color_model());
460 for(int i = 0; i < src->get_h(); i++)
462 float *input_pixel = (float*)src->get_rows()[i] + column * components;
463 memcpy(dst, input_pixel, sizeof(float) * components);
468 static void put_column(float *src, VFrame *dst, int column)
470 int components = BC_CModels::components(dst->get_color_model());
471 for(int i = 0; i < dst->get_h(); i++)
473 float *output_pixel = (float*)dst->get_rows()[i] + column * components;
474 memcpy(output_pixel, src, sizeof(float) * components);
479 void UnsharpUnit::process_package(LoadPackage *package)
481 UnsharpPackage *pkg = (UnsharpPackage*)package;
482 // int w = server->src->get_w();
483 // int h = server->src->get_h();
484 int color_model = server->src->get_color_model();
485 int components = BC_CModels::components(color_model);
487 int cmatrix_length = 0;
488 int padded_y1 = pkg->y1;
489 int padded_y2 = pkg->y2;
491 cmatrix_length = calculate_convolution_matrix(
492 plugin->config.radius,
496 if(padded_y2 < server->src->get_h())
498 padded_y2 += cmatrix_length / 2;
499 padded_y2 = MIN(server->src->get_h(), padded_y2);
503 padded_y1 -= cmatrix_length / 2;
504 padded_y1 = MAX(0, padded_y1);
507 int padded_rows = padded_y2 - padded_y1;
509 if(!temp || temp->get_h() != padded_rows)
518 temp->set_use_shm(0);
524 server->src->get_w(),
526 components == 3 ? BC_RGB_FLOAT : BC_RGBA_FLOAT,
530 float *temp_in = new float[MAX(temp->get_w(), padded_rows) * components];
531 float *temp_out = new float[MAX(temp->get_w(), padded_rows) * components];
534 for(int i = padded_y1; i < padded_y2; i++)
536 get_row(temp_in, server->src, i);
543 // printf("UnsharpUnit::process_package %d %p %p %p %d %d\n",
546 // temp->get_rows()[0],
549 // temp->get_bytes_per_line());
550 memcpy(temp->get_rows()[i - padded_y1],
552 temp->get_bytes_per_line());
555 //Now we're 100% floating point. Blur the columns
556 for(int i = 0; i < temp->get_w(); i++)
558 get_column(temp_in, temp, i);
565 put_column(temp_out, temp, i);
569 //printf("%f %f %d\n", plugin->config.radius,plugin->config.amount, plugin->config.threshold);
572 #define UNSHARPEN(type, components, max) \
574 float threshold = (float)plugin->config.threshold * max / 0xff; \
575 float amount = plugin->config.amount; \
577 for(int i = pkg->y1; i < pkg->y2; i++) \
579 float *blurry_row = (float*)temp->get_rows()[i - padded_y1]; \
580 type *orig_row = (type*)server->src->get_rows()[i]; \
581 for(int j = 0; j < server->src->get_w(); j++) \
583 for(int k = 0; k < components; k++) \
585 float diff = *orig_row - *blurry_row; \
586 if(fabsf(2 * diff) < threshold) \
588 float value = *orig_row + amount * diff; \
589 if(sizeof(type) == 4) \
590 *orig_row = (type)value; \
592 *orig_row = (type)CLIP(value, 0, max); \
600 // Apply unsharpening
605 UNSHARPEN(unsigned char, 3, 0xff);
609 UNSHARPEN(unsigned char, 4, 0xff);
612 UNSHARPEN(float, 3, 1.0);
615 UNSHARPEN(float, 4, 1.0);
618 UNSHARPEN(uint16_t, 3, 0xffff);
620 case BC_YUVA16161616:
621 UNSHARPEN(uint16_t, 4, 0xffff);
638 UnsharpEngine::UnsharpEngine(UnsharpMain *plugin,
643 total_clients, total_packages
646 this->plugin = plugin;
649 UnsharpEngine::~UnsharpEngine()
654 void UnsharpEngine::init_packages()
656 for(int i = 0; i < get_total_packages(); i++)
658 UnsharpPackage *pkg = (UnsharpPackage*)get_package(i);
659 pkg->y1 = src->get_h() * i / get_total_packages();
660 pkg->y2 = src->get_h() * (i + 1) / get_total_packages();
664 LoadClient* UnsharpEngine::new_client()
666 return new UnsharpUnit(this, plugin);
669 LoadPackage* UnsharpEngine::new_package()
671 return new UnsharpPackage;
675 void UnsharpEngine::do_unsharp(VFrame *src)