2017-07-17 87 views
1

我正在创建一个移动窗口,该窗口使用人脸检测坐标作为输入来分配窗口的新位置。目前,人脸检测功能正常,但直到捕捉循环的最后才显示窗口。实时移动GTK +窗口

我的问题是:
- 如何在整个拍摄和脸部检测过程中保持窗口?
- 是否需要“gtk_main”循环,是否在此场景中正确使用?
- 即使当“gtk_widget_show(window)”被放置在捕获循环中时,窗口为什么不打开?
- 是否有更好的论坛提供更详细的GTK +问题?

我想在OpenCV的“moveWindow”函数之后进行建模。这个函数对于我所需要的完美工作,使用这个函数的唯一问题是我无法自定义窗口。对于OpenCV的的“的MoveWindow”功能

的源代码:下window.cpp和window_gtk.cpp 看 https://github.com/opencv/opencv/tree/master/modules/highgui/src

#include "FlyCapture2.h" 
#include <opencv2/core/core.hpp> 
#include <opencv2/highgui/highgui.hpp> 
#include <opencv2/objdetect/objdetect.hpp> 
#include <opencv2/core/cuda.hpp> 
#include <opencv2/cudalegacy/NCVHaarObjectDetection.hpp> 
#include <opencv2/cudaobjdetect.hpp> 
#include <math.h> 
#include <thread> 
#include <iostream> 
#include <vector> 
#include <gtk-3.0/gtk/gtk.h> 

using namespace FlyCapture2; 


cv::Ptr<cv::cuda::CascadeClassifier> face_detect; 

int x,y; 

void detect_faces(cv::Mat img, cv::cuda::GpuMat buf) 
{ 
    std::vector<cv::Rect>faces; 

    //Detect faces 
    ... 

    if (faces.size() > 0) 
    { 
     float x_f = faces[0].x; 
     float y_f = faces[0].y; 
     x = roundf(x_f*40/51); 
     y = roundf(y_f*135/256);  

    } 

} 

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

    //Camera initialization 
    ... 

    //face detect variables 
    face_detect = cv::cuda::CascadeClassifier::create("/home/nvidia/opencv/data/haarcascades_cuda/haarcascade_frontalface_default.xml"); 
    cv::cuda::GpuMat objbuf; 

    //GTK+ Params 
    GtkWidget *window; 
    gtk_init (&argc, &argv); 
    window = gtk_window_new (GTK_WINDOW_TOPLEVEL); 
    gtk_window_set_decorated(GTK_WINDOW (window),FALSE); 
    gtk_window_set_position(GTK_WINDOW (window), GTK_WIN_POS_CENTER); 
    gtk_widget_show (window); 

    // capture loop 
    double t = (double)cv::getTickCount(); 
    for (int i=0;i<100;i++) 
    { 
     // Get the image 
     ... 

     // convert to OpenCV Mat 
     ... 


     //Detect Faces 
     detect_faces(image,objbuf); 
      std::cout<<"x: "<<x<<" "<<"y: "<<y<<std::endl; 
     gtk_window_move(GTK_WINDOW (window),x,y); 
     while (gtk_events_pending()) 
      gtk_main_iteration(); 

    } 

    //Record Time 
    t = ((double)cv::getTickCount() - t)/cv::getTickFrequency(); 
     std::cout << "Time: " << (t/100)*1000 << std::endl; 

    //Disconnect Camera 
    camera.StopCapture(); 
    camera.Disconnect(); 

    gtk_main(); 

    return 0; 
} 
+0

您可能需要为每个循环运行多个gtk_main_iteration()。尝试['gtk_events_pending()'](https://developer.gnome.org/gtk3/stable/gtk3-General.html#gtk-events-pending)。 –

+0

感谢您的建议丹这工作。虽然,我担心这会重复GTK + Params部分中gtk_main循环中的所有操作,从而大幅减慢速度。 OpenCV的版本相当快,而这种方式很慢。 –

回答

1

最好的办法是在两个不同的线程分开的面部识别程序和GUI操作,GUI应该总是在主线程中运行(或者是首先创建窗口的那个,这在X11上并不是必需的,但它在Win32和Cocoa GTK后端)。

然后识别线程可以根据需要忙于循环,并将窗口更新“发送”到主线程使用和空闲回调。这是常用的GTK多线程方法。

下面是一些代码(支持功能和替代捕集环),解释方法:

/// support function 
struct WindowData 
{ 
    GtkWindow win; 
    int x, y; 
}; 

int move_window(WindowData *p) 
{ 
    gtk_move_window(p->win, p->x, p->y); 
    delete p; 
    return FALSE; 
} 

[...] 

// updated capture loop inside main (capture the variables you need, or this if you are working in a class environment 
std::thread t([window, image, objectbuf]{ 
    for (int i=0;i<100;i++) { 
     // Get the image 
     ... 
     // convert to OpenCV Mat 
     ... 

     //Detect Faces 
     detect_faces(image,objbuf); 
     WindowData *p = new WindowData(); 
     p.win = window; 
     p.x = x; p.y = y; 
     g_idle_add((GFunction)move_window, p); 

    } 
}); 
gtk_main(); 
t.join(); 

[...] 

请注意,您还可以使“窗口”全局变量(或类成员),并x和y std :: atomic以避免需要为每个窗口移动分配/取消分配WindowData。

+0

谢谢@gabry,这非常有帮助。我收到错误“'p'在编译时未在此范围内声明”,你知道这可能是为什么吗?另外,变量'窗口'是否必须在捕获列表中 std :: thread t([window] {})? –

+0

修正,这是伪代码,是窗口应该在捕获列表中,我已经纠正了我的答案。 – gabry