/*************************************************************************************** * * histogram.cc is part of SimpleSkyCam. * *****************************************************************************************/ #include #include "simpleskycam.h" #include "histogram.h" #include "gui.h" #include "configuration.h" #include "video.h" #define HISTOGRAM_WIDTH 256 #define HISTOGRAM_MARGIN 16 GtkWidget *histogram_da = NULL; int histogram[3][HISTOGRAM_WIDTH]; // 6* hist_width min, max, min , max..... int histogram_max; // max vlaue int histogram_zoom_start = 0; // first zoom value int histogram_zoom_stop = HISTOGRAM_WIDTH; // second zoom value int histogram_x; // current mouse x-coordinate int histogram_pressed_x; // window x-coordinate when pressing a button int histogram_released_x; // window x-coordinate when releasing a button int histogram_pressed = 0; // indicates button pressed or not int histogram_zoomed = 0; // indicates zoom extern GtkBuilder *_builder_; // work around for threads void cb_histogramda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data) { int clientw, clienth, px, px2, py2; GdkRGBA color; char txt[255]; if (histogram_da == NULL) // should only be called once histogram_da = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "histogram-da")); clienth = gtk_widget_get_allocated_height(histogram_da); clientw = gtk_widget_get_allocated_width(histogram_da); // // put the drawing area on the screen cairo_paint(cr); cairo_fill (cr); if (histogram_max == 0) return; for (int chan = 0; chan < 3; chan++) { switch (chan) { case 0: color.blue = 0.0; color.red = 1.0; color.green = 0.0; color.alpha = 0.5; break; case 1: color.blue = 0.0; color.red = 0.0; color.green = 1.0; color.alpha = 0.5; break; case 2: color.blue = 1.0; color.red = 0.0; color.green = 0.0; color.alpha = 0.5; break; } gdk_cairo_set_source_rgba(cr, &color); int histogram_width = histogram_zoom_stop - histogram_zoom_start; for (int i = 0; i < histogram_width; i++) { px = HISTOGRAM_MARGIN + ((clientw-HISTOGRAM_MARGIN*2) * i) / histogram_width; py2 = (clienth-HISTOGRAM_MARGIN) - ((clienth-HISTOGRAM_MARGIN*2) * log10(histogram[chan][histogram_zoom_start+i]+1) / log10(histogram_max)); if (i == 0) cairo_move_to(cr, px, py2); else cairo_line_to(cr, px, py2); } cairo_stroke(cr); if (histogram_pressed) { if (histogram_pressed_x < histogram_x) { px = histogram_pressed_x; px2 = histogram_x; } else { px2 = histogram_pressed_x; px = histogram_x; } cairo_set_source_rgba(cr, 0.5, 0.5, 0.5, 0.5); cairo_rectangle (cr, px, 0, px2-px, clienth); cairo_fill (cr); } } // draw some text snprintf (txt, 255, "%d", histogram_max); for (int i = 0; i < 5; i++) { int dx, dy; switch (i) { case 0: cairo_set_source_rgb(cr, 1.0, 1.0, 1.0); dx = -1; dy = 0; break; case 1: dx = +1; dy = 0; break; case 2: dx = 0; dy = -1; break; case 3: dx = 0; dy = +1; break; case 4: cairo_set_source_rgb(cr, 0.1, 0.1, 0.1); dx = 0; dy = 0; break; } cairo_select_font_face (cr, "sans-serif", CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_BOLD); cairo_set_font_size (cr, 12); cairo_move_to (cr, 10+dx, 15+dy); cairo_show_text(cr, txt); cairo_stroke(cr); } }; /* * test function */ void histogram_update(VideoFrame *vf) { // save some time static int to = 0; if ((++to) % 8 == 0) return; int chan, i, x, y; if (vf == NULL) return; if (vf->w <= 0 ) return; // initialize histogram memset (histogram, 0, sizeof(histogram)); for (i = 0, x = 0; x < vf->w; x++) { for (y = 0; y < vf->h; y++) { for (chan = 0; chan < 3; chan++) { histogram[chan][vf->data[i++]]++; } } } if (histogram_da) gdk_window_invalidate_rect(gtk_widget_get_window(histogram_da), NULL, true); for (histogram_max = 0, chan = 0; chan < 3; chan++) for (i = 0; i < HISTOGRAM_WIDTH; i++) if (histogram_max < histogram[chan][i]) histogram_max = histogram[chan][i]; }; void cb_histogramda_motion (GtkWidget *widget, GdkEvent *event, gpointer data) { if(!histogram_zoomed) { histogram_x = (int)round(event->button.x); } }; void cb_histogramda_btnpress (GtkWidget *widget, gpointer data) { if (!histogram_zoomed) { if (!histogram_pressed) { histogram_pressed = 1; histogram_pressed_x = histogram_x; } } else { histogram_zoomed = 0; histogram_zoom_start = 0; histogram_zoom_stop = HISTOGRAM_WIDTH; } }; void cb_histogramda_btnrelease (GtkWidget *widget, gpointer data) { if (!histogram_zoomed) { if (histogram_pressed) { histogram_pressed = 0; histogram_released_x = histogram_x; histogram_zoomed = 1; // here we need to compute start/stop coordinates inside histogram int clientw; clientw = gtk_widget_get_allocated_width(histogram_da); // translate first coordinate histogram_zoom_start = (histogram_pressed_x - HISTOGRAM_MARGIN) * HISTOGRAM_WIDTH / (clientw - HISTOGRAM_MARGIN*2); if (histogram_zoom_start < 0) histogram_zoom_start = 0; if (histogram_zoom_start > HISTOGRAM_WIDTH) histogram_zoom_start = HISTOGRAM_WIDTH; // translate second coordinate histogram_zoom_stop = (histogram_released_x - HISTOGRAM_MARGIN) * HISTOGRAM_WIDTH / (clientw - HISTOGRAM_MARGIN*2) + 1; // limit the values if (histogram_zoom_stop < 0) histogram_zoom_stop = 0; if (histogram_zoom_stop > HISTOGRAM_WIDTH) histogram_zoom_stop = HISTOGRAM_WIDTH; // exchange the values if necessary if (histogram_zoom_start > histogram_zoom_stop) { int t = histogram_zoom_start; histogram_zoom_start = histogram_zoom_stop; histogram_zoom_stop = t; } } } };