# Identifying specific players with the kinect?

I have some code below that takes different detected users recognized by the Kinect and assigns them a specific random id range based on the player they are. I use this to grab the x,y coordinates of their left or right hand. I was trying to have the Kinect get at least 6 peoples coordinates with the code. Am I taking the approach right or should I perform it differently? I am using the Kinect SDK v1.8.

            Using skeletonFrameData As SkeletonFrame = e.OpenSkeletonFrame

If skeletonFrameData Is Nothing Then
Exit Sub
End If
'  sensor.SkeletonStream.AppChoosesSkeletons = True
Dim allSkeletons(skeletonFrameData.SkeletonArrayLength - 1) As Skeleton
skeletonFrameData.CopySkeletonDataTo(allSkeletons)


Player Identification:

            'identify specific players by ID
'ResetValues()
For j = 0 To playerid.Length - 1
'all players
playerid(i) = CInt(Rnd() * 4 + (i * 5))
allSkeletons(i).TrackingId = playerid(0)
Next j
'force each player to be moved to first blank spot
Dim tempList As New List(Of Skeleton)(allSkeletons)
tempList.RemoveAll(Function(sk) IsNothing(sk))
allSkeletons = tempList.ToArray
Log("Tracking id for player#1: " + allSkeletons(0).TrackingId.ToString)
Log("Tracking id for player#2: " + allSkeletons(1).TrackingId.ToString)
Log("Tracking id for player#3: " + allSkeletons(2).TrackingId.ToString)


Make sure current player is getting tracked or not:

                If IsNothing(s) Then
Exit Sub
End If
If s.TrackingState = SkeletonTrackingState.Tracked Then
activeCount = activeCount + 1
End If
If s.TrackingState = SkeletonTrackingState.PositionOnly Then
passiveCount = passiveCount + 1
End If
If s.TrackingState = SkeletonTrackingState.NotTracked Then
nottracked = nottracked + 1
End If
totalplayers = activeCount + passiveCount + nottracked
'Log("passive count: " + passiveCount.ToString + " date: " + Now.ToString)


Player x,y display:

                     ' the first found/tracked skeleton moves the mouse cursor
If s.TrackingState = SkeletonTrackingState.Tracked Then

' make sure both hands are tracked
'If Skeleton.Joints(JointType.HandLeft).TrackingState = JointTrackingState.Tracked AndAlso Skeleton.Joints(JointType.HandRight).TrackingState = JointTrackingState.Tracked Then
Dim cursorX, cursorY As Integer

' get the left and right hand Joints
Dim jointRight As Joint = s.Joints(JointType.HandRight)
Dim jointLeft As Joint = s.Joints(JointType.HandLeft)

' scale those Joints to the primary screen width and height
Dim scaledRight As Joint = jointRight.ScaleTo(CInt(Fix(SystemParameters.PrimaryScreenWidth)), CInt(Fix(SystemParameters.PrimaryScreenHeight)), SkeletonMaxX, SkeletonMaxY)
Dim scaledLeft As Joint = jointLeft.ScaleTo(CInt(Fix(SystemParameters.PrimaryScreenWidth)), CInt(Fix(SystemParameters.PrimaryScreenHeight)), SkeletonMaxX, SkeletonMaxY)
' relativemouselocation.Content = jointRight.Position
' figure out the cursor position based on left/right handedness
If LeftHand.IsChecked.GetValueOrDefault() Then
cursorX = CInt(Fix(scaledLeft.Position.X))
cursorY = CInt(Fix(scaledLeft.Position.Y))
Else
cursorX = CInt(Fix(scaledRight.Position.X))
cursorY = CInt(Fix(scaledRight.Position.Y))
End If

Dim leftClick As Boolean
' figure out whether the mouse button is down based on where the opposite hand is
If (LeftHand.IsChecked.GetValueOrDefault() AndAlso jointRight.Position.Y > ClickThreshold) OrElse ((Not LeftHand.IsChecked.GetValueOrDefault()) AndAlso jointLeft.Position.Y > ClickThreshold) Then
leftClick = True
'  MsgBox("clicked")
Else
leftClick = False
End If

