summaryrefslogtreecommitdiff
path: root/capture.c
diff options
context:
space:
mode:
Diffstat (limited to 'capture.c')
-rw-r--r--capture.c251
1 files changed, 251 insertions, 0 deletions
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 <stdlib.h>
+#include <string.h>
+#include <math.h>
+#include <glib.h>
+#include <gtk/gtk.h>
+
+#include <cv.h>
+#include <highgui.h>
+
+/* 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;
+}