domenica 13 aprile 2014

Codemotion Roma 2014 : le slide

Venerdì e sabato si è svolta la tappa romana di Codemotion 2014. Due giorni ricchi di incontri, formazione e nuove cosa da apprendere.

La mia sessione, dedicata interamente alle nuove funzionalità di Kinect, ha visto una buona affluenza di pubblico con tante domande e un interesse crescente verso questo genere di dispositivi e delle loro possibili applicazioni.

Se volete scaricare le slide utilizzate il link.

Alla prossima!!! Thumbs up

 

lunedì 7 aprile 2014

Kinect V2: MultiFrameSource

Nei precedenti post abbiamo dato un’occhiata alle varie sorgenti messe a disposizione dalla nuova versione del Kinect.

Abbiamo visto come sia possibile recuperare il reader opportuno e sfruttare tale reader per ottenere i singoli frame desiderati.

Nella stragrande maggioranza delle applicazioni, però, abbiamo la necessità di elaborare più sorgenti contemporaneamente (basti pensare, ad esempio ad una applicazione che rileva il body del giorcatore e contemporaneamente mostra l’immagine proveniente dalla cam).

In questo caso, l’SDK ci viene in aiuto mettendoci a disposizione una sorgente particolare della MultiFrameSource.

L’utilizzo di questo tipo particolare di sorgente si differenzia rispetto all’utilizzo delle altre sorgenti “singole”. Le sorgenti singole sono esposte direttamente, tramite delle proprietà, dalla classe KinectSensor. Una volta ottenuta la reference alla sorgente, possimao utilizzare il metodo OpenReader per avere a disposizione il reader che, effettivamente, ci permette di consumare i dati.

Nel caso della MultiFrameSource, questa non è direttamente accessibile tramite la classe KinectSensor, ma quest’ultima ci fornisce un metodo (il metodo OpenMultiSourceFrameReader() ) per aprire il reader opportuno.

Sensor = KinectSensor.Default
If Sensor IsNot Nothing Then
    Sensor.Open()
    MultiReader = Sensor.OpenMultiSourceFrameReader(FrameSourceTypes.Color Or
                                                    FrameSourceTypes.BodyIndex Or
                                                    FrameSourceTypes.Body)
End If

Nel precedente pezzo di codice osserviamo che il metodo OPenMultiSourceFrameReader accetta come argomento l’elenco delle sorgenti a cui siamo effettivamente interessati (enumerazione FrameSourceTypes):

image

Una volta ottenuto il reader, il procedimento con cui elaboriamo i frame provenienti dal device è analogo a quello delle altre sorgenti.

Il reader espone il metodo MultiSourceFrameArrived che possiamo gestire e che viene richiamato ogni volta che il frame è disponibile per l’eleborazione:

If MultiReader IsNot Nothing Then
    AddHandler MultiReader.MultiSourceFrameArrived, AddressOf MultiSourceFrameArrivedHandler
End If

L’argomento fornito dal metodo (di tipo MultiSourceFrameArrivedEventArgs) espone, in maniera analoga a quanto fanno i corrispettivi argomenti forniti dagli altri metodi di gestione dei frame, una proprietà, di tipo MultiSourceFrameReference.
Ancora una volta, come per gli altri source reference, abbiamo a disposizione il metodo AcquireFrame() per recuperare, effettivamente il frame.

image

L’istanza di MultiSourceFrame espone le reference ai singoli frame il cui utilizzo è già stato trattato nei precedenti post.

Nel seguente pezzo di codice, ad esempio, andiamo a gestire l’immagine proveniente dal device, i body e il body index:

Private Sub MultiSourceFrameArrivedHandler(sender As Object, e As MultiSourceFrameArrivedEventArgs)
    Dim frameReference = e.FrameReference
    Dim frame As MultiSourceFrame = Nothing
    Try
        frame = frameReference.AcquireFrame()
        If frame IsNot Nothing Then
            Using dc = DrawingGroup.Open()
                DrawColorImage(frame, dc)

                DrawBody(frame, dc)

                DrawPlayerIndex(frame, dc)
            End Using
        End If
    Catch ex As Exception

    Finally
        If frame IsNot Nothing Then frame.Dispose()
    End Try
