OpenNI 1.5.4: Device.cpp file

OpenNI

Device.cpp file

Source files: Click the following link to view the source code file:

  • Device.cpp

This file contains the code for declaring, initalizing, and creating the basic OpenNI objects and nodes, and provides the basic access routiese.

Main File Declarations

Main File Declarations

The declarations at the head of this file define the main OpenNI objects and other environment variables.

The following declarations define two of the main OpenNI objects required for building the OpenNI production graph. The production graph is the main object in OpenNI.

            Context g_Context;
            ScriptNode g_scriptNode;

These two declarations are described separately in the following paragraphs.

the xn::ScriptNode object loads an XML script from a file or string, and then runs the XML script to build a production graph.

The Production Graph is a network of software objects - called production nodes - that can identify blobs as hands or human users. In this sample program the production graph identifies blobs as human users, and tracks them as they move.

a xn::Context object is a workspace in which the application builds an OpenNI production graph.

The following declarations define some environment variables. They are not OpenNI related.

            DeviceStringProperty g_PrimaryStream;
            ...

The following declarations define more main OpenNI objects.

            Device g_Device;
            DepthGenerator g_Depth;
            ImageGenerator g_Image;
            IRGenerator g_IR;
            AudioGenerator g_Audio;
            Player g_Player;

Each of these declarations is described separately in the following paragraphs.

A Device node represents a physical hardware device currently connected in the system and used for generating data. The Device node represents the hardware device by providing, for example, the device's name, serial number, and specific vendors. The Device node itself does not generate data.

a xn::DepthGenerator node generates a depth map. Each map pixel value represents a distance from the sensor.

            DepthGenerator depthGen;

A ImageGenerator node generates color image maps of various formats, such as the RGB24 image format. Call its SetPixelFormat() method to set the image format to be generated.

A IRGenerator node is a map generator that outputs infra-red maps. The IR Generator node supports all MapGenerator functionality, as well as adding additional functionality.

A AudioGenerator node generates audio data.

A Player node plays a saved recording of an OpenNI data generation session.

The following declarations define OpenNI use metadata classes to create frame objects. The metadata classes provide frame objects to the corresponding generator nodes to support fast data access. for example, the DepthMetaData object provides a frame object for a DepthGenerator node, and so on.

            DepthMetaData g_DepthMD;
            ImageMetaData g_ImageMD;
            IRMetaData g_irMD;
            AudioMetaData g_AudioMD;

This program file makes extensive use of g_pPrimary. This is a pointer to a ProductionNode object to point to just one of the Generator nodes. This node is then termed the primary node in this sample program. g_pPrimary selectas which output map to display on the graphic display. g_pPrimary is assigned its value in the changePrimaryStream() function.

The ProductionNode class is a base class for all production nodes of the Production Graph, including all Generator nodes. Note that the g_pPrimary pointer is never itself used to make an object or node, but just to point to a node created somewhere else.

            ProductionNode* g_pPrimary = NULL;

Function: initConstants() - Initializes the Primary Stream and the Resolutions

In the following code block (shown in part), g_PrimaryStream is initialized with the enum IDs of all different types of production nodes, e.g., xn::XN_NODE_TYPE_DEPTH means a DepthGenerator node.

            g_PrimaryStream.pValues[nIndex++] = "Any";
            g_PrimaryStream.pValues[nIndex++] = xnProductionNodeTypeToString(XN_NODE_TYPE_DEPTH);
            g_PrimaryStream.pValues[nIndex++] = xnProductionNodeTypeToString(XN_NODE_TYPE_IMAGE);
            g_PrimaryStream.pValues[nIndex++] = xnProductionNodeTypeToString(XN_NODE_TYPE_IR);
             ...

In the following code block (shown in part), g_Resolution is initialized with all possible image map resolutions.

            g_Resolution.pValues[nIndex++] = XN_RES_QVGA;
            g_Resolution.pValueToName[XN_RES_QVGA] = Resolution(XN_RES_QVGA).GetName();
            g_Resolution.pValues[nIndex++] = XN_RES_VGA;
            g_Resolution.pValueToName[XN_RES_VGA] = Resolution(XN_RES_VGA).GetName();           