'if i is less then the total amount of players then send players coordinates for person that is active.
If i <= 5 Then
Select Case True
Case Is = s.TrackingId >= 1 And s.TrackingId <= 4
i = 0
playeractive(i) = True
player1xy.Content = cursorX & ", " & cursorY & ", " & leftClick
Status.Text = "player1 identified" & cursorX.ToString & ", " & cursorY.ToString & ", " & leftClick.ToString
' sensor.SkeletonStream.ChooseSkeletons(1, 2)
Case Is = s.TrackingId >= 5 And s.TrackingId <= 9
i = 1
playeractive(i) = True
player2xy.Content = cursorX & ", " & cursorY & ", " & leftClick
Status.Text = "player2 identified" & cursorX.ToString & ", " & cursorY.ToString & ", " & leftClick.ToString

Case Is = s.TrackingId >= 10 And s.TrackingId <= 14
i = 2
playeractive(i) = True
player3xy.Content = cursorX & ", " & cursorY & ", " & leftClick
Status.Text = "player3 identified" & cursorX.ToString & ", " & cursorY.ToString & ", " & leftClick.ToString

Case Is = s.TrackingId >= 15 And s.TrackingId <= 19
i = 3
playeractive(i) = True
player4xy.Content = cursorX & ", " & cursorY & ", " & leftClick
Status.Text = "player4 identified" & cursorX.ToString & ", " & cursorY.ToString & ", " & leftClick.ToString
Case Is = s.TrackingId >= 20 And s.TrackingId <= 24
i = 4
playeractive(i) = True
player5xy.Content = cursorX & ", " & cursorY & ", " & leftClick
Status.Text = "player5 identified" & cursorX.ToString & ", " & cursorY.ToString & ", " & leftClick.ToString
Case Is = s.TrackingId >= 25 And s.TrackingId <= 29
i = 5
playeractive(i) = True
player6xy.Content = cursorX & ", " & cursorY & ", " & leftClick
Status.Text = "player6 identified" & cursorX.ToString & ", " & cursorY.ToString & ", " & leftClick.ToString
End Select
Log("person #: " + i.ToString + "Tracking ID: " + s.TrackingId.ToString)
currentperson.Content = i.ToString + "Tracking ID: " + s.TrackingId.ToString
End If
'If playeractive(i) = True And i >= 0 And frame.SkeletonArrayLength > 0 Then
'NativeMethods.SendMouseInput(cursorX, cursorY, CInt(Fix(SystemParameters.PrimaryScreenWidth)), CInt(Fix(SystemParameters.PrimaryScreenHeight)), leftClick, totalplayers, i)

'End If

'if total players is 1 or greater send coordinate data.
If totalplayers >= 1 Then
DefineMouseData(cursorX, cursorY, leftClick)
End If
'make the below code active when I get multiple player tracking working
If playeractive(i) = True Then
' Environment.SetEnvironmentVariable("Player" + i.ToString + "xcoords", player(i).bytex.ToString, EnvironmentVariableTarget.Machine)
' Environment.SetEnvironmentVariable("Player" + i.ToString + "ycoords", player(i).bytey.ToString, EnvironmentVariableTarget.Machine)
'Environment.SetEnvironmentVariable("Player" + i.ToString + "leftclick", player(i).leftclick.ToString, EnvironmentVariableTarget.Machine)
End If
If i <= 5 Then
If playeractive(5) = True Then
'if 6th player exit for loop and open next frame.
playeractive(5) = False
Exit For
Else
'd = d + 1
End If

End If
End If
NumPassive.Content = "passive count: " + passiveCount.ToString
Numactive.Content = "active count: " + activeCount.ToString
nottrackedplayers.Content = "not tracked players: " + nottracked.ToString
playeractive(i) = False


Choose specific player:

               For h = 0 To activeCount - 1
If h >= 2 Then
If activeCount - 1 > 0 Then
sensor.SkeletonStream.ChooseSkeletons(playerid(h), playerid(h + 1))
End If
End If
Next
Next

ResetValues()

End Using


As you can see I go from 1-4 for player one (it might be 0-4), 5-9 for player 2, and so on for each player. If anyone can improve this code or know of any methods I am not using please post a solution below. Sorry for the long code post but if someone thinks that what I have commented out is irrelevant please edit this and remove the comments. I plan on using the multiple Kinect code too I commented out to do more then 6 players later but wish to get 4-6 players working for now. Edit: I removed the unimportant parts. The important part is the sensor.SkeletonStream.ChooseSkeletons(s.TrackingId) Line here.