End Sub

Il codice per la gestione dell’immagine è, come possiamo vedere, del tutto simile a quello visto nel precedente post.

Private Sub DrawColorImage(ByVal frame As MultiSourceFrame, dc As DrawingContext)
    If frame Is Nothing Then Return
    Using colorFrame = frame.ColorFrameReference.AcquireFrame()
        If colorFrame IsNot Nothing Then
            If colorFrame.RawColorImageFormat = ColorImageFormat.Bgra Then
                colorFrame.CopyRawFrameDataToArray(Me.ColorData)
            Else
                colorFrame.CopyConvertedFrameDataToArray(Me.ColorData, ColorImageFormat.Bgra)
            End If

            Dim bitmap = New WriteableBitmap(colorFrame.FrameDescription.Width, colorFrame.FrameDescription.Height,
                                             96.0, 96.0, PixelFormats.Bgr32, Nothing)
            bitmap.WritePixels(New Int32Rect(0, 0, colorFrame.FrameDescription.Width, colorFrame.FrameDescription.Height),
                               Me.ColorData,
                               colorFrame.FrameDescription.Width * BytesPerPixel,
                               0)

            dc.DrawImage(bitmap, New System.Windows.Rect(0, 0, colorFrame.FrameDescription.Width, colorFrame.FrameDescription.Height))
        End If
    End Using
End Sub

Le reference ai frame che non abbiamo selezionato in fase di apertura del reader non sono valorizzati.

 

Technorati Tags: ,,,

mercoledì 2 aprile 2014

Windows Store App: dalla build allo Store

Vi segnalo un mio articolo comparso su HTML.it riguardante il processo di pubblicazione di una app Windows Store.

Potete trovare la versione per C# e XAML all’indirizzo:

http://www.html.it/pag/47817/windows-store-app-dalla-build-allo-store-2/

Esiste anche una versione HTML+WinJS all’indirizzo:

http://www.html.it/pag/47756/windows-store-app-dalla-build-allo-store/

 

Buona lettura!!

 

lunedì 31 marzo 2014

Kinect V2 : Body stream – Activities, Appearance e Expressions

In questo post prenderemo alcune nuove funzionalità messe a disposizione dall’SDK del Kinect 2 e che riguardano il modo di apparire e di porsi dell’utente davanti al device.

La classe Body, vista in dettaglo nel precedente post, ci permette di accedere ad alcune caratteristiche “dinamiche” del singolo player che si pone davanti al device.

In particolare abbiamo a disposizione:

  • Activities : ci dicono cosa sta facendo il player. Ad esempio se ha l’occhio destro chiuso o se ha la bocca aperta;
  • Appearance : come appare l’utente. Ad esempio se indossa gli occhiali;
  • Expressions : le espressioni che l’utente assume. Ad esempio se sta ridendo.

La classe Body espone tre Dictionary che contengono le tre caratteristiche elencate in precedenza:

image

La proprietà Activities è un Dictionary (a sola lettura) con chiave uno dei valori dell’enumerazione Activity e valore l’enumerazione DetectionResult.
Le altre due collezioni funzionano in maniera del tutto analoga cambiando esclusivamente l’enumerazione chiave.

In questo momento abbiamo le seguenti Activity:

  • EyeLeftClosed : il player ha l’occhio sinistro chiuso;
  • EyeRightClosed : il player ha l’occhio destro chiuso;
  • LookingAway : il player non sta guardando il sensore;
  • MouthMoved : il player sta muovendo la bocca;
  • MouthOpen : il player ha la bocca aperta.

Se interroghiamo la proprietà Acivities con uno dei valori di enumerazione precedente, otteniamo un oggetto di tipo DetectionResult i cui valori ci permettono di capire se l’activity in esame è attiva o meno o potrebbe esserlo (MayBe).

