Passa ai contenuti principali

Alla scoperta del Kinect : utilizzo del Kinect in modalità polling

Nei precedenti post abbiamo visto che il Kinect ci mette a disposizione una serie di eventi che ci permettono di recuperare i frame video, di profondità o gli skeleton data.

Possiamo utilizzare le potenzialità del Kinect anche senza fare ricorso alla gestione di tali eventi ma utilizzando una tecnica di polling sugli streams.

Partiamo dall’inizio: la classe Runtime (già vista in precedenza) ci mette a disposizione 3 proprietà utilissime in questo contesto e che contengono proprio gli stream di cui sopra.

image

  • VideoStream : è un’istanza di ImageStream che incapsula lo stream video;
  • DepthStream : è un’istanza di ImageStream che incapsula lo stream dei dati di profondità;
  • SkeletonEngine : è il motore di skeletal Tracking che permette l’accesso ai frem di skeleton data.

In particolare osserviamo la presenza, in tutte le classi in gioco, del metodo GetNextFrame il cui risultato è un oggetto di tipo ImageFrame per il VideoStream e per il DepthStream e SkeletonFrame per lo SkeletonEngine.

ImageFrame e SkeletonFrame sono esattamente le istanze che ci vengono restituite all’interno degli eventi della classe Runtime utilizzati in precedenza.

Per questo motivo possiamo utilizzare questo metodo per accedere allo stream e recuperare il frame che ci interessa.

L’applicazione allegata a questo post altro non fa che visualizzare lo stream video e depth utilizzando un polling.

In particolare vengono utilizzati due Task che si occupano di eseguire il “polling” accedendo ai differenti stream.

  1. Private Nui As Runtime
  2.  
  3. Private VideoWorkTask As Task
  4. Private DepthWorkTask As Task
  5. Private WorkTaskTokenSource As CancellationTokenSource
  6.  
  7. Private Sub MainWindow_Loaded(sender As Object, e As System.Windows.RoutedEventArgs) Handles Me.Loaded
  8.     Try
  9.         Nui = New Runtime
  10.         Nui.Initialize(RuntimeOptions.UseColor Or RuntimeOptions.UseDepthAndPlayerIndex)
  11.         Nui.VideoStream.Open(ImageStreamType.Video, 2, ImageResolution.Resolution640x480, ImageType.Color)
  12.         Nui.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240, ImageType.DepthAndPlayerIndex)
  13.  
  14.         WorkTaskTokenSource = New CancellationTokenSource()
  15.  
  16.         Dim cancellationToken = WorkTaskTokenSource.Token
  17.         VideoWorkTask = New Task(New Action(Of Object)(AddressOf VideoWorkTaskCode), Nui, cancellationToken)
  18.         VideoWorkTask.Start()
  19.  
  20.         cancellationToken = WorkTaskTokenSource.Token
  21.         DepthWorkTask = New Task(New Action(Of Object)(AddressOf DepthWorkTaskCode), Nui, cancellationToken)
  22.         DepthWorkTask.Start()
  23.     Catch ex As Exception
  24.  
  25.     End Try
  26. End Sub

Viene inizializzata l’istanza di Runtime e gli stream Video e Depth, non vengono agganciati i gestori di evento ma vengono avviati due task che si occupano di recuperare i frame:

  1. Private Sub VideoWorkTaskCode(obj As Object)
  2.     Dim nui = CType(obj, Runtime)
  3.     While Not WorkTaskTokenSource.IsCancellationRequested
  4.         If nui IsNot Nothing AndAlso nui.VideoStream IsNot Nothing Then
  5.             Dim frame = nui.VideoStream.GetNextFrame(0)
  6.             If frame IsNot Nothing Then
  7.                 Dispatcher.BeginInvoke(Sub()
  8.                                            Me.VideoImage.Source = frame.ToBitmapSource()
  9.                                        End Sub)
  10.             End If
  11.         End If
  12.         System.Threading.Thread.Sleep(100)
  13.     End While
  14. End Sub
  1. Private Sub DepthWorkTaskCode(obj As Object)
  2.     Dim nui = CType(obj, Runtime)
  3.     While Not WorkTaskTokenSource.IsCancellationRequested
  4.         If nui IsNot Nothing AndAlso nui.DepthStream IsNot Nothing Then
  5.             Dim frame = nui.DepthStream.GetNextFrame(0)
  6.             If frame IsNot Nothing Then
  7.                 Dispatcher.BeginInvoke(Sub()
  8.                                            Me.DepthImage.Source = frame.ToBitmapSource()
  9.                                        End Sub)
  10.             End If
  11.         End If
  12.         System.Threading.Thread.Sleep(100)
  13.     End While
  14. End Sub

