2017-07-17 83 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