Le Expression che abbiamo a disposizione in questo momento sono:

  • Happy : il player ha un espressione allegra (ad esempio sta ridendo);
  • Neutral : il player non ha nessuna espressione particolare.

Infine, per quanto riguarda le Appearance, in questo momento, abbiamo solo la WearingGlass che ci dice se il player porta gli occhiali.

 

Disclaimer: “This is preliminary software and/or hardware and APIs are preliminary and subject to change.”

 

Technorati Tags: ,,

lunedì 24 marzo 2014

Kinect V2 : body stream – hand tracking

In questo post continuiamo l’analisi delle informazioni forniteci dallo stream body del Kinect V2 prendendo in esame la funzionalità di tracking delle mani dei player.

Le funzionalità di tracking delle mani dei player sono accessibili grazie alla classe Body vista nel precedente post.

In particolare la classe Body espone due proprietà per ogni mano:

  • HandRighState, HandLeftState: permette di conoscere lo stato della mano ovvero se la mano è non tracciata, aperta, chiusa o con le dita a V oppure se l’SDK non è riuscito a riconoscerla;
  • HandRghtConfience, HandeLeftConfidence: indica la confidence (low o high) dello stato della mano.

image

Possiamo, quindi, utilizzare queste proprietà per prendere decisioni in base allo stato della mano o delle mani del player.

A livello di codice abbiamo la necessità di inizializzare il device e gestire la sorgente Body in maniera analoga a quanto visto nel precedente post:

Sensor = KinectSensor.Default
If Sensor IsNot Nothing Then
    Sensor.Open()

    BodyData = New Body(CInt(Sensor.BodyFrameSource.BodyCount - 1)) {}
    
    BodyReader = Sensor.BodyFrameSource.OpenReader()
End If

dove

Private Property Sensor As KinectSensor
Private Property BodyReader As BodyFrameReader
Private Property BodyData As Body()

Per ricevere i frame riguardanti i Body rilevati dal device dobbiamo gestire l’evento FrameArrived del BodyReader:

If BodyReader IsNot Nothing Then
    AddHandler BodyReader.FrameArrived, AddressOf BodyFrameArrivedHandler
End If

E, quindi, possiamo recuperare la collezione di Body:

Private Sub BodyFrameArrivedHandler(sender As Object, e As BodyFrameArrivedEventArgs)
    Dim frameReference = e.FrameReference
    Dim frame As BodyFrame = Nothing
    Try
        frame = frameReference.AcquireFrame()
        If frame IsNot Nothing Then
            frame.GetAndRefreshBodyData(BodyData)
            OnPropertyChanged("Player0HandRightState")
            OnPropertyChanged("Player0HandLeftState")
            OnPropertyChanged("Player0HandRightConfidence")
            OnPropertyChanged("Player0HandLeftConfidence")
        End If
    Catch ex As Exception

    Finally
        If frame IsNot Nothing Then
            frame.Dispose()
        End If
    End Try
End Sub

Supponiamo di avere un’applicazione WPF e di voler semplicemente visualizzare lo stato delle mani con immagini differenti e la confidence con un differente valore di opacità (senza necessariamente dover visualizzare la mano nella posizione spaziale in cui si trova).

Per fare questo, esponeniamo le 4 proprietà riguardanti lo stato e la confidence delle mani del player con indice 0:

Public ReadOnly Property Player0HandRightState As HandState
    Get
        Return GetHandStateForPlayer(0, Hand.Right)
    End Get
End Property

Public ReadOnly Property Player0HandLeftState As HandState
    Get
        Return GetHandStateForPlayer(0, Hand.Left)
    End Get
End Property

Public ReadOnly Property Player0HandRightConfidence As TrackingConfidence
    Get
        Return GetHandConfidenceForPlayer(0, Hand.Right)
    End Get
End Property

