Month: August 2011

Windows Phone SDK 7.1 Release Candidate

E’ stata rilasciata la Release Candidate (RC) del Windows Phone SDK 7.1 per Mango. E’ possibile scaricarlo al seguente link sul sito ufficiale.

Esso include :

  • Windows Phone SDK 7.1 (RC)
  • Windows Phone Emulator (RC)
  • Windows Phone SDK 7.1 Assemblies (RC)
  • Silverlight 4 SDK and DRT
  • Windows Phone SDK 7.1 Extensions for XNA Game Studio 4.0
  • Microsoft Expression Blend SDK for Windows Phone 7
  • Microsoft Expression Blend SDK for Windows Phone OS 7.1
  • WCF Data Services Client for Window Phone
  • Microsoft Advertising SDK for Windows Phone

Per poterlo installare è necessario disinstallare le versioni precedenti Windows Phone SDK 7.1 Beta1/Beta2 ma non i Windows Phone 7 Developer Tools; per non commettere errori eccovi un interessante articolo che vi segue passo passo per l’installazione.

Questo rilascio preannuncia che il lancio di Mango è ormai alle porte !!

Advertisements

WPF Dispatcher.CheckAccess() vs Windows Forms Control.InvokeRequired

Coloro che utilizzano quotidianamente le Windows Forms conosceranno il significato della property InvokeRequired nell’ambito della classe Windows.Forms.Control. Sappiamo infatti che i controlli di una Windows Forms sono legati ad uno specifico thread (generalmente il main thread) e non sono thread safe. Per questo motivo, se intendiamo invocare un qualsiasi metodo su un controllo oppure modificare una sua property (es. modificare il testo di una label o di una textbox) da un thread differente, è necessario invocare uno dei metodi che permettono di eseguire il marshal nel thread giusto. Questi ultimi sono : Invoke() per l’invocazione sincrona, BeginInvoke() e EndInvoke() per un’invocazione asincrona.

La property InvokeRequired ci permette di capire se è necessario eseguire questa operazione di marshal in un altro thread o meno. Per questo motivo, quando bisogna intervenire tipicamente sulla UI, all’interno del nostro metodo adottiamo un codice di questo tipo :

if (this.myControl.InvokeRequired)
{
    // accesso indiretto attraverso Invoke() o BeginInvoke()
    this.myControl.Invoke(.....);
}
else
{
    // accesso diretto a myControl
    this.myControl.SomeMethod();
    this.myControl.SomeProperty = value;
}

Ma esiste in WPF una controparte della InvokeRequired ?

In WPF, ogni controllo ha la property Dispatcher sulla quale è possibile invocare i medesimi metodi Invoke() e BeginInvoke() per eseguire il marshal nel thread giusto. Sempre Dispatcher fornisce la controparte della InvokeRequired, ossia il metodo CheckAccess() che ritorna true se l’invocazione avviene già nel thread giusto. Per questo motivo il codice suddetto diventa :

if (this.myControl.Dispatcher.CheckAccess())
{
    // accesso diretto a myControl
    this.myControl.SomeMethod();
    this.myControl.SomeProperty = value;
}
else
{
    // accesso indiretto attraverso Invoke() o BeginInvoke()
    this.myControl.Dispatcher.Invoke(.....);
}

E’ importante sottolineare che se in Visual Studio provate a farvi aiutare dall’Intellisense, il metodo CheckAccess() non vi verrà mostrato ma se lo scrivete senza alcun aiuto e compilate, tutto funzionerà correttamente. La sua invisibilità è dovuta alla sua dichiarazione :

[EditorBrowsable(EditorBrowsableState.Never)]
public bool CheckAccess();

Il gate per salire a bordo del Kinect : la classe Runtime

Tra tutte le classi messe a disposizione dal Kinect SDK, quella sicuramente più importante è la classe Runtime. Attraverso quest’ultima è possibile gestire tutti i sottosistemi, quali la video camera, il sensore di profondità ed il riconoscitore della figura umana. Di seguito riporto il relativo class diagram :

6153.Runtime-Class_56547733

Inizializzazione e deinizializzazione

Per poter utilizzare il Kinect, la prima cosa da fare è istanziare la classe Runtime.

