Passa ai contenuti principali

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: ,,

Commenti

Post popolari in questo blog

MVP Reconnect …… ovvero quando entri nella “famigghia” resti sempre nella “famigghia”!!!

Ma di che “famigghia” stiamo parlando!!!!

Fermi tutti, non si tratta di robe strane o sette segrete o affari malavitosi….stiamo parlando della grande famiglia dei Microsoft MVP.

Per chi non sapesse cosa sono i Microsoft MVP, vi consiglio di fare un giro sul sito ufficiale del programma (link), ma, volendolo spiegare in pochisime parole, si tratta di un riconoscimento che Microsoft da a persone che si distinguono per il loro impegno, aiutando gli altri ad ottenere il massimo grazie alle tecnologie Microsoft. Si tratta di persone, non dipendenti Microsoft, che mettono la loro passione, il loro tempo, la loro buona volontà per la divulgazione e la condivisione della conoscenza. Non necessariamente (come qualcuno erroneamente sostiene, evidentemente non conoscendo le basi del programma) si tratta di professionisti nel termine letterale del termine ma si tratta comunque di un gruppo di persone che sacrifica un pò del suo tempo (e, a volte, vi assicuro neanche pò!!!) per la sua passione.

Pe…

Nuova versione del Band SDK

E’ di ieri l’annuncio del rilascio della nuova versione dell’SDK per il Microsoft Band.
Si tratta della versione 1.3.10417 (la precedente e, prima della serie, era la 1.3.10219 preview).
Maggiori informazioni, download dell’SDK per le tre piattaforme Windows Phone, iOS e Android all’indirizzo http://developer.microsoftband.com/.
Allo stesso indirizzo potrete trovare anche la documentazione.
Nei mesi scorsi mi sono gia’ occupato della precedente versione e questi sono i post che ne parlano:
Microsoft Band SDK Preview - First LookMicrosoft Band SDK Preview - ”Hello Band”Microsoft Band SDK Preview - Accesso ai sensoriMicrosoft Band SDK Preview - TileMicrosoft Band SDK Preview - NotificheMicrosoft Band SDK Preview - Personalizzazione
Gli argomenti trattati e il codice proposto dovrebbe, ad una prima lettura delle nuove funzionalita’ inserite, essere ancora valido e funzionante ma nei prossimi giorni prendero’ in esame tutti gli argomenti dei precedenti post e vedremo cosa cambia e cosa e’ …

Template di progetto per sviluppare applicazioni WPF con Intel® RealSense™

E’ disponibile, nella gallery di Visual Studio, la prima versione del mio template di progetto per applicazioni WPF scritte in C# che permette di realizzare applicazioni con l’SDK di Intel® RealSense™.Il template si può scaricare direttamente all’interno Visual Studio utilizzando il tool “Extensions and Updates”oppure all’indirizzo https://visualstudiogallery.msdn.microsoft.com/1c36ecfd-8c00-4aee-b20c-a1726ab6424dIl template esegue le seguenti operazioni per voi:Aggiunge la reference all’assembly libpxcclr.cs.dll (nelle due distinte versioni per x86 e x64);Aggiunge lo script di post build per copiare la libreria libpxccpp2c.dll dalla cartella dell’SDK alla cartella bin del vostro progetto.Una volta creato il progetto dovete rimuovere la configurazione di compilazione AnyCPU (che non ha più senso) dalla vostra solution e sarete pronti per sviluppare con Intel® RealSense™.Ovviamente dovete installare l’SDK che potete scaricare all’indirizzo https://software.intel.com/en-us/intel-realsen…