Public ReadOnly Property Player0HandLeftConfidence As TrackingConfidence
    Get
        Return GetHandConfidenceForPlayer(0, Hand.Left)
    End Get
End Property

 

Private Function GetHandStateForPlayer(playerIndex As Int16, hand As Hand) As HandState
    If playerIndex < 0 Or playerIndex > 5 Then Throw New ArgumentOutOfRangeException

    If BodyData(playerIndex) Is Nothing Then Return HandState.NotTracked
    Select Case hand
        Case MainWindowViewModel.Hand.Left
            Return BodyData(playerIndex).HandLeftState
        Case MainWindowViewModel.Hand.Right
            Return BodyData(playerIndex).HandRightState
    End Select
    Throw New NotImplementedException()
End Function

Private Function GetHandConfidenceForPlayer(playerIndex As Int16, hand As Hand) As TrackingConfidence
    If playerIndex < 0 Or playerIndex > 5 Then Throw New ArgumentOutOfRangeException

    If BodyData(playerIndex) Is Nothing Then Return TrackingConfidence.Low
    Select Case hand
        Case MainWindowViewModel.Hand.Left
            Return BodyData(playerIndex).HandLeftConfidence
        Case MainWindowViewModel.Hand.Right
            Return BodyData(playerIndex).HandRightConfidence
    End Select
    Throw New NotImplementedException()
End Function

e le mettiamo in binding con la nostra interfaccia:

<TextBlock Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="center" FontWeight="Bold" FontSize="24">Player 0</TextBlock>
<Image Grid.Row="1" Grid.Column="1" Width="64" Height="64"
       Source="{Binding Path=Player0HandRightState, Converter={StaticResource ResourceKey=HandStateConverter}, ConverterParameter=Right}"
       Opacity="{Binding Path=Player0HandRightConfidence, Converter={StaticResource ResourceKey=HandConfidenceConverter}}"
       Margin="20,10,20,10"/>
<Image Grid.Row="1" Grid.Column="2" Width="64" Height="64"
       Source="{Binding Path=Player0HandLeftState, Converter={StaticResource ResourceKey=HandStateConverter}, ConverterParameter=Left}"
       Opacity="{Binding Path=Player0HandLeftConfidence, Converter={StaticResource ResourceKey=HandConfidenceConverter}}"
       Margin="20,10,20,10"/>

Nel precedente XAML sfruttiamo due converter che, rispetivamente, selezionano l’immagine da visualizzare e decidono l’opacità della stessa:

Public Class HandStateToImageConverter
    Implements IValueConverter

    Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IValueConverter.Convert
        If TypeOf value Is HandState And TypeOf parameter Is String Then
            Dim handString = parameter.ToString()
            Return GetImageForHandState(CType(value, HandState), handString)
        End If
        Return Nothing
    End Function

    Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack
        Throw New NotImplementedException()
    End Function

    Private Function GetImageForHandState(state As HandState, hand As String) As ImageSource
        Dim uriString As String = Nothing
        Select Case state
            Case HandState.Closed
                uriString = String.Format("./Assets/{0}HandClose.png", hand)
            Case HandState.Lasso
                uriString = String.Format("./Assets/{0}HandLasso.png", hand)
            Case HandState.Open
                uriString = String.Format("./Assets/{0}HandOpen.png", hand)
            Case HandState.Unknown
                uriString = "./Assets/UnknowState.png"
        End Select
        If uriString IsNot Nothing Then
            Dim bitmap = New BitmapImage(New Uri(uriString, UriKind.RelativeOrAbsolute))
            Return bitmap
        Else
            Return Nothing
        End If
    End Function
End Class

