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

VB.NET : Aggregare stringhe con LINQ

Tip facile facile, ma a qualcuno potrebbe servire. Supponiamo di avere una lista di stringhe (magari come risultato di una query LINQ) e di voler ottenere una stringa con la concatenazione delle stesse: Dim list = CreateList() Dim concatStr = (From s In list _ Select s).Aggregate( Function (currentString, nextString) currentString + nextString) MessageBox.Show(concatStr) Il metodo CreateList non ci interessa, in questo momento, ma crea una lista di oggetti String. Protected Function CreateList() As IEnumerable( Of String ) Dim list As String () = {" stringa1 ", " stringa2 ", " stringa3 ", " stringa4 ", " stringa5 "} Return list.AsEnumerable() End Function Questo metodo potrebbe restituire una qualsiasi lista di oggetti di cui, nella select successiva recuperiamo solo stringhe. La stessa tecnica è utilizzabile per concatenare stringhe inserendovi un carattere separatore Dim list = CreateList() Dim

VB.NET: SplashScreen con effetto fade-in

In questo post vorrei proporvi un modo per realizzare una splash screen per le nostre applicazioni Windows Form che appare progressivamente con un effetto fade. Supponiamo di avere il nostro progetto VB.NET in una soluzione Visual Studio 2008 in cui abbiamo il sorgente della nostra applicazione Windows Form. Inseriamo una splash screen utilizzando il menù Progetto->Aggiungi Nuovo Elemento e selezionando il tipo di elemento “Schermata Iniziale” A questo punto Visual Studio creerà, automaticamente, la schermata iniziale che possiamo personalizzare graficamente come vogliamo. Per poter fare in modo che questa finestra appaia nel momento in cui avviamo l’applicazione, è necessario aprire le proprietà del progetto e impostare la maschera di avvio: In questo modo, all’avvio dell’applicazione, la schermata appare immediatamente e scompare un attimo prima della visualizzazione della finestra dell’applicazione. Possiamo far apparire la schermata iniziale con un ef

VB.NET: Convertire un file DOC in RTF e PDF con office interop

In questo post vorrei proporvi del codice per poter convertire un file .doc in un file .rtf oppure .pdf utilizzando le API di interoperabilità di Office. Creeremo una classe, DocConverter, che esporrà le due funzionalità sopra citate. Cominciamo con il prevedere un attributo privato della classe che rappresenterà l’applicazione Word che utilizzeremo per la conversione. Creeremo l’istanza dell’attributo privato all’interno del costruttore della classe: Public Sub New () If Not CreateWordApp() Then Throw New ApplicationException(" Assembly di interoperabilità con Office non trovato! ") End If End Sub Private _wordApp As Word.ApplicationClass Protected Function CreateWordApp() As Boolean Dim retval = True Try _wordApp = New Word.ApplicationClass() _wordApp.Visible = False Catch ex As System.Exception _wordApp = Nothing retval = False End Try Return retval End Function La conve