nui = new Runtime();
Oltre al costruttore di default, senza alcun parametro, è previsto un suo overload che ha in ingresso un index che rappresenta l’identificativo del Kinect da inizializzare nel caso in cui al PC ve ne fosse collegato più di uno. Tale indice è inoltre accessibile successivamente attraverso la property InstanceIndex di sola lettura.
Successivamente, è necessario eseguirne l’inizializzazione, in modo che vengano allocate tutte le risorse unmanaged che sono necessarie per utilizzare i sottosistemi del dispositivo stesso. Per fare ciò, è necessario invocare il metodo Initialize().
nui.Initialize(RuntimeOptions.UseColor | RuntimeOptions.UseDepth);
Tale metodo prevede in ingresso un parametro di tipo RuntimeOptions, ossia un enumerativo attraverso il quale specificare quali sensori vogliamo utilizzare. Ovviamente, i valori possibili possono essere messi in OR tra loro in modo da utilizzare più sensori contemporaneamente. Più precisamente, sono i seguenti :
  • UseDepthAndPlayerIndex : utilizzo del sensore di profondità con riconoscimento del giocatore (ciascuna giocatore viene individuato attraverso un index diverso);
  • UseColor : utilizzo della video camera;
  • UseSkeletalTracking : riconoscimento della figura umana di ciascun giocatore;
  • UseDepth : utilizzo del sensore di profondità;
Una volta inizializzato ed utilizzato, l’istanza della Runtime va deinizializzata attraverso l’utilizzo del metodo Uninitialize() per poter permettere la deallocazione di tutte le risorse unmanaged.
nui.Uninitialize();
Gli stream, lo skeleton e la video camera
La classe Runtime dispone di alcune proprietà attraverso le quali è possibile accedere a tutte le funzionalità del Kinect.
In primo luogo, vi sono i due seguenti stream :
  • VideoStream : rappresenta lo stream della video camera, fornendo allo sviluppatore i fotogrammi ripresi da quest’ultima;
  • DepthStream : rappresenta lo stream del sensore di profondità, in cui ciascun pixel non esprime un punto di un’immagine (in termini RGB, come nel caso del VideoStream) ma fornisce l’informazione della distanza di quel punto rispetto al Kinect;

Entrambe le property rappresentano un riferimento alla classe ImageStream.

Per poter utilizzare tali stream, è necessario la loro apertura invocando su ciascuno di essi il relativo metodo Open() della classe ImageStream. Tale metodo prevede i seguenti parametri :

  • streamType : di tipo ImageStreamType che permette di dichiarare il tipo di stream al quale siamo interessati (Invalid, Depth o Video);
  • poolSize : dimensione del buffer (espresso in numero di frame) che il runtime dovrà utilizzare. Tipico valore è 2;
  • resolution : di tipo ImageResolution che indica la risoluzione da adottare per lo stream;
  • image : di tipo ImageType che indica il tipo di contenuto nell’immagine. Alcuni possibili valori sono ad esempio Depth per indicare un’immagine che contiene informazioni sulla distanza, Color per indicare un’immagine ripresa dalla video camera in formato RGB oppure ColorYuv per indicare un’immagine ripresa dalla video camera in formato YUV;
nui.VideoStream.Open(ImageStreamType.Video, 2,
ImageResolution.Resolution640x480, ImageType.Color);
nui.DepthStream.Open(ImageStreamType.Depth, 2,
ImageResolution.Resolution640x480, ImageType.Depth);

Per accedere al motore per il riconoscimento della figura umana, è disponibile la propertySkeletonEngine che rappresenta un riferimento alla classe SkeletonEngine. Infine, attraverso la property NuiCamera si ottiene un riferimento alla classe Camera, con la quale poter accedere alla video camera e modificarne per esempio l’inclinazione.

Intercettazione delle frame : gli eventi

Per evitare un utilizzo in modalità polling del Kinect, la classe Runtime mette a disposizione alcuni eventi che vengono sollevati quando sono disponibili nuove frame dalla video camera, dal sensore di profondità e dal riconoscitore della figura umana.

nui.VideoFrameReady += new EventHandler<ImageFrameReadyEventArgs>(nui_VideoFrameReady);
nui.DepthFrameReady += new EventHandler<ImageFrameReadyEventArgs>(nui_DepthFrameReady);
nui.SkeletonFrameReady += new EventHandler<SkeletonFrameReadyEventArgs>(nui_SkeletonFrameReady);

Essi rappresentano :

  • VideoFrameReady : sollevato quando è disponibile, nel buffer, una frame dello stream video (VideoStream);
  • DepthFrameReady : sollevato quando è disponibile, nel buffer, una frame dello stream di profondità (DepthStream);
  • SkeletonFrameReady : sollevato quando è disponibile un’immagine della figura umana rilevata dallo skeleton engine;

Kinect : il dispositivo, l’installazione dell’SDK ed i primi passi

Tutti i possessori o meno di una console XBOX sono a conoscenza dell’esistenza del Kinect, un fantastico dispositivo attraverso il quale la Microsoft ha iniziato a fare concorrenza alla Nintendo Wii, relativamente ai giochi che non prevedono l’utilizzo di un normale gamepad ma che si basano sui movimenti del corpo del giocatore.

