Finding the related user ID for each hand ID

When dealing with nite::HandTracker and nite::HandData, there is no way to find out which hand belongs to which user. Actually, there is no direct way of finding this out in NiTE at all. In this recipe, we will show you how it's possible to use nite::UserTracker and nite::UserMap along with nite::HandTracker and nite::HandData to determine the user ID of each hand.

Getting ready

Create a project in Visual Studio and prepare it for working with OpenNI and NiTE using the Create a project in Visual Studio 2010 recipe in Chapter 2, OpenNI and C++.

How to do it...

  1. Copy ReadLastCharOfLine() and HandleStatus() from the first recipe of this chapter to the top of your source code (just below the #include lines).
  2. Then, locate the following line:
    int _tmain(int argc, _TCHAR* argv[])
    {
  3. Add the following code inside the preceding line:
      nite::Status status = nite::STATUS_OK;
      status = nite::NiTE::initialize();
      if (!HandleStatus(status)) return 1;
    
      printf("Creating user tracker ...
    ");
      nite::UserTracker uTracker;
      status = uTracker.create();
      if (!HandleStatus(status)) return 1;
    
      printf("Creating hand tracker ...
    ");
      nite::HandTracker hTracker;
      status = hTracker.create();
      if (!HandleStatus(status)) return 1;
      printf("Searching for Hand Raise gestures ...
    ");
      hTracker.startGestureDetection(nite::GESTURE_HAND_RAISE);
    
      printf("Reading data from hand/user trackers ...
    ");
    
      while(!_kbhit())
      {
        nite::HandTrackerFrameRef handFrame;
        status = hTracker.readFrame(&handFrame);
        if (!HandleStatus(status) ||
          !handFrame.isValid()) return 1;
        nite::UserTrackerFrameRef userFrame;
        status = uTracker.readFrame(&userFrame);
        if (!HandleStatus(status) ||
          !userFrame.isValid()) return 1;
        nite::UserMap usersMap = userFrame.getUserMap();
        const nite::Array<nite::GestureData>& gestures =
          handFrame.getGestures();
        for (int i = 0; i < gestures.getSize(); ++i){
          if (gestures[i].isComplete()){
            nite::HandId handId;
            status = hTracker.startHandTracking(
              gestures[i].getCurrentPosition(), &handId);
          }
        }
        const nite::Array<nite::HandData>& hands = 
          handFrame.getHands();
        for (int i = 0; i < hands.getSize(); ++i){
          if (hands[i].isTracking()){
            float posX, posY;
            status = 
              hTracker.convertHandCoordinatesToDepth(
              hands[i].getPosition().x,
              hands[i].getPosition().y,
              hands[i].getPosition().z,
              &posX, &posY);
            if (status == nite::STATUS_OK)
            {
              nite::UserId* userId =
                (nite::UserId*)(
                  (char*)usersMap.getPixels() + 
                  ((int)posY * usersMap.getStride())
                ) +	(int)posX;
              printf("User %d: Hand #%d @%g,%g,%g 
    ",
                *userId, hands[i].getId(),
                hands[i].getPosition().x,
                hands[i].getPosition().y,
                hands[i].getPosition().z);
            }
          }
        }
      }
      
      hTracker.destroy();
      uTracker.destroy();
      nite::NiTE::shutdown();
      return 0;

How it works...

Again in the first step, we have the two ReadLastCharOfLine() and HandleStatus() functions that are going to be used for handling the returned nite::Status value and to read keys from the user.

Our main code starts at the second step, which is about the main function (starting point) of our project. In this function, we first initialize NiTE, as always, and then define and create a nite::HandTracker object. But as we need to recognize each user in the scene as well as each hand, we need to define and create a nite::UserTracker object too.

  nite::UserTracker uTracker;
  status = uTracker.create();
  .
  .
  .
  nite::HandTracker hTracker;
  status = hTracker.create();

Then, as we need a gesture to locate hands, we need to request a search for one. In this recipe, we prefer using the Hand Raise gesture:

  hTracker.startGestureDetection(nite::GESTURE_HAND_RAISE);

To read data from NiTE, we need to put our application almost in an infinite loop. So we used a while loop to wait until the user presses a key to read the data.

In our while loop, we must read a frame of data from both nite::HandTracker and nite::UserTracker. This can be done using the nite::HandTracker::readFrame() and nite::UserTracker::readFrame() methods:

    nite::HandTrackerFrameRef handFrame;
    status = hTracker.readFrame(&handFrame);
    if (!HandleStatus(status) ||
      !handFrame.isValid()) return 1;
    nite::UserTrackerFrameRef userFrame;
    status = uTracker.readFrame(&userFrame);
    if (!HandleStatus(status) ||
      !userFrame.isValid()) return 1;

As you can clearly see, we checked whether the reading process has successfully been completed and also checked whether the returned frame is valid before doing anything.

We will use the nite::UserMap object associated with the returned nite::UserTrackerFrameRef object later, so keeping it in another variable will help in enhancing the readability of our code.

     nite::UserMap usersMap = userFrame.getUserMap();

Before you start looping through the hands being tracked and find the related user IDs of each, you need to take care of each recognized gesture by nite::HandTracker and request hand tracking in the location of the gesture. To do this, we need to use the nite::HandTrackerFrameRef::getGestures() method for retrieving an array of recognized gestures and the nite::HandTracker::startHandTracking() method to start the tracking of a hand:

    const nite::Array<nite::GestureData>& gestures =
      handFrame.getGestures();
    for (int i = 0; i < gestures.getSize(); ++i){
      if (gestures[i].isComplete()){
        nite::HandId handId;
        status = hTracker.startHandTracking(
          gestures[i].getCurrentPosition(), &handId);
      }
    }

Now is the time to loop through the list of hands being tracked and see which ones are retrievable using the nite::HandTrackerFrameRef::getHands() method:

    const nite::Array<nite::HandData>& hands = 
      handFrame.getHands();
    for (int i = 0; i < hands.getSize(); ++i){
      if (hands[i].isTracking()){

nite::UserMap is like a depth frame, only with different values stored in each frame instead of the depth value. So if we want to know the value of a pixel, we first need to convert the position of the tracked hand to the position of the pixel relative to the depth frame. As we did before, this can be done using the nite::HandTracker::convertHandCoordinatesToDepth() method:

        float posX, posY;
        status = 
          hTracker.convertHandCoordinatesToDepth(
          hands[i].getPosition().x,
          hands[i].getPosition().y,
          hands[i].getPosition

If the process of converting ends without a problem, we will have the correct coordinates of the hand either relative to the depth frame or relative to nite::UserMap in the posX and posY variables. Now we can use these variables to read the value of this pixel from nite::UserMap:

        if (status == nite::STATUS_OK)
        {
          nite::UserId* userId =
            (nite::UserId*)(
              (char*)usersMap.getPixels() + 
              ((int)posY * usersMap.getStride())
            ) +	(int)posX;

After these lines of code, the userId variable contains the address of the related value that indicates the user ID of a hand. The value of this address is either 0, which means no user or an unknown user, or a value other than 0, which is the user ID of the user. As you can see in the preceding lines of code, reading from a nite::UserMap object is no different than reading from an openni::VideoFrameRef variable.

Now after having this info, we can print it to the console:

          printf("User %d: Hand #%d @%g,%g,%g 
",
            *userId, hands[i].getId(),
           hands[i].getPosition().x,
            hands[i].getPosition().y,
            hands[i].getPosition().z);

The output of our application is as follows:

How it works...

See also

  • The Getting a list of all the active users recipe in Chapter 5, NiTE and User Tracking
  • The Identifying and coloring users' pixels in depth map recipe in Chapter 5, NiTE and User Tracking
  • The Event-based reading of hands' data recipe
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.223.170.63