diff options
-rw-r--r-- | Makefile | 4 | ||||
-rw-r--r-- | roi.c | 295 |
2 files changed, 254 insertions, 45 deletions
@@ -1,9 +1,9 @@ CC = gcc CFLAGS = -ggdb -std=c99 -pedantic -Wall $(DEFINES) \ - $(shell pkg-config --cflags gdk-pixbuf-2.0 glib-2.0 gthread-2.0) \ + $(shell pkg-config --cflags gdk-pixbuf-2.0 gtk+-2.0 glib-2.0 gthread-2.0) \ -DN_THREADS=$(shell grep -c ^processor /proc/cpuinfo || echo 2) LDFLAGS = $(LIBS) -lm \ - $(shell pkg-config --libs gdk-pixbuf-2.0 glib-2.0 gthread-2.0) + $(shell pkg-config --libs gdk-pixbuf-2.0 gtk+-2.0 glib-2.0 gthread-2.0) PROGS = wimmel wimmel_gl roi OBJS = wimmel.o wimmel_gl.o util.o roi.o @@ -1,50 +1,57 @@ #include <stdlib.h> +#include <string.h> +#include <math.h> #include <glib.h> #include <gdk-pixbuf/gdk-pixbuf.h> -#include <math.h> +#include <gtk/gtk.h> -int -main(int argc, char *argv[]) -{ - char *file; - GdkPixbuf *input; - GdkPixbuf *match_tmp, *match; - int x, y, i, j; - int x1, y1, mwidth, mheight, width, height; - gint stride, nch; - guchar *pix, *row; +struct rect { + gint x, y, width, height; +}; - g_type_init(); +struct roi { + GtkWidget *window; + GtkWidget *drawing_area; - if (argc < 5) - exit(EXIT_FAILURE); - - file = argv[1]; - x1 = atoi(argv[2]); - y1 = atoi(argv[3]); - mwidth = atoi(argv[4]); - mheight = atoi(argv[5]); + struct key_press { + guint8 state; + guint32 key; + } key_press; - input = gdk_pixbuf_new_from_file(file, NULL); - if (!input) - exit(EXIT_FAILURE); + GdkPixbuf *input, *modified_input; - match_tmp = gdk_pixbuf_new_subpixbuf(input, x1, y1, mwidth, mheight); - match = gdk_pixbuf_copy(match_tmp); - g_object_unref(match_tmp); + struct rect motion; + struct rect roi_area; + struct rect previous_draw; +}; +void +do_roi(struct roi *roi) +{ + GdkPixbuf *match; + int x, y, i; + int width, height; + gint stride, nch; + guchar *pix, *row; + gint s; + gint middle[3] = { 0, 0, 0 }; + gint sigma[3] = { 0, 0, 0 }; struct match_interval { gint min, max; } interval[3]; + match = gdk_pixbuf_new_subpixbuf(roi->input, + roi->roi_area.x, + roi->roi_area.y, + roi->roi_area.width, + roi->roi_area.height); nch = gdk_pixbuf_get_n_channels(match); stride = gdk_pixbuf_get_rowstride(match); - gint s = mwidth * mheight; + s = roi->roi_area.width * roi->roi_area.height; - gint middle[3] = { 0, 0, 0 }; for (y = 0, row = gdk_pixbuf_get_pixels(match); - y < mheight; ++y, row += stride) { - for (x = 0, pix = row; x < mwidth; ++x, pix += nch) { + y < roi->roi_area.height; ++y, row += stride) { + for (x = 0, pix = row; x < roi->roi_area.width; ++x, pix += nch) { for (i = 0; i < 3; ++i) middle[i] += pix[i]; } @@ -52,10 +59,9 @@ main(int argc, char *argv[]) for (i = 0; i < 3; ++i) middle[i] /= s; - gint sigma[3] = { 0, 0, 0 }; for (y = 0, row = gdk_pixbuf_get_pixels(match); - y < mheight; ++y, row += stride) { - for (x = 0, pix = row; x < mwidth; ++x, pix += nch) { + y < roi->roi_area.height; ++y, row += stride) { + for (x = 0, pix = row; x < roi->roi_area.width; ++x, pix += nch) { for (i = 0; i < 3; ++i) sigma[i] += (pix[i] - middle[i]) * @@ -70,31 +76,234 @@ main(int argc, char *argv[]) printf("sigma: %3d, %3d, %3d\n", sigma[0], sigma[1], sigma[2]); for (i = 0; i < 3; ++i) { - interval[i].min = middle[i] - 2 * sigma[i]; - interval[i].max = middle[i] + 2 * sigma[i]; + interval[i].min = middle[i] - 3 * sigma[i]; + interval[i].max = middle[i] + 3 * sigma[i]; printf("interval %d: [%3d - %3d]\n", i, interval[i].min, interval[i].max); } - nch = gdk_pixbuf_get_n_channels(input); - stride = gdk_pixbuf_get_rowstride(input); - width = gdk_pixbuf_get_width(input); - height = gdk_pixbuf_get_height(input); - for (y = 0, row = gdk_pixbuf_get_pixels(input); + nch = gdk_pixbuf_get_n_channels(roi->input); + stride = gdk_pixbuf_get_rowstride(roi->input); + width = gdk_pixbuf_get_width(roi->input); + height = gdk_pixbuf_get_height(roi->input); + + if (roi->modified_input) + g_object_unref(roi->modified_input); + roi->modified_input = gdk_pixbuf_copy(roi->input); + + for (y = 0, row = gdk_pixbuf_get_pixels(roi->modified_input); y < height; ++y, row += stride) { for (x = 0, pix = row; x < width; ++x, pix += nch) { int H = 1; for (i = 0; i < 3; ++i) { if (!(pix[i] >= interval[i].min && pix[i] <= interval[i].max)) - H = 0; + H = 0; } if (H) pix[0] = pix[1] = pix[2] = 0; } } - gdk_pixbuf_save(input, "output_roi.tiff", "tiff", NULL, NULL); - g_object_unref(input); g_object_unref(match); } + +gboolean +motion_notify_event(GtkWidget *widget, GdkEventMotion *event, gpointer userdata) +{ + struct roi *roi = userdata; + GdkWindow *win = gtk_widget_get_window(widget); + GdkRectangle rect; + cairo_t *cr; + + rect.x = roi->motion.x; + rect.y = roi->motion.y; + rect.width = event->x - roi->motion.x; + rect.height = event->y - roi->motion.y; + + /* gdk_window_begin_paint_rect(win, &rect); */ + cr = gdk_cairo_create(win); + cairo_set_line_width(cr, 2.0); + + gdk_cairo_set_source_pixbuf(cr, roi->input, 0, 0); + cairo_rectangle(cr, + roi->previous_draw.x, + roi->previous_draw.y, + roi->previous_draw.width, + roi->previous_draw.height); + cairo_fill_preserve(cr); + cairo_stroke(cr); + + roi->previous_draw.x = roi->motion.x; + roi->previous_draw.y = roi->motion.y; + roi->previous_draw.width = event->x - roi->motion.x; + roi->previous_draw.height = event->y - roi->motion.y; + +#if 0 + const double dashed[] = {1.0}; + cairo_set_dash(cr, dashed, 1, 0); +#endif + + cairo_rectangle(cr, + roi->previous_draw.x, + roi->previous_draw.y, + roi->previous_draw.width, + roi->previous_draw.height); + + cairo_set_source_rgba(cr, 0.0, 0.0, 0.5, 0.3); + cairo_stroke_preserve(cr); + cairo_set_source_rgba(cr, 0.0, 0.0, 0.5, 0.5); + cairo_fill(cr); + + cairo_destroy(cr); + /* gdk_window_end_paint(win); */ + + return TRUE; +} + +gboolean +button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer userdata) +{ + struct roi *roi = userdata; + + if (event->button != 1) + return TRUE; + + roi->motion.x = event->x; + roi->motion.y = event->y; + + return FALSE; +} + +gboolean +button_release_event(GtkWidget *widget, GdkEventButton *event, gpointer userdata) +{ + struct roi *roi = userdata; + + if (event->button != 1) + return TRUE; + + roi->roi_area.x = roi->motion.x; + roi->roi_area.y = roi->motion.y; + roi->roi_area.width = event->x - roi->motion.x; + roi->roi_area.height = event->y - roi->motion.y; + + if (roi->roi_area.width < 0) { + roi->roi_area.x -= roi->roi_area.width; + roi->roi_area.width = -roi->roi_area.width; + } + + if (roi->roi_area.height < 0) { + roi->roi_area.y -= roi->roi_area.height; + roi->roi_area.height = -roi->roi_area.height; + } + + do_roi(roi); + roi->previous_draw.width = roi->previous_draw.height = 0; + + gtk_widget_queue_draw(roi->drawing_area); + + return FALSE; +} + +gboolean +key_event(GtkWidget *widget, GdkEventKey *event, gpointer userdata) +{ + struct roi *roi = userdata; + + roi->key_press.state = (event->type == GDK_KEY_PRESS); + roi->key_press.key = event->keyval; + + if (!roi->key_press.state) { + switch (roi->key_press.key) { + case 'd': + g_object_unref(roi->modified_input); + roi->modified_input = NULL; + gtk_widget_queue_draw(roi->drawing_area); + break; + case 'q': + gtk_main_quit(); + break; + } + } + + return FALSE; +} + +gboolean +configure_event(GtkWidget *widget, GdkEventConfigure *event, gpointer data) +{ + return FALSE; +} + +gboolean +expose_event(GtkWidget *widget, GdkEventExpose *event, gpointer userdata) +{ + struct roi *roi = userdata; + cairo_t *cr; + + cr = gdk_cairo_create(gtk_widget_get_window(widget)); + gdk_cairo_set_source_pixbuf(cr, roi->modified_input ? + roi->modified_input : roi->input, 0, 0); + cairo_rectangle(cr, + event->area.x, event->area.y, + event->area.width, event->area.height); + /* cairo_paint(cr); */ + cairo_fill(cr); + cairo_destroy(cr); + + return FALSE; +} + +int +main(int argc, char *argv[]) +{ + struct roi roi; + + memset(&roi, 0, sizeof roi); + + gtk_init(&argc, &argv); + + roi.input = gdk_pixbuf_new_from_file(argv[1], NULL); + roi.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + roi.drawing_area = gtk_drawing_area_new(); + + gtk_widget_set_size_request(roi.drawing_area, + gdk_pixbuf_get_width(roi.input), + gdk_pixbuf_get_height(roi.input)); + + gtk_container_add(GTK_CONTAINER(roi.window), roi.drawing_area); + + g_signal_connect(roi.window, "destroy", + G_CALLBACK(gtk_main_quit), NULL); + g_signal_connect(G_OBJECT(roi.drawing_area), "expose-event", + G_CALLBACK(expose_event), &roi); + g_signal_connect(G_OBJECT(roi.drawing_area), "configure-event", + G_CALLBACK(configure_event), &roi); + + gtk_widget_set_events(roi.drawing_area, + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | + GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK | + GDK_BUTTON1_MOTION_MASK); + + g_signal_connect(G_OBJECT(roi.window), "key-press-event", + G_CALLBACK(key_event), &roi); + g_signal_connect(G_OBJECT(roi.window), "key-release-event", + G_CALLBACK(key_event), &roi); + + g_signal_connect(G_OBJECT(roi.drawing_area), "button-press-event", + G_CALLBACK(button_press_event), &roi); + g_signal_connect(G_OBJECT(roi.drawing_area), "button-release-event", + G_CALLBACK(button_release_event), &roi); + g_signal_connect (G_OBJECT (roi.drawing_area), "motion-notify-event", + G_CALLBACK(motion_notify_event), &roi); + + gtk_widget_show_all(roi.window); + gtk_main(); + + g_object_unref(roi.input); + if (roi.modified_input) + g_object_unref(roi.modified_input); + + return 0; +} |