Va sottolineato, però, che nel caso del Kinect il solo uso con la XBOX è piuttosto riduttivo ed infatti la Microsoft ha rilasciato ultimamente un SDK attraverso il quale poter sviluppare delle applicazioni che prevedono l’utilizzo del dispositivo collegandolo al PC.

Prima di poter iniziare ad esplorare gli strumenti messi a disposizione nell’SDK, è utile comprendere le funzionalità del dispositivo e preparare il nostro PC con il relativo ambiente di sviluppo.

Il Kinect visto da vicino

Il Kinect è costituito dai quattro seguenti dispositivi principali :

  • Videocamera RGB (RGB camera) : una normale video camera con una risoluzione di 640 x 480 a 30 fps (frames per second);
  • Sensore di profondità (3D Depth Sensors) : costituito da una trasmettitore ad infrarossi ed il corrispondente ricevitore attraverso i quali è possibile calcolare le distanze degli oggetti;
  • Un motore per l’inclinazione (Motorized Tilt) : un piccolo motore che permette di variare l’inclinazione della video camera fino ad un massimo di 27 gradi (in alto o in basso);
  • Una serie di microfoni (Multi-Array Mic) : una serie di quattro microfoni per l’audio;

6406.kinect_69CB3395

Installazione : SDK e driver Kinect

L’ambiente necessario per lo sviluppo è Visual Studio 2010, almeno nella sua versione Express (nel mio caso è la Ultimate che uso quotidianamente).

Ad esso vanno aggiunti ed installati :

  • Kinect SDK (ovviamente ancora in versione Beta) che possiamo scaricare al seguentelink (in entrambe le versioni 32 o 64 bit);
  • DirectX Software Development Kit che possiamo scaricare al seguente link:

Al termine dell’installazione, per verificare che il tutto sia avvenuto correttamente, possiamo collegare il Kinect al nostro PC attraverso il cavo USB e verificarne la sua presenza attraversoGestione Dispositivi nel Pannello di Controllo.

2703.kinect_device_manager_3DDA940C

Inoltre, il gruppo dei microfoni dovrebbe essere visibile nella scheda dei Dispositivi di Registrazione.

8507.kinect_mic_array_6A171AF0

Per quanto riguarda il cavo di collegamento del Kinect al PC, va sottolineato che quest’ultimo non ha nativamente un connettore USB ma è necessario acquistare un adattatore con relativo alimentatore. Sul Microsoft Store, al seguente link, è riportata la versione per gli Stati Uniti ma è ovviamente possibile acquistare anche la versione Italiana.

Sviluppo : i primi passi

Affrontiamo adesso i primi passi per poter iniziare a sviluppare con il Kinect SDK, introducendo la classe principale di quest’ultimo : la Runtime.

Creiamo un nuovo progetto WPF (ovviamente possiamo utilizzare anche le Windows Forms) e per prima cosa aggiungiamo il riferimento al seguente assembly :Microsot.Research.Kinect.

6457.assembly_2A3D0E9E

Inoltre, per poter utilizzare tutte le classi disponibili nell’SDK è necessario aggiungere lo using dei seguenti namespace.

using Microsoft.Research.Kinect.Audio;
using Microsoft.Research.Kinect.Nui;

Definiamo un campo privato nella classe MainWindow di tipo Runtime ed istanziamolo.

public partial class MainWindow : Window
{
    private Runtime nui = new Runtime();

    public MainWindow()
    {
...
...

Infine, utilizzando i due eventi di Loaded ed Unloaded della Window, aggiungiamo nei corrispondenti event handlers le istruzioni per poter inizializzare e deinizializzare l’instanza della Runtime.

private void Window_Loaded(object sender, RoutedEventArgs e)
{
    this.nui.Initialize(RuntimeOptions.UseColor | RuntimeOptions.UseDepth);
}

private void Window_Unloaded(object sender, RoutedEventArgs e)
{
    this.nui.Uninitialize();
}

Attraverso il metodo Initialize() vengono specificate quale features vogliamo utilizzare del Kinect (in questo caso la video camera ed il sensore di profondità). Il metodo Uninitialize()è invece necessario per rilasciare tutte le risorse unmanaged che il sistema ha allocato per l’utilizzo del Kinect.

Eseguendo questa banalissima applicazione, che non fa assolutamente nulla, noteremo solamente che all’esecuzione del metodo Initialize(), il dispositivo accenderà il trasmettitore ad infrarossi del sensore di profondità; già questo indica che l’inizializzazione è andata a buon fine. Viceversa, chiudendo la finestra dell’applicazione, il trasmettitore verrà spento (in quanto viene eseguito il metodo Uninitialize()); la deallocazione delle risorse è avvenuta correttamente.