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.
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.
#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()); } };
int _tmain(int argc, _TCHAR* argv[]) {
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();
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.
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:
18.118.162.201