Public Class HandConfidenceToOpacityConverter
    Implements IValueConverter

    Public Function Convert(value As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IValueConverter.Convert
        If TypeOf value Is TrackingConfidence Then
            Dim confidence = CType(value, TrackingConfidence)
            Select Case confidence
                Case TrackingConfidence.High
                    Return 1
                Case TrackingConfidence.Low
                    Return 0.5
                Case Else
                    Return 0
            End Select
        End If
        Return Nothing
    End Function

    Public Function ConvertBack(value As Object, targetType As Type, parameter As Object, culture As Globalization.CultureInfo) As Object Implements IValueConverter.ConvertBack
        Throw New NotImplementedException()
    End Function
End Class

Il primo converter agisce su un oggetto di tipo HandState e si aspetta un parametro stringa che indica di quale mano si tratta, mentre il secondo agisce su un oggetto di tipo TrackingConfidence.

Come possiamo vedere, una volta a disposizione l’istanza di Body, è relativamente semplice capire quale è lo stato delle mani dei singoli player.

Attualmente, l’SDK del Kinect è in grado di tracciare, per quanto riguarda le mani, solo due player (di default il player 0 ed il player 1). Possiamo modificare qualli player vengono tracciati grazie al metodo OverrideHandTracking() esposto dalla sorgente Body.

Disclaimer: “This is preliminary software and/or hardware and APIs are preliminary and subject to change.”

 

Technorati Tags: ,,

martedì 18 marzo 2014

HTML.it : CodedUI test per Windows Store Apps

 

Vi segnalo il mio l’articolo “CodedUI test per Windows Store Apps” pubblicato su HTML.it e facente parte della guida avanzata per la creazione di applicazioni Windows Store App.

E’ disponibile anche la versione per HTML+Javascript (link).

Per completare la “marchetta”, vi ricordo che il 28 Marzo 2014, all’Università Partenope di Napoli, si terrà l’ALM Day che vedrà coinvolte 3 community (DotNetCampania, DotNetMarche e DomusDotNet) con 8 sessioni che vanno dalla gestione dell’ALM al test passando per la qualità del software.

banner-300x250-almday

L’evento è completamente gratuito e da non perdere!!!!

lunedì 17 marzo 2014

Kinect V2: body source – joints

In questo post prenderemo in esame lo stream body source fornito dal Kinect V2 e, in particolare, ci occuperemo della funzionalità che sostituisce quella, già presente nella versione 1 dell’SDK e che prendeva il nome di Skeletal Tracking.

Come accadeva per la versione precedente, il device è in grado di fornirci la posizione nello spazio di un insieme di punti del corpo umano.

Nella precedente versione del Kinect avevamo a disposizione 20 punti (detti joints) mentre nella nuova versione sono 25. Sono stati aggiunti il collo (neck), il pollice (Thumb) di entrambe le mani e la punta dell’insieme delle altre dita (Hand_Tip).

image

Nella precedente versione dell’SDK, la struttura dati che conteneva le informazioni relative ai joints prendeva il nome di Skeleton, in questa versione la struttura dati che contiene i dati dei joints si chiama Body.
Questo perchè, come vedremo anche nei prossimi post, la classe Body contiene un numero di informazioni superiore rispetto alla vecchia skeleton: tra queste troviamo le espressioni, le attività, lo stato delle mani.

Inoltre, a differenza della vecchia versione, in questa abbiamo fino a 6 player tracciati contemporaneamente in modo completo (nella vecchia ne avevamo 2 completamente e 4 solo per il baricentro).

Occupiamoci, in questo post di analizzare solo la parte relativa allo scheletro (sia in termini di joints che di orientamento di questi).

Come già visto in precedenti post, abbiamo la necessità di recuperare il device e, quindi, il reader dello stream body:

Sensor = KinectSensor.Default
If Sensor IsNot Nothing Then
    Sensor.Open()

   BodyReader = Sensor.BodyFrameSource.OpenReader()
End If

In maniera analoga a quanto visto in precedenza dobbiamo gestire l’evento FrameArrived:

If BodyReader IsNot Nothing Then
    AddHandler BodyReader.FrameArrived, AddressOf BodyFrameArrivedHandler
End If

La struttura delle classi in gioco per quanto riguarda reader ed evento è la seguente:

image

image

Il metodo AcquireFrame() della classe BodyFrameReference ci permette di recuperare l’istanza di BodyFrame:

Private Sub BodyFrameArrivedHandler(sender As Object, e As BodyFrameArrivedEventArgs)
    Dim frameReference = e.FrameReference
    Dim frame As BodyFrame = Nothing
    Try
        frame = frameReference.AcquireFrame()
        If frame IsNot Nothing Then

            'Elabora il frame

        End If
    Catch ex As Exception

    Finally
        If frame IsNot Nothing Then
            frame.Dispose()
        End If
    End Try
End Sub

La classe BodyFrame ci mette a disposizione il metodo GetAndRefreshBodyData che ci permette di recuperare effettivamente le istanze dei Body tracciati.

In particolare, il metodo GetAndRefreshBodyData ha un comportamento del tutto particolare:

  • E’ nostro compito preparare e dimensionare opportunamente l’array di oggetti Body da passare al metodo. Il numero di body tracciabili dal Kinect è contenuto nella proprietà  BodyCount della classe BodyFrameSource;
  • Per ogni elemento dell’array da noi passato:
    • se l’elemento è Nothing, viene creata una nuova istanza di Body e memorizzata nell’array;
    • se l’elemento non è nullo, l’istanza viene riutilizzata e riempita con i nuovi dati ottenuti dal nuovo frame.

Questo meccanismo consente di ottimizzare la memoria, riutilizzando le strutture dati e allocando, quindi, meno memoria.

Se abbiamo la necessità di memorizzare una particolare istanza di Body in un determinato frame, è sufficiente salvare l’elemento dell’array desiderato in una variabile d’appoggio e impostare l’elemento al valore Nothing. L’SDK ne creerà uno nuovo quando recupereremo il frame e la vecchia istanza resterà a nostra disposizione )avendo un puntatore valido nella variabile d’appoggio).

