【问题标题】:How to get webcam feed to GTK window?如何将网络摄像头提要到 GTK 窗口?
【发布时间】:2016-02-18 06:57:55
【问题描述】:

我需要使用 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;
}

【问题讨论】:

  • 可能想看看直接与Gtk集成的奶酪库。
  • @TingPing 我已经担心了。问题是没有足够的学习材料开始。

标签: c opencv gtk cairo webcam-capture


【解决方案1】:

我在这里看到的主要问题是您没有正确地将您的 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)或在没有其他事件要处理时(g_idle_add)调用回调. 在该回调中调用gtk_widget_queue_draw 即可完成。

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

【讨论】:

  • 你是对的。现在我可以显示一帧。但是我们如何才能在没有循环的情况下获得连续帧呢?
  • 刚刚添加了有关此的更多信息
  • 对于这种特殊情况,添加 gtk_widget_queue_draw 和 g_timeout_add 有点不可思议。你能用一个简单的例子来解释一下吗?
  • 嘿,我找到了你的方法,现在它工作正常。
猜你喜欢
  • 1970-01-01
  • 2012-06-11
  • 2017-02-09
  • 1970-01-01
  • 2022-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-02-05
相关资源
最近更新 更多