Tag Archives: Qt

[Tutorial] Riconoscimento facce con OpenCV

Nei precedenti (parte 1, parte 2) ho illustrato come realizzare un Qt per le immagini in una GUI, è ora di realizzare un’applicazione pratica che sfrutti tutta la potenza OpenCV.

Il tutorial che segue illustrerà come realizzare un semplice Face Detector: un programma in grado di identificare tutte le facce presenti in ogni frame di un flusso video proveniente da un camera digitale (una webcam in questo caso particolare).
Per ogni faccia individuata sarà inoltre possibile scegliere se riconoscere anche la zona degli occhi, del naso e della bocca.
Il che andrò a illustrarvi è la base degli strumenti automatici (autoscatto sorrisi, autoscatto con occhi aperti, ecc) che ormai si trovano in tutte le macchine fotografiche digitali di ultima generazione.

Il tutorial vi permetterà di realizzare un’applicazione come quella mostrata nel seguente video:

La Face Detection sfrutta l’algoritmo “Cascade Classification” implementato in OpenCV e addestrato a riconoscere facce, occhi, nasi e bocche.
In questo caso particolare un primo classificatore si occuperà innanzitutto di identificare tutte le facce presenti nell’immagine analizzata, quindi per ogni faccia tre diversi classificatori identificheranno gli occhi, il naso e la bocca.

Iniziamo dal codice sorgente realizzato per la seconda parte del tutorial sul Widget Qt, che potete reperire qui.

Prima di tutto aggiungiamo al progetto il modulo OpenCV di “Object Detection”, apriamo il file “pro” e aggiungiamo il modulo della libreria:

LIBS +=  -lopencv_core \
               -lopencv_objdetect \
               -lopencv_highgui

Nel file della finestra principale della GUI inseriamo il seguente codice di inclusione:

#include "opencv2 /objdetect/objdetect.hpp"

e le seguenti variabili private:

int mCameraEventId;
cv::Mat mOrigImage;
cv::Mat mElabImage;
cv::VideoCapture mCapture;
// ---> Face detectors
cv::CascadeClassifier mFaceDetector;
cv::CascadeClassifier mEyeDetector;
cv::CascadeClassifier mMouthDetector;
cv::CascadeClassifier mNoseDetector;
// < --- Face detectors

Nella funzione di "Start" della camera dobbiamo verificare che i classificatori siano inizializzati:

void CMainWindow::on_actionStart_triggered()
{
   if( mFaceDetector.empty() )
      mFaceDetector.load( FEAT_FACE_FILE );
   if( mEyeDetector.empty() )
      mEyeDetector.load( FEAT_EYE_FILE );
   if( mNoseDetector.empty() )
      mNoseDetector.load( FEAT_NOSE_FILE );
   if( mMouthDetector.empty() )
      mMouthDetector.load( FEAT_MOUTH_FILE );
   if( !mCapture.isOpened() )
   {
      mCapture.open(0);
      mCameraEventId = startTimer( 50 );
   }
}

I classificatori per essere inizializzati hanno bisogno di quattro file, definiti con delle MACRO:

#define FEAT_FACE_FILE "haarcascade_frontalface_default.xml"
#define FEAT_EYE_FILE "haarcascade_mcs_eyepair_big.xml"
#define FEAT_NOSE_FILE "haarcascade_mcs_nose.xml"
#define FEAT_MOUTH_FILE "haarcascade_mcs_mouth.xml"

i quattro file devono essere copiati dalla cartella “[OpenCV]/data/haarcascades” nella cartella in cui viene generato l’eseguibile del nostro programma.

Inizializzati i classificatori è possibile utilizzarli ogni volta che la webcam ci fornirà una nuova immagine, cioè all’interno della funzione di gestione del timer (vd tutorial precedente):

