#include #include #include #include #include struct cvg { GtkWidget *drawing_area1; GtkWidget *drawing_area2; GtkButton *open_btn; CvCapture *capture; IplImage *image; IplImage *output; cairo_surface_t *input_surface; cairo_surface_t *output_surface; guint last_press; int idle_source; IplImage *(*filter)(struct cvg *cvg, IplImage *image); }; 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; } static void update_right_drawing_area(struct cvg *cvg) { if (!cvg->image) return; if (cvg->output) cvReleaseImage(&cvg->output); cvg->output = cvg->filter(cvg, cvg->image); if (cvg->output_surface) cairo_surface_destroy(cvg->output_surface); cvg->output_surface = NULL; if (cvg->output) cvg->output_surface = cairo_surface_create_from_ipl_image(cvg->output); gtk_widget_queue_draw(cvg->drawing_area2); } static gboolean capture(gpointer userdata) { struct cvg *cvg = userdata; IplImage *image; image = cvQueryFrame(cvg->capture); if (!image) { fprintf(stderr, "ERROR: frame is null...\n"); exit(EXIT_FAILURE); } if (cvg->image) cvReleaseImage(&cvg->image); if (cvg->input_surface) cairo_surface_destroy(cvg->input_surface); cvg->image = cvCreateImage(cvGetSize(image), image->depth, image->nChannels); cvCopy(image, cvg->image, NULL); if (!cvg->image) return FALSE; cvg->input_surface = cairo_surface_create_from_ipl_image(cvg->image); gtk_widget_queue_draw(cvg->drawing_area1); update_right_drawing_area(cvg); return TRUE; } static void stop_capture(struct cvg *cvg) { if (cvg->idle_source) { g_source_remove(cvg->idle_source); cvg->idle_source = 0; } } 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_o: g_signal_emit_by_name(cvg->open_btn, "released", NULL); if (cvg->last_press == event->keyval) g_signal_emit_by_name(cvg->open_btn, "clicked", NULL); break; } return FALSE; case GDK_KEY_PRESS: cvg->last_press = event->keyval; switch (event->keyval) { 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_s: case GDK_KEY_S: stop_capture(cvg); break; case GDK_KEY_c: case GDK_KEY_C: if (!cvg->idle_source) cvg->idle_source = g_idle_add(capture, cvg); 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; stop_capture(cvg); filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(widget)); open_file(cvg, filename); g_free(filename); gtk_widget_queue_draw(cvg->drawing_area1); update_right_drawing_area(cvg); } static IplImage * pass_through_filter(struct cvg *cvg, IplImage *image) { IplImage *out; out = cvCreateImage(cvGetSize(image), image->depth, image->nChannels); cvCopy(image, out, NULL); return out; } static IplImage * gauss_filter(struct cvg *cvg, IplImage *image) { IplImage *out; out = cvCreateImage(cvGetSize(image), image->depth, image->nChannels); cvSmooth(image, out, CV_GAUSSIAN, 9, 9, 0, 0); return out; } static IplImage * sobel_filter(struct cvg *cvg, IplImage *image) { IplImage *out, *tmp, *tmp2, *gray; gray = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1); tmp = cvCreateImage(cvGetSize(image), IPL_DEPTH_16S, 1); tmp2 = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1); out = cvCreateImage(cvGetSize(image), image->depth, image->nChannels); cvCvtColor(image, gray, CV_BGR2GRAY); cvSobel(gray, tmp, 0, 1, 3); cvConvertScaleAbs(tmp, tmp2, 1, 0); cvCvtColor(tmp2, out, CV_GRAY2BGR); cvReleaseImage(&gray); cvReleaseImage(&tmp); cvReleaseImage(&tmp2); return out; } static IplImage * good_features_to_track(struct cvg *cvg, IplImage *image) { IplImage *output, *gray_frame, *eig_image, *temp_image; CvPoint2D32f corners[100]; int corner_count = sizeof(corners)/sizeof(corners[0]); double quality_level = 0.1, min_distance = 5; int i, eig_block_size = 3, use_harris = 0; output = pass_through_filter(cvg, image); gray_frame = cvCreateImage(cvGetSize(image), IPL_DEPTH_8U, 1); eig_image = cvCreateImage(cvGetSize(image), IPL_DEPTH_32F, 1); temp_image = cvCreateImage(cvGetSize(image), IPL_DEPTH_32F, 1); cvCvtColor(image, gray_frame, CV_BGR2GRAY); memset(corners, 0, sizeof corners); cvGoodFeaturesToTrack(gray_frame, eig_image, temp_image, corners, &corner_count, quality_level, min_distance, NULL, eig_block_size, use_harris, 0.04); for (i = 0; i < corner_count; ++i) { CvPoint center = { corners[i].x, corners[i].y }; cvCircle(output, center, 5, CV_RGB(255, 0, 0), 3, 8, 0); } cvReleaseImage(&gray_frame); cvReleaseImage(&eig_image); cvReleaseImage(&temp_image); return output; } static IplImage * hide_filter(struct cvg *cvg, IplImage *image) { return NULL; } 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); } void method_set(GtkComboBox *widget, gpointer userdata) { struct cvg *cvg = userdata; gchar *text; text = gtk_combo_box_text_get_active_text(GTK_COMBO_BOX_TEXT(widget)); if (text == NULL) return; if (strcmp(text, "Gauss") == 0) cvg->filter = gauss_filter; else if (strcmp(text, "GoodFeaturesToTrack") == 0) cvg->filter = good_features_to_track; else if (strcmp(text, "Pass-Through") == 0) cvg->filter = pass_through_filter; else if (strcmp(text, "Sobel") == 0) cvg->filter = sobel_filter; else if (strcmp(text, "Hide") == 0) cvg->filter = hide_filter; update_right_drawing_area(cvg); } int main(int argc, char *argv[]) { struct cvg cvg; GtkBuilder *builder; GObject *file_chooser; GObject *combobox; gchar *path, *file; int index = 0; memset(&cvg, 0, sizeof cvg); gtk_init(&argc, &argv); if (argc >= 2) open_file(&cvg, argv[argc-1]); cvg.capture = cvCreateCameraCapture(index); if (!cvg.capture) { fprintf(stderr, "ERROR: capture is NULL \n"); exit(EXIT_FAILURE); } #if 1 cvSetCaptureProperty(cvg.capture, CV_CAP_PROP_FRAME_WIDTH, 10000); cvSetCaptureProperty(cvg.capture, CV_CAP_PROP_FRAME_HEIGHT, 10000); #endif printf("width: %.f, height: %.f\n", cvGetCaptureProperty(cvg.capture, CV_CAP_PROP_FRAME_WIDTH), cvGetCaptureProperty(cvg.capture, CV_CAP_PROP_FRAME_HEIGHT)); builder = gtk_builder_new(); path = g_path_get_dirname(argv[0]); file = g_build_filename(path, "cvg.ui", NULL); gtk_builder_add_from_file(builder, file, NULL); g_free(path); g_free(file); 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")); 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); combobox = gtk_builder_get_object(builder, "comboboxtext1"); gtk_combo_box_set_active(GTK_COMBO_BOX(combobox), 0); cvg.idle_source = g_idle_add(capture, &cvg); cvg.filter = hide_filter; gtk_widget_show_all(GTK_WIDGET(gtk_builder_get_object(builder, "win"))); g_object_unref(builder); gtk_main(); destroy_images(&cvg); return 0; }