lunedì 19 dicembre 2011

Deserializzazione JSON e costruttori: OnDeserialized e OnDeserializing

In questo post vorrei illustrarvi l’utilizzo degli attributi OnDeserializingAttribute e OnDeserializedAttribute contenuti nel namespace System.Runtime.Serialization.

Il loro scopo è quello di decorare dei metodi che verranno richiamati, rispettivamente, prima (OnDeserializing) e dopo (OnDeserialized) la deserializzazione di un oggetto tramite determinati serializzatori che vedremo più avanti.

Vediamo il loro possibile utilizzo in caso di deserializzazione JSON.

Supponiamo di avere il seguente JSON:

  1. {"nome":"Giuseppe","cognome":"Verdi"}

una possibile classe che permette la deserializzazione di tale JSON potrebbe essere:

  1. Imports System.Xml.Serialization
  2. Imports System.Runtime.Serialization
  3.  
  4. <DataContract()>
  5. Public Class Persona
  6.  
  7.     Public Sub New()
  8.  
  9.     End Sub
  10.  
  11.     <DataMember(Name:="nome")>
  12.     Public Property Nome As String
  13.     <DataMember(Name:="cognome")>
  14.     Public Property Cognome As String
  15.  
  16.     Private _DataCreazione As DateTime = DateTime.Now
  17.     Public ReadOnly Property DataCreazione As DateTime
  18.         Get
  19.             Return Me._DataCreazione
  20.         End Get
  21.     End Property
  22.  
  23. End Class

Ho inserito la proprietà che contiene la data di creazione dell’oggetto per dimostrare una cosa che vedremo tra poco.

Prendiamo il seguente metodo che deserializza il JSON di cui sopra:

  1. Imports System.Xml.Serialization
  2. Imports System.IO
  3. Imports System.Runtime.Serialization.Json
  4. Imports System.Text
  5.  
  6. Module Module1
  7.  
  8.     Sub Main()
  9.         Dim persona As Persona
  10.         Dim serializer = New DataContractJsonSerializer(GetType(Persona))
  11.         Using memStream = New MemoryStream(Encoding.Default.GetBytes(GetJSON()))
  12.             persona = CType(serializer.ReadObject(memStream), Persona)
  13.         End Using
  14.     End Sub
  15.     
  16.     Private Function GetJSON() As String
  17.         Return "{""nome"":""Giuseppe"",""cognome"":""Verdi""}"
  18.     End Function
  19.  
  20. End Module

Se eseguiamo il metodo e ci fermiamo immediatamente dopo la deserializzazione (metodo ReadObject della classe DataContractJsonSerializer), otteniamo:

image

cioè la data di creazione non è stata impostata.

Questo accade perché il serializzatore DataContractJsonSerializer (ma non è l’unico in quanto avviene anche con il DataContractSerializer, il NetDataContractSerializer e il BinaryFormatter) non richiama il costruttore.

Quindi, se abbiamo dei valori di default da impostare o dei valori da assegnare alla creazione dell’oggetto, con la deserializzazione siamo fregati.

E’ in questo scenario che ci vengono in aiuto i due attributi OnDeserializing e OnDeserialized:

  1. Imports System.Xml.Serialization
  2. Imports System.Runtime.Serialization
  3.  
  4. <DataContract()>
  5. Public Class Persona
  6.  
  7.     Public Sub New()
  8.  
  9.     End Sub
  10.  
  11.     <DataMember(Name:="nome")>
  12.     Public Property Nome As String
  13.     <DataMember(Name:="cognome")>
  14.     Public Property Cognome As String
  15.  
  16.     Private _DataCreazione As DateTime = DateTime.Now
  17.     Public ReadOnly Property DataCreazione As DateTime
  18.         Get
  19.             Return Me._DataCreazione
  20.         End Get
  21.     End Property
  22.  
  23.     <OnDeserialized()>
  24.     Public Sub OnDeserialized(context As StreamingContext)
  25.  
  26.     End Sub
  27.  
  28.     <OnDeserializing()>
  29.     Public Sub OnDeserializing(context As StreamingContext)
  30.         Me._DataCreazione = DateTime.Now
  31.     End Sub
  32. End Class

Il metodo decorato con Ondeserializing viene richiamato immediatamente prima della deserializzazione, mentre quello decorato con OnDeserialized immediatamente dopo.

In questo modo, se rieseguiamo il metodo di prima in cui deserializziamo il JSON:

image

la data è effettivamente valorizzata.

I metodi decorati con questi attributi debbono avere come argomento un oggetto di tipo StreamingContext e possono essere utilizzati per controllare la deserializzazione dei nostri oggetti:

Ad esempio il seguente metodo solleva un’eccezione quando si tenta di serializzare oggetti in orari con minuti pari Sorriso :

  1. <OnDeserializing()>
  2. Public Sub OnDeserializing(context As StreamingContext)
  3.     If DateTime.Now.Minute Mod 2 = 0 Then
  4.         Throw New Exception()
  5.     End If
  6.     Me._DataCreazione = DateTime.Now
  7. End Sub

Esistono dei corrispettivi attributi OnSerializing e OnSerialized per le operazioni di serializzazione.

 

venerdì 16 dicembre 2011

Community Days 2012 - Milano, 16 e 17 febbraio 2012

DomusDotNet presenta, in collaborazione con le altre community ed user group italiani,
il maggior evento community dell'anno: 12 track spalmate su 2 giorni interamente dedicati alle ultime tecnologie, 4 lab ed i migliori speaker italiani.

Windows 8, Windows Phone, Entity Framework, ASP.NET, .NET Framework 4.5 e Visual Studio 2011, applicazioni mobili, HTML 5 e tanto, tanto altro ancora!

La partecipazione, come sempre, è totalmente gratuita. Le iscrizioni sono aperte e l'agenda è
disponibile sul sito. ISCRIVITI SUBITO!

