diff options
-rw-r--r-- | Makefile | 6 | ||||
-rw-r--r-- | gauss_cv.c | 242 | ||||
-rw-r--r-- | gauss_cv.ui | 114 |
3 files changed, 361 insertions, 1 deletions
@@ -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> |