A differenza della gestione degli eventi vista nei precedenti post, in questo caso i task vengono eseguiti in threads differenti dal principale ed è, quindi, necessario l’utilizzo del Dispatcher per aggiornare l’interfaccia.

Il metodo GetNextFrame prevede un parametro che indica quanti millisecondi attendere prima di restituire il frame.

Il valore di ritorno di GetFrame può anche essere nothing (nel caso che il frame non sia ancora pronto).

Questa tecnica è un “pelino” più complicata di quella Event-Driven e deve essere utilizzata quando l’applicazione lo richiede (ad esempio abbiamo la necessità di recuperare un frame ogni x secondi).


Commenti

Post popolari in questo blog

VB.NET : Aggregare stringhe con LINQ

Tip facile facile, ma a qualcuno potrebbe servire. Supponiamo di avere una lista di stringhe (magari come risultato di una query LINQ) e di voler ottenere una stringa con la concatenazione delle stesse: Dim list = CreateList() Dim concatStr = (From s In list _ Select s).Aggregate( Function (currentString, nextString) currentString + nextString) MessageBox.Show(concatStr) Il metodo CreateList non ci interessa, in questo momento, ma crea una lista di oggetti String. Protected Function CreateList() As IEnumerable( Of String ) Dim list As String () = {" stringa1 ", " stringa2 ", " stringa3 ", " stringa4 ", " stringa5 "} Return list.AsEnumerable() End Function Questo metodo potrebbe restituire una qualsiasi lista di oggetti di cui, nella select successiva recuperiamo solo stringhe. La stessa tecnica è utilizzabile per concatenare stringhe inserendovi un carattere separatore Dim list = CreateList() Dim

VB.NET: SplashScreen con effetto fade-in

In questo post vorrei proporvi un modo per realizzare una splash screen per le nostre applicazioni Windows Form che appare progressivamente con un effetto fade. Supponiamo di avere il nostro progetto VB.NET in una soluzione Visual Studio 2008 in cui abbiamo il sorgente della nostra applicazione Windows Form. Inseriamo una splash screen utilizzando il menù Progetto->Aggiungi Nuovo Elemento e selezionando il tipo di elemento “Schermata Iniziale” A questo punto Visual Studio creerà, automaticamente, la schermata iniziale che possiamo personalizzare graficamente come vogliamo. Per poter fare in modo che questa finestra appaia nel momento in cui avviamo l’applicazione, è necessario aprire le proprietà del progetto e impostare la maschera di avvio: In questo modo, all’avvio dell’applicazione, la schermata appare immediatamente e scompare un attimo prima della visualizzazione della finestra dell’applicazione. Possiamo far apparire la schermata iniziale con un ef

VB.NET: Convertire un file DOC in RTF e PDF con office interop

In questo post vorrei proporvi del codice per poter convertire un file .doc in un file .rtf oppure .pdf utilizzando le API di interoperabilità di Office. Creeremo una classe, DocConverter, che esporrà le due funzionalità sopra citate. Cominciamo con il prevedere un attributo privato della classe che rappresenterà l’applicazione Word che utilizzeremo per la conversione. Creeremo l’istanza dell’attributo privato all’interno del costruttore della classe: Public Sub New () If Not CreateWordApp() Then Throw New ApplicationException(" Assembly di interoperabilità con Office non trovato! ") End If End Sub Private _wordApp As Word.ApplicationClass Protected Function CreateWordApp() As Boolean Dim retval = True Try _wordApp = New Word.ApplicationClass() _wordApp.Visible = False Catch ex As System.Exception _wordApp = Nothing retval = False End Try Return retval End Function La conve