From 1877e5951cdd6ff7231df8c4f907c940f0ee0cec Mon Sep 17 00:00:00 2001 From: Steffen Pohle Date: Fri, 25 Nov 2022 21:15:17 +0100 Subject: [PATCH] adding histogram --- Makefile | 3 +- gui.cc | 3 +- gui.h | 6 ++ histogram.cc | 173 ++++++++++++++++++++++++++++++++++++++++++++++++ histogram.h | 21 ++++++ simpleskycam.ui | 29 ++++++++ video.cc | 3 +- 7 files changed, 235 insertions(+), 3 deletions(-) create mode 100644 histogram.cc create mode 100644 histogram.h diff --git a/Makefile b/Makefile index 97f19c1..f52d4fb 100644 --- a/Makefile +++ b/Makefile @@ -7,7 +7,8 @@ APP = simpleskycam OBJECTS := $(OBJECTS) gui.oo main.oo \ video.oo videoframe.oo \ videodev.oo videodev-v4l2.oo videodev-dumpfile.oo \ - convert.oo filter.oo detect.oo json.oo configuration.oo ser.oo dng.oo + convert.oo filter.oo detect.oo histogram.oo \ + json.oo configuration.oo ser.oo dng.oo DISTNAME=simpleskycam-$(VERSION) DEPENDFILE=.depend diff --git a/gui.cc b/gui.cc index d6804d0..82b4457 100644 --- a/gui.cc +++ b/gui.cc @@ -62,10 +62,11 @@ void cb_window_show (GtkWidget *widget, gpointer data) { GtkWidget *win_detect = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "window-detect")); GtkWidget *win_input = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "window-input")); GtkWidget *win_output = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "window-output")); + GtkWidget *win_histogram = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "window-histogram")); gtk_widget_show (win_detect); gtk_widget_show (win_input); gtk_widget_show (win_output); - + gtk_widget_show (win_histogram); // changing the value, will cause the 'change' event to be triggered gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(rboff), true); diff --git a/gui.h b/gui.h index 5a747a3..ac122af 100644 --- a/gui.h +++ b/gui.h @@ -98,6 +98,12 @@ G_MODULE_EXPORT void cb_detect_btnsetsize (GtkWidget *widget, gpointer data); G_MODULE_EXPORT void cb_detect_followtype (GtkWidget *widget, gpointer data); G_MODULE_EXPORT void cb_detect_detecttype (GtkWidget *widget, gpointer data); + +// +// histogram elements +G_MODULE_EXPORT void cb_histogramda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data); + + #ifdef __cplusplus } #endif diff --git a/histogram.cc b/histogram.cc new file mode 100644 index 0000000..3eda5c0 --- /dev/null +++ b/histogram.cc @@ -0,0 +1,173 @@ +/*************************************************************************************** + * + * histogram.cc is part of SimpleSkyCam. + * + *****************************************************************************************/ + +#include "simpleskycam.h" +#include "histogram.h" +#include "gui.h" +#include "configuration.h" +#include "video.h" + + +GtkWidget *histogram_da = NULL; +GdkPixbuf *histogram_pixbuf = NULL; +int *hist_minmax = NULL; // 2* hist_width min, max, min , max..... +int hist_width = 0; + +extern GtkBuilder *_builder_; // work around for threads + + +#define S_X(_x_) (((_x_) * clientw / pixbufw)) +#define S_Y(_y_) (((_y_) * clienth / pixbufh)) +void cb_histogramda_draw(GtkWidget *area, cairo_t *cr, int w, int h, gpointer data) { + int clientw, clienth, pixbufw, pixbufh; + GdkRGBA color; + + if (histogram_da == NULL) // should only be called once + histogram_da = GTK_WIDGET(gtk_builder_get_object (GTK_BUILDER(_builder_), "histogram-da")); + + // + // create or resize pixbuf if needed + clienth = gtk_widget_get_allocated_height(histogram_da); + clientw = gtk_widget_get_allocated_width(histogram_da); + if (histogram_pixbuf == NULL) { + histogram_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, false, 8, clientw, clienth); + memset (gdk_pixbuf_get_pixels(histogram_pixbuf), 0, 3 * gdk_pixbuf_get_height(histogram_pixbuf) * gdk_pixbuf_get_width(histogram_pixbuf)); + } + + pixbufh = gdk_pixbuf_get_height(histogram_pixbuf); + pixbufw = gdk_pixbuf_get_width(histogram_pixbuf); + if (pixbufw != clientw || pixbufh != clienth) { + g_object_unref(histogram_pixbuf); + histogram_pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, false, 8, clientw, clienth); + memset (gdk_pixbuf_get_pixels(histogram_pixbuf), 0, 3 * gdk_pixbuf_get_height(histogram_pixbuf) * gdk_pixbuf_get_width(histogram_pixbuf)); + } + + // + // put the drawing area on the screen + gdk_cairo_set_source_pixbuf(cr, histogram_pixbuf, 0, 0); + cairo_paint(cr); + cairo_fill (cr); + + // + // draw cross + color.blue = 1.0; + color.red = 0.0; + color.green = 1.0; + color.alpha = 1.0; + gdk_cairo_set_source_rgba(cr, &color); + + cairo_move_to(cr, 0, 0); + cairo_line_to(cr, pixbufw, pixbufh); + cairo_move_to(cr, pixbufw, 0); + cairo_line_to(cr, 0, pixbufh); + + cairo_stroke(cr); + + // + // draw basic histogram + if (hist_minmax != NULL) { + // + // draw cross + color.blue = 0.75; + color.red = 0.75; + color.green = 0.75; + color.alpha = 0.8; + gdk_cairo_set_source_rgba(cr, &color); + + int x, i; // position in histogram + int px, py1, py2; // screen pos x and line from to + + for (i = 0, x = 0; x < hist_width; x++) { + + px = (pixbufw * x) / hist_width; + py1 = (pixbufh * hist_minmax[i++]) / 255; + py2 = (pixbufh * hist_minmax[i++]) / 255; + + cairo_move_to(cr, px, py1); + cairo_line_to(cr, px, py2); + + cairo_stroke(cr); + } + } + + // draw some text + 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, "Test"); + cairo_stroke(cr); + } +}; + + +/* + * test function + */ +void histogram_update(VideoFrame *vf) { + int i, x, y, min, max, v; + + if (vf == NULL) return; + if (vf->w <= 0 ) return; + + if (hist_minmax == NULL ) { + hist_minmax = (int*) malloc (2 * sizeof(int) * vf->w); + hist_width = vf->w; + } + if (hist_width != vf->w) { + free (hist_minmax); + hist_minmax = (int*) malloc (2 * sizeof(int) * vf->w); + hist_width = vf->w; + } + + for (i = 0, x = 0; x < vf->w; x++) { + for (y = 0; y < vf->h; y++) { + v = (vf->data[3*y*vf->w+x + 0] + + vf->data[3*y*vf->w+x + 1] + + vf->data[3*y*vf->w+x + 2]) / 3; + if (y == 0) { + min = v; + max = v; + } + + if (v < min) min = v; + if (v > max) max = v; + } + hist_minmax[i++] = min; + hist_minmax[i++] = max; + } + + if (histogram_da) + gdk_window_invalidate_rect(gtk_widget_get_window(histogram_da), NULL, true); +}; + diff --git a/histogram.h b/histogram.h new file mode 100644 index 0000000..2ca1d97 --- /dev/null +++ b/histogram.h @@ -0,0 +1,21 @@ +/*************************************************************************************** + * + * histogram.h is part of SimpleSkyCam. + * + ***************************************************************************************/ + +#ifndef _HISTOGRAM_H_ +#define _HISTOGRAM_H_ + +#include +#include +#include + +#include "gui.h" +#include "config.h" +#include "videoframe.h" + +void histogram_update(VideoFrame *vf); + +#endif // _HISTOGRAM_H_ + diff --git a/simpleskycam.ui b/simpleskycam.ui index e5f0dfb..8406c46 100644 --- a/simpleskycam.ui +++ b/simpleskycam.ui @@ -11,6 +11,7 @@ False + Detect 440 250 @@ -447,8 +448,20 @@ + + False + Histogram + + + True + False + + + + False + Input 400 300 @@ -665,6 +678,11 @@ False True + + + False + + False @@ -767,6 +785,11 @@ 800x600 640x480 + + + False + + False @@ -796,6 +819,11 @@ YUYV RGB4 + + + False + + False @@ -959,6 +987,7 @@ False + Output 400 300 diff --git a/video.cc b/video.cc index 28d204f..f6baf2e 100644 --- a/video.cc +++ b/video.cc @@ -15,7 +15,7 @@ #include "configuration.h" #include "video.h" #include "videodev.h" - +#include "histogram.h" VideoDev *videodev = NULL; GThread *videodev_thread = NULL; @@ -535,6 +535,7 @@ gboolean cb_thread_video (gpointer data) { } vf->ToPixbuf(video_pixbuf); // convert Frame to pixeldata + histogram_update(vf); // update histogram detect.NewFrame(vf); // push new data to detect object videodev->UnLockMutex();