From f829f179582f7cb03c87a67b67e54a09c624bb13 Mon Sep 17 00:00:00 2001 From: Benjamin Franzke Date: Wed, 4 Apr 2012 17:21:35 +0200 Subject: Add capture.c: OpenCV capture displayed with GTK+3 --- Makefile | 12 ++- capture.c | 251 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 260 insertions(+), 3 deletions(-) create mode 100644 capture.c diff --git a/Makefile b/Makefile index fce35b1..65c0cfe 100644 --- a/Makefile +++ b/Makefile @@ -5,14 +5,15 @@ CFLAGS = -ggdb -std=c99 -pedantic -Wall $(DEFINES) \ LDFLAGS = $(LIBS) -lm \ $(shell pkg-config --libs gdk-pixbuf-2.0 glib-2.0 gthread-2.0) -PROGS = wimmel wimmel_gl roi -OBJS = wimmel.o wimmel_gl.o util.o roi.o +PROGS = wimmel wimmel_gl roi capture +OBJS = wimmel.o wimmel_gl.o util.o roi.o capture.o all: $(PROGS) wimmel: wimmel.o util.o wimmel_gl: wimmel_gl.o util.o roi: roi.o +capture: capture.o .PHONY: clean all @@ -24,12 +25,17 @@ roi: roi.o wimmel_gl: - $(CC) $(LDFLAGS) `pkg-config --cflags --libs egl glesv2` -o $@ $+ + $(CC) $(LDFLAGS) `pkg-config --cflags --libs egl glesv2` -o $@ $+ roi.o: roi.c $(CC) $(CFLAGS) `pkg-config --cflags gtk+-3.0` -c -o $@ $< roi: $(CC) $(LDFLAGS) `pkg-config --libs gtk+-3.0` -o $@ $+ +capture.o: capture.c + $(CC) $(CFLAGS) `pkg-config --cflags gtk+-3.0 opencv` -c -o $@ $< +capture: + $(CC) $(LDFLAGS) `pkg-config --libs gtk+-3.0 opencv` -o $@ $+ + clean: rm -f $(PROGS) $(OBJS) diff --git a/capture.c b/capture.c new file mode 100644 index 0000000..2a02d32 --- /dev/null +++ b/capture.c @@ -0,0 +1,251 @@ +#include +#include +#include +#include +#include + +#include +#include + +/* Only available as of GTK 3.4 */ +#ifndef GDK_BUTTON_PRIMARY +#define GDK_BUTTON_PRIMARY 1 +#endif + +struct ct { + GtkWidget *window; + GtkWidget *drawing_area; + cairo_surface_t *surface; + + CvCapture *capture; + gint timer; + + gboolean doing_rubberband; + struct { + double x1, y1, x2, y2; + } rubberband; +}; + +static inline void +calc_rubberband_rect(struct ct *ct, + double *x, double *y, + double *width, double *height) +{ + *x = MIN(ct->rubberband.x1, ct->rubberband.x2); + *y = MIN(ct->rubberband.y1, ct->rubberband.y2); + *width = ABS(ct->rubberband.x1 - ct->rubberband.x2); + *height = ABS(ct->rubberband.y1 - ct->rubberband.y2); +} + +static gboolean +motion_notify_event(GtkWidget *widget, GdkEventMotion *event, gpointer userdata) +{ + struct ct *ct = userdata; + + if (ct->doing_rubberband) { + ct->rubberband.x2 = event->x; + ct->rubberband.y2 = event->y; + gtk_widget_queue_draw(ct->drawing_area); + } + + return TRUE; +} + +static gboolean +button_press_event(GtkWidget *widget, GdkEventButton *event, gpointer userdata) +{ + struct ct *ct = userdata; + + switch (event->button) { + case GDK_BUTTON_PRIMARY: + ct->rubberband.x1 = event->x; + ct->rubberband.x2 = event->x; + ct->rubberband.y1 = event->y; + ct->rubberband.y2 = event->y; + + ct->doing_rubberband = TRUE; + return FALSE; + default: + return TRUE; + } +} + +static gboolean +button_release_event(GtkWidget *widget, GdkEventButton *event, gpointer userdata) +{ + struct ct *ct = userdata; + + if (event->button != GDK_BUTTON_PRIMARY) + return TRUE; + + ct->doing_rubberband = FALSE; + + return FALSE; +} + +static gboolean +key_event(GtkWidget *widget, GdkEventKey *event, gpointer userdata) +{ + switch (event->type) { + case GDK_KEY_RELEASE: + switch (event->keyval) { + case GDK_KEY_q: + case GDK_KEY_Q: + gtk_main_quit(); + break; + } + return FALSE; + default: + return TRUE; + } +} + +static void +draw_rubberband(struct ct *ct, GtkWidget *widget, cairo_t *cr) +{ + GtkStyleContext *context; + double x, y, width, height; + + context = gtk_widget_get_style_context(widget); + gtk_style_context_save(context); + + gtk_style_context_add_class(context, GTK_STYLE_CLASS_RUBBERBAND); + calc_rubberband_rect(ct, &x, &y, &width, &height); + gtk_render_background(context, cr, x, y, width, height); + gtk_render_frame(context, cr, x, y, width, height); + + gtk_style_context_restore(context); +} + +static gboolean +draw_cb(GtkWidget *widget, cairo_t *cr, gpointer userdata) +{ + struct ct *ct = userdata; + + cairo_set_source_surface(cr, ct->surface, 0, 0); + cairo_paint(cr); + + if (ct->doing_rubberband) + draw_rubberband(ct, widget, cr); + + return FALSE; +} + +static void +capture(struct ct *ct) +{ + IplImage *image; + guchar *row1, *row2, *p1, *p2; + int x, y; + + image = cvRetrieveFrame(ct->capture, 0); + if (!image) { + fprintf(stderr, "ERROR: frame is null...\n"); + exit(EXIT_FAILURE); + } + + if (!ct->surface || + cairo_image_surface_get_width(ct->surface) != image->width || + cairo_image_surface_get_height(ct->surface) != image->height) { + if (ct->surface) + cairo_surface_destroy(ct->surface); + ct->surface = + cairo_image_surface_create(CAIRO_FORMAT_RGB24, + image->width, image->height); + } + + row1 = (guchar *) image->imageData; + row2 = cairo_image_surface_get_data(ct->surface); + for (y = 0; y < image->height; ++y) { + p1 = row1; + p2 = row2; + + for (x = 0; x < image->width; ++x) { + /* + p2[0] = p1[0]; + p2[1] = p1[1]; + p2[2] = p1[2]; + p2[3] = 0; + */ + memcpy(p2, p1, 3); + + p1 += image->nChannels; + p2 += 4; + } + row1 += image->widthStep; + row2 += cairo_image_surface_get_stride(ct->surface); + } +} + +static gboolean +grab(gpointer userdata) +{ + struct ct *ct = userdata; + + if (cvGrabFrame(ct->capture) == 0) + return TRUE; + + capture(ct); + gtk_widget_queue_draw(ct->drawing_area); + + return TRUE; +} + +int +main(int argc, char *argv[]) +{ + struct ct ct; + + memset(&ct, 0, sizeof ct); + + gtk_init(&argc, &argv); + + ct.capture = cvCreateCameraCapture(CV_CAP_ANY); + if (!ct.capture) { + fprintf(stderr, "ERROR: capture is NULL \n"); + exit(EXIT_FAILURE); + } + + cvSetCaptureProperty(ct.capture, CV_CAP_PROP_FRAME_WIDTH, 10000); + cvSetCaptureProperty(ct.capture, CV_CAP_PROP_FRAME_HEIGHT, 10000); + + printf("width: %.f, height: %.f\n", + cvGetCaptureProperty(ct.capture, CV_CAP_PROP_FRAME_WIDTH), + cvGetCaptureProperty(ct.capture, CV_CAP_PROP_FRAME_HEIGHT)); + + while (cvGrabFrame(ct.capture) == 0); + capture(&ct); + + ct.window = gtk_window_new(GTK_WINDOW_TOPLEVEL); + ct.drawing_area = gtk_drawing_area_new(); + + gtk_widget_set_size_request(ct.drawing_area, + cairo_image_surface_get_width(ct.surface), + cairo_image_surface_get_height(ct.surface)); + + gtk_container_add(GTK_CONTAINER(ct.window), ct.drawing_area); + + g_signal_connect(ct.window, "destroy", + G_CALLBACK(gtk_main_quit), NULL); + g_signal_connect(ct.window, "key-release-event", + G_CALLBACK(key_event), &ct); + + gtk_widget_set_events(ct.drawing_area, GDK_BUTTON1_MOTION_MASK | + GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK); + + g_signal_connect(ct.drawing_area, "draw", G_CALLBACK(draw_cb), &ct); + g_signal_connect(ct.drawing_area, "button-press-event", + G_CALLBACK(button_press_event), &ct); + g_signal_connect(ct.drawing_area, "button-release-event", + G_CALLBACK(button_release_event), &ct); + g_signal_connect(ct.drawing_area, "motion-notify-event", + G_CALLBACK(motion_notify_event), &ct); + + g_idle_add(grab, &ct); + gtk_widget_show_all(ct.window); + gtk_main(); + + cvReleaseCapture(&ct.capture); + + return 0; +} -- cgit