I want a specific user to be looped through such as player 1's coordinates retrieved first, then second, and so on so it does not seem slow. But I need the best method to do so. The problem is: ChooseSkeletons only does 2 people. I can loop through each person passing their id to chooseskeleton and this gives me 4-6 people but this seems inefficient because chooseskeleton takes too long (maybe improper usage?).

• Note: the full source is located here: kinectmultipoint.codeplex.com/releases/view/104786
– jeff
Dec 5 '13 at 16:47
• Code works for the most part but full source is too much to post here so I listed full source link. Also, here's more information on my programming environment: Xbox 360 Kinect (debug environment only), windows 7, and a laptop computer.
– jeff
Dec 5 '13 at 16:52
• Is this using XNA libraries? I'm hesitant to retag - if it's using XNA you should tag your question with the XNA tag :) Dec 5 '13 at 18:41
• Is the procedure much longer than that? It would be helpful if the code included at least Sub ProcedureName up to End Sub. You've posted an incomplete Using scope... Dec 5 '13 at 18:42
• Rather than trying to make us review your entire project, which is apparently too large to post. I recommend breaking it into working parts and asking separate questions for those parts. The shorter and more focused your question is, the more likely you are to get a relatively quick and useful answer. Dec 5 '13 at 19:27

I'm just going to review what's here:

1. Your comments are excessive. Commented out code helps no one. If you remove code and want it later, that's what version control is for.
2. Your method is too long. You should break it into smaller pieces.
3. Use loops instead of very similar repeated code for instance:

For i As Integer = 0 To playerid.Length - 1
playerid(i) = CInt(Rnd() * 4 + (i * 5))
allSkeletons(i).TrackingId = playerid(i)
Next

4. Do not use multiple if statements to check the same variable. Either use an if-else block or Select Case
5. You do not have to post all of your project, but you should at least post pieces that are whole. If we must go to a separate site to even properly review what you posted, it probably isn't going to happen.
• Thanks Daniel. I thing the problem is that I need to have chooseskeletons track one- two skeletons at a time and return that person's x,y coordinates (both need to be done fast though - this is the problem).
– jeff
Dec 5 '13 at 21:40

Anything that defines a scope or a code block, should make you hit that Tab key on the next line. Using defines a scope, so your indentation is off.

This might be personal preference, but I find this:

If skeletonFrameData Is Nothing Then
Exit Sub
End If


Would look cleaner written like this:

If skeletonFrameData Is Nothing Then Exit Sub


Since your allSkeletons array is populated by copying another array, I think you could just do this - less verbose, and still clear; note that I'm coming from so I'm not sure if this is legal :

Dim allSkeletons() As Skeleton = skeletonFrameData.CopySkeletonDataTo(allSkeletons)


What comes next really looks like something that should be refactored into its own function, and called in a loop (see point 3 of @DanielCook's answer):

Private Sub AssignSkeletonTrackingId(playerSkeleton As Skeleton, playerIndex As Integer)
playerSkeleton.TrackingId = CInt(Rnd() * 4 + (playerIndex * 5))
Log("Tracking id for player#" playerIndex + 1 + ": " + playerSkeleton.TrackingId.ToString()
End Sub


It appears traversing your allSkeletons array after that would be redundant.

The rest is pretty much unreviewable, please update your original post with enough code.

• That definitely is personal preference. Personally, I dislike VB.Net single line If statements. It almost feels like a syntax error cause of the missing End If. There is functionality to copy an array, but it definitely isn't a method called CopySkeletonDataTo using CopyTo would be appropriate. Dec 5 '13 at 19:22
• @DanielCook I didn't make up the CopySkeletonDataTo method, it's from the OP's code ;) Dec 5 '13 at 19:49
• Oh, well in that case you deserve the +1 I already gave you even more. Dec 5 '13 at 20:37
• Great solution! I am having problems with the code but it seems you guys were right I reeated a section twice. No, retailcoder that would cause an error in VB.NET with the allskeletons variable not being declared or cause memory leak issues. As far as I remember you need Redim to avoid this error. But If it works I will have to give you kudos.
– jeff
Dec 5 '13 at 21:54