Event-based reading of data

In OpenNI 2.x, instead of using openni::OpenNI::waitForAnyStream(), we can use the openni::VideoStream object's events for reading new frames of data. This is a more standard way than creating an infinite loop around code. In this recipe, we will try to capture this event but we are not actually going to use it in any way. Read the older recipes about how to show and read a frame from sensors.

Getting ready

Create a project in Visual Studio 2010 and prepare it for working with OpenNI using the Creating a project in Visual Studio 2010 recipe of Chapter 2, Open NI and C++.We don't need OpenGL in this recipe.

How to do it...

  1. Add the following lines above your source code (just below the #include lines):
    char ReadLastCharOfLine()
    {
      int newChar = 0;
      int lastChar;
      fflush(stdout);
      do 
      {
        lastChar = newChar;
        newChar = getchar();
      }
      while ((newChar != '
    ') 
        && (newChar != EOF));
      return (char)lastChar;
    }
    
    bool HandleStatus(Status status)
    {
      if (status == STATUS_OK)
        return true;
      printf("ERROR: #%d, %s", status,
        OpenNI::getExtendedError());
      ReadLastCharOfLine();
      return false;
    }
    struct OurOpenNINewFrameMonitorer : public VideoStream::NewFrameListener
    {
      void onNewFrame(VideoStream& videoStream)
      {
        printf("%d. New data is available to read.
    ",
          clock());
      }
    };
  2. Then locate the following lines of code:
    int _tmain(int argc, _TCHAR* argv[])
    {
  3. Write the following code snippet below the preceding lines of code:
      Status status = STATUS_OK;
      printf("Scanning machine for devices and loading "
          "modules/drivers ...
    ");
      
      status = OpenNI::initialize();
      if (!HandleStatus(status)) return 1;
      printf("Completed.
    ");
    
      Device device;
      printf("Opening first device ...
    ");
      status = device.open(ANY_DEVICE);
      if (!HandleStatus(status)) return 1;
      printf("%s Opened, Completed.
    ",
        device.getDeviceInfo().getName());
    
      printf("Checking if stream is supported ...
    ");
      if (!device.hasSensor(SENSOR_DEPTH))
      {
        printf("Stream not supported by this device.
    ");
        return 1;
      }
    
      printf("Asking device to create a depth stream ...
    ");
      VideoStream depthSensor;
      status = depthSensor.create(device, SENSOR_DEPTH);
      if (!HandleStatus(status)) return 1;
    
      printf("Registering callback ...
    ");
      OurOpenNINewFrameMonitorer p;
      status = depthSensor.addNewFrameListener(&p);
      if (!HandleStatus(status)) return 1;
    
      printf("Starting stream ...
    ");
      status = depthSensor.start();
      if (!HandleStatus(status)) return 1;
      printf("Done.
    ");
    
      ReadLastCharOfLine();
      depthSensor.destroy();
      device.close();
      OpenNI::shutdown();

How it works...

I would recommend reading the Listening to the device connect and disconnect events recipe of Chapter 2, Open NI and C++, for knowing what listener classes are and how OpenNI implements its event callback system, because we are not going to describe it here again.

In step 1 of the previous code, we have two functions for waiting for user input, checking the openni::Status object, and printing error messages to the console, if any, just as in the last recipe. But right after defining these two functions, we have a definition for a structure named OurOpenNINewFrameMonitorer, which inherits from the openni:VideoStream::NewFrameListener class. If you have read the Listening to the device connect and disconnect events recipe of Chapter 2, OpenNI and C++, you will know that we need to define a class or structure from a listener class and then introduce it to OpenNI to capture OpenNI's events. Because of this logic, we defined the structure here as a child of openni::VideoStream::NewFrameListener. Please note that we used the openni::VideoStream::NewFrameListener class because we wanted to capture the openni::VideoStream object's events.

In this structure, we defined a method named onNewFrame(). The signature of this method is very important because we want to override the internal virtual method of the parent class.

In the onNewFrame() method, we have only one line of code for printing to the console and informing the user that there is a new frame available to be read. We don't actually want to use this data, but just inform the user and show him/her how to use this event instead of using the openni::OpenNI::waitForAnyStream() method.

struct OurOpenNINewFrameMonitorer : public VideoStream::NewFrameListener
{
  void onNewFrame(VideoStream& videoStream)
  {
    printf("%d. New data is available to read.
",
      clock());
  }
};

In step 3, things are pretty much the same as older recipes. Just as always, we initialized OpenNI, opened a device, and created depth by using openni::VideoStream. But there is a slight difference here. We used the openni::VideoStream::addNewFrameListener() method for the first time. This method accepts an argument of type openni::VideoStream::NewFrameListener and passes new frames to this class. This class is an almost empty class with only one virtual method named onNewFrame. But in step 1, we defined a structure from this class, named OurOpenNINewFrameMonitorer, and wrote our custom onNewFrame method. Because OurOpenNINewFrameMonitorer inherits from openni::VideoStream::NewFrameListener, we can pass it as an argument to the openni::VideoStream::addNewFrameListener() method without any problem. Whenever any new event is raised, this is our method that will be called.

  OurOpenNINewFrameMonitorer p;
  status = depthSensor.addNewFrameListener(&p);

In the first line, we created an object from the OurOpenNINewFrameMonitorer structure and, in the second line, we used the pointer of our new object as a parameter of the openni::VideoStream::addNewFrameListener() method.

Then we started the depth's openni::VideoStream stream and waited for new data or for the user to press the Enter key to end the execution process.

  ReadLastCharOfLine();

After this line, we will destroy, close, and shut down everything, including OpenNI, and return 0 as a sign of the application's successful end.

Tip

Please note that structures and classes are almost the same thing in C++ and there is little difference when we use a structure instead of a class and viceversa. So here you can use a class instead of defining a structure, and it is probably a better idea. Our reason for using a structure here is only to show you that using a structure is also possible.

The following is the output of this code at the very beginning of the run:

How it works...
..................Content has been hidden....................

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