summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Makefile4
-rw-r--r--roi.c295
2 files changed, 254 insertions, 45 deletions
diff --git a/Makefile b/Makefile
index 879d1af..1d9e0a0 100644
--- a/Makefile
+++ b/Makefile
@@ -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
diff --git a/roi.c b/roi.c
index 6e8ed74..a3465c4 100644
--- a/roi.c
+++ b/roi.c
@@ -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;
+}