如何将网络摄像头提供给GTK窗口?

时间:2016-02-18 06:57:56

标签: c opencv gtk cairo webcam-capture

我需要使用C,GTK2 / 3,Cairo获取网络摄像头视频。 但无法找到任何关于它的参考资料。

下面显示了我如何尝试使用opencv。这是不成功的。我需要知道一些使用gstreamer,cairo的其他方法。

我期待简单的代码将视频传输到GTK窗口。真的很感激,如果有人可以提供示例代码。

    /*
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;
}

1 个答案:

答案 0 :(得分:2)

我在这里看到的主要问题是你没有正确地将你的opencv代码集成到GTK事件模型中。

GTK基本上可以使用消息泵。消息在队列中发送,GTK读取并取消它们以对这些消息作出反应。在GTK 2中,当需要绘制小部件或其一部分时触发expose-event事件(在GTK 3中,使用draw事件)。您可以绘制一个帧,然后将控制权交还给GTK。它会在需要下一帧时给你打电话。

这里的问题是你永远不会把手交还给GTK,因为你的opencv代码是在无限while(1)循环中包围的。您应该只绘制一个帧,然后返回。

关键事件逻辑也应使用GTK处理,而不是在expose-event回调中处理。一旦看到你正在等待的击键,就打电话给gtk_main_quit

修改

一旦显示一帧,就必须全部显示。调用gtk_widget_queue_draw告诉GTK需要重新绘制窗口小部件。

完成此操作后,您会发现需要某种方式定期调用gtk_widget_queue_draw。使用g_timeout_addg_idle_add等GLib功能可以轻松完成此操作。这些函数告诉主事件循环(我称之为“消息泵”上面的“),在确定的时间(g_timeout_add)之后调用回调,或者只是在没有其他事件需要处理时({{ 1}})。在回调中调用g_idle_add,你就完成了。

请注意,g_timeout_add不允许具有完美的时序,因此每帧之间的时间可能因帧而异。您可以通过增加传递给g_timeout_add的优先级来避免这种情况。您还可以使用GTimer在超时回调中计算最后一帧与当前时间之间经过的时间,并推断到下一帧之前的剩余时间。然后用更准确的时间调用g_timeout_add。如果使用gtk_widget_queue_draw技巧,请不要忘记在超时回调结束时返回FALSE而不是TRUE,否则您将在GTimer帧处运行n超时回调。< / p>