La classe Body contiene moltissime informazioni (alcune delle quali verranno prese in esame nei prossimi post) tra le quali troviamo quelle relative ai joint e al loro orientamento:

image

Chi conosce la funzione di skeletal tracking del Kinect V1, potrà osservare che le classi in gioco sono praticamente le stesse.

Ogni joint, identificato da un valore dell’enumerazione JointType, espone una posizione nello spazio (CameraSpacePoint) e un TrackingState.

Ogni JointOrientation, anch’esso identificato dal valore di JointType, un vettore a 4 dimensioni il cui significato è mostrato nella seguente figura:

image

Da notare anche la proprietà ClippedEdges della classe Body che ci permette di sapere se lo scheletro corrispondente viene “tagliato” da uno o più dei bordi (cioè uno dei joints finisce fuori dallo schermo da uno dei lati).

Un esempio di elaborazione dei dati ottenuti dallo stream del body può essere il seguente:

Private Property DrawingGroup As DrawingGroup

Private Property DrawingImage As DrawingImage

Private Sub BodyFrameArrivedHandler(sender As Object, e As BodyFrameArrivedEventArgs)
    Dim frameReference = e.FrameReference
    Dim frame As BodyFrame = Nothing
    Try
        frame = frameReference.AcquireFrame()
        If frame IsNot Nothing Then

            Using dc = DrawingGroup.Open()
                frame.GetAndRefreshBodyData(BodyData)
                dc.DrawRectangle(Brushes.Black, Nothing, New Rect(0.0, 0.0, DisplayWidth, DisplayHeight))
                For Each Body In BodyData

                    If Body.IsTracked Then
                        BodyGraphicHelper.DrawClippedEdges(Body, DisplayHeight, DisplayWidth, dc)
                        Dim joints = Body.Joints

                        Dim jointPoints = New Dictionary(Of JointType, Point)()
                        For Each jointType In joints.Keys
                            Dim depthSpacePoint = CoordinateMapper.MapCameraPointToDepthSpace(joints(jointType).Position)
                            jointPoints(jointType) = New Point(depthSpacePoint.X, depthSpacePoint.Y)
                        Next

                        BodyGraphicHelper.DrawBody(joints, jointPoints, dc)
                    End If
                Next
                DrawingGroup.ClipGeometry = New RectangleGeometry(New Rect(0.0, 0.0, DisplayWidth, DisplayHeight))
            End Using
        End If
    Catch ex As Exception

    Finally
        If frame IsNot Nothing Then
            frame.Dispose()
        End If
    End Try
