2
\$\begingroup\$

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)
                        'System.Threading.Thread.Sleep(300)
                    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.

For more explanation: http://msdn.microsoft.com/en-us/library/microsoft.kinect.skeletonstream.chooseskeletons.aspx

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?).

\$\endgroup\$
  • \$\begingroup\$ Note: the full source is located here: kinectmultipoint.codeplex.com/releases/view/104786 \$\endgroup\$ – jeff Dec 5 '13 at 16:47
  • \$\begingroup\$ 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. \$\endgroup\$ – jeff Dec 5 '13 at 16:52
  • \$\begingroup\$ Is this using XNA libraries? I'm hesitant to retag - if it's using XNA you should tag your question with the XNA tag :) \$\endgroup\$ – Mathieu Guindon Dec 5 '13 at 18:41
  • \$\begingroup\$ 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... \$\endgroup\$ – Mathieu Guindon Dec 5 '13 at 18:42
  • 2
    \$\begingroup\$ 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. \$\endgroup\$ – Daniel Dec 5 '13 at 19:27
4
\$\begingroup\$

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.
\$\endgroup\$
  • \$\begingroup\$ 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). \$\endgroup\$ – jeff Dec 5 '13 at 21:40
4
\$\begingroup\$

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.

\$\endgroup\$
  • \$\begingroup\$ 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. \$\endgroup\$ – Daniel Dec 5 '13 at 19:22
  • \$\begingroup\$ @DanielCook I didn't make up the CopySkeletonDataTo method, it's from the OP's code ;) \$\endgroup\$ – Mathieu Guindon Dec 5 '13 at 19:49
  • \$\begingroup\$ Oh, well in that case you deserve the +1 I already gave you even more. \$\endgroup\$ – Daniel Dec 5 '13 at 20:37
  • \$\begingroup\$ 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. \$\endgroup\$ – jeff Dec 5 '13 at 21:54

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.