OpenNI 1.5.4: SimpleViewer.net - sample program (C#/.NET)

OpenNI

SimpleViewer.net - sample program (C#/.NET)

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

  • SimpleViewer.net/MainWindow.cs

This section describes the SimpleViewer.net sample program in the C# language for .NET.

This sample program demonstrates using a DepthGenerator node to build an accumulative histogram from depth values.

The documentation describes the sample program's code from the top of the program file(s) to bottom.

Every OpenNI feature is described the first time it appears in this sample program. Further appearances of the same feature are not decribed again.

"Declaration Block" section

The reader may find it convenient to study the global declaration block before continuing to study the code statements. The global declaration block is documented later in this section, corresponding to its position in the program file – see Global Declaration Block .

MainWindow()

Use Script to Set up a Context and Production Graph

The CreateFromXmlFile() method is a shorthand combination of two other initialization methods — Create() and then RunXmlScriptFromFile() — which initializes the Context object and then creates a production graph from an XML file. The method returns a scriptNode which is the owner of all the nodes created by the script. This node should be kept until those nodes aren't needed anymore.

The XML script file describes all the nodes you want to create. For each node description in the XML file, this method creates a node in the production graph.

                InitializeComponent();
                this.context = Context.CreateFromXmlFile(SAMPLE_XML_FILE, out scriptNode);

Assuming that the above call to CreateFromXmlFile succeeded, a production graph is then created.

Get a DepthGenerator Node from the Production Graph

The FindExistingNode() method in the following code block tries to get a reference to any one of the production nodes. This call specifies NodeType.Depth to get a reference to a DepthGenerator node. A DepthGenerator node generates a depth map as an array of pixels, where each pixel is a depth value representing a distance from the sensor in millimeters. A reference to the node is returned in the depth parameter.

                this.depth = context.FindExistingNode(NodeType.Depth) as DepthGenerator;

The code block that follows the FindExistingNode() call just checks that OpenNI found a DepthGenerator node in the production graph.

                if (this.depth == null)
                {
                    throw new Exception("Viewer must have a depth node!");
                }

Using DepthGenerator characterstics to set up Histogram and Image Buffer

The following sets up the array for the histogram array that is a key part of this sample program. (This is not OpenNI specific.) xn::DepthGenerator::GetDeviceMaxDepth() "GetDeviceMaxDepth" gets the maximum depth (depth resolution) that the DepthGenerator node can produce. This is the same as the resolution of the depth axis (i.e., DeviceMaxDepth() + 1).

                this.histogram = new int[this.depth.DeviceMaxDepth];

The following statement gets the Map Output mode of the DepthGenerator node. The xnMapOutputMode value returned by xn::MapGenerator::GetMapOutputMode is the combination of the node's scene resolution and frame rate.

                MapOutputMode mapMode = this.depth.MapOutputMode;

The following statement accesses the Map Output mode to get the DepthGenerator's map dimensions. XRes and YRes get the frame's X and Y resolutions of the most recently generated data. X and Y are the number of columns and rows, respectively, in the frame after any required cropping has been applied. See Map Wrapper Classes for more information. A default format, 'Rgb24', is used for pixel color format.

                this.bitmap = new Bitmap((int)mapMode.XRes, (int)mapMode.YRes,
                                System.Drawing.Imaging.PixelFormat.Format24bppRgb);

The following statements start the main reader thread. These statements are not OpenNI specific.

                this.shouldRun = true;
                this.readerThread = new Thread(ReaderThread);
                this.readerThread.Start();

OnPaint() method

This method is not OpenNI specific.

OnPaintBackground() method

This method is not OpenNI specific.

OnClosing() method

This method is not OpenNI specific.

OnKeyPress() method

This method is not OpenNI specific.

CalcHist() method

This method uses the depth values to build an accumulative histogram of frequency of occurrence of each depth value. The pDepth pointer accesses each value in the depth buffer and then uses it as an index into the histogram array.

                private unsafe void CalcHist(DepthMetaData depthMD)
                {
                    ... 
                    ... 
                    for (int y = 0; y < depthMD.YRes; ++y)
                    {
                        for (int x = 0; x < depthMD.XRes; ++x, ++pDepth)
                        {
                            ushort depthVal = *pDepth;
                            if (depthVal != 0)
                            {
                                this.histogram[depthVal]++;
                                points++;
                            }
                        }
                    }   
                    ... 
                    ...                     

ReaderThread() method

The DepthMetaData object provides a frame object for the DepthGenerator node. A generator node's frame object contains the generated data frame) and all its associated properties. This frame object, comprising the data frame and its properties, is accessible through the node's metadata object.

            DepthMetaData depthMD = new DepthMetaData();

Main Loop

The following statement updates all generator nodes in the context that have new data available, first waiting for a specified node to have new data available.

            try
            {
                this.context.WaitOneUpdateAll(this.depth);
            }

Global Declaration Block

The global declaration block is at the bottom of the public MainWindow() block. The declarations are as follows.

            private readonly string SAMPLE_XML_FILE = @"../../../../Data/SamplesConfig.xml";

            private Context context;
            private ScriptNode scriptNode;
            private DepthGenerator depth;
            private Thread readerThread;
            private bool shouldRun;
            private Bitmap bitmap;
            private int[] histogram;

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

The following definition is for the path to an OpenNI XML script file for inputting and building a stored production graph. The production graph is a network of production nodes and is the principal OpenNI object model. The identifies blobs as hands or human users (focusing mainly on OpenNI specific declarations).

            #define SAMPLE_XML_FILE "../../../../Data/SamplesConfig.xml"

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

The ScriptNode object loads an XML script from a file or string, and then runs the XML script to build a production graph. The ScriptNode object keeps references to all nodes created from the script, so they will not be destroyed. (This is since OpenNI will delete a node that has no remaining references to it.)

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

The following declarations are not OpenNI specific. histogram is a key part of this sample program.

            private Thread readerThread;
            private bool shouldRun;
            private Bitmap bitmap;
            private int[] histogram;
Generated on Wed May 16 2012 10:16:06 for OpenNI 1.5.4 by   doxygen 1.7.5.1