6 #include "bcdisplayinfo.h"
11 #include "histogram.h"
12 #include "histogramconfig.h"
13 #include "histogramwindow.h"
16 #include "loadbalance.h"
17 #include "plugincolors.h"
23 class HistogramEngine;
24 class HistogramWindow;
30 REGISTER_PLUGIN(HistogramMain)
43 HistogramMain::HistogramMain(PluginServer *server)
44 : PluginVClient(server)
46 PLUGIN_CONSTRUCTOR_MACRO
48 for(int i = 0; i < HISTOGRAM_MODES; i++)
54 preview_lookup[i] = 0;
57 mode = HISTOGRAM_VALUE;
63 HistogramMain::~HistogramMain()
65 PLUGIN_DESTRUCTOR_MACRO
66 for(int i = 0; i < HISTOGRAM_MODES;i++)
69 delete [] smoothed[i];
72 delete [] preview_lookup[i];
77 char* HistogramMain::plugin_title() { return N_("Histogram"); }
78 int HistogramMain::is_realtime() { return 1; }
81 #include "picon_png.h"
82 NEW_PICON_MACRO(HistogramMain)
84 SHOW_GUI_MACRO(HistogramMain, HistogramThread)
86 SET_STRING_MACRO(HistogramMain)
88 RAISE_WINDOW_MACRO(HistogramMain)
90 LOAD_CONFIGURATION_MACRO(HistogramMain, HistogramConfig)
92 void HistogramMain::render_gui(void *data)
97 // Process just the RGB values to determine the automatic points or
98 // all the points if manual
101 // Generate curves for value histogram
102 // Lock out changes to curves
103 thread->window->lock_window("HistogramMain::render_gui 1");
104 tabulate_curve(HISTOGRAM_RED, 0);
105 tabulate_curve(HISTOGRAM_GREEN, 0);
106 tabulate_curve(HISTOGRAM_BLUE, 0);
107 thread->window->unlock_window();
110 calculate_histogram((VFrame*)data, !config.automatic);
117 calculate_automatic((VFrame*)data);
120 // Generate curves for value histogram
121 // Lock out changes to curves
122 thread->window->lock_window("HistogramMain::render_gui 1");
123 tabulate_curve(HISTOGRAM_RED, 0);
124 tabulate_curve(HISTOGRAM_GREEN, 0);
125 tabulate_curve(HISTOGRAM_BLUE, 0);
126 thread->window->unlock_window();
129 // Need a second pass to get the luminance values.
130 calculate_histogram((VFrame*)data, 1);
135 thread->window->lock_window("HistogramMain::render_gui 2");
136 thread->window->update_canvas();
139 thread->window->update_input();
141 thread->window->unlock_window();
146 void HistogramMain::update_gui()
150 thread->window->lock_window("HistogramMain::update_gui");
151 int reconfigure = load_configuration();
154 thread->window->update(0);
155 if(!config.automatic)
157 thread->window->update_input();
160 thread->window->unlock_window();
165 int HistogramMain::load_defaults()
167 char directory[BCTEXTLEN], string[BCTEXTLEN];
168 // set the default directory
169 sprintf(directory, "%shistogram.rc", BCASTDIR);
172 defaults = new BC_Hash(directory);
175 for(int j = 0; j < HISTOGRAM_MODES; j++)
177 while(config.points[j].last) delete config.points[j].last;
179 sprintf(string, "TOTAL_POINTS_%d", j);
180 int total_points = defaults->get(string, 0);
182 for(int i = 0; i < total_points; i++)
184 HistogramPoint *point = new HistogramPoint;
185 sprintf(string, "INPUT_X_%d_%d", j, i);
186 point->x = defaults->get(string, point->x);
187 sprintf(string, "INPUT_Y_%d_%d", j, i);
188 point->y = defaults->get(string, point->y);
189 config.points[j].append(point);
194 for(int i = 0; i < HISTOGRAM_MODES; i++)
196 sprintf(string, "OUTPUT_MIN_%d", i);
197 config.output_min[i] = defaults->get(string, config.output_min[i]);
198 sprintf(string, "OUTPUT_MAX_%d", i);
199 config.output_max[i] = defaults->get(string, config.output_max[i]);
202 config.automatic = defaults->get("AUTOMATIC", config.automatic);
203 mode = defaults->get("MODE", mode);
204 CLAMP(mode, 0, HISTOGRAM_MODES - 1);
205 config.threshold = defaults->get("THRESHOLD", config.threshold);
206 config.plot = defaults->get("PLOT", config.plot);
207 config.split = defaults->get("SPLIT", config.split);
213 int HistogramMain::save_defaults()
215 char string[BCTEXTLEN];
219 for(int j = 0; j < HISTOGRAM_MODES; j++)
221 int total_points = config.points[j].total();
222 sprintf(string, "TOTAL_POINTS_%d", j);
223 defaults->update(string, total_points);
224 HistogramPoint *current = config.points[j].first;
228 sprintf(string, "INPUT_X_%d_%d", j, number);
229 defaults->update(string, current->x);
230 sprintf(string, "INPUT_Y_%d_%d", j, number);
231 defaults->update(string, current->y);
238 for(int i = 0; i < HISTOGRAM_MODES; i++)
240 sprintf(string, "OUTPUT_MIN_%d", i);
241 defaults->update(string, config.output_min[i]);
242 sprintf(string, "OUTPUT_MAX_%d", i);
243 defaults->update(string, config.output_max[i]);
246 defaults->update("AUTOMATIC", config.automatic);
247 defaults->update("MODE", mode);
248 defaults->update("THRESHOLD", config.threshold);
249 defaults->update("PLOT", config.plot);
250 defaults->update("SPLIT", config.split);
257 void HistogramMain::save_data(KeyFrame *keyframe)
261 // cause data to be stored directly in text
262 output.set_shared_string(keyframe->data, MESSAGESIZE);
263 output.tag.set_title("HISTOGRAM");
265 char string[BCTEXTLEN];
268 for(int i = 0; i < HISTOGRAM_MODES; i++)
270 sprintf(string, "OUTPUT_MIN_%d", i);
271 output.tag.set_property(string, config.output_min[i]);
272 sprintf(string, "OUTPUT_MAX_%d", i);
273 output.tag.set_property(string, config.output_max[i]);
274 //printf("HistogramMain::save_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
277 output.tag.set_property("AUTOMATIC", config.automatic);
278 output.tag.set_property("THRESHOLD", config.threshold);
279 output.tag.set_property("PLOT", config.plot);
280 output.tag.set_property("SPLIT", config.split);
282 output.append_newline();
288 for(int j = 0; j < HISTOGRAM_MODES; j++)
290 output.tag.set_title("POINTS");
292 output.append_newline();
295 HistogramPoint *current = config.points[j].first;
298 output.tag.set_title("POINT");
299 output.tag.set_property("X", current->x);
300 output.tag.set_property("Y", current->y);
302 output.append_newline();
307 output.tag.set_title("/POINTS");
309 output.append_newline();
317 output.terminate_string();
320 void HistogramMain::read_data(KeyFrame *keyframe)
324 input.set_shared_string(keyframe->data, strlen(keyframe->data));
327 int current_input_mode = 0;
332 result = input.read_tag();
336 if(input.tag.title_is("HISTOGRAM"))
338 char string[BCTEXTLEN];
339 for(int i = 0; i < HISTOGRAM_MODES; i++)
341 sprintf(string, "OUTPUT_MIN_%d", i);
342 config.output_min[i] = input.tag.get_property(string, config.output_min[i]);
343 sprintf(string, "OUTPUT_MAX_%d", i);
344 config.output_max[i] = input.tag.get_property(string, config.output_max[i]);
345 //printf("HistogramMain::read_data %d %f %d\n", config.input_min[i], config.input_mid[i], config.input_max[i]);
347 config.automatic = input.tag.get_property("AUTOMATIC", config.automatic);
348 config.threshold = input.tag.get_property("THRESHOLD", config.threshold);
349 config.plot = input.tag.get_property("PLOT", config.plot);
350 config.split = input.tag.get_property("SPLIT", config.split);
353 if(input.tag.title_is("POINTS"))
355 if(current_input_mode < HISTOGRAM_MODES)
357 HistogramPoints *points = &config.points[current_input_mode];
362 result = input.read_tag();
365 if(input.tag.title_is("/POINTS"))
370 if(input.tag.title_is("POINT"))
373 input.tag.get_property("X", 0.0),
374 input.tag.get_property("Y", 0.0));
380 current_input_mode++;
389 float HistogramMain::calculate_linear(float input,
418 // Get 2 points surrounding current position
419 HistogramPoints *points = &config.points[subscript];
420 HistogramPoint *current = points->first;
422 while(current && !done)
424 if(current->x > input)
434 current = points->last;
436 while(current && !done)
438 if(current->x <= input)
452 if(!EQUIV(x2 - x1, 0))
453 output = (input - x1) * (y2 - y1) / (x2 - x1) + y1;
466 output = calculate_linear(output, HISTOGRAM_VALUE, 0);
470 float output_min = config.output_min[subscript];
471 float output_max = config.output_max[subscript];
476 // Compress output for value followed by channel
477 output = output_min +
479 (output_max - output_min);
485 float HistogramMain::calculate_smooth(float input, int subscript)
487 float x_f = (input - MIN_INPUT) * HISTOGRAM_SLOTS / FLOAT_RANGE;
490 CLAMP(x_i1, 0, HISTOGRAM_SLOTS - 1);
491 CLAMP(x_i2, 0, HISTOGRAM_SLOTS - 1);
492 CLAMP(x_f, 0, HISTOGRAM_SLOTS - 1);
494 float smooth1 = smoothed[subscript][x_i1];
495 float smooth2 = smoothed[subscript][x_i2];
496 float result = smooth1 + (smooth2 - smooth1) * (x_f - x_i1);
497 CLAMP(result, 0, 1.0);
502 void HistogramMain::calculate_histogram(VFrame *data, int do_value)
505 if(!engine) engine = new HistogramEngine(this,
506 get_project_smp() + 1,
507 get_project_smp() + 1);
511 for(int i = 0; i < HISTOGRAM_MODES; i++)
512 accum[i] = new int[HISTOGRAM_SLOTS];
515 engine->process_packages(HistogramEngine::HISTOGRAM, data, do_value);
517 for(int i = 0; i < engine->get_total_clients(); i++)
519 HistogramUnit *unit = (HistogramUnit*)engine->get_client(i);
523 for(int j = 0; j < HISTOGRAM_MODES; j++)
525 memcpy(accum[j], unit->accum[j], sizeof(int) * HISTOGRAM_SLOTS);
530 for(int j = 0; j < HISTOGRAM_MODES; j++)
533 int *in = unit->accum[j];
534 for(int k = 0; k < HISTOGRAM_SLOTS; k++)
540 // Remove top and bottom from calculations. Doesn't work in high
541 // precision colormodels.
542 for(int i = 0; i < HISTOGRAM_MODES; i++)
545 accum[i][HISTOGRAM_SLOTS - 1] = 0;
550 void HistogramMain::calculate_automatic(VFrame *data)
552 calculate_histogram(data, 0);
553 config.reset_points(1);
556 for(int i = 0; i < 3; i++)
558 int *accum = this->accum[i];
559 int pixels = data->get_w() * data->get_h();
560 float white_fraction = 1.0 - (1.0 - config.threshold) / 2;
561 int threshold = (int)(white_fraction * pixels);
563 float max_level = 1.0;
564 float min_level = 0.0;
566 // Get histogram slot above threshold of pixels
567 for(int j = 0; j < HISTOGRAM_SLOTS; j++)
570 if(total >= threshold)
572 max_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + MIN_INPUT;
577 // Get slot below 99% of pixels
579 for(int j = HISTOGRAM_SLOTS - 1; j >= 0; j--)
582 if(total >= threshold)
584 min_level = (float)j / HISTOGRAM_SLOTS * FLOAT_RANGE + MIN_INPUT;
590 config.points[i].insert(max_level, 1.0);
591 config.points[i].insert(min_level, 0.0);
600 int HistogramMain::process_buffer(VFrame *frame,
601 int64_t start_position,
605 int need_reconfigure = load_configuration();
614 if(!engine) engine = new HistogramEngine(this,
615 get_project_smp() + 1,
616 get_project_smp() + 1);
618 this->output = frame;
620 // Always plot to set the curves if automatic
621 if(config.plot || config.automatic) send_render_gui(frame);
624 // Generate tables here. The same table is used by many packages to render
625 // each horizontal stripe. Need to cover the entire output range in each
626 // table to avoid green borders
627 if(need_reconfigure ||
634 // Calculate new curves
637 calculate_automatic(input);
641 // Generate transfer tables with value function for integer colormodels.
642 for(int i = 0; i < 3; i++)
643 tabulate_curve(i, 1);
650 engine->process_packages(HistogramEngine::APPLY, input, 0);
657 void HistogramMain::tabulate_curve(int subscript, int use_value)
660 if(!lookup[subscript])
661 lookup[subscript] = new int[HISTOGRAM_SLOTS];
662 if(!smoothed[subscript])
663 smoothed[subscript] = new float[HISTOGRAM_SLOTS];
664 if(!linear[subscript])
665 linear[subscript] = new float[HISTOGRAM_SLOTS];
666 if(!preview_lookup[subscript])
667 preview_lookup[subscript] = new int[HISTOGRAM_SLOTS];
670 float *current_smooth = smoothed[subscript];
671 float *current_linear = linear[subscript];
674 for(i = 0; i < HISTOGRAM_SLOTS; i++)
676 float input = (float)i / HISTOGRAM_SLOTS * FLOAT_RANGE + MIN_INPUT;
677 current_linear[i] = calculate_linear(input, subscript, use_value);
685 // Make smooth curve (currently a copy of the linear curve)
687 for(i = 0; i < HISTOGRAM_SLOTS; i++)
689 // current_smooth[i] = current_linear[i] * 0.001 +
691 // prev = current_smooth[i];
693 current_smooth[i] = current_linear[i];
696 // Generate lookup tables for integer colormodels
699 switch(input->get_color_model())
703 for(i = 0; i < 0x100; i++)
704 lookup[subscript][i] =
705 (int)(calculate_smooth((float)i / 0xff, subscript) * 0xff);
707 // All other integer colormodels are converted to 16 bit RGB
709 for(i = 0; i < 0x10000; i++)
710 lookup[subscript][i] =
711 (int)(calculate_smooth((float)i / 0xffff, subscript) * 0xffff);
716 // Lookup table for preview only used for GUI
719 for(i = 0; i < 0x10000; i++)
720 preview_lookup[subscript][i] =
721 (int)(calculate_smooth((float)i / 0xffff, subscript) * 0xffff);
735 HistogramPackage::HistogramPackage()
743 HistogramUnit::HistogramUnit(HistogramEngine *server,
744 HistogramMain *plugin)
747 this->plugin = plugin;
748 this->server = server;
749 for(int i = 0; i < HISTOGRAM_MODES; i++)
750 accum[i] = new int[HISTOGRAM_SLOTS];
753 HistogramUnit::~HistogramUnit()
755 for(int i = 0; i < HISTOGRAM_MODES; i++)
759 void HistogramUnit::process_package(LoadPackage *package)
761 HistogramPackage *pkg = (HistogramPackage*)package;
763 if(server->operation == HistogramEngine::HISTOGRAM)
765 int do_value = server->do_value;
769 #define HISTOGRAM_HEAD(type) \
771 for(int i = pkg->start; i < pkg->end; i++) \
773 type *row = (type*)data->get_rows()[i]; \
774 for(int j = 0; j < w; j++) \
777 #define HISTOGRAM_TAIL(components) \
778 /* Value takes the maximum of the output RGB values */ \
781 CLAMP(r, 0, HISTOGRAM_SLOTS - 1); \
782 CLAMP(g, 0, HISTOGRAM_SLOTS - 1); \
783 CLAMP(b, 0, HISTOGRAM_SLOTS - 1); \
784 r_out = lookup_r[r]; \
785 g_out = lookup_g[g]; \
786 b_out = lookup_b[b]; \
787 /* v = (r * 76 + g * 150 + b * 29) >> 8; */ \
788 v = MAX(r_out, g_out); \
790 v += -HISTOGRAM_MIN * 0xffff / 100; \
791 CLAMP(v, 0, HISTOGRAM_SLOTS - 1); \
795 r += -HISTOGRAM_MIN * 0xffff / 100; \
796 g += -HISTOGRAM_MIN * 0xffff / 100; \
797 b += -HISTOGRAM_MIN * 0xffff / 100; \
798 CLAMP(r, 0, HISTOGRAM_SLOTS - 1); \
799 CLAMP(g, 0, HISTOGRAM_SLOTS - 1); \
800 CLAMP(b, 0, HISTOGRAM_SLOTS - 1); \
812 VFrame *data = server->data;
813 int w = data->get_w();
814 int h = data->get_h();
815 int *accum_r = accum[HISTOGRAM_RED];
816 int *accum_g = accum[HISTOGRAM_GREEN];
817 int *accum_b = accum[HISTOGRAM_BLUE];
818 int *accum_v = accum[HISTOGRAM_VALUE];
819 int32_t r, g, b, a, y, u, v;
820 int r_out, g_out, b_out;
821 int *lookup_r = plugin->preview_lookup[HISTOGRAM_RED];
822 int *lookup_g = plugin->preview_lookup[HISTOGRAM_GREEN];
823 int *lookup_b = plugin->preview_lookup[HISTOGRAM_BLUE];
825 switch(data->get_color_model())
828 HISTOGRAM_HEAD(unsigned char)
829 r = (row[0] << 8) | row[0];
830 g = (row[1] << 8) | row[1];
831 b = (row[2] << 8) | row[2];
835 HISTOGRAM_HEAD(float)
836 r = (int)(row[0] * 0xffff);
837 g = (int)(row[1] * 0xffff);
838 b = (int)(row[2] * 0xffff);
842 HISTOGRAM_HEAD(unsigned char)
843 y = (row[0] << 8) | row[0];
844 u = (row[1] << 8) | row[1];
845 v = (row[2] << 8) | row[2];
846 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
850 HISTOGRAM_HEAD(unsigned char)
851 r = (row[0] << 8) | row[0];
852 g = (row[1] << 8) | row[1];
853 b = (row[2] << 8) | row[2];
857 HISTOGRAM_HEAD(float)
858 r = (int)(row[0] * 0xffff);
859 g = (int)(row[1] * 0xffff);
860 b = (int)(row[2] * 0xffff);
864 HISTOGRAM_HEAD(unsigned char)
865 y = (row[0] << 8) | row[0];
866 u = (row[1] << 8) | row[1];
867 v = (row[2] << 8) | row[2];
868 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
872 HISTOGRAM_HEAD(uint16_t)
879 HISTOGRAM_HEAD(uint16_t)
883 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
886 case BC_RGBA16161616:
887 HISTOGRAM_HEAD(uint16_t)
893 case BC_YUVA16161616:
894 HISTOGRAM_HEAD(uint16_t)
898 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v);
904 if(server->operation == HistogramEngine::APPLY)
909 #define PROCESS(type, components) \
911 for(int i = pkg->start; i < pkg->end; i++) \
913 type *row = (type*)input->get_rows()[i]; \
914 for(int j = 0; j < w; j++) \
916 if ( plugin->config.split && ((j + i * w / h) < w) ) \
918 row[0] = lookup_r[row[0]]; \
919 row[1] = lookup_g[row[1]]; \
920 row[2] = lookup_b[row[2]]; \
926 #define PROCESS_YUV(type, components, max) \
928 for(int i = pkg->start; i < pkg->end; i++) \
930 type *row = (type*)input->get_rows()[i]; \
931 for(int j = 0; j < w; j++) \
933 if ( plugin->config.split && ((j + i * w / h) < w) ) \
935 /* Convert to 16 bit RGB */ \
938 y = (row[0] << 8) | row[0]; \
939 u = (row[1] << 8) | row[1]; \
940 v = (row[2] << 8) | row[2]; \
949 plugin->yuv.yuv_to_rgb_16(r, g, b, y, u, v); \
951 /* Look up in RGB domain */ \
956 /* Convert to 16 bit YUV */ \
957 plugin->yuv.rgb_to_yuv_16(r, g, b, y, u, v); \
976 #define PROCESS_FLOAT(components) \
978 for(int i = pkg->start; i < pkg->end; i++) \
980 float *row = (float*)input->get_rows()[i]; \
981 for(int j = 0; j < w; j++) \
983 if ( plugin->config.split && ((j + i * w / h) < w) ) \
989 r = plugin->calculate_smooth(r, HISTOGRAM_RED); \
990 g = plugin->calculate_smooth(g, HISTOGRAM_GREEN); \
991 b = plugin->calculate_smooth(b, HISTOGRAM_BLUE); \
1003 VFrame *input = plugin->input;
1004 VFrame *output = plugin->output;
1005 int w = input->get_w();
1006 int h = input->get_h();
1007 int *lookup_r = plugin->lookup[0];
1008 int *lookup_g = plugin->lookup[1];
1009 int *lookup_b = plugin->lookup[2];
1010 int r, g, b, y, u, v, a;
1011 switch(input->get_color_model())
1014 PROCESS(unsigned char, 3)
1020 PROCESS(unsigned char, 4)
1026 PROCESS(uint16_t, 3)
1028 case BC_RGBA16161616:
1029 PROCESS(uint16_t, 4)
1032 PROCESS_YUV(unsigned char, 3, 0xff)
1035 PROCESS_YUV(unsigned char, 4, 0xff)
1038 PROCESS_YUV(uint16_t, 3, 0xffff)
1040 case BC_YUVA16161616:
1041 PROCESS_YUV(uint16_t, 4, 0xffff)
1052 HistogramEngine::HistogramEngine(HistogramMain *plugin,
1055 : LoadServer(total_clients, total_packages)
1057 this->plugin = plugin;
1060 void HistogramEngine::init_packages()
1065 total_size = data->get_h();
1068 total_size = data->get_h();
1073 int package_size = (int)((float)total_size /
1074 get_total_packages() + 1);
1077 for(int i = 0; i < get_total_packages(); i++)
1079 HistogramPackage *package = (HistogramPackage*)get_package(i);
1080 package->start = total_size * i / get_total_packages();
1081 package->end = total_size * (i + 1) / get_total_packages();
1084 // Initialize clients here in case some don't get run.
1085 for(int i = 0; i < get_total_clients(); i++)
1087 HistogramUnit *unit = (HistogramUnit*)get_client(i);
1088 for(int i = 0; i < HISTOGRAM_MODES; i++)
1089 bzero(unit->accum[i], sizeof(int) * HISTOGRAM_SLOTS);
1094 LoadClient* HistogramEngine::new_client()
1096 return new HistogramUnit(this, plugin);
1099 LoadPackage* HistogramEngine::new_package()
1101 return new HistogramPackage;
1104 void HistogramEngine::process_packages(int operation, VFrame *data, int do_value)
1107 this->operation = operation;
1108 this->do_value = do_value;
1109 LoadServer::process_packages();