Function: initConstants() - Initializes the Primary Stream and the Resolutions

This function tests whether the error state is now xn::XN_STATUS_OK, i.e., no error, or is an error. On error, the error message is accessed according to the value of errorState. The high word represents the error group of the error. The low word is the sequential error number within the group.

- openCommon() - Common Initialize Function

This is a common initialize function called from a number of more specific functions that initialize the production graph.

            void openCommon()
            {
                ...
            }           

This function uses xn::Context::EnumerateExistingNodes to enumerate for all production nodes defined in the production graph, which returns in the list return parameter a xn::NodeInfoList containing all the context's existing created nodes. Each node is represented by a NodeInfo object in the list.

The following for-loop iterates for all NodeInfo objects in the list. For each NodeInfo object found, this function calls GetInstance() to return a reference to the actual production node instance represented by this NodeInfo object. The for-loop is shown below (in part):

            for (NodeInfoList::Iterator it = list.Begin(); it != list.End(); ++it)
            {
                switch ((*it).GetDescription().Type)
                {
                case XN_NODE_TYPE_DEVICE:
                    (*it).GetInstance(g_Device);
                    break;
                case XN_NODE_TYPE_DEPTH:
                    g_bIsDepthOn = true;
                    (*it).GetInstance(g_Depth);
                    break;
                ...
            }

The above loop sets the generating state of all nodes to 'On', e.g., g_bIsDepthOn = true.

The following statement registers an event handler, onErrorStateChanged(), for all OpenNI errors that might occur.

            g_Context.RegisterToErrorStateChange(onErrorStateChanged, NULL, hDummy);

The following statements initialize the constants (see Function: initConstants() - Initializes the Primary Stream and the Resolutions above) and calls the readFrame() method to read the first data frame. The readFrame() method reads the data frame from each and every one of all the generators in the production graph.

            initConstants();
            readFrame();

- openDeviceFile() - Builds a Production Graph from an OpenNI Recording File

This function sets up a replay of a session of OpenNI data generation exactly as it was recorded on an ONI file.

The following call to the Context::Init() method builds the context's general software environment. This method initializes runtime variables and data structures, and examines all registered plug-ins to learn the purpose and specific capabilities of each. In particular, during initialization the context initialization examines all registered plug-ins to learn the purpose and specific capabilities of each.

            XnStatus nRetVal = g_Context.Init();

In the following, if nRetVal is an error value, the XN_IS_STATUS_OK() macro halts program execution, returning nRetVal as the error value.

            XN_IS_STATUS_OK(nRetVal);

The following call to OpenFileRecording() recreates a production graph from a recorded ONI file and then replays the data generation exactly as it was recorded. The csFile parameter provides the name of the recorded file to be run. The g_Player parameter returns a xn::ProductionNode object through which playback can be controlled, e.g., seeking and setting playback.

            nRetVal = g_Context.OpenFileRecording(csFile, g_Player);

The openCommon() method, called in the following statement, is descibed above in

.

- openDeviceFromXml() - Builds a Production Graph from an OpenNI XML Script File

The following call to the Context.InitFromXmlFile() method builds the context's general software environment (see g_Context.Init() above) and then recreates a production graph from the specified OpenNI XML script file. This method is not for replaying a recording (compare with OpenFileRecording above).

            nRetVal = g_Context.InitFromXmlFile(csXmlFile, g_scriptNode, &errors);

In the following statement, if nRetVal is an error value, the XN_IS_STATUS_OK() macro halts program execution, returning nRetVal as the error value.

            XN_IS_STATUS_OK(nRetVal);

- openDeviceFromXmlWithChoice() - Builds a Production Graph from an XML Script, Allowing User to Select a Device

This function does the same as the previous function, i.e., it builds the Production Graph from an OpenNI XML Script File, but it allows the user to intervene and select a device.

the xn::Context::EnumerateProductionTrees() method enumerates all available production nodes for a specific node type (e.g., the application wants to create a xn::Device node) and returns a full list of matching production nodes.

This function then gets the device IDs of all the devices it finds in the production graph using xn::Device::GetIdentificationCap() "GetIdentificationCap()".

The function then interacts with the user using simple C functions to allow the user to select which device to use.

- closeDevice() - Releases all the Production Nodes

This function releases all the production graph nodes.

readFrame() function - Reads a Data frame from each Generator

This function reads a data frame from each of the generators in the production graph.

If g_pPrimary has been set to point to any particular node (i.e., not NULL; g_pPrimary is initialized in the changePrimaryStream() function) then this function calls WaitOneUpdateAll() to wait only for that particular node to generate new data, and then this function refreshes the data available in all the nodes.

g_pPrimary can be pointing to NULL. This is a valid user selection, available from the GUI menu. g_pPrimary == NULL means that the user is not selcting any particular generator node.

Then the function checks if all the node pointers (e.g., g-depth) point to real nodes, and if so the function gets the node's frame object, saving it in a metadata object. For example: the application saves a frame object from a DepthGenerator node as a ref xn::DepthMetaData object.

            if (g_Depth.IsValid())
            {
                g_Depth.GetMetaData(g_DepthMD);
            }

This frame object provides fast access to the saved generated data and its associated configuration.

changeRegistration() - Changes the View Point Registration

Viewpoint registration is an OpenNI term for performing the mathematical conversion of one node's coordinate system to match the coordinate system of another node.

In this sample program, this specific function can toggle the viewpoint registration of the DepthGenerator node to that of the ImageGenerator node and back again - i.e., reset it - depending on the input parameter. This particular conversion is a consequence of the particular type of the supplied hardware sensor.

The following test checks verifies that the DepthGenerator node is a valid node and that it supports the Alternative View Point capability.

            if (!g_Depth.IsValid() || !g_Depth.IsCapabilitySupported(XN_CAPABILITY_ALTERNATIVE_VIEW_POINT))
            {
                return;
            }               

The following code block calls xn::AlternativeViewPointCapability methods to toggle the viewpoint registration, as explained above.

            if (!nValue)
            {
                g_Depth.GetAlternativeViewPointCap().ResetViewPoint();
            }
            else if (g_Image.IsValid())
            {
                g_Depth.GetAlternativeViewPointCap().SetViewPoint(g_Image);
            }

changePrimaryStream() function - Change the Primary stream

This function selects from which node the application will take generated data. It selects the new production node acording to the index into the g_PrimaryStream array. The xnProductionNodeTypeFromString() function returns an enum specifting a particular node type, e.g., XN_NODE_TYPE_DEPTH specifies a DepthGenerator node.

The user can invoke this functionality from the GUI user menu. The user can select a menu item to call this function.

The following statement calls the xn::Context::CreateAnyProductionTree() method.

createStream() - Creates a New Data Generatation Node

This function creates a new stream by creating a new data generation node of a specified type calling the xn::Context::CreateAnyProductionTree() method, as follows.

            EnumerationErrors errors;
            XnStatus nRetVal = g_Context.CreateAnyProductionTree(type, NULL, generator, &errors);

This method enumerates for production nodes of a specific node type, and creates the first production node found of that type.

toggleStream() - Toggles between Starting and Stopping a Generator Node

This function toggles between starting and stopping a generator node. The first two statements ensure that the specified generator is a valid node, and if not it calls createStream() (described above) to create a node of the required type.

In the following statement, the xn::Generator::IsValid() method checks that the reference points to a real node instance, or to to NULL, where in the latter case the function calls createStream() to create the generator node.

            if (!generator.IsValid())
            {
                createStream(generator, type);
            }

In the following code block, the IsGenerating() method returns whether the node is currently in Generating state. StartGenerating() enters the node into Generating state, and StopGenerating() makes the node leave Generating state (it enters Non-Generating state).

            if (generator.IsGenerating())
            {
                generator.StopGenerating();
            }
            else
            {
                generator.StartGenerating();
                ...
            }                       

After the application has called StartGenerating() it can call an 'Update Data()' method, e.g., xn::Generator::WaitAndUpdateData(), to make a new frame available for getting. The application can then get the data (for example, using a metadata GetData() method, or some other mechanism depending on the type of node).

This toggleStream() function is used by a number of other functions to start and stop each of the generators in this application - see below.

Finally, this function then sets the boolean return parameter bIsOn from the IsGenerating() method. This parameter returns the updated 'Is Generating' state for all the 'Toggle Generating State' functions that follow below.

Starting and Stopping each of the Generators

The following group of functions start and stop each of the generators in this application.

            void toggleDepthState(int nDummy)
            {
                toggleStream(g_Depth, XN_NODE_TYPE_DEPTH, &g_bIsDepthOn);
            }

            void toggleImageState(int nDummy)
            {
                toggleStream(g_Image, XN_NODE_TYPE_IMAGE, &g_bIsImageOn);
            }

            void toggleIRState(int nDummy)
            {
                toggleStream(g_IR, XN_NODE_TYPE_IR, &g_bIsIROn);
            }

            void toggleAudioState(int nDummy)
            {
                toggleStream(g_Audio, XN_NODE_TYPE_AUDIO, &g_bIsAudioOn);
            }       

Function: toggleMirror() - Toggles the Global Mirror

This function can enable or disable the GlobalMirror flag. For a detailed introduction to mirroring in OpenNI see xn::MirrorCapability.

The following statement gets the current value of the Global Mirror using the GetGlobalMirror() method and then inverses it using the GetGlobalMirror() method.

            XnStatus nRetVal = g_Context.SetGlobalMirror(!g_Context.GetGlobalMirror())

Use the GUI menu access to toggle the GlobalMirrior.

Function: seekFrame() - Seeks a Data Frame in a Recording

This function seeks a data frame from the primary stream (generator node) in an OpenNI recording.

The first thing this function does is to get the node name of the primary stream. if the primary stream is found to be NULL, this function then gets node name of any other valid node.

The following statement calls the SeekToFrame() method to moves the player to a specific frame of a specific played node so that playing will continue from that frame onwards.

            nRetVal = g_Player.SeekToFrame(strNodeName, nDiff, XN_PLAYER_SEEK_CUR);

In the call above, the nDiff and xn::XN_PLAYER_SEEK_CUR parameters specify that the seek operation moves nDiff frames from the current frame of the specified node. A positive value means to move forward, and a negative value means to move backwards.

In the following statement, the call to the TellFrame() method gets the absolute current frame number of a specific node played by a player, i.e., the number of frames passed since the beginning of the recording.

In the following statement, the call to the GetNumFrames() method gets the number of frames of a specific node played by a player.

Function: is 'Generator' On function

The following group of functions all return whether the production node is on. For example:

            bool isDepthOn()
            {
                return (g_bIsDepthOn);
            }           

Function: setResolution() - Sets the Resolution of the Output Map

This function sets the resolution component of the generator node's current map output mode. This map output mode includes the frame resolution, i.e., its X and Y dimensions, which are the number of elements in each of the X- and Y- axes) and also the frame rate. This is the map output mode that the generator node will use to generate its next data frame.

The resolution is provided y the res parameter to this function call, which is an enum value of type XnResolution, e.g., XN_RES_QVGA.

The following code block calls the GetMapOutputMode() method to get an xn::XnMapOutputMode struct containing the generator node's current map output mode. The code then updates the mode's resolution fields with new values, and then completes the operation by calling SetMapOutputMode(), passing the xn::XnMapOutputMode struct as a parameter, to update the node's map output mode.

            XnMapOutputMode Mode;
            pGenerator->GetMapOutputMode(Mode);
            Mode.nXRes = Resolution((XnResolution)res).GetXResolution();
            Mode.nYRes = Resolution((XnResolution)res).GetYResolution();
            XnStatus nRetVal = pGenerator->SetMapOutputMode(Mode);

See also the setFPS() function (the next function, below) for setting the frame rate.

In the above, the 'Resolution' term is an OpenNI utility class for easy handling of resolution information. It creates a Resolution object from an enum value of type XnResolution, from which you can then get the X and Y dimensions if the frame.

Function: setFPS() - Selects a Resolution for the Output Map

This function sets the frame rate component of the generator node's current map output mode.

This function works in a similar way to the setResolution() function above.

The following code block calls the GetMapOutputMode() method to get an xn::XnMapOutputMode struct containing the generator node's current map output mode. The code then updates the mode's frmae rate field, nFPS, with a new value, and then completes the operation by calling SetMapOutputMode(), passing the xn::XnMapOutputMode struct as a parameter, to update the node's map output mode.

            XnMapOutputMode Mode;
            pGenerator->GetMapOutputMode(Mode);
            Mode.nFPS = fps;
            XnStatus nRetVal = pGenerator->SetMapOutputMode(Mode);

'setResolution/Fps()' - Group of Functions for Setting Resolutions and Frame Rates

The next functions defined in this file are a group of functions for setting resolutions and frame rates for all generators in this sample application. All use the methods just defined above, setResolution() and setFPS(). The code below shows some examples.

            void setDepthResolution(int res)
            {
                setResolution(getDepthGenerator(), res);
            }
            ...
            ...
            void setImageFPS(int fps)
            {
                setFPS(getImageGenerator(), fps);
            }

The 'get' functions used in the above are defined later in this file.

All these 'set resolution/fps' functions are invoked by the user clicking the GUI menu items to make these settings.

Function: setStreamCropping() - Crops the Map Area of the Generator Output

This function crops the map area of the generator output.

Usage: For user area selections where the user can use the mouse to select just a part of the full map area for applying OpenNI or other graphic operations.

Parameters:

pGenerator - generator node for which to set the cropping area.

pCropping - xn::XnCropping struct containing the cropping details.

The following statement checks that the generator node exists.

            if (pGenerator == NULL)
            {
                displayMessage("Stream does not exist!");
                return;
            }           

The code first checks that the capability exists using the IsCapabilitySupported() method.

The code then gets the crop capability using the GetCroppingCap() method, and through it calls the xn::CroppingCapability::SetCropping() method.

Function: setPlaybackSpeed() - Sets the playback speed

Group: Recording and Playback {If I want to use this format I will have to go back and make it consistent - ie at least for this sample NiViewer.}

Parameter: ratioDiff - Ratio of recording rate

This function sets the playback speed of an OpenNI recording as a ratio of the rate that the recording was made at. This OpenNI recording is a recording of all the actual map data that was generated during the time that recording was enabled. This is not the same as a production graph stired in an OpenNI XML script file: a script file stores only the structure of the production graph but not the data that the production graph has or will generate.

    
            XnDouble dNewSpeed = g_Player.GetPlaybackSpeed() * pow(2.0, (XnDouble)ratioDiff);
            XnStatus nRetVal = g_Player.SetPlaybackSpeed(dNewSpeed);

Function: getPlaybackSpeed() - Gets the playback speed

Group: Recording and Playback

This function calls the xn::Player::GetPlaybackSpeed() to get current playback speed. If the player is not valid it returns the "identity' ratio, 1.

Function: setFPS() - Group of Functions for Setting Resolutions and Frame Rates

Next is a group of functions for getting pointers to certain OpenNI objects: to production nodes, generators, and metadata objects. The code below shows some examples. These functions achieve a way of simply indicating as a boolean flag whether the nodes are actual created nodes, i.e., whether they have been initialized and made operational in the production graph, or they are still in the 'pre-creation' state, i.e., they have been constructed as C++ objects but have not yet undergone creation.

            Device* getDevice()
            {
                return g_Device.IsValid() ? &g_Device : NULL;
            }
            DepthGenerator* getDepthGenerator()
            {
                return g_Depth.IsValid() ? &g_Depth : NULL;
            }
            ...
            ...
            const AudioMetaData* getAudioMetaData()
            {
                return g_Audio.IsValid() ? &g_AudioMD : NULL;
            }
Generated on Wed May 16 2012 10:16:06 for OpenNI 1.5.4 by   doxygen 1.7.5.1