End Sub

In questo caso, utilizziamo un’istanza della classe DrawingGroup come superfice di disegno e, per ogni body tracciato (proprietà IsTracked a true), disegnamo una riga rossa lungo gli eventuali bordi che “tagliano” lo scheletro e lo scheletro vero e proprio.
Per eseguire il disegno utilizziamo la seguente classe statica:

Imports Microsoft.Kinect

Public Class BodyGraphicHelper

    Private Shared HandSize As Double = 30

    Private Shared JointThickness As Double = 3

    Private Shared ClipBoundsThickness As Double = 10

    Private Shared ReadOnly HandClosedBrush As Brush = New SolidColorBrush(Color.FromArgb(128, 255, 0, 0))

    Private Shared ReadOnly HandOpenBrush As Brush = New SolidColorBrush(Color.FromArgb(128, 0, 255, 0))

    Private Shared ReadOnly HandLassoBrush As Brush = New SolidColorBrush(Color.FromArgb(128, 0, 0, 255))

    Private Shared ReadOnly TrackedJointBrush As Brush = New SolidColorBrush(Color.FromArgb(255, 68, 192, 68))

    Private Shared ReadOnly InferredJointBrush As Brush = Brushes.Yellow

    Private Shared ReadOnly TrackedBonePen As Pen = New Pen(Brushes.Green, 6)

    Private Shared ReadOnly InferredBonePen As Pen = New Pen(Brushes.Gray, 1)

    Public Shared Sub DrawBody(joints As IReadOnlyDictionary(Of JointType, Joint),
                                 jointPoints As IDictionary(Of JointType, Point),
                                 drawingContext As DrawingContext)
        ' Draw the bones

        ' Torso
        DrawBone(joints, jointPoints, JointType.Head, JointType.Neck, drawingContext)
        DrawBone(joints, jointPoints, JointType.Neck, JointType.SpineShoulder, drawingContext)
        DrawBone(joints, jointPoints, JointType.SpineShoulder, JointType.SpineMid, drawingContext)
        DrawBone(joints, jointPoints, JointType.SpineMid, JointType.SpineBase, drawingContext)
        DrawBone(joints, jointPoints, JointType.SpineShoulder, JointType.ShoulderRight, drawingContext)
        DrawBone(joints, jointPoints, JointType.SpineShoulder, JointType.ShoulderLeft, drawingContext)
        DrawBone(joints, jointPoints, JointType.SpineBase, JointType.HipRight, drawingContext)
        DrawBone(joints, jointPoints, JointType.SpineBase, JointType.HipLeft, drawingContext)

        ' Right Arm    
        DrawBone(joints, jointPoints, JointType.ShoulderRight, JointType.ElbowRight, drawingContext)
        DrawBone(joints, jointPoints, JointType.ElbowRight, JointType.WristRight, drawingContext)
        DrawBone(joints, jointPoints, JointType.WristRight, JointType.HandRight, drawingContext)
        DrawBone(joints, jointPoints, JointType.HandRight, JointType.HandTipRight, drawingContext)
        DrawBone(joints, jointPoints, JointType.WristRight, JointType.ThumbRight, drawingContext)

        ' Left Arm
        DrawBone(joints, jointPoints, JointType.ShoulderLeft, JointType.ElbowLeft, drawingContext)
        DrawBone(joints, jointPoints, JointType.ElbowLeft, JointType.WristLeft, drawingContext)
        DrawBone(joints, jointPoints, JointType.WristLeft, JointType.HandLeft, drawingContext)
        DrawBone(joints, jointPoints, JointType.HandLeft, JointType.HandTipLeft, drawingContext)
        DrawBone(joints, jointPoints, JointType.WristLeft, JointType.ThumbLeft, drawingContext)

        ' Right Leg
        DrawBone(joints, jointPoints, JointType.HipRight, JointType.KneeRight, drawingContext)
        DrawBone(joints, jointPoints, JointType.KneeRight, JointType.AnkleRight, drawingContext)
        DrawBone(joints, jointPoints, JointType.AnkleRight, JointType.FootRight, drawingContext)

        ' Left Leg
        DrawBone(joints, jointPoints, JointType.HipLeft, JointType.KneeLeft, drawingContext)
        DrawBone(joints, jointPoints, JointType.KneeLeft, JointType.AnkleLeft, drawingContext)
        DrawBone(joints, jointPoints, JointType.AnkleLeft, JointType.FootLeft, drawingContext)

        ' Draw the joints
        For Each jointType In joints.Keys
            Dim drawBrush As Brush = Nothing

            Dim trackingState = joints(jointType).TrackingState

            If trackingState = trackingState.Tracked Then

                drawBrush = TrackedJointBrush
            ElseIf trackingState = trackingState.Inferred Then
                drawBrush = InferredJointBrush
            End If

            If drawBrush IsNot Nothing Then drawingContext.DrawEllipse(drawBrush, Nothing, jointPoints(jointType), JointThickness, JointThickness)
        Next
    End Sub

    Public Shared Sub DrawBone(joints As IReadOnlyDictionary(Of JointType, Joint),
                                  jointPoints As IDictionary(Of JointType, Point),
                                   jointType0 As JointType, jointType1 As JointType,
                                    drawingContext As DrawingContext)

        Dim joint0 = joints(jointType0)
        Dim joint1 = joints(jointType1)

        If joint0.TrackingState = TrackingState.NotTracked Or joint1.TrackingState = TrackingState.NotTracked Then Exit Sub

        If joint0.TrackingState = TrackingState.Inferred And joint1.TrackingState = TrackingState.Inferred Then Exit Sub

        Dim drawPen = InferredBonePen
        If joint0.TrackingState = TrackingState.Tracked And joint1.TrackingState = TrackingState.Tracked Then drawPen = TrackedBonePen

        drawingContext.DrawLine(drawPen, jointPoints(jointType0), jointPoints(jointType1))
    End Sub

    Public Shared Sub DrawClippedEdges(body As Body, displayHeight As Double, displayWidth As Double, drawingContext As DrawingContext)
        Dim clippedEdges = body.ClippedEdges

        If clippedEdges.HasFlag(FrameEdges.Bottom) Then drawingContext.DrawRectangle(Brushes.Red, Nothing,
            New Rect(0, displayHeight - ClipBoundsThickness, displayWidth, ClipBoundsThickness))

        If clippedEdges.HasFlag(FrameEdges.Top) Then drawingContext.DrawRectangle(Brushes.Red, Nothing,
            New Rect(0, 0, displayWidth, ClipBoundsThickness))

        If clippedEdges.HasFlag(FrameEdges.Left) Then drawingContext.DrawRectangle(Brushes.Red, Nothing,
            New Rect(0, 0, ClipBoundsThickness, displayHeight))

        If clippedEdges.HasFlag(FrameEdges.Right) Then drawingContext.DrawRectangle(Brushes.Red, Nothing,
            New Rect(displayWidth - ClipBoundsThickness, 0, ClipBoundsThickness, displayHeight))
    End Sub
End Class

In sostanza andiamo a disegnare le linee che congiungono le parti del corpo (in pratica le ossa), disegnando lo scheletro del player.

Nei prossimi post andremo ad esaminare quali altre informazioni ci mette a disposizione la classe Body e come possiamo sfruttarle.

Disclaimer: “This is preliminary software and/or hardware and APIs are preliminary and subject to change.”

Technorati Tags: ,,,