728x90

 

Tag di Technorati: ,,

lunedì 12 dicembre 2011

Uguaglianza tra tipi in VB.NET

Se abbiamo due istanze della classe Type e vogliamo verificare che tali istanze rappresentino effettivamente lo stesso tipo, possiamo procedere in due modi

Siano Type1 e Type2 le due istanze di Type da controllare.

Un primo modo è utilizzare l’operatore Is:

  1. If Type1 Is Type2 Then
  2.     ' i tipi sono uguali
  3. Else
  4.     ' i tipi non sono uguali
  5. End If

In alternativa possiamo utilizzare il metodo statico (shared) Equals:

  1. If Type.Equals(type1, type2) Then
  2.     ' i tipi sono uguali
  3. Else
  4.     ' i tipi non sono uguali
  5. End If

In quest’ultimo caso, in realtà, stiamo utilizzando il metodo Equals (shared) di Object, la cui definizione è:

image

 

Tag di Technorati: ,,

lunedì 28 novembre 2011

Aprire un file xml in un’applicazione LightSwitch

Da qualche giorno sto lavorando con LightSwitch (ed il buon Alessandro sa quanto apprezzo il prodotto!!!) e la logica con cui si approccia alla soluzione di un problema, anche banale, di programmazione è piuttosto differente da chi proviene dalle applicazioni desktop classico.

Ricordatevi sempre che stiamo parlando di Silverlight, quindi, già per questo, non date per scontato che possiate fare quello che volete, in più sotto LightSwitch.

Per questo motivo, ogni volta che mi scontrerò con un problema da “desktoppiano” classico e riuscirò a venirne a capo, cercherò di postarlo qui. Probabilmente la soluzione sarà banale e puerile, ma magari potrà servire ad altri!!

Detto questo, supponendo di voler aprire un file Xml e creare un oggetto XDocument utilizzando il metodo statico Load(String), normalmente scriveremmo

  1. Dim xmlTemplate As XDocument
  2. xmlTemplate = XDocument.Load(fullFileName)

dove fullFileName è il nome completo (con tanto di path) del file xml da aprire.

Questo funziona benissimo nelle nostre applicazioni desktop classiche ma non in LightSwitch che ci restituirà l’errore:

image

Per risolvere il problema è sufficiente utilizzare il metodo Load(Stream, LoadOptions):

  1. Dim xmlTemplate As XDocument
  2. Using fileStream = New FileStream(fileFullName, FileMode.Open)
  3.     xmlTemplate = XDocument.Load(fileStream)
  4. End Using

In questo modo non otteniamo l’errore precedente e riusciamo a creare il nostro XDocument (a patto, ovviamente che il file sia ben formato).

 

mercoledì 16 novembre 2011

Rilasciata la versione 3 di Async CTP

In attesa di avere, “di serie”, la programmazione asincrona a task all’interno di Visual Studio e del framework (sarà presente in Dev11), è stata rilasciata la versione 3 di Async CTP.

Async CTP è un pacchetto che introduce la programmazione asincrona a task (che semplifica di molto la scrittura del codice multithread) all’interno di Visual Studio 2010.

Async CTP, di fatto, introduce nuove parole chiave e tutta l’infrastruttura che permette al compilatore di gestirle.

Per maggiori info sulla programmazione asincrona a task, vi consiglio il link: http://msdn.microsoft.com/en-us/vstudio/gg316360

Per il download del pacchetto di installazione di Async CTP 3, potete utilizzare il link: http://www.microsoft.com/download/en/details.aspx?id=9983

