2017-07-17 5 views
1

Ich erstelle ein bewegliches Fenster, das Gesichtserkennungs-Koordinaten als Eingabe verwendet, um die neue Position des Fensters zuzuweisen. Momentan ist die Gesichtserkennung funktional, aber das Fenster wird erst am Ende der Aufnahme-Schleife angezeigt.GTK + Fenster in Echtzeit verschieben

Meine Fragen sind:
-wie kann ich das Fenster im Blick behalten die gesamte Zeit die Bilderfassung und Gesichtserkennung stattfindet?
-Ist eine Schleife "gtk_main" erforderlich, und wird sie in diesem Szenario ordnungsgemäß verwendet?
-Warum öffnet sich das Fenster nicht, selbst wenn "gtk_widget_show (window)" in der Capture-Schleife platziert ist?
- Gibt es ein besseres Forum für detailliertere Fragen zu GTK +?

Ich möchte dies nach OpenCVs "moveWindow" -Funktion modellieren. Diese Funktion funktioniert perfekt für das, was ich brauche, das einzige Problem bei der Verwendung dieser Funktion ist, dass ich das Fenster nicht anpassen kann.

Quellcode für OpenCV des „Movewindow“ -Funktion: Sehen Sie unter window.cpp und 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

Möglicherweise müssen Sie mehr als eine 'gtk_main_iteration()' pro Schleife ausführen. Versuchen Sie ['gtk_events_pending()'] (https://developer.gnome.org/gtk3/stable/gtk3-General.html#gtk-events-pending). –

+0

Danke für den Rat Dan hat funktioniert. Obwohl ich befürchte, dass dies jede Aktion in der gtk_main-Schleife in der GTK + Params-Sektion dieses Programms wiederholt, was die Dinge drastisch verlangsamt. OpenCVs Version ist ziemlich schnell, während dieser Weg langsam ist. –

Antwort

1

Der beste Ansatz ist die Gesichtserkennung Verfahren und die GUI-Operationen in zwei verschiedenen Threads zu trennen , sollte die GUI immer im Hauptthread laufen (oder dem, der das Fenster an erster Stelle erstellt hat, dies ist nicht unbedingt notwendig für X11, aber es ist zum Beispiel in Win32 und Cocoa GTK Backends).

Der Erkennungs-Thread kann dann nach Bedarf eine Schleife durchlaufen und die Fensteraktualisierungen an den Hauptthread senden und den Leerlauf-Rückruf verwenden. Dies ist der häufig verwendete GTK-Ansatz für Multithread.

Hier ist ein Code (eine Stützfunktion und eine alternative Einfangschleife), die den Ansatz erklärt:

/// 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(); 

[...] 

Beachten Sie, dass auch „Fenster“ eine globale Variable (oder ein Klassenmitglied) machen können und machen x und y std :: atomic, um zu vermeiden, dass WindowData für jede Fensterbewegung zugewiesen/freigegeben werden muss.

+0

Danke @gabry, das war sehr hilfreich. Ich erhalte den Fehler "'p' wurde in diesem Bereich nicht deklariert" beim Kompilieren, weißt du, warum das so ist? Muss sich die Variable 'window' auch in der Capture-Liste befinden? std :: thread t ([window] {})? –

+0

Fixed, das war Pseudo-Code, ja Fenster sollte in der Aufnahmeliste sein, habe ich meine Antwort korrigiert. – gabry

Verwandte Themen