如何将网络摄像头提要发送到GTK窗口? [英] How to get webcam feed to GTK window?

查看:52
本文介绍了如何将网络摄像头提要发送到GTK窗口?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要使用C,GTK2/3,开罗获取网络摄像头视频供稿.但是找不到关于它的任何引用.

I need to get webcam video feed using C, GTK2/3, Cairo. However can't find any references about it.

下面显示了如何尝试使用opencv.无法成功.我需要使用gstreamer,cairo了解其他方法.

Below shows how did I try using opencv. It is unsuccessful.I need to know some other method using gstreamer, cairo.

我期望通过简单的代码将视频传递到GTK窗口.非常感谢有人可以提供示例代码.

I'm expecting simple code to get video to GTK window. Really appreciate if someone can provide example 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;
}

推荐答案

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

The main problem I see here is that you're not properly integrating your opencv code into the GTK event model.

GTK基本上与消息泵一起使用.消息以队列发送,而GTK读取并取消排队以对这些消息作出反应.在GTK 2中,当需要绘制窗口小部件或其一部分时,发出 expose-event 事件(在GTK 3中,使用 draw 事件).您可能想将回调连接到该事件以捕获该事件.然后在回调中,绘制一个框架,然后将控件交还给GTK.需要下一帧时,它将再次调用您的回调.

GTK basically works with a message pump. Messages are sent in a queue, and GTK reads and unqueue them to react to those messages. In GTK 2, the expose-event event is emitted when a widget or portion of it needs to be drawn (in GTK 3, the draw event is used). You're suposed to connect a callback to that event to catch the event. Then in your callback, you draw a single frame, and then give the control back to GTK. It will call your callback again when it needs the next frame.

这里的问题是,您永远不会将手交给GTK,因为您的opencv代码包含在无限的 while(1)循环中.您应该只画一个框架然后返回.

The problem here is that you never give the hand back to GTK, as your opencv code is enclosed in an infinite while(1) loop. You should instead just draw a single frame, and return.

键事件逻辑也应使用GTK处理,而不应在 expose-event 回调中进行.看到等待的按键后,只需致电 gtk_main_quit .

The key event logic should also be handled using GTK, and not in your expose-event callback. Just call gtk_main_quit once you have seen the keystroke you're waiting for.

一旦可以显示一帧,就必须全部显示.呼叫 gtk_widget_queue_draw 告诉GTK,该小部件需要重绘.

Once you can display one frame, you have to display them all. Call gtk_widget_queue_draw to tell GTK that the widget needs to be redrawn.

完成此操作后,您将看到需要定期调用 gtk_widget_queue_draw 的某种方式.这可以通过GLib函数轻松实现,例如 g_timeout_add g_idle_add .这些函数告诉主事件循环(在上面称为消息泵"),在确定的时间(对于 g_timeout_add )之后,或者在没有其他事件需要处理时,才调用回调(for g_idle_add ).在该回调中调用 gtk_widget_queue_draw 即可.

Once this is done, you'll see that you need some way of calling gtk_widget_queue_draw periodically. This is easilly done with GLib functions like g_timeout_add or g_idle_add. These functions tell the main event loop (what I called "message pump" above") to call a callback after a determined amount of time (for g_timeout_add) or just when there is no other events to process (for g_idle_add). Call gtk_widget_queue_draw in that callback and you're done.

请注意,g_timeout_add不允许有完美的定时,因此,每一帧之间的时间可能在一个帧与另一个帧之间的时间差异太大.您可以通过增加传递给g_timeout_add的优先级来避免这种情况.您还可以使用GTimer在超时回调中计算从上一帧到当前时间之间经过的时间,并推断出直到下一帧为止的剩余时间.然后使用更准确的时间调用g_timeout_add.如果使用 GTimer 技巧,请不要忘记在超时回调的末尾返回FALSE而不是TRUE,否则,您将在帧<下运行 n 超时回调代码> n .

Be aware that g_timeout_add doesn't allow to have a perfect timing, so the time between each frame may be too different from one frame to another. You may avoid this by augmenting the priority passed to g_timeout_add. You may also use a GTimer to compute in your timeout callback the time elapsed between the last frame and the current time, and deduce time remaining until your next frame. Then call g_timeout_add with that more accurate time. Don't forget to return FALSE instead of TRUE at the end of the timeout callback if you use the GTimer trick, otherwise you'll have n timeout callbacks running at frame n.

这篇关于如何将网络摄像头提要发送到GTK窗口?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