lunedì 12 marzo 2012

Kinect: cosa cambia nella nuova SDK

Con questo post vorrei iniziare una serie dedicata alle novità e ai cambiamenti presenti nell’SDK rilasciato il 1 febbraio 2012.

Cominciamo con riportare il link del portale Kinect in cui trovare il pacchetto di installazione dell’SDK e le risorse necessarie per cominciare a lavorare con lo stesso.

In questi post prenderò spunto dagli esempi che avevo a suo tempo riportato in un’analoga serie di post (ai tempi della beta2) e proverò di farli funzionare nuovamente con il nuovo SDK analizzando ciò che è cambiato.

Installato l’SDK, abbiamo a disposizione un browser che ci permette di accedere facilmente alla documentazione e agli esempi.

SNAGHTML1cbd41a8

Prima cosa che balza all’occhio quando tentiamo di utilizzare l’assembly contenente le classi di gestione del Kinect è che l’assembly da referenziare non è più Microsoft.Research.Kinect.dll ma Microsoft.Kinect.dll.

In maniera analoga, il namespace principale delle classi dell’SDK non è più Microsoft.Research.Kinect ma Microsoft.Kinect.

La classe principale utilizzata nella Beta2 per accedere alle funzionalità del Kinect era la classe Runtime, nella versione 1.0 questa è completamente sparita ed è sparito anche il modo con cui si accede alla classe di gestione del Kinect.

La classe Runtime è stata sostituita dalla classe KInectSensor contenuta nel namespace Microsoft.Kinect.

Il seguente disegno mostra la struttura della classe KinectSensor:

KinectSensor class

La classe KinectSensor non ha costruttori ma espone una proprietà Shared chiamata KinectSensors che ci consente di avere a disposizione l’elenco dei sensori Kinect attaccati al nostro PC (fino a 4) e rilevati dal sistema. Altra cosa importante (di cui ci occuperemo in un prossimo post) è l’esistenza dell’evento AllFrameReady il cui scopo è quello di fornire dei frame sincronizzati per le sorgenti abilitate.

Possiamo, quindi, accedere al nostro Kinect nel seguente modo:

  1. If KinectSensor.KinectSensors.Any() Then
  2.     Sensor = KinectSensor.KinectSensors(0)
  3. End If

dove Sensor è la variabile che utilizzeremo per accedere al dispositivo.

Una volta recuperata l’istanza della classe per la gestione del Kinect, dobbiamo sottoscrivere gli eventi da gestire per i frame che arrivano dal dispositivo e aprire gli opportuni stream.

Anche per questo, ci sono stati dei cambiamenti. In particolare, l’evento VideoFrameReady della vecchia Runtime, è stato rinominato in ColorFrameReady e l’attivazione degli stream non avviene più con il metodo Initialize (che apriva gli stream e avviava la gestione degli stessi) ma richiamando il metodo Enable (o Disable per disabilitare) delle proprietà ColorStream, DepthStream o SkeletonStream (in base a quale stream gestire) seguito dal metodo Start.

Il metodo Enable prevede, nel caso del ColorStream, la possibilità di passare come argomento la risoluzione delle immagini da recuperare. La presenza dell’Enable e del Disable fa si che si possano attivare e disattivare i flussi provenienti dal Kinect “a caldo” senza dover fermare l’istanza del KinectSensor e riavviarla.

Ad esempio per gestire una risoluzione video di 640x480 a 30 fps, possiamo scrivere:

  1. If KinectSensor.KinectSensors.Any() Then
  2.     Sensor = KinectSensor.KinectSensors(0)
  3.     If Sensor.Status = KinectStatus.Connected Then
  4.         AddHandler Sensor.ColorFrameReady, AddressOf ColorFrameReadyHandler
  5.         Sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30)
  6.         Try
  7.             Sensor.Start()
  8.         Catch ex As Exception
  9.  
  10.         End Try
  11.     End If
  12. End If

La proprietà Status della KinectSensor ci consente di sapere lo stato del sensore (nel nostro caso se è connesso) in modo da eseguire le operazioni di apertura degli stream e di aggancio degli eventi solo se effettivamente il sensore è connesso.

Anche la firma del gestore dell’evento ColorFrameReady è cambiata rispetto alla firma del precedente evento presente nella classe Runtime.

  1. Private Sub ColorFrameReadyHandler(sender As Object, e As ColorImageFrameReadyEventArgs)
  2.  
  3. End Sub

L’argomento ColorImageFrameReadyArgs permette di accedere alle informazioni relative al frame recuperato dal Kinect

image


Da notare la presenza del metodo OpenColorImageFrame per recuperare l’istanza della classe ColorImageFrame che è il vero contenitore dei dati provenienti dalla video camera del Kinect.



Per ottenere l’array di byte costituenti l’immagine effettiva è necessario definire un array di byte della lunghezza pari a PixelDataLenght e copiarvi dentro i dati con il metodo CopyPixelDataTo().







  1. Using colorImageFrame = e.OpenColorImageFrame()

  2.     If colorImageFrame IsNot Nothing Then

  3.         Dim imageArray() = New Byte(colorImageFrame.PixelDataLength - 1) {}

  4.         colorImageFrame.CopyPixelDataTo(imageArray)

  5.         '

  6.         ' Gestione dell'array dati proveniente dal Kinect

  7.         '

  8.     End If

  9. End Using






Dato l’array di byte possiamo creare una BitmapSource e possiamo visualizzare la stessa all’interno, ad esempio, di un controllo image WPF:







  1. Private Sub ColorFrameReadyHandler(sender As Object, e As ColorImageFrameReadyEventArgs)

  2.     Dim colorImageFrame = e.OpenColorImageFrame()

  3.     Dim imageArray(colorImageFrame.PixelDataLength) As Byte

  4.     colorImageFrame.CopyPixelDataTo(imageArray)

  5.     Dim stride = colorImageFrame.Width * colorImageFrame.BytesPerPixel

  6.     Me.VideoImage.Source = BitmapSource.Create(colorImageFrame.Width, colorImageFrame.Height,

  7.                                                96, 96,

  8.                                                PixelFormats.Bgr32, Nothing,

  9.                                                imageArray, stride)

  10. End Sub






Ogni volta che l’SDK avrà ricevuto un frame dalla video camera del dispositivo, richiamerà il nostro gestore di evento e visualizzeremo l’immagine corrispondente.



Infine, nel momento in cui dobbiamo chiudere la nostra applicazione e rilasciare la classe di gestione del Kinect, possiamo utilizzare il metodo Stop (per fermare il flusso degli stream e il Dispose per rilasciare effettivamente l’istanza:







  1. If Sensor IsNot Nothing Then

  2.     If Sensor.IsRunning Then

  3.         Sensor.Stop()

  4.         Sensor.Dispose()

  5.     End If

  6. End If






Prima di concludere questo primo post, un accenno allo stride di una immagine per capire meglio il codice precedente.



Quando memorizziamo una immagine in memoria, in realtà, questa è memorizzata in un buffer che potrebbe contenere dei byte in più rispetto a quelli necessari a memorizzare l’immagine stessa (vedi figura). Questi byte in più non influenzano la visualizzazione ma solo lo spazio occupato.



IC156482



Lo stride di un’immagine altro non è che la lunghezza di una riga della precedente matrice buffer. Nella fattispecie è data dalla larghezza del frame per il numero di byte per pixel.



In allegato trovate una solution di esempio:




 



Nessun commento: