Event-based reading of hands' data

In the preceding recipes, we use a while loop to read frames of data from nite::HandTracker. This is not a good idea since this will block our application and even the while loop itself until new data becomes available. Fortunately, NiTE has given us this ability to introduce a class/struct with a method in it to be called when a new frame of data becomes available. So our application can do what we want it to do and, when new data becomes available, we can read it without busying our main application thread. In this recipe, we will show you how to use this feature.

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. Define the hTrackerNewFrameListener structure (or class) right after that as follows:
    struct hTrackerNewFrameListener :
      public nite::HandTracker::NewFrameListener
    {
        void onNewFrame(nite::HandTracker& hTracker)
        {
        nite::Status status = nite::STATUS_OK;
        nite::HandTrackerFrameRef newFrame;
        status = hTracker.readFrame(&newFrame);
        if (!HandleStatus(status) ||
          !newFrame.isValid()) return;
        system("cls");
        const nite::Array<nite::GestureData>& gestures =
          newFrame.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 =
          newFrame.getHands();
        for (int i = 0; i < hands.getSize(); ++i){
          if (hands[i].isTracking()){
            printf("Tracking Hand #%d @ %g,%g,%g 
    ",
              hands[i].getId(),
              hands[i].getPosition().x,
              hands[i].getPosition().y,
              hands[i].getPosition().z);
          }
        }
        }
    };
  3. Then, locate the following line:
    int _tmain(int argc, _TCHAR* argv[])
    {
  4. Add the following code inside the preceding function:
      nite::Status status = nite::STATUS_OK;
      status = nite::NiTE::initialize();
      if (!HandleStatus(status)) return 1;
    
      printf("Creating hand tracker ...
    ");
      nite::HandTracker hTracker;
      status = hTracker.create();
      if (!HandleStatus(status)) return 1;
      hTrackerNewFrameListener listener;
      hTracker.addNewFrameListener(&listener);
    
      hTracker.startGestureDetection(nite::GESTURE_CLICK);
      printf("Reading data from hand tracker ...
    ");
    
      ReadLastCharOfLine();
      
      nite::NiTE::shutdown();
      openni::OpenNI::shutdown();
      return 0;

How it works...

As always, we have ReadLastCharOfLine() and HandleStatus() in the first step of this recipe. In the next step, we declare a structure named hTrackerNewFrameListener that has been inherited from nite::HandTracker::NewFrameListener as follows:

struct hTrackerNewFrameListener :
  public nite::HandTracker::NewFrameListener
{

nite::HandTracker::NewFrameListener itself has an empty method named onNewFrame() that we need to override in our child structure/class so we can capture the frame available event as follows:

    void onNewFrame(nite::HandTracker& hTracker)
    {

In the body of this method, we first read the newly available frame from nite::HandTracker and then clear the console using a system command:

    nite::HandTrackerFrameRef newFrame;
    status = hTracker.readFrame(&newFrame);
    if (!HandleStatus(status) ||
      !newFrame.isValid()) return;
    system("cls");

Then, we retrieve a list of recognized gestures and of the requested hands that are being tracked where a gesture happened:

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

And at the end, we print the ID and position of each hand currently under tracking, as follows:

    const nite::Array<nite::HandData>& hands =
      newFrame.getHands();
    for (int i = 0; i < hands.getSize(); ++i){
      if (hands[i].isTracking()){
        printf("Tracking Hand #%d @ %g,%g,%g 
",
          hands[i].getId(),
          hands[i].getPosition().x,
          hands[i].getPosition().y,
          hands[i].getPosition().z);
      }
    }

You can change the body of this method with what you want depending on your application's behavior. Step two has nothing more.

In the next steps, we have the initialization process; this includes the initialization of NiTE and the creation of the nite::HandTracker variable:

  status = nite::NiTE::initialize();
  .
  .
  .
  nite::HandTracker hTracker;
  status = hTracker.create();

Then we add our newly defined structure/class as a listener to nite::HandTracker, so nite::HandTracker can call it later when a new frame becomes available.

  hTrackerNewFrameListener listener;
  hTracker.addNewFrameListener(&listener);

Also, we need to have an active search for a hand gesture because we need to locate the position of the hands. So we need to call the nite::HandTracker::startGestureDetection() method. We used the Click (also known as the push) gesture here:

  hTracker.startGestureDetection(nite::GESTURE_CLICK);

At the end, we wait until a user presses the Enter key to end the app. We do nothing more in our main thread except just waiting. Everything happens in the other thread.

  ReadLastCharOfLine();
  
  nite::NiTE::shutdown();
  openni::OpenNI::shutdown();
  return 0;

The output of our application is as follows:

How it works...

See also

  • Event-based reading of data in Chapter 3, Using Low-level Data
  • Event-based reading of users' data in Chapter 5, NiTE and User Tracking
  • The Working sample for controlling the mouse by hand recipe
..................Content has been hidden....................

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