2016-02-18 1 views
0

Je dois obtenir le flux vidéo de la webcam en utilisant C, GTK2/3, Cairo. Cependant, ne trouve pas de références à ce sujet.Comment obtenir le flux de la webcam vers la fenêtre GTK?

Ci-dessous montre comment j'ai essayé d'utiliser opencv. Il est infructueux. J'ai besoin de connaître une autre méthode utilisant gstreamer, cairo.

Je m'attends à du code simple pour obtenir la vidéo dans la fenêtre GTK. Vraiment apprécier si quelqu'un peut fournir un exemple de code.

/* 
gcc -o weby3 att3.c `pkg-config --libs --cflags gtk+-2.0 opencv` 
*/ 

#include "highgui.h" 
#include <gtk/gtk.h> 
#include <opencv/cv.h> 
#include <opencv/cxcore.h> 

GdkPixbuf* pix; 
IplImage* frame; 
CvCapture* capture; 

gboolean 
expose_event_callback(GtkWidget *widget, GdkEventExpose *event, gpointer data) 
{ 
    while(1) { 
     frame = cvQueryFrame(capture); 
      if(!frame) break; 

     pix = gdk_pixbuf_new_from_data((guchar*) frame->imageData, 
     GDK_COLORSPACE_RGB, FALSE, frame->depth, frame->width, 
     frame->height, (frame->widthStep), NULL, NULL); 


     gdk_draw_pixbuf(widget->window, 
    widget->style->fg_gc[GTK_WIDGET_STATE (widget)], pix, 0, 0, 0, 0, 
    -1, -1, GDK_RGB_DITHER_NONE, 0, 0); /* Other possible values are GDK_RGB_DITHER_MAX, GDK_RGB_DITHER_NORMAL */ 

     char c = cvWaitKey(33); 
     if(c == 27) break; 
    } 

    cvReleaseCapture(&capture); 
    return TRUE; 
} 

int main(int argc, char** argv) { 

    /* GtkWidget is the storage type for widgets */ 
    GtkWidget *window; 
    GtkWidget *drawing_area; 

    gtk_init (&argc, &argv); 

    CvCapture* capture = cvCreateCameraCapture(0); 
    /* create a new window */ 
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL); 
    gtk_window_set_title (GTK_WINDOW (window), "Hello WebCam and OpenCV!"); 
    g_signal_connect (G_OBJECT (window), "destroy", 
    G_CALLBACK (gtk_main_quit), NULL); 

    /* Sets the border width of the window. */ 
    gtk_container_set_border_width (GTK_CONTAINER (window), 10); 

    /* Now add a child widget to the aspect frame */ 
    drawing_area = gtk_drawing_area_new(); 


    /* window since we are forcing a aspect ratio */ 
    gtk_widget_set_size_request(drawing_area, 600, 400); 
    gtk_container_add(GTK_CONTAINER (window), drawing_area); 
    gtk_widget_show(drawing_area); 

    g_signal_connect (G_OBJECT (drawing_area), "expose_event", 
     G_CALLBACK (expose_event_callback), NULL); 

    /* and the window */ 
    gtk_widget_show (window); 

    /* All GTK applications must have a gtk_main(). Control ends here 
    * and waits for an event to occur (like a key press or 
    * mouse event). */ 
    gtk_main(); 

    return 0; 
} 
+0

Peut vouloir vérifier la bibliothèque de fromage qui s'intègre directement avec Gtk. – TingPing

+0

@TingPing Je m'inquiétais déjà. Le problème est qu'il n'y a pas assez de matériel d'apprentissage pour commencer. – inckka

Répondre

2

Le problème principal que je vois ici est que vous n'intégrez pas correctement votre code opencv dans le modèle d'événement GTK.

GTK fonctionne fondamentalement avec une pompe de message. Les messages sont envoyés dans une file d'attente et GTK les lit et les désactive pour réagir à ces messages. Dans GTK 2, l'événement expose-event est déclenché lorsqu'un widget ou une partie de celui-ci doit être dessiné (dans GTK 3, utilisez l'événement draw). Vous êtes censé dessiner une seule image, puis redonner le contrôle à GTK. Il vous appellera quand il aura besoin de l'image suivante.

Le problème ici est que vous ne remettez jamais la main à GTK, car votre code opencv est enclins dans une boucle infinie while(1). Vous devriez plutôt dessiner un seul cadre, et revenir.

La logique d'événement clé doit également être gérée à l'aide de GTK, et non dans votre rappel expose-event. Appelez simplement gtk_main_quit une fois que vous avez vu la frappe que vous attendez.

EDIT:

Une fois que vous pouvez afficher une image, vous devez les afficher tous. Appelez gtk_widget_queue_draw pour indiquer à GTK que le widget doit être redessiné.

Une fois cela fait, vous verrez que vous avez besoin d'un moyen d'appeler gtk_widget_queue_draw périodiquement. Ceci est facilement fait avec les fonctions GLib comme g_timeout_add ou . Ces fonctions indiquent à la boucle d'événement principale (ce que j'ai appelé "message pump" ci-dessus ") d'appeler un rappel après une durée déterminée (pour g_timeout_add) ou juste lorsqu'il n'y a pas d'autres événements à traiter (pour g_idle_add). Rappelez-vous que g_timeout_add ne permet pas d'avoir un timing parfait, donc le temps entre chaque image peut être trop différent d'une image à l'autre, vous pouvez éviter cela en augmentant la priorité Vous pouvez également utiliser un GTimer pour calculer le temps écoulé entre la dernière image et l'heure actuelle, et déduire le temps restant jusqu'à la prochaine image, puis appeler g_timeout_add avec un temps plus précis. pour retourner FALSE au lieu de TRUE à la fin du rappel de timeout si vous utilisez le GTimer tour, sinon vous aurez n rappels de délai d'attente en cours d'exécution à l'image n.

+0

Vous avez raison. Maintenant, je peux afficher un cadre. Mais comment pouvons-nous obtenir des images continues sans boucle? – inckka

+0

Juste ajouté plus d'informations à ce sujet – liberforce

+0

Pour ce scénario particulier, ajouter un gtk_widget_queue_draw et g_timeout_add est un peu étrange. pouvez-vous expliquer cela en utilisant un exemple rapide s'il vous plaît? – inckka