void CMainWindow::timerEvent(QTimerEvent *event)
{
    if( event->timerId() == mCameraEventId )
    {
        // Stop Timer to stop receiving data from camera during elaboration
        killTimer( mCameraEventId );
        mCapture >> mOrigImage;
        mOrigImage.copyTo( mElabImage );
        if( ui->checkBox_fullFace->isChecked() )
        {
            vector< cv::Rect > faceVec;
            float scaleFactor = 1.5f; // Change Scale Factor to change speed
            mFaceDetector.detectMultiScale( mOrigImage, faceVec, scaleFactor );
            //mFaceDetector.detectSingleScale() mOrigImage, rectVec );
            for( size_t i=0; i Eye Detection
                if( ui->checkBox_eyes->isChecked() )
                {
                    vector< cv::Rect > eyeVec;
                    mEyeDetector.detectMultiScale( face, eyeVec );
                    for( size_t j=0; j Nose Detection
                if( ui->checkBox_nose->isChecked() )
                {
                    vector< cv::Rect > noseVec;
                    mNoseDetector.detectMultiScale( face, noseVec, 3 );
                    for( size_t j=0; j Mouth Detection
                // [Searched in the bottom half face]
                if( ui->checkBox_mouth->isChecked() )
                {
                    vector< cv::Rect > mouthVec;
                    cv::Rect halfRect = faceVec[i];
                    halfRect.height /= 2;
                    halfRect.y += halfRect.height;
                    cv::Mat halfFace = mOrigImage( halfRect );
                    mMouthDetector.detectMultiScale( halfFace, mouthVec, 3 );
                    for( size_t j=0; jcameraWidget->showImage( mElabImage );
        // Timer reactivation
        mCameraEventId = startTimer( 50 );
    }
}

Il codice è molto articolato, di seguito una descrizione riga per riga:

  • [3]: Verifica dell’ID del Timer che ha scatenato l’evento
  • [6]: Interruzione momentanea del timer in che la webcam non scateni nessun nuovo evento durante l’elaborazione dell’ultima immagine acquisita
  • [7]: Acquisizione dell’immagine
  • [8]: Copia dell’immagine originale in modo che le elaborazioni non la rovinino
  • [9]: Ricerca delle facce solo se abilitata (vd filmato di esempio)
  • [11]: Vettore contenente i Bounding Rect delle facce identificate
  • [12]: Parametro di scala per l’identificazione delle facce (vd documentazione OpenCV per maggiori dettagli
  • [13]: Ricerca delle facce nelle immagini. Questa funzione popolerà il vettore “faceVec” con tutti i rettangoli che contengono le facce identificate.
  • [15]: il “for” serve ad eseguire le elaborazioni di seguito descritte per ogni faccia identificata.
  • [17]: disegno in rosso del rettangolo della faccia corrente. Il rettangolo è disegnato su “mElabImage” in modo che l’immagine originale non venga sporcata per le successive elaborazioni.
  • [18]: estrazione dall’immagine originale della porzione che contiene unicamente la faccia analizzata. In questo modo possono essere estratte le “sottoparti” solo dalla faccia corrente.
  • [21]: verifica dell’attivazione della ricerca degli occhi
  • [23]: vettore contenente i rettangoli relativi alla zona degli occhi.
  • [24]: ricerca degli occhi
  • [25-31]: disegno dei rettangoli degli occhi (normalmente il rettangolo è uno solo visto che ognuno di noi ha solo due occhi ;-) )
  • [34-68]: analogamente a quanto fatto per gli occhi, ricercati il naso e la bocca.
  • [53-56]: per migliorare il risultato finale la bocca è ricercata solo nella metà inferiore della faccia.
  • [69]: visualizzazione del risultato
  • [71]: riattivazione del timer per l’acquisizione dell’immagine successiva

Il tutorial è giunto alla conclusione. Il codice dell’applicazione è disponibile qui.

Grazie a OpenCV un’operazione molto complessa come quella di riconoscere le facce e le loro sotto-parti può essere implementata con solo 70-80 righe di codice.
Dietro queste 80 righe di codice ci sono anni e anni di studi sull’intelligenza artificiale e il machine learning e vi invito a leggere la documentazione OpenCV per riendervi conto cosa effettivamente ci sia dietro.

Se volete discutere le tecniche utilizzate non esitate a contattarmi via email, su Facebook, Twitter o LinkedIn.

Tags: , , , , , , , , , , , ,

Qt Kinect Viewer Widget

A questo indirizzo è possibile trovare un per le nuvole di punti provenienti da e organizzate in formato (Point Cloud Library).
Il widget è ancora ad uno stadio “larvale”, ma è molto funzionale. Lo conosco bene in quanto l’ del io ( :) ), il widget è stato reso pubblico in questo stadio iniziale a scopo pubblicitario, quindi se decidete di utilizzarlo fate un po’ di pubblicità :)

Tags: , , , , , , , , ,

Microsoft Kinect e Qt/libfreenect

Un video del che ho realizzato per il Centro di Ricerca Gustavo Stefanini di La Spezia, con cui collaboro tramite l’azienda per cui lavoro.
Utilizzando 4.7.1 (), e l’ libfreenect ho realizzato un’interfaccia per la visualizzazione dei dati 2D e 3D provenienti dall’ottimo RGBD prodotto da per il mondo videoludico, ma ampiamente utilizzato dalla comunità internazionale in robotica e nell’interfacciamento /macchina.

Tags: , , , , , , , , , , ,

[New Tutorial] Nuova interfaccia Kinect in OpenCV

Una novità fresca fresca riguardo OpenCV e . In un di giornata è stata annunciata l’integrazione dell’acquisizione da direttamente in OpenCV tramite interfaccia “standard” cv:: capture.
La nuova funzionalità è disponibile solo nell’ultima versione SVN.

Sto preparando un suo utilizzo e sulla creazione di un widget in per la visualizzazione sia delle immagini estratte dal , sia nuvola di punti 3D delle distanze in metri calcolate.

Restate collegati per le novità a riguardo.

===============================================

Aggiornamento del 19 Febbraio 2011

Purtroppo l’interfaccia messa a disposizione da OpenCV utilizza l’ per Kinect OpenNUI. Questo richiede l’utilizzo del compilatore di Visual Studio.
Visto che per lo sviluppo delle mie interfacce utilizzo Qt in ambiente Eclipse, l’utilizzo del compilatore non mi permetterebbe di effettuare il debug dell’applicazione (spero che prima o poi si decidano a integrare anche questa possibilità visto che Qt Creator ad esempio lo permette!).

Per questo motivo sto realizzando il mio sistema di interfacciamento e visualizzazione dei dati per il Kinect basato su OpenCV, OpenGL e Qt utilizzando come compilatore e le librerie opensource di gestione del Kinect “Libfreenect”, qui disponibili.

Tags: , , , , ,
Powered by WordPress | Designed by: Email Search