summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile6
-rw-r--r--gauss_cv.c242
-rw-r--r--gauss_cv.ui114
3 files changed, 361 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index afdc528..d80fd4c 100644
--- a/Makefile
+++ b/Makefile
@@ -19,7 +19,10 @@ capture_LIBS=$(shell pkg-config --libs gtk+-3.0 opencv glib-2.0)
unvignette_CFLAGS=$(shell pkg-config --cflags cairo)
unvignette_LIBS=$(shell pkg-config --libs cairo) -lm
-PROGS = wimmel wimmel_gl roi capture unvignette
+gauss_cv_CFLAGS=$(shell pkg-config --cflags gtk+-3.0 gmodule-2.0 opencv)
+gauss_cv_LIBS=$(shell pkg-config --libs gtk+-3.0 gmodule-2.0 opencv)
+
+PROGS = wimmel wimmel_gl roi capture unvignette gauss_cv
OBJS = $(PROGS:=.o) util.o
all: $(PROGS)
@@ -29,6 +32,7 @@ wimmel_gl: wimmel_gl.o util.o
roi: roi.o
capture: capture.o
unvignette: unvignette.o
+gauss_cv: gauss_cv.o
.PHONY: clean all
diff --git a/gauss_cv.c b/gauss_cv.c
new file mode 100644
index 0000000..da832ae
--- /dev/null
+++ b/gauss_cv.c
@@ -0,0 +1,242 @@
+#include <string.h>
+#include <gtk/gtk.h>
+#include <cv.h>
+#include <highgui.h>
+
+struct cvg {
+ GtkWidget *drawing_area1;
+ GtkWidget *drawing_area2;
+ GtkButton *gauss_btn;
+ GtkButton *open_btn;
+ IplImage *image;
+ IplImage *output;
+ cairo_surface_t *input_surface;
+ cairo_surface_t *output_surface;
+};
+
+static cairo_surface_t *
+cairo_surface_create_from_ipl_image(IplImage *image)
+{
+ cairo_surface_t *surface;
+ guchar *row1, *row2, *p1, *p2;
+ int x, y;
+
+ surface = cairo_image_surface_create(CAIRO_FORMAT_RGB24,
+ image->width, image->height);
+ row1 = (guchar *) image->imageData;
+ row2 = cairo_image_surface_get_data(surface);
+ for (y = 0; y < image->height; ++y) {
+ p1 = row1;
+ p2 = row2;
+ for (x = 0; x < image->width; ++x) {
+ memcpy(p2, p1, 3);
+
+ p1 += image->nChannels;
+ p2 += 4;
+ }
+ row1 += image->widthStep;
+ row2 += cairo_image_surface_get_stride(surface);
+ }
+
+ return surface;
+}
+
+static inline double
+min3(double x1, double x2, double x3)
+{
+ return MIN(MIN(x1, x2), x3);
+}
+
+static void
+scale_centered(cairo_t *cr, double w, double h, double sw, double sh)
+{
+ double scale = min3(sw / w, sh / h, 1.0);
+
+ cairo_translate(cr, (sw - scale * w) / 2.0, (sh - scale * h) / 2.0);
+ cairo_scale(cr, scale, scale);
+}
+
+gboolean
+draw(GtkWidget *widget, cairo_t *cr, gpointer userdata)
+{
+ struct cvg *cvg = userdata;
+ cairo_surface_t *surface;
+
+ if (widget == cvg->drawing_area1)
+ surface = cvg->input_surface;
+ else
+ surface = cvg->output_surface;
+
+ if (surface) {
+ scale_centered(cr,
+ cairo_image_surface_get_width(surface),
+ cairo_image_surface_get_height(surface),
+ gtk_widget_get_allocated_width(widget),
+ gtk_widget_get_allocated_height(widget));
+ cairo_set_source_surface(cr, surface, 0, 0);
+ } else {
+ cairo_set_source_rgba(cr, 0.0, 0.0, 0.0, 0.0);
+ }
+ cairo_paint(cr);
+
+ return FALSE;
+}
+
+static void
+destroy_images(struct cvg *cvg)
+{
+ if (cvg->image)
+ cvReleaseImage(&cvg->image);
+ if (cvg->output)
+ cvReleaseImage(&cvg->output);
+
+ if (cvg->input_surface)
+ cairo_surface_destroy(cvg->input_surface);
+ cvg->input_surface = NULL;
+ if (cvg->output_surface)
+ cairo_surface_destroy(cvg->output_surface);
+ cvg->output_surface = NULL;
+}
+
+gboolean
+key_event(GtkWidget *widget, GdkEventKey *event, gpointer userdata)
+{
+ struct cvg *cvg = userdata;
+
+ switch (event->type) {
+ case GDK_KEY_RELEASE:
+ switch (event->keyval) {
+ case GDK_KEY_g:
+ g_signal_emit_by_name(cvg->gauss_btn, "released", NULL);
+ g_signal_emit_by_name(cvg->gauss_btn, "clicked", NULL);
+ break;
+ case GDK_KEY_o:
+ g_signal_emit_by_name(cvg->open_btn, "released", NULL);
+ g_signal_emit_by_name(cvg->open_btn, "clicked", NULL);
+ break;
+ }
+ return FALSE;
+ case GDK_KEY_PRESS:
+ switch (event->keyval) {
+ case GDK_KEY_g:
+ g_signal_emit_by_name(cvg->gauss_btn, "pressed", NULL);
+ break;
+ case GDK_KEY_o:
+ g_signal_emit_by_name(cvg->open_btn, "pressed", NULL);
+ break;
+ case GDK_KEY_d:
+ destroy_images(cvg);
+ gtk_widget_queue_draw(cvg->drawing_area1);
+ gtk_widget_queue_draw(cvg->drawing_area2);
+ break;
+ case GDK_KEY_q:
+ gtk_main_quit();
+ break;
+ }
+ return FALSE;
+ default:
+ return TRUE;
+ }
+}
+
+static void
+open_file(struct cvg *cvg, const gchar *file)
+{
+ if (cvg->image)
+ cvReleaseImage(&cvg->image);
+ if (cvg->input_surface)
+ cairo_surface_destroy(cvg->input_surface);
+
+ cvg->image = cvLoadImage(file, CV_LOAD_IMAGE_COLOR);
+ if (!cvg->image)
+ return;
+ cvg->input_surface = cairo_surface_create_from_ipl_image(cvg->image);
+}
+
+void
+file_set(GtkFileChooserButton *widget, gpointer userdata)
+{
+ struct cvg *cvg = userdata;
+ gchar *filename;
+
+ filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget));
+ open_file(cvg, filename);
+ g_free(filename);
+
+ gtk_widget_queue_draw(cvg->drawing_area1);
+}
+
+void
+on_gauss_button_click(GtkButton *button, gpointer userdata)
+{
+ struct cvg *cvg = userdata;
+
+ if (!cvg->image)
+ return;
+
+ if (cvg->output)
+ cvReleaseImage(&cvg->output);
+
+ cvg->output = cvCreateImage(cvGetSize(cvg->image), IPL_DEPTH_8U, 3);
+ cvSmooth(cvg->image, cvg->output, CV_GAUSSIAN, 9, 9, 0, 0);
+
+ if (cvg->output_surface)
+ cairo_surface_destroy(cvg->output_surface);
+ cvg->output_surface = cairo_surface_create_from_ipl_image(cvg->output);
+
+ gtk_widget_queue_draw(cvg->drawing_area2);
+}
+
+void
+destroy(GtkWidget *widget, gpointer userdata)
+{
+ gtk_main_quit();
+}
+
+static void
+find_button(GtkWidget *widget, gpointer data)
+{
+ GtkButton **p = data;
+
+ if (GTK_IS_BUTTON(widget))
+ *p = GTK_BUTTON(widget);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct cvg cvg;
+ GtkBuilder *builder;
+ GObject *file_chooser;
+
+ memset(&cvg, 0, sizeof cvg);
+ gtk_init(&argc, &argv);
+
+ if (argc >= 2)
+ open_file(&cvg, argv[argc-1]);
+ builder = gtk_builder_new();
+ gtk_builder_add_from_file(builder, "gauss_cv.ui", NULL);
+ gtk_builder_connect_signals(builder, &cvg);
+
+ cvg.drawing_area1 = GTK_WIDGET(gtk_builder_get_object(builder,
+ "drawingarea1"));
+ cvg.drawing_area2 = GTK_WIDGET(gtk_builder_get_object(builder,
+ "drawingarea2"));
+ cvg.gauss_btn = GTK_BUTTON(gtk_builder_get_object(builder, "gauss"));
+ file_chooser = gtk_builder_get_object(builder, "file-chooser");
+ gtk_file_chooser_set_current_folder(GTK_FILE_CHOOSER(file_chooser),
+ g_get_current_dir());
+ /* There is no way to retreive the GtkButton from GtkFileChooserButton,
+ * Try to find a GtkButton in the inherited GtkContainer.
+ */
+ gtk_container_forall(GTK_CONTAINER(file_chooser),
+ find_button, &cvg.open_btn);
+
+ gtk_widget_show_all(GTK_WIDGET(gtk_builder_get_object(builder, "win")));
+ g_object_unref(builder);
+ gtk_main();
+
+ destroy_images(&cvg);
+
+ return 0;
+}
diff --git a/gauss_cv.ui b/gauss_cv.ui
new file mode 100644
index 0000000..302711d
--- /dev/null
+++ b/gauss_cv.ui
@@ -0,0 +1,114 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <!-- interface-requires gtk+ 3.0 -->
+ <object class="GtkFileFilter" id="filefilter1">
+ <mime-types>
+ <mime-type>image/tiff</mime-type>
+ <mime-type>image/png</mime-type>
+ <mime-type>image/jpeg</mime-type>
+ <mime-type>image/gif</mime-type>
+ </mime-types>
+ </object>
+ <object class="GtkWindow" id="win">
+ <property name="can_focus">False</property>
+ <property name="default_width">600</property>
+ <property name="default_height">400</property>
+ <signal name="destroy" handler="destroy" swapped="no"/>
+ <signal name="key-release-event" handler="key_event" swapped="no"/>
+ <signal name="key-press-event" handler="key_event" swapped="no"/>
+ <child>
+ <object class="GtkGrid" id="grid1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="hexpand">True</property>
+ <property name="column_homogeneous">True</property>
+ <child>
+ <object class="GtkDrawingArea" id="drawingarea1">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">1</property>
+ <property name="margin_right">1</property>
+ <property name="margin_top">1</property>
+ <property name="margin_bottom">1</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <signal name="draw" handler="draw" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkDrawingArea" id="drawingarea2">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="margin_left">1</property>
+ <property name="margin_right">1</property>
+ <property name="margin_top">1</property>
+ <property name="margin_bottom">1</property>
+ <property name="hexpand">True</property>
+ <property name="vexpand">True</property>
+ <signal name="draw" handler="draw" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkFileChooserButton" id="file-chooser">
+ <property name="visible">True</property>
+ <property name="can_focus">False</property>
+ <property name="filter">filefilter1</property>
+ <property name="title" translatable="yes">Bild auswählen</property>
+ <signal name="file-set" handler="file_set" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <object class="GtkButton" id="gauss">
+ <property name="label" translatable="yes">Gauss-Filter</property>
+ <property name="use_action_appearance">False</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="receives_default">True</property>
+ <property name="hexpand">True</property>
+ <property name="use_action_appearance">False</property>
+ <signal name="clicked" handler="on_gauss_button_click" swapped="no"/>
+ </object>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="width">1</property>
+ <property name="height">1</property>
+ </packing>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ <child>
+ <placeholder/>
+ </child>
+ </object>
+ </child>
+ </object>
+</interface>