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: 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:PublicSubNew()
IfNot CreateWordApp() Then
ThrowNew ApplicationException("Assembly di interoperabilità con Office non trovato!")
EndIf
EndSub
Private _wordApp As Word.ApplicationClass
ProtectedFunction CreateWordApp() AsBoolean
Dim retval = True
Try
_wordApp = New Word.ApplicationClass()
_wordApp.Visible = False
Catch ex As System.Exception
_wordApp = Nothing
retval = False
EndTry
Return retval
EndFunction

La conversione del file doc sarà effettuata aprendo il file stesso ed eseguendo un’operazione di SaveAs:

Pr…

Cambiare la lingua di Visual Studio 2008

Oggi ho avuto qualche problema installando Windows Mobile 6 Professional SDK Refresh e Windows Mobile 6 Standard SDK Refresh.Scaricati i file di installazione e installati, ho provato a creare un progetto di tipo Windows Mobile 6.0 e mi sono beccato questo errore:Dopo qualche smanettamento abbiamo scoperto (e ringrazio il mitico Matteo per l’aiuto) che il mio Visual Studio 2008, pur essendo in Inglese (prova ne era il fatto che gli hotfix e la SP installata erano nella lingua di Albione) aveva come lingua impostata quella del sistema operativo (italiano).Ovviamente, non avrebbe mai potuto trovare la cartella 1040 (italiano) visto che l’installazione dell’SDK aveva supposto che la lingua del Visual Studio fosse Inglese (1033).La soluzione del problema è duplice:1) Duplicate la cartella 1033 presente nel percorso evidenziato dall’errore e la rinominate 10402) cambiate la lingua di Visual Studio.Per questa ultima eventualità basta andare nel menù Strumenti/Opzioni:e cambiare il linguaggi…

Tascam DR-05 registratore digitale per tutti

Diverso tempo fa ho acquistato il registratore digitale Tascam DR-05 e, ora, dopo diversi mesi di utilizzo, posso dire la mia a proposito.

Si tratta di un ottimo registratore digitale con microfono stereo che permette di ottenere registrazioni di ottima qualitaà anche in ambienti non perfetti dal punto di vista acustico.

Interessante la possibilità di utilizzare un cavalletto di piccole dimensioni come HAMA Mini treppiede o Mini Cavalletto Universale per tenere il microfono sollevato dal tavolo in fase di registrazione grazie allàattacco universale per macchina fotografica che il microfono ha nella parte inferiore.

Da segnalare anche il menu’ ben fatto e la possibilita’ di utilizzare una scheda SD esterna per memorizzare i file audio. Anche a livello di consumo batterie non e’ niente male. Consiglio l’uso delle alcaline non ricaricabili.

Il mio utilizzo e’ stato prettamente di registrazione di podcast vocali (no musica) ma le recensioni confermano che se la cava egregiamente con la mu…