La versione 3 di Async CTP è compatibile con le installazioni non in lingua inglese di VS, Silverlight 5 e Roslyn ed include una EULA (http://it.wikipedia.org/wiki/EULA) che ne permette (ma non incoraggia) l’utilizzo della stessa in produzione.

 

Tag di Technorati: ,,

domenica 13 novembre 2011

FT Toolkit v.1.0 is out!!

Finalmente sono orgoglioso di comunicarvi che la prima release di FT Toolkit è out!!

FTToolkit

Cosa è FT Toolkit?

FT Toolkit è un insieme di classi che consentono di accedere in maniera semplice ai servizi di Fotolia.

Per chi non la conoscesse, Fotolia è una delle maggiori agenzie on-line per stock-foto con circa 14 milioni di immagini a disposizione dei propri clienti.
Fotolia mette a disposizione degli sviluppatori una serie di servizi (inizialmente con protocollo XmlRpc e adesso anche in Rest) per accedere alle funzionalità della piattaforma (come ad esempio eseguire ricerche sulla banca dati immagini, creare gallerie, gestire il  proprio account e così via).

Per maggiori info sulle API esposte fare riferimento al link http://it.fotolia.com/Services/API/Introduction

Fino ad ora (almeno che io sappia e avendo ricevuto conferma dal gruppo si sviluppo interno a Fotolia stessa) non esisteva un toolkit che permettesse facilmente, a chi sviluppa con linguaggi .NET, di accedere ai servizi (lo si poteva fare ma implementando le interfacce XmlRpc).

FT Toolkit nasce proprio per questo, fornire un Object Model e dei servizi per wrappare le chiamate ai servizi della piattaforma Fotolia.

Attualmente ci sono solamente due moduli:

  • FTTK.Core (che contiene le entità dell’object model e le interfacce dei servizi)
  • FTTK.XmlRpc (che contiene le implementazioni delle interfacce contenute nel Core e che accedono ai servizi XmlRpc).

Entrambi sono pensati per il framework .NET 4.0 e funzionano per applicazioni Desktop o server (no silverlight o wp7).

Prossimamente saranno rilasciati i moduli per Silverlight e WP7 , nonchè le implementazioni per il protocollo REST.

Il sito ufficiale di FTTK è http://fttk.codeplex.com ma i moduli sono disponibili anche su NuGet:

image

FTTK.Core : http://www.nuget.org/List/Packages/FTTK.Core

FTTK.XmlRpc: http://www.nuget.org/List/Packages/FTTK.XmlRpc

Se siete interessati restate connessi, perhè prossimamente pubblicherò altri post al riguardo!!!!

 

sabato 5 novembre 2011

Nuova release dell’SDK per Kinect

Dopo una settimana intensa dal punto di vista lavorativo e non (evento ALM Revolutions da sovraintendere), eccomi qui a postare qualcosa (come non mi capita più spesso nell’ultimo periodo Triste).

Questa volta si tratta della nuova versione del Kinect SDK per Windows rilasciata il 1 Novembre.

Cominciamo dal nuovo sito ridisegnato (http://www.kinectforwindows.org/):

image

Nel sito trovate documentazione, risorse e il link per il download del nuovo SDK (sia nella versione 32bit che 64 bit).

Le novità presenti in questa release (che tengo a precisare non è ancora una versione commercial la quale sarà disponibile “early 2012”) sono, fondamentalmente :

  • Miglioramenti e ottimizzazioni del motore di skeletal tracking. Viene dichiarato un 20% di incremento delle performance rispetto alla precedente versione e un miglioramento nell’accuratezza e tracciatura dei joint dello scheletro;
  • E’ possibile attaccare e staccare a caldo il Kinect senza avere problemi con la classe Runtime di gestione dello stesso;
  • Supporto per Windows 8 Developer Preview.

Nei prossimi giorni vedrò di analizzare l’SDK nuovo e segnalarvi eventuali differenze (non dovrebbero esserci) in termini di classi o utilizzo, rispetto alla precedente versione.

Per ora, il consiglio che vi posso dare è di guardarvi i seguenti video:

Kinect Effect Video

Shape game image

 

mercoledì 2 novembre 2011

venerdì 21 ottobre 2011

Windows Phone 7.5 Developer Day/Lab a Roma

logo_wp75-v_web


Vi segnalo due eventi (che si svolgeranno in contemporanea)organizzati da Microsoft in collaborazione con Nokia per il 15 Novembre 2011 presso la sede Microsoft di Roma (Viale Avignone 10).

  • Windows Phone 7.5 Developer Day – una giornata dedicata allo sviluppo per Windows Phone 7.5, dove si parlerà del Windows Phone Runtime, delle novità della versione 7.5 (Fast Application Switching, Tombstoning, Multitasking, Live Tiles e Push Notification, etc…), di come costruire un’applicazione completa, del marketplace e di come monetizzare le proprie applicazioni. Gli speaker saranno Daniele Bochicchio e Cristian Civera, che hanno realizzato alcune tra le più importanti e conosciute applicazioni italiane per Windows Phone 7 e 7.5.
    Per iscrivervi potete andare qui.
  • Windows Phone 7.5 Developer Lab – un laboratorio pratico dedicato a Windows Phone 7.5, dove provare sul campo lo sviluppo di applicazioni per Windows Phone 7.5. Affiancati da me e da altre persone molto competenti sullo sviluppo Phone, potrete anche testare le applicazioni su telefoni reali anche dotati di giroscopio, bussola, etc..
    Durante il laboratorio sarà possibile avere assistenza anche nella migrazione delle proprie applicazioni da altre piattaforme mobili.
    Per partecipare al laboratorio bisogna portare il proprio portatile con il Windows Phone SDK e lo Zune Client installati. Per iscrivervi potete andare qui.

In entrambi gli eventi se avete delle applicazioni pronte, in sviluppo o appena rilasciate sul Marketplace portatele e fatecele vedere, riceverete una sorpresa!

 

giovedì 20 ottobre 2011

Rilasciata la versione CTP di Roslyn

Ieri sera (da noi) è stata rilasciata la versione CTP di Roslyn.

Roslyn, in poche parole (insufficienti e parziali), è un progetto che nasce con lo scopo di “aprire” la scatola nera Compilatore in modo da permettere una personalizzazione dello stesso.

Il download della CTP e risorse per poter approfondire il discorso sono disponibili all’indirizzo http://msdn.microsoft.com/it-it/roslyn

 

Tag di Technorati: ,,

lunedì 17 ottobre 2011

Alcuni web cast su Denali in BEIT

Vi segnalo che sono stati pubblicati alcuni Web Cast su BEIT relativi a Denali la nuova versione di SQL Server.

L’indirizzo a cui potete trovare il materiale è:

http://www.microsoft.com/italy/beit/Msdn.aspx?search=denali&type=-1&audience=2&userlevel=-1&product=-1&authorName=-1

Buona visione!!

 

Tag di Technorati: ,,

Visual Studio 11 – Impostare il target framework e la CPU

Visual Studio 11, come il suo predecessore Visual Studio 2010, consente di selezionare per quale versione del framework compilare il nostro progetto solo che permette di farlo in maniera più semplice.

Se vogliamo impostare il framework di compilazione in Visual Studio 2010, dobbiamo andare nelle proprietà del progetto, selezionare la scheda “Compile”

SNAGHTML102b74a7

e il bottone “Advanced Compile Option” in modo da aprire la finestra delle impostazioni avanzate di compilazione:

SNAGHTML102d32a8

In questa finestra troviamo la casella a discesa che ci consente di selezionare il framework di destinazione.

In VS11 la procedura è stata semplificata e la combo di scelta è stata inserita direttamente nella scheda “Application”:

image

Possiamo osservare, inoltre, che la scelta della CPU di destinazione, che nel VS2010 è contenuta sempre nella finestra delle impostazioni avanzate di compilazione, è stata spostata all’interno della scheda delle impostazioni di compilazione:

image

Da notare la presenza del flag “Prefer 32-bit” (utilizzabile solo se si è scelta l’opzione “Any CPU”) che consente di compilare in modo che l’applicazione verrà eseguita in modalità 32-bit ove è possibile.

 

giovedì 13 ottobre 2011

WPC2011 sta per arrivare!!!

WPC è il più importante evento italiano di formazione: 3 giorni di sessioni di ottimo livello con ottimi speaker!! Che aspettate!!!!

Fate un giro sul sito ufficiale (http://www.wpc2011.it), guardate l’agenda e non potrete non iscrivervi!!!!

Stampa

 

Tag di Technorati: ,,,

martedì 11 ottobre 2011

ALM Revolutions e FREE Web Workshop

Siete interessati all’ALM (Application LIfecycle Management)?

Se si vi segnalo due interessanti appuntamenti.

Il primo è un pomeriggio, organizzato da DomusDotNet, con 4 sessioni tutte incentrate, appunto, su ALM.

L’evento si terrà il giorno 3 Novembre 2011 presso la sede Microsoft di Roma e l’agenda è la seguente:

14:00-14:30 Registrazione

14:30-14:45 Keynote di benvenuto

14:45-15:30 Non si vive di solo check-out e check-in
(Gian Maria Ricci, MVP Visual Studio ALM e fondatore DotNetMarche)
Il source control è lo strumento fondamentale per la gestione dei propri progetti e spesso purtroppo anche il meno conosciuto. Troppo spesso i team utilizzano solamente le funzionalità più base di un VCS senza usufruire a pieno di tutte le sue potenzialità. In questa sessione vedremo alcune best practice da adottare per la gestione del codice basandoci sul source control di TFS e parleremo quindi di branch, shelvest, integration platform ed altro.

15:30-16:15 Real World Team Foundation Server
(Matteo Emili, MVP Visual Studio ALM e fondatore DomusDotNet)
Tips and tricks per l'amministratore "casuale". Avete installato in test Team Foundation Server e siete diventati de facto amministratori di uno dei sistemi più importanti per il team di sviluppo? Avete ereditato l'installazione da qualcun'altro e vi state chiedendo come è potuto succedere? In questa sessione vedremo una serie di cose che avreste voluto sapere prima di diventare "casualmente" amministratori di Team Foundation Server.

16:15-16:30 Pausa

16:30-17:15 TFS Team process template customization
(Gian Maria Ricci, MVP Visual Studio ALM e fondatore DotNetMarche)
Team Foundation Server garantisce una estrema flessibilità nella personalizzazione dei Work Item, permettendovi di adattarlo al vostro processo di sviluppo. In questa sessione vedremo come modificare la definizione di Work Item aggiungendo campi, regole ed andando a modificare il workflow che regola la gestione degli stati.

17:15-18:00 What's new on Visual Studio ALM 11?
(Matteo Emili, MVP Visual Studio ALM e fondatore DomusDotNet)
In questa sessione per la prima volta inizieremo a vedere cosa Microsoft sta preparando per la prossima release di Visual Studio ALM.
Local Workspaces, Team Foundation Service, Feedback Manager e Storyboarding sono solo alcune delle novità che verranno affrontate.
Da non perdere per non farsi cogliere impreparati "dall'onda".

18:00 Conclusioni

Per maggiori info, dettagli logistici ed iscrizioni, trovate la pagina dell’evento all’indirizzo http://www.domusdotnet.org/eventi/alm-revolutions.aspx

Vi segnalo, infine, una serie di Workshop organizzati da Microsoft e segnalati nel seguente post di Lorenzo Barbieri: http://blogs.msdn.com/b/italy/archive/2011/10/10/free-web-workshop-microsoft-visual-studio-2010-alm-tools.aspx

Ora non avete più scuse per non approfondire il discorso su ALM!!!!

 

lunedì 19 settembre 2011

Comunicando: History Tech Day

Vi segnalo l’evento Comunicando - da strumenti di calcolo a strumenti di comunicazione- che si terrà il prossimo 24 Settembre 2011.
L’evento è dedicato all'evoluzione delle piattaforme di sviluppo, e si terrà ad Avellino, presso il Carcere Borbonico di Avellino sito in Corso Vittorio Emanuele II, dalle 9.00 alle 17.30.

Immagine mappa

Purtroppo i posti sono limitati quindi affrettatevi a registrarvi.
Tag di Technorati: ,

mercoledì 14 settembre 2011

Webinar LightSwitch DevExpress

Vi segnalo un interessante webinar (un americanismo per chiamare una sessione on-line) interamente dedicato a LightSwitch e tenuto da Alessandro Del Sole.

Il webinar è a cura di DevExpress e si terrà il giorno 4 Ottobre 2011 alle ore 19:00 (il link del webinar è http://www.devexpress.com/Support/Webinars/details.xml?id=IntroLightSwitchDelSole.

Maggiori informazioni sul post di Alessandro.

Se volete cominciare a capire cosa è LightSwitch e se fa al caso vostro, non perdete l’occasione!!!

 

Tag di Technorati: ,,

Windows 8 @ BUILD : arrivato!!!!

Ieri, durante la keynote di BUILD tenutasi ad Anaheim in California, Steven Sinofsky mostrato alcune delle potenzialità del nuovo Windows 8.

Per vedere la Keynote potete collegarvi all'indirizzo: http://www.microsoft.com/presspass/events/build/

Da questa mattina presto è stata rilasciata la preview di Windows 8 e degli strumenti di sviluppo. Per scaricare le ISO usate l'indirizzo http://msdn.microsoft.com/en-us/windows/home/

Le sessioni dell'evento BUILD sono disponibili all'indirizzo: http://channel9.msdn.com/Events/BUILD/BUILD2011?sort=sequential&direction=desc&term=

A questo punto non ci resta che “giocare”!!!!

 

venerdì 9 settembre 2011

DomusDotNet : Pomeriggio Entity Framework

image

DomusDotNet, in collaborazione con Microsoft, EF Profiler by Hibernating Rhinos, Edizioni FAG, O’Reilly, organizza l’evento Pomeriggio Entity Framework. Un pomeriggio dedicato all’ORM di casa Microsoft.

Se avete dubbi, perplessità, domande o semplicemente volete conoscere EF, potrebbe essere il caso di investire un pomeriggio e venire a seguirci!!!

 

mercoledì 7 settembre 2011

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).


lunedì 5 settembre 2011

Alla scoperta del Kinect: gli smooth parameters

Abbiamo accennato in questo post come sia possibile eseguire un filtro sui dati grezzi provenienti dal Kinect per “smussare” e correggere le fluttuazioni.

In questo post vorrei cercare di capire (per primo io) quale è il significato dei vari parametri utilizzabili.

Riprendiamo il discorso dall’inizializzazione della classi Runtime e l’impostazione dei parametri di smoothing:

  1. Try
  2.     _Nui = New Runtime
  3.     _Nui.Initialize(RuntimeOptions.UseSkeletalTracking)
  4.     AddHandler _Nui.SkeletonFrameReady, AddressOf SkeletonFrameReadyHandler
  5.  
  6.     _Nui.SkeletonEngine.TransformSmooth = True
  7.     Dim parameters = New TransformSmoothParameters() With {.Smoothing = 1.0F,
  8.                                                         .Correction = 0.1F,
  9.                                                         .Prediction = 0.1F,
  10.                                                         .JitterRadius = 0.05F,
  11.                                                         .MaxDeviationRadius = 0.05F}
  12.     _Nui.SkeletonEngine.SmoothParameters = parameters
  13. Catch ex As Exception
  14.  
  15. End Try

La classe TransformSmoothParameters, come possiamo vedere, ha 5 proprietà che dovrebbero consentire il filtraggio delle imprecisioni e dei rumori che i sensori del Kinect introducono nei dati grezzi.

Smooting : lo smoothing (il termine italiano più vicino è “pulizia”), in elaborazione delle immagini, consiste nell’applicare una funzione di filtro il cui scopo è quello di mettere in evidenza la parte del segnale “buona” cercando di sopprimere l’eventuale rumore dovuto da cause di diversa natura che, comunque, sporcano il segnale stesso. Nel nostro caso, piccoli movimenti del corpo umano, possono determinare del rumore che rende la tracciatura dello stesso poco affidabile. La proprietà Smoothing (che accetta il range [0,1]) permette di impostare la quantità di smoothing da applicare. Il valore 0 indica che non viene applicato alcun smoothing mentre l’effetto smoothing aumenta all’avvicinarsi al valore 1. Aumentare il valore di questa proprietà aumenta la latenza del segnale.

Correction : la proprietà permette di impostare la correzione

Prediction : permette di impostare il numero di frame predetti dal motore.

Jitter Radius : il jitter è la variazione di una o più grandezze caratteristiche di un segnale che possono minare l’integrità del segnale stesso. La proprietà JitterRadius consente di impostare il raggio di riduzione del jitter (espresso in metri). Qualsiasi jitter che superi il raggio impostato viene normalizzato al raggio stesso.

Maximum Deviation Radius : permette di specificare il massimo scostamento (in metri) dei dati filtrati rispetto ai dati grezzi. I valori filtrati che superano la distanza impostata rispetto ai dati grezzi, vengono normalizzati a questa distanza (rispetto al valore filtrato).

Non esistono dei valori “buoni” per qualsiasi applicazione ma è necessario procedere sperimentando i migliori valori di smoothing. L’apporto di tali correzioni dipende dall’ambiente circostante e, quindi, anche a parità di applicazione possono variare in base a dove il Kinect è posizionato.

Per chi fosse interessato ad approfondire, è necessario sapere che il filtro attualmente utilizzato nell’SDK del Kinect si basa sul metodo a doppio esponenziale di Holt (link).

 

lunedì 29 agosto 2011

Alla scoperta del Kinect : gli scheletri e l’uomo vitruviano

Cosa c’entra Leonardo e il suo Uomo Vitruviano, gli scheletri ed il Kinect?

Apparentemente nulla, ma leggendo questo post scoprirete che, invece, un legame c’è.

Abbiamo visto in precedenti post che l’infernale aggeggio (il Kinect) ci permette di ottenere, in maniera molto facile, le immagini video e le immagini di profondità. Già con questi due insiemi di informazioni potremmo realizzare una sorta di interazione tra i player ed il nostro applicativo.

L’SDK del Kinect, però, fa molto di più perché è in grado di fornirci gli “scheletri” dei player disposti davanti ad esso.

Vediamo come procedere per ricavare ciò.

La classe Runtime (di cui abbiamo parlato in questo post) prevede un evento chiamato SkeletonFrameReady che viene sollevato quando SDK ha a disposizione un oggetto di tipo SkeletonFrame pronto per essere elaborato.

L’istanza di questo oggetto è passata come proprietà dell’argomento dell’evento SkeletonFrameReady:

image

La classe SkeletonFrame, come possiamo vedere, espone una serie di proprietà decisamente interessanti:

  • FloorClipPlane : l’oggetto Vector contenuto in questa proprietà ci fornisce i coefficienti dell’equazione del piano di terra (pavimento) stimata dall’SDK. L’equazione ha la forma:

Ax+By+Cz+D=0

dove:

A = FloorClipPlane.X

B = FloorClipPlane.Y

C = FloorClipPlane.Z

D = FloorClipPlane.W

L’equazione del piano è normalizzata, quindi D rappresenta, di fatto, l’altezza della camera rispetto al pavimento. Nella versione Beta dell’SDK il vettore è sempre nullo;

  • NormalToGravity : consente di avere informazioni sul vettore di  gravità. Nella versione Beta dell’SDK il vettore è sempre nullo.;
  • FrameNumber : è il numero del frame in esame;
  • TimeStamp : timestamp del frame (in maniera analoga a quanto visto per il video e la profondità);
  • Quality : indica la qualità del frame;
  • Skeletons : contiene un array di “scheletri” dei giocatori tracciati.

Il Kinect è in grado di tracciare fino a 6 giocatori contemporaneamente anche se:

  • solo 2 giocatori possono essere tracciati “attivamente”. Di questi si conoscono tantissime info all’interno della struttura SkeletonData;
  • fino a 4 giocatori possono essere tracciati “passivamente”. L’SDK mantiene solo alcune informazioni di questi giocatori.

La classe SkeletonData contiene, per ogni giocatore, i dati relativi alla posizione dello stesso nello spazio:

image

Lo scheletro è individuato da una collezione di punti del corpo umano, denominati Joint, e memorizzati nell’array Joints. Ogni Joint è individuato da un Id (di tipo JointID) e, allo stato attuale, possiamo contare su ben 20 punti mostrati nella seguente figura (ecco l’uomo vitruviano del titolo):

VitruvialMan

Ogni Joint fornisce la propria posizione nello spazio (proprietà Position) e lo stato di tracciamento (proprietà TrackingState). La posizione è identificata dalle tre coordinate spaziali secondo il seguente schema:

xyz

X e Y variano in un intervallo [-1,1] mentre Z esprime la distanza (in metri) dal sensore. Il valore di W, secondo quanto riportato dalla documentazione ufficiale dovrebbe variare tra 0 e 1 e identificare la precisione della posizione (1 posizione affidabile, 0 posizione totalmente inaffidabile) ma, allo stato attuale, il valore di W è sempre pari a 1.

La proprietà TrackingState della classe SkeletonData ci fornisce informazioni relative al tipo di tracciamento a cui è sottoposto lo scheletro e cioè se si tratta di un giocatore attivo (Tracked), passivo (PositionOnly) oppure se non è tracciato (NotTracked).

La proprietà Quality ci dice se lo scheletro è stato “tagliato”. Se, ad esempio, il Kinect riesce ad individuare lo scheletro dalle ginocchia in su (ad esempio perché caviglie e piedi sono nascosti), allora nella proprietà Quality avremo il valore ClippedBottom ad indicare che lo scheletro è stato “tagliato” in basso.

Interessante la proprietà Position di SkeletonData che contiene la posizione (approssimata) del centro di massa dello scheletro.

L’applicazione pratica che vi vorrei proporre a corollario di questo post è la realizzazione di una semplice applicazione che mostra, in tempo reale, la posizione dei venti punti dell’uomo vitruviano di cui sopra.

Cominciamo con il mostrare cosa vogliamo ottenere:

image

In pratica abbiamo, istantaneamente, la posizione di tutti i Joints disponibili del primo SkeletonData tracciato e, per ogni Joint, abbiamo un diverso colore di sfondo in base al loro stato di tracciamento.

In più visualizziamo il centro di massa (la TextBox in posizione “equivoca”),la qualità dello SkeletonFrame, il vettore NormalToGravity, il vettore FloorClipPlane (questi ultimi due sempre nulli).

L’applicazione è un’applicazione WPF in cui ho deciso di adottare il pattern MVVM, quindi, per spiegare il funzionamento, ci occuperemo, innanzitutto del ViewModel per poi usare il motore di binding di WPF per agganciare la UI.

Nel costruttore del View Model (MainWindowViewModel) avviamo l’istanza della classe Runtime dell’SDK del Kinect:

  1. Public Sub New()
  2.     If Not DesignerProperties.GetIsInDesignMode(New DependencyObject()) Then
  3.         Try
  4.             Nui = New Runtime
  5.             AddHandler Nui.DepthFrameReady, AddressOf DepthFrameReadyHandler
  6.             AddHandler Nui.SkeletonFrameReady, AddressOf SkeletonFrameHandler
  7.             Nui.Initialize(RuntimeOptions.UseDepthAndPlayerIndex Or RuntimeOptions.UseSkeletalTracking)
  8.             Nui.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240, ImageType.DepthAndPlayerIndex)
  9.             Catch ex As Exception
  10.  
  11.         End Try
  12.     End If
  13. End Sub

Se non ci troviamo in design mode (primo if) eseguiamo i seguenti passi:

  1. creiamo l’istanza di Runtime;
  2. agganciamo il gestore dell’evento DepthFrameReady che ci servirà esclusivamente per mostrare l’immagine di profondità a video;
  3. agganciamo il gestore dell’evento SkeletonFrameReady che ci servirà per elaborare gli scheletri che il Kinect ci fornirà nel tempo;
  4. inizializziamo la Runtime selezionando lo stream di profondità e di Skeletal tracking;
  5. apriamo lo stream di profondità decidendo una risoluzione di 320x240 (per la profondità abbiamo solamente 320x240 e 80x60).

Tralasciamo il gestore di evento per le immagini di profondità (che abbiamo già visto nel precedente post) e ci dedichiamo a quello dello Skeletal Tracking:

  1. Private Sub SkeletonFrameHandler(sender As Object, e As SkeletonFrameReadyEventArgs)
  2.     Me.NormalToGravity = e.SkeletonFrame.NormalToGravity
  3.     Me.FloorClipPlane = e.SkeletonFrame.FloorClipPlane
  4.     Me.Quality = e.SkeletonFrame.Quality.ToString()
  5.     Dim skeleton = (From s In e.SkeletonFrame.Skeletons
  6.                   Where s.TrackingState = SkeletonTrackingState.Tracked
  7.                   Select s).FirstOrDefault()
  8.  
  9.     If skeleton IsNot Nothing Then
  10.         Me.CenterPosition = skeleton.Position
  11.         Me.Joints = skeleton.Joints.OfType(Of Joint)()
  12.     Else
  13.         Me.Joints = Nothing
  14.         Me.CenterPosition = New Vector()
  15.     End If
  16. End Sub

Le prime tre istruzioni non fanno altro che recuperare, rispettivamente, NormalToGravity, FloorClipPlane e Quality e valorizzare le relative proprietà del View Model (che andranno in binding con opportuni controlli di visualizzazione).

Tramite la query LINQ seguente andiamo a selezionare, tra tutti gli scheletri forniti nell’argomento dell’evento, il primo che abbia stato di tracciamento pari a Tracked.
Se ne esiste almeno uno (abbiamo, quindi, una istanza valida di SkeletonData), andiamo a valorizzare le proprietà del View Model che ci consentono di visualizzare il valore del centro di massa (proprietà CenterPosition) e il valore di ogni singolo Joint dello scheletro (proprietà Joints).

A questo punto abbiamo due tipologie di proprietà nel nostro View Model: quelle di tipo Vector (NormalToGravity, FloorClipPlane e CenterPosition) e la collezione di Joint esposta dalla Joints.

Tutte queste proprietà verranno visualizzate tramite TextBox e utilizzeremo degli appositi Converter per formattare opportunamente le stesse.

Per le proprietà di tipo Vector creiamo il converter:

  1. Public Class VectorToStringConverter
  2.     Implements IValueConverter
  3.  
  4.     Public Function Convert(value As Object,
  5.                             targetType As System.Type,
  6.                             parameter As Object,
  7.                             culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
  8.         If TypeOf value Is Vector Then
  9.             Dim vector = CType(value, Vector)
  10.             Dim strFormat = "{0:0.000} {1:0.000} {2:0.000} [{3:0.000}]"
  11.             If parameter IsNot Nothing Then
  12.                 strFormat = parameter.ToString()
  13.             End If
  14.             Dim str = String.Format(strFormat, vector.X, vector.Y, vector.Z, vector.W)
  15.             Return str
  16.         Else
  17.             Return Nothing
  18.         End If
  19.     End Function
  20.  
  21.     Public Function ConvertBack(value As Object,
  22.                                 targetType As System.Type,
  23.                                 parameter As Object,
  24.                                 culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
  25.         Throw New NotImplementedException
  26.     End Function
  27. End Class

In sostanza, prendiamo il valore da convertire e se è di tipo Vector e eseguiamo il metodo String.Format utilizzando la stringa di formato passata come parametro (o quella di default se il parametro non è impostato) e i valori di X, Y, Z e W del vettore.
Grazie all’utilizzo di questo converter possiamo visualizzare il centro di massa con il seguente XAML:

  1. <TextBox Text="{Binding Path=CenterPosition, Converter={StaticResource VectorToStringConverter}, ConverterParameter=\\cf1 {0:0.000\\cf1 } \\cf1 {1:0.000\\cf1 } \\cf1 {2:0.000\\cf1 } }"
  2.          Canvas.Left="448" Canvas.Top="460" Style="{StaticResource PosizionTextBox}"
  3.          Background="LightSteelBlue" Foreground="White"/>

Più interessante è sicuramente il converter che ci permetterà di visualizzare i dati di posizione del singolo Joint all’interno dei 20 TextBox che circondano l’uomo vitruviano.
In questo caso il converter accetta come parametri la stringa identificante l’id del Joint (as esempio “HandRight” per la mano destra) e la stringa di formattazione (questa è opzionale) separati dal carattere “|”.
Il codice del converter è il seguente:

  1. Public Class SkeletonJointPositionToStringConverter
  2.     Implements IValueConverter
  3.  
  4.     Public Function Convert(value As Object,
  5.                             targetType As System.Type,
  6.                             parameter As Object,
  7.                             culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
  8.         If TypeOf value Is IEnumerable(Of Joint) Then
  9.             Dim joints = CType(value, IEnumerable(Of Joint))
  10.             Dim parameters = parameter.ToString.Split("|"c)
  11.             If parameters.Count > 0 Then
  12.                 Dim jointId = parameters(0)
  13.                 Dim jointQuery = From j In joints
  14.                                 Where j.ID = CType([Enum].Parse(GetType(JointID), jointId), JointID)
  15.                                 Select j
  16.                 If jointQuery.Any() Then
  17.                     Dim joint = jointQuery.First()
  18.                     Dim strFormat = "{0:0.000} {1:0.000} {2:0.000}"
  19.                     If parameters.Count > 1 Then
  20.                         strFormat = parameters(1)
  21.                     End If
  22.                     Dim str = String.Format(strFormat, joint.Position.X, joint.Position.Y, joint.Position.Z)
  23.                     Return str
  24.                 Else
  25.                     Return Nothing
  26.                 End If
  27.             Else
  28.                 Return Nothing
  29.             End If
  30.             Else
  31.                 Return Nothing
  32.             End If
  33.     End Function
  34.  
  35.     Public Function ConvertBack(value As Object,
  36.                                 targetType As System.Type,
  37.                                 parameter As Object,
  38.                                 culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
  39.         Throw New NotImplementedException
  40.     End Function
  41. End Class

In questo caso, se il valore che stiamo convertendo è di tipo IEnumerable(Of Joint) (come la proprietà Joints del ViewModel), andiamo a ricercare, tramite una query LINQ, il Joint che ha id passato come parametro (notare la chiamata al metodo Split di String per ricavare i due argomenti separati da “|”). Se la query LINQ restituisce un joint valido (se la stringa di ID passata per argomento è uno dei valori ammessi), allora creiamo la stringa da visualizzare utilizzando la posizione del joint stesso e la restituiamo al chiamante.

Grazie a questo converter possiamo utilizzare il binding per visualizzare tutti e 20 i punti dell’uomo vitruviano senza dover creare 20 differenti proprietà nel view model. Ad esempio la visualizzazione della posizione della testa (Head) è la seguente:

  1. <TextBox Canvas.Left="470" Canvas.Top="70" Style="{StaticResource PosizionTextBox}"
  2.          Text="{Binding Path=Joints, Converter={StaticResource SkeletonJointPositionToStringConverter1}, ConverterParameter=Head|\\cf1 {0:0.000\\cf1 } \\cf1 {1:0.000\\cf1 } \\cf1 {2:0.000\\cf1 }}"
  3.          Background="{Binding Path=Joints, Converter={StaticResource SkeletonJointTrackingStateToSolidColorBrushConverter}, ConverterParameter=Head|LightGreen|LightYellow|LightCoral}" />

Osservando lo XAML, possiamo notare l’utilizzo di un binding anche sul background del TextBox e, questo, per fare in modo che in base allo stato di tracciamento del joint, si abbia un differente colore di sfondo. Anche in questo caso ricorriamo ad un converter:

  1. Public Class SkeletonJointTrackingStateToSolidColorBrushConverter
  2.     Implements IValueConverter
  3.  
  4.     Public Function Convert(value As Object,
  5.                             targetType As System.Type,
  6.                             parameter As Object,
  7.                             culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.Convert
  8.         If TypeOf value Is IEnumerable(Of Joint) Then
  9.             Dim joints = CType(value, IEnumerable(Of Joint))
  10.             Dim parameters = parameter.ToString.Split("|"c)
  11.             If parameters.Count > 0 Then
  12.                 Dim jointId = parameters(0)
  13.                 Dim jointQuery = From j In joints
  14.                                 Where j.ID = CType([Enum].Parse(GetType(JointID), jointId), JointID)
  15.                                 Select j
  16.  
  17.                 If jointQuery.Any() Then
  18.                     Dim joint = jointQuery.First()
  19.                     Dim color As Color?
  20.                     Select Case joint.TrackingState
  21.                         Case JointTrackingState.Tracked
  22.                             color = If(parameters.Count() < 1, Colors.LightGreen, ColorUtility.GetColorFromName(parameters(1)))
  23.                         Case JointTrackingState.Inferred
  24.                             color = If(parameters.Count() < 2, Colors.LightYellow, ColorUtility.GetColorFromName(parameters(2)))
  25.                         Case Else
  26.                             color = If(parameters.Count() < 3, Colors.LightCoral, ColorUtility.GetColorFromName(parameters(3)))
  27.                     End Select
  28.                     If color.HasValue Then
  29.                         Dim brush = New SolidColorBrush(color.Value)
  30.                         Return brush
  31.                     Else
  32.                         Return Nothing
  33.                     End If
  34.                 Else
  35.                     Return Nothing
  36.                 End If
  37.             Else
  38.                 Return Nothing
  39.             End If
  40.             Else
  41.                 Return Nothing
  42.             End If
  43.     End Function
  44.  
  45.     Public Function ConvertBack(value As Object,
  46.                                 targetType As System.Type,
  47.                                 parameter As Object,
  48.                                 culture As System.Globalization.CultureInfo) As Object Implements System.Windows.Data.IValueConverter.ConvertBack
  49.         Throw New NotImplementedException
  50.     End Function
  51. End Class

Il converter è del tutto analogo al precedente con la differenza che utilizza i parametri per ricevere la stringa identificante l’id del joint da analizzare e la terna di colori da utilizzare per gli stati Tracked, Inferred e NotTracked.

Ultima cosa prima di chiudere il post riguarda la possibilità di affinare la precisione dello skeletal tracking.

Se provate ad utilizzare lo skeletal tracking, infatti, vi renderete conto che anche rimanendo immobili, i valori di posizione oscillano.

E’ possibile intervenire su questo fenomeno di jittering impostando alcune proprietà del motore di skeletal tracking. La classe SkeletonEngine esposta dalla classe Runtime tramite la proprietà omonima, consente di impostare i parametri di Smooth Transform.

Questi parametri permettono il controllo della precisione del rilevamento dello scheletro da parte del KInect e la loro disamina accurata sarà oggetto di un altro post.

Nel nostro caso potremmo modificare il costruttore nel seguente modo:

  1. Public Sub New()
  2.     If Not DesignerProperties.GetIsInDesignMode(New DependencyObject()) Then
  3.         Try
  4.             Nui = New Runtime
  5.             AddHandler Nui.DepthFrameReady, AddressOf DepthFrameReadyHandler
  6.             AddHandler Nui.SkeletonFrameReady, AddressOf SkeletonFrameHandler
  7.             Nui.Initialize(RuntimeOptions.UseDepthAndPlayerIndex Or RuntimeOptions.UseSkeletalTracking)
  8.  
  9.             Nui.SkeletonEngine.TransformSmooth = True
  10.             Dim parameters = New TransformSmoothParameters With {.Smoothing = 0.75F,
  11.                                                                 .Correction = 0.0F,
  12.                                                                 .Prediction = 0.0F,
  13.                                                                 .JitterRadius = 0.05F,
  14.                                                                 .MaxDeviationRadius = 0.04F}
  15.             Nui.SkeletonEngine.SmoothParameters = parameters
  16.  
  17.             Nui.DepthStream.Open(ImageStreamType.Depth, 2, ImageResolution.Resolution320x240, ImageType.DepthAndPlayerIndex)
  18.         Catch ex As Exception
  19.  
  20.         End Try
  21.     End If
  22. End Sub

A seguito dell’initialize attiviamo la gestione dello smoothing (TransformSmooth=true), istanziamo un oggetto di classe TransformSmoothParameters e impostiamo la proprietà SmoothParameters dello SkeletonEngine.

La classe TransformSmoothParameters è poco documentata e per questo motivo cercheremo di approfondire il suo utilizzo in un ulteriore post.