In questo articolo cominceremo ad analizzare in dettaglio le classi e le interfacce esposte dall’Intel® RealSense™ SDK ed in particolare cominceremo analizzando la PXCSession (o meglio la omologa PXCMSession dedicata al mondo .NET).
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
La classe PXCMSession
Riprendendo il discorso architetturale, già visto in un precedente articolo, l’SDK è composto, ad eccezione delle funzionalità core e di infrastruttura, di moduli di I/O e di moduli algoritmici (tipicamente i moduli che contengono gli algoritmi di riconoscimento facciale, delle gesture, vocale e via dicendo).
La classe PXCMSession (omologa della PXCSession nativa), può essere vista come una sorta di contesto che permette l’accesso all’insieme dei moduli (sia I/O che algoritmici).
Una applicazione che fa uso di Intel® RealSense™ SDK può utilizzare una o più istanze della PXCMSession e, ognuna delle quali ha un proprio contesto distinto e separato dalle altre.
La PXCMSession ci consente di creare istanze per qualsiasi classe o interfaccia dell’SDK e viene utilizzata quando abbiamo necessità di un completo controllo sulla gestione degli oggetti dell’SDK stesso.
Nella seguente figura possiamo vedere la struttura della PXCMSession:
La classe PXCMBase è la classe base di tutte le classi dell’SDK.
Osserviamo che la classe PXCMSession (come la PXCMBase da cui deriva) espone una costante pubblica denominata CUID che rappresenta l’identificativo univoco della classe all’interno dell’SDK (di tipo intero).
Questa è una caratteristica comune a tutte le classi dell’SDK: ognuna espone un proprio identificativo univoco che può essere utilizzato per poterla creare attraverso delle factory.
Per poter creare un’istanza valida di PXCMSession possiamo sfruttare il metodo statico CreateInstance che funge da Factory method per la classe:
dim session = PXCMSession.CreateInstance()
Una volta ottenuta un’istanza della PXCMSession, possiamo sfruttarla per creare qualsiasi modulo ci interessa utilizzando il metodo CreateImpl o uno dei metodi Create specializzato per un particolare modulo.
Il metodo CreateImpl è la versione generica che ci permette di ottenere una istanza di un modulo a partire, ad esempio dal tipo del modulo o dal suo CUID.
In realtà, questo metodo fornisce una istanza di PXCMBase che sta a noi fare il cast al tipo corretto.
Se, ad esempio, volessimo creare un’istanza di PXCMSenseManager utilizzando il metodo CreateImpl, dovremo scrivere:
Dim cuid = PXCMSenseManager.CUID Dim anotherSenseManager As PXCMBase = Nothing If Session.CreateImpl(cuid, anotherSenseManager) = pxcmStatus.PXCM_STATUS_NO_ERROR Then MessageBox.Show(anotherSenseManager.GetType().FullName) Else MessageBox.Show("Errore nella CreateImpl!") End If
Questo pezzo di codice ci consente anche di osservare che l’SDK ha un approccio alle API di tipo C++. Come già visto in un precedente articolo, le classi sono raggruppate logicamente sfruttando classi innestate anziché i namespace, inoltre la stragrande maggioranza dei metodo ha come valore di ritorno l’enumerazione pxcmStatus (la cui struttura è riportata nella figura) che ci informa della corretta esecuzione del metodo e l’istanza vera e propria richiesta viene restituita attraverso un parametro passato per riferimento.
La firma esatta del metodo CreateImpl utilizzato nel pezzo di codice precedente è, infatti:
Public Function CreateImpl(ByVal cuid As Integer, <Out> ByRef instance As PXCMBase) As pxcmStatus
Per chi proviene dall’approccio .NET in cui, generalmente, si ha come valore di ritorno l’istanza desiderata e, eventualmente, il sollevamento di un’eccezione in caso di errore, può risultare inizialmente indigesto, ma questa sensazione sparisce dopo un po’ di utilizzo.
Tra le firme del metodo CreateImpl troviamo anche quella generica che ci consente di ottenere direttamente l’istanza desiderata e non un’istanza di PXCMBase da castare. In particolare, l’esempio precedente si può scrivere:
Dim senseManager As PXCMSenseManager = Nothing If Session.CreateImpl(Of PXCMSenseManager)(senseManager) = pxcmStatus.PXCM_STATUS_NO_ERROR Then MessageBox.Show("SenseManager creato con successo!") Else MessageBox.Show("Errore nella creazione del SenseManager!") End If
Tra i metodi creazionali esposti dalla classe PXCMSession, troviamo anche alcuni specific, già tipizzati, in base alla tipologia di modulo che ci interessa e con un approccio più vicino alla filosofia .NET.
Nell’esempio precedente, volendo creare un’istanza di PXCMSenseManager, possiamo scrivere:
Dim senseManager As PXCMSenseManager = Session.CreateSenseManager() If senseManager IsNot Nothing Then MessageBox.Show("SenseManager creato con successo!") Else MessageBox.Show("Errore nella creazione del SenseManager!") End If
Se analizziamo, utilizzando un decompilatore, il metodo in oggetto, osserviamo che e’ del tipo:
Public Function CreateSenseManager() As PXCMSenseManager Dim manager As PXCMSenseManager If (Me.CreateImpl(Of PXCMSenseManager)(manager) < pxcmStatus.PXCM_STATUS_NO_ERROR) Then Return Nothing End If Return manager End Function
Se vogliamo utilizzare il CreateImpl generico, l’SDK ci mette a disposizione dei metodi di estensione che ci consentono di testare se una chiamata è andata a buon fine o meno in maniera più leggibile e senza eseguire il confronto con l’enumerazione pxcmStatus:
<Extension> _ Public Shared Function IsSuccessful(ByVal status As pxcmStatus) As Boolean Return (status >= pxcmStatus.PXCM_STATUS_NO_ERROR) End Function<Extension> _ Public Shared Function IsError(ByVal status As pxcmStatus) As Boolean Return (status < pxcmStatus.PXCM_STATUS_NO_ERROR) End Function<Extension> _ Public Shared Function IsWarning(ByVal status As pxcmStatus) As Boolean Return (status < pxcmStatus.PXCM_STATUS_NO_ERROR) End Function
In questo modo possiamo scrivere:
Dim senseManager As PXCMSenseManager = Nothing If Session.CreateImpl(Of PXCMSenseManager)(senseManager).IsSuccessful() Then MessageBox.Show("SenseManager creato con successo!") Else MessageBox.Show("Errore nella creazione del SenseManager!") End If
Altre funzionalità esposte dalla PXCMSession sono quelle che ci permettono di recuperare informazioni specifiche da un modulo o dalla versione dell’SDK, ed in particolare:
QueryModuleDesc: dato un modulo (creato con uno dei factory method visti in precedenza) di ottenere un’istanza ImplDesc contenente le informazioni specifiche del modulo come UID dell’algoritmo implementato, il suo gruppo e sottogruppo, l’identificativo univoco del vendor (ad esempio l’identificativo di Intel è 0x8086), la versione e via dicendo
Un esempio di utilizzo è il seguente:
Dim captureManager As PXCMCaptureManager = Session.CreateCaptureManager() If captureManager IsNot Nothing Then Dim desc As PXCMSession.ImplDesc = Nothing If Session.QueryModuleDesc(captureManager, desc).IsSuccessful() Then Console.WriteLine("friendlyName {0}", desc.friendlyName) Console.WriteLine("version {0}.{1}", desc.version.major, desc.version.minor) Console.WriteLine("vendor {0:X}", desc.vendor) End If End If
Se eseguiamo il codice otteniamo il seguente risultato:
QueryVersion: consente di ottenere i dati di versione delle API che stiamo utilizzando contenuti in un’istanza di ImplVersion
Un esempio di utilizzo è il seguente:
Dim version As PXCMSession.ImplVersion = Session.QueryVersion() Console.WriteLine("version {0}.{1}", version.major, version.minor)
che genera il seguente risultato
QueryImpl: questo metodo ci consente di eseguire una ricerca tra i moduli a disposizione in base a dei filtri impostati nel parametro template. Ad esempio, se volessimo cercare tutti i moduli che hanno come vendor Intel, potremo scrivere:
Dim result As PXCMSession.ImplDesc = Nothing Dim template = New PXCMSession.ImplDesc() With {.vendor = &H8086} Dim modules = New List(Of String)() Dim implIndex = 0 While (True) If Session.QueryImpl(template, implIndex, result).IsError() Then Exit While modules.Add(result.friendlyName) implIndex += 1 End While
ottenendo
QueryCoordinateSystem: permette di ricavare il sistema di coordinate attuale della camera. L’insieme delle coordinate ammesse è disponibile nell’enumerazione CoordinateSystem:
Il significato di ciascun tipo di coordinate è illustrato nella seguente figura:
La chiamata al metodo è molto semplice:
Dim coordinate As PXCMSession.CoordinateSystem = Session.QueryCoordinateSystem()
ed il risultato è
L’enumerazione che definisce il sistema di coordinate è un’enumerazione di tipo Flags (maschera di bit), questo perché’ il sistema di coordinate definisce sia le coordinate per un’eventuale camera frontale che per una camera posteriore. Il sistema di coordinate è modificabile utilizzando il metodo SetCoordinateSystem() della PXCMSession.
Per concludere, la PXCMSession espone i due metodi LoadImplFromFile e UnloadImplFromFile che ci permettono, rispettivamente, di caricare o rilasciare un modulo contenuto in una libreria esterna a runtime.
La classe PXCMSession non è disponibile nelle applicazioni universal.