In questo articolo daremo un’occhiata alle funzionalità di riconoscimento della posizione del viso dell’utente fornita di serie dall’Intel RealSense SDK.
L’articolo si riferisce alla versione 6.0.x dell’SDK di Intel® RealSense™ attualmente scaricabile all’indirizzo https://software.intel.com/en-us/intel-realsense-sdk/download
Cosa è Face Pose
Intel RealSense SDK permette di riconoscere la posizione di una faccia tracciata dalla camera in termini di posizione nello spazio e rotazione della stessa rispetto ai seguenti angoli:
- Imbardata (Yaw): angolo di rotazione della testa relativamente all’asse parallelo alla spina dorsale;
- Rollio (Roll): angolo di rotazione della testa rispetto all’asse perpendicolare alla faccia;
- Beccheggio (Pitch): angolo di rotazione della testa secondo l’asse passante per le orecchie.
L’immagine seguente chiarisce ulteriormente il discorso:
Abilitare il modulo di Face
I Face Pose sono una funzionalità di face tracking e, quindi, abbiamo la necessità di attivare il modulo stesso attraverso l’istanza di PXCMSenseManager ed in particolare utilizzando il metodo EnableFace:
SenseManager = PXCMSenseManager.CreateInstance(); SenseManager.EnableStream(PXCMCapture.StreamType.STREAM_TYPE_COLOR, 1280, 720); SenseManager.EnableFace();
Una volta abilitato l’utilizzo del modulo di face tracking, è necessario recuperare l’istanza del modulo stesso e lo possiamo fare utilizzando il metodo QueryFace della PXCMSenseManager:
FaceModule = SenseManager.QueryFace();
Il valore di ritorno del metodo è un’istanza della classe PXCMFaceModule.
Il modulo PXCMFaceModule
La classe PXCMFaceModule incapsula tutte le funzionalità che riguardano il face tracking degli utenti.
La sua struttura è la seguente:
La classe espone due metodi il cui utilizzo è il seguente:
- CreateActiveConfiguration: restituisce un oggetto di tipo che ci consente di configurare il modulo per decidere quali funzionalità vogliamo utilizzare (ad esempio il tracking o i landmarks);
- CreateOutput: permette di ottenere un oggetto di tipo che è l’handler attraverso il quale recuperare effettivamente i dati del viso che ci interessano.
Configurare il modulo di face tracking
La configurazione del modulo di face tracking (una volta abilitato tramite la PXCMSenseManager) avviene attraverso l’istanza della classe PXCMFaceConfiguration recuperata grazie al metodo CreateActiveConfiguration della classe PXCMFaceModule.
La classe di configurazione espone una serie di metodi che ci permettono di gestire gli alerts (che saranno presi in esame in un futuro articolo), gestire la tipologia di tracking (SetTrackingMode) e abilitare la funzionalità di Face Pose (proprietà pose).
Nel caso di face pose, argomento di questo articolo, possiamo configurare il modulo nel seguente modo:
var config = FaceModule.CreateActiveConfiguration(); config.detection.isEnabled = false; config.landmarks.isEnabled = false; config.pose.isEnabled = true; config.strategy = PXCMFaceConfiguration.TrackingStrategyType. STRATEGY_CLOSEST_TO_FARTHEST; if (config.ApplyChanges().IsSuccessful()) { if (SenseManager.Init().IsError()) { MessageBox.Show("Errore nell'inizializzazione della camera"); Close(); } } config.Dispose();
Nella fattispecie, abilitiamo i face pose e disabilitiamo il face detection e i face landmarks e scegliamo come strategia di tracking quella che prevede un tracciamento dei volti dal più vicino al più lontano.
La classe PoseConfiguration (classe innestata nella PXCMFaceConfiguration) ha la seguente struttura:
L’attributo isEnabled permette di abilitare la funzionalità, maxTrackedFaces definisce il numero massimo di facce che possono essere tracciate mentre smoothingLevel permette di impostare il livello di accuratezza del riconoscimento.
Se la configurazione viene applicata con successo (metodo ApplyChanges) possiamo cominciare a recuperare i frame ed analizzarli alla scoperta delle pose di eventuali facce rilevate.
Gestire i frame
Come già visto in precedenti articoli, abbiamo due approcci possibili per gestire il recupero dei frame (in questo caso quelli del modulo di face tracking) e l’analisi degli stessi.
Data l’istanza di PXCMSenseManager, possiamo:
- Implementare un loop all’interno del quale eseguiamo le opportune query ed analizziamo i frame;
- Ci affidiamo agli “eventi” sollevati dalla PXCMSenseManager.
Nell’esempio di questo articolo useremo il primo dei due approcci.
Per prima cosa, dunque, è necessario creare un task al cui “interno” faremo girare il nostro loop:
private Task PollingTask; private CancellationTokenSource TaskCancellationTokenSource; private CancellationToken PollingTaskCancellationToken; private void ConfigurePollingTask() { TaskCancellationTokenSource = new CancellationTokenSource(); PollingTaskCancellationToken = TaskCancellationTokenSource.Token; PollingTask = new Task(PollingCode); PollingTask.Start(); }
Il metodo PollingCode contiene l’effettivo codice di recupero dei frame (il loop) e utilizza il CancellationTokenSource per essere informato del momento in cui deve chiudersi (ad esempio perché l’applicazione si sta chiudendo).
private void PollingCode() { PXCMFaceData faceData = FaceModule.CreateOutput(); while (!PollingTaskCancellationToken.IsCancellationRequested) { if (SenseManager.AcquireFrame().IsSuccessful()) { faceData.Update(); var face = faceData.QueryFaceByIndex(0); var sample = SenseManager.QuerySample(); ElaborateSample(sample, face); if (!PollingTaskCancellationToken.IsCancellationRequested) SenseManager.ReleaseFrame(); } } }
Il primo step fondamentale per poter recuperare i dati relativi al face tracking è quello di ottenere l’istanza di PXCMFaceData che ci occorre per effettuare le opportune query allo scopo di ottenere i dati del tracking:
PXCMFaceData faceData = FaceModule.CreateOutput();
La classe PXCMFaceData ha la seguente struttura:
I metodi che ci interessano in questo caso sono:
- Update: permette di aggiornare l’handler PXCMFaceData con i dati correnti recuperati dalla camera relativamente ai volti tracciati;
- QueryFaceByIndex: permette di recuperare i dati di tracciatura (contenuti in un oggetto di classe PXCMFaceData.Face) del viso i-esimo.
In particolare per prima cosa abbiamo la necessità di dire all’SDK di eseguire l’acquisizione del frame attraverso la PXCMSenseManager:
if (SenseManager.AcquireFrame().IsSuccessful()) { // // ..... // }
In caso di acquisizione avvenuta con successo, possiamo aggiornare i dati relativi ai volti tramite il metodo Update e recuperare i dati relativi al primo volto tracciato:
faceData.Update(); var face = faceData.QueryFaceByIndex(0);
Il metodo QueryFaceByIndex restituisce, come già detto, un oggetto di classe PXCMFaceData.Face la cui struttura è la seguente:
Come possiamo vedere dalla precedente figura, la classe espone solamente dei metodi che ci consentono di recuperare le più svariate informazioni per la singola faccia.
Nel nostro caso, utilizzeremo il metodo QueryPose:
PXCMFaceData.PoseData poseData = face.QueryPose();
La classe PXCMFaceData.PoseData permette l’accesso alle informazioni relative ai face pose ed ha la seguente struttura:
I metodi hanno il seguente utilizzo:
- QueryConfidence: restituisce un valore intero tra 0 e 100 che indica con quale precisione (confidenza) la faccia è stata tracciata;
- QueryHeadPosition: restituisce una struttura dati che contiene la posizione del centro della faccia e un valore intero (confidence che indica la precisione con cui è stata rilevata);
- QueryPoseAngles: restituisce una struttura dati contenente gli angoli di rollio, beccheggio e imbardata citati in precedenza;
- QueryPoseQuaternion: restituisce una struttura dati contenente le informazioni del quaternione della faccia. I quaternioni forniscono una notazione matematica conveniente per la rappresentazione di orientamenti e rotazioni di oggetti in tre dimensioni. In confronto agli angoli di Eulero (PoseEulerAngles) presentano funzioni più semplici da comporre mentre in confronto con le matrici di rotazione più efficienti numericamente;
- QueryRotationMatrix: restituisce una matrice 3x3 di Single che rappresenta la matrice di rotazione della faccia.
Se, quindi, volessimo recuperare gli angoli di Eulero relativi ad imbardata, rollio e beccheggio, potremmo procedere con il seguente codice:
float pitchValue = 0, yawValue = 0, rollValue = 0; PXCMFaceData.PoseEulerAngles poseAngles; if (poseData.QueryPoseAngles(out poseAngles)) { pitchValue = poseAngles.pitch; yawValue = poseAngles.yaw; rollValue = poseAngles.roll; }
Conclusioni
Il modulo di face tracking espone molte funzionalità interessanti e di pronto utilizzo nelle nostre applicazioni. Il modo con cui si approccia a ciascuna di esse è sempre simile, l’unica variazione è l’impostazione della configurazione (in modo da abilitare le funzionalità che ci servono) e l’utilizzo degli opportuni metodi della classe Face.
L’esempio riportato in questo articolo è disponibile all’indirizzo https://github.com/massimobonanni/RealSenseSamples in cui potete trovare tutte le demo presenti nei miei articoli su RealSense.