Skip to content

NodeMapInfo_CSharp

NodeMapInfo_CSharp.cs shows how to retrieve node map information. It relies on information provided in the Enumeration_CSharp example. Following this, check out the Acquisition_CSharp and ExceptionHandling_CSharp example if you haven't already. It explores acquiring images.


//=============================================================================
// Copyright (c) 2026 FLIR Integrated Imaging Solutions, Inc. All Rights Reserved.
//
// This software is the confidential and proprietary information of FLIR
// Integrated Imaging Solutions, Inc. ("Confidential Information"). You
// shall not disclose such Confidential Information and shall use it only in
// accordance with the terms of the license agreement you entered into
// with FLIR Integrated Imaging Solutions, Inc. (FLIR).
//
// FLIR MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY OF THE
// SOFTWARE, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE, OR NON-INFRINGEMENT. FLIR SHALL NOT BE LIABLE FOR ANY DAMAGES
// SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
// THIS SOFTWARE OR ITS DERIVATIVES.
//=============================================================================

/**
 *  @example NodeMapInfo_CSharp.cs
 *
 *  @brief NodeMapInfo_CSharp.cs shows how to retrieve node map information.
 *  It relies on information provided in the Enumeration_CSharp example.
 *  Following this, check out the Acquisition_CSharp and
 *  ExceptionHandling_CSharp example if you haven't already. It explores
 *  acquiring images.
 *
 *  This example explores retrieving information from all major node types on
 *  the camera. This includes string, integer, float, boolean, command,
 *  enumeration, category, and value types. Looping through multiple child nodes
 *  is also covered. A few node types are not covered here - base, port, and
 *  register - as they are not representations of a fundamental data types.
 *  Enumeration entry node type is explored only in terms of its enumeration
 *  type parent.
 *
 *  Once comfortable with Acquisition_CSharp and NodeMapInfo_CSharp, we suggest
 *  checking out ImageFormatControl_CSharp and Exposure_CSharp.
 *  ImageFormatControl_CSharp explores customizing image settings on a camera
 *  while Exposure_CSharp introduces the standard structure of configuring a
 *  device, acquiring some images, and then returning the device to a default
 *  state.
 *
 *  Please leave us feedback at: https://www.surveymonkey.com/r/TDYMVAPI
 *  More source code examples at: https://github.com/Teledyne-MV/Spinnaker-Examples
 *  Need help? Check out our forum at: https://teledynevisionsolutions.zendesk.com/hc/en-us/community/topics
 */

using System;
using System.Collections.Generic;
using SpinnakerNET;
using SpinnakerNET.GenApi;

namespace NodeMapInfo_CSharp
{
    class Program
    {
        // This constant defines the maximum number of characters that will be
        // printed out for any information retrieved from a node.
        const int MaxChars = 35;

        // Use the following enum and global static variable to select whether
        // nodes are read as 'value' nodes or their individual types.
        enum readType
        {
            Value,
            Individual
        }

        static readType chosenRead = readType.Value;

        // This helper function deals with output indentation, of which there
        // is a lot.
        void indent(int level)
        {
            for (int i = 0; i < level; i++)
            {
                Console.Write("   ");
            }
        }

        // This function retrieves and prints the display name and value of all
        // node types as value nodes. A value node is a general node type that
        // allows for the reading and writing of any node type as a string.
        int printValueNode(INode node, int level)
        {
            int result = 0;

            try
            {
                // Cast as value node
                IValue iValueNode = (IValue) node;

                //
                // Retrieve display name
                //
                // *** NOTES ***
                // A node's 'display name' is generally more appropriate for
                // output and user interaction whereas its 'name' is what the
                // camera understands. Generally, its name is the same as its
                // display name but without spaces - for instance, the name of
                // the node that houses a camera's serial number is
                // 'DeviceSerialNumber' while its display name is 'Device
                // Serial Number'.
                //
                string displayName = iValueNode.DisplayName;

                //
                // Retrieve value of any node type as string
                //
                // *** NOTES ***
                // Because value nodes return any node type as a string, it can be much
                // easier to deal with nodes as value nodes rather than their actural
                // individual types. However, certain type-based functionality
                // - e.g. getMin(), which is only available on integer and float nodes
                // - is unavailable if cast as a value node.
                string value = iValueNode.ToString();

                // Ensure that the value length is not excessive for printing
                if (value.Length > MaxChars)
                {
                    value = value.Substring(0, MaxChars) + "...";
                }

                // Print value
                indent(level);
                Console.WriteLine("{0}: {1}", displayName, value);
            }
            catch (SpinnakerException ex)
            {
                Console.WriteLine("Error: {0}", ex.Message);
                result = -1;
            }

            return result;
        }

        // This function retrieves and prints the display name and value of a
        // string node, limiting the number of printed characters to a maximum
        // defined by MaxChars constant. Level parameter determines the
        // indentation level for the output.
        int printStringNode(INode node, int level)
        {
            int result = 0;

            try
            {
                // Cast as string node
                IString iStringNode = (IString) node;

                // Retrieve display name
                string displayName = iStringNode.DisplayName;

                //
                // Retrieve string node value
                //
                // *** NOTES ***
                // String node values in C# return string literals.
                //
                string value = iStringNode.Value;

                // Ensure that the value length is not excessive for printing
                if (value.Length > MaxChars)
                {
                    value = value.Substring(0, MaxChars) + "...";
                }

                // Print value
                indent(level);
                Console.WriteLine("{0}: {1}", displayName, value);
            }
            catch (SpinnakerException ex)
            {
                Console.WriteLine("Error: {0}", ex.Message);
                result = -1;
            }

            return result;
        }

        // This function retrieves and prints the display name and value of an
        // integer node.
        int printIntegerNode(INode node, int level)
        {
            int result = 0;

            try
            {
                // Cast node as integer node
                IInteger iIntegerNode = (IInteger) node;

                // Retrieve display name
                string displayName = iIntegerNode.DisplayName;

                //
                // Retrieve integer node value
                //
                // *** NOTES ***
                // Keep in mind that the data type of an integer node value is
                // a long as opposed to a standard int. While it is true that
                // the two are often interchangeable, it is recommended to use
                // long to avoid the introduction of bugs.
                //
                // All node types except for base and port nodes include a handy
                // ToString() method which returns a value as a string literal.
                //
                long value = iIntegerNode.Value;

                // Print value
                indent(level);
                Console.WriteLine("{0}: {1}", displayName, value);
            }
            catch (SpinnakerException ex)
            {
                Console.WriteLine("Error: {0}", ex.Message);
                result = -1;
            }

            return result;
        }

        // This function retrieves and prints the display name and value of a
        // float node.
        int printFloatNode(INode node, int level)
        {
            int result = 0;

            try
            {
                // Cast as float node
                IFloat iFloatNode = (IFloat) node;

                // Retrieve display name
                string displayName = iFloatNode.DisplayName;

                //
                // Retrieve float node value
                //
                // *** NOTES ***
                // Please take note that floating point numbers in the Spinnaker
                // SDK are almost always represented by the larger data type
                // double rather than float.
                //
                double value = iFloatNode.Value;

                // Print value
                indent(level);
                Console.WriteLine("{0}: {1}", displayName, value);
            }
            catch (SpinnakerException ex)
            {
                Console.WriteLine("Error: {0}", ex.Message);
                result = -1;
            }

            return result;
        }

        // This function retrieves and prints the display name and value of a
        // boolean, printing "true" for true and "false" for false rather than
        // the corresponding integer value ('1' and '0', respectively).
        int printBooleanNode(INode node, int level)
        {
            int result = 0;

            try
            {
                // Cast as boolean node
                IBool iBooleanNode = (IBool) node;

                // Retrieve display name
                string displayName = iBooleanNode.DisplayName;

                //
                // Retrieve value as a string representation
                //
                // *** NOTES ***
                // Boolean node type values are represented by the standard
                // bool data type. The boolean ToString() method returns either
                // a '1' or '0' as a string rather than a more descriptive word
                // like 'true' or 'false'.
                //
                string value = (iBooleanNode.Value ? "true" : "false");

                // Print value
                indent(level);
                Console.WriteLine("{0}: {1}", displayName, value);
            }
            catch (SpinnakerException ex)
            {
                Console.WriteLine("Error: {0}", ex.Message);
                result = -1;
            }

            return result;
        }

        // This function retrieves and prints the display name and tooltip of a
        // command node, limiting the number of printed characters to a
        // constant-defined maximum. The tooltip is printed because command
        // nodes do not have an intelligible value.
        int printCommandNode(INode node, int level)
        {
            int result = 0;

            try
            {
                // Cast as command node
                ICommand iCommandNode = (ICommand) node;

                // Retrieve display name
                string displayName = iCommandNode.DisplayName;

                //
                // Retrieve tooltip
                //
                // *** NOTES ***
                // All node types have a tooltip available. Tooltips provide
                // useful information about nodes. Command nodes do not have a
                // method to retrieve values as their is no intelligible value
                // to retrieve.
                //
                string tooltip = iCommandNode.ToolTip;

                // Ensure that the value length is not excessive for printing
                if (tooltip.Length > MaxChars)
                {
                    tooltip = tooltip.Substring(0, MaxChars) + "...";
                }

                // Print tooltip
                indent(level);
                Console.WriteLine("{0}: {1}", displayName, tooltip);
            }
            catch (SpinnakerException ex)
            {
                Console.WriteLine("Error: {0}", ex.Message);
                result = -1;
            }

            return result;
        }

        // This function retrieves and prints the display names of an enumeration
        // node and its current entry (which is actually housed in another node
        // unto itself).
        int printEnumerationNodeAndCurrentEntry(INode node, int level)
        {
            int result = 0;

            try
            {
                // Cast as enumeration node
                IEnum iEnumerationNode = (IEnum) node;

                //
                // Retrieve current entry as enumeration node
                //
                // *** NOTES ***
                // Enumeration nodes have three methods to differentiate between:
                // first, GetIntValue() returns the integer value of the current
                // entry node; second, GetCurrentEntry() returns the entry node
                // itself; and third, ToString() returns the symbolic of the
                // current entry.
                //
                EnumValue iEnumEntryValue = iEnumerationNode.Value;

                // Retrieve display name
                string displayName = iEnumerationNode.DisplayName;

                //
                // Retrieve current symbolic
                //
                // *** NOTES ***
                // Rather than retrieving the current entry node and then
                // retrieving its symbolic, ToString() accomplishes both
                // in a single step.
                //
                string currentEntrySymbolic = iEnumEntryValue.String;

                // Print current entry symbolic
                indent(level);
                Console.WriteLine("{0}: {1}", displayName, currentEntrySymbolic);
            }
            catch (SpinnakerException ex)
            {
                Console.WriteLine("Error: {0}", ex.Message);
                result = -1;
            }

            return result;
        }

        // This function retrieves and prints out the display name of a category
        // node before printing all child nodes. Child nodes that are also
        // category nodes are  printed recursively.
        int printCategoryNodeAndAllFeatures(INode node, int level)
        {
            int result = 0;

            try
            {
                // Cast as category node
                ICategory iCategoryNode = (ICategory) node;

                // Retrieve display name
                string displayName = iCategoryNode.DisplayName;

                // Print display name
                indent(level);
                Console.WriteLine("{0}", displayName);

                //
                // Retrieve children
                //
                // *** NOTES ***
                // The two nodes that typically have children are category nodes
                // and enumeration nodes. Throughout the examples, the children
                // of category nodes are referred to as features while the
                // children of enumeration nodes are referred to as entries.
                // Keep in mind that enumeration nodes can be cast as category
                // nodes, but category nodes cannot be cast as enumerations.
                //
                INode[] features = iCategoryNode.Features;

                //
                // Iterate through all children
                //
                // *** NOTES ***
                // If dealing with a variety of node types and their values, it
                // may be simpler to cast them as value nodes rather than as
                // their individual types. However, with this increased
                // ease -of-use, functionality is sacrificed.
                //
                foreach(INode iFeatureNode in features)
                {
                    // Ensure node is readable
                    if (!iFeatureNode.IsReadable)
                    {
                        continue;
                    }

                    // Category nodes must be dealt with separately in order to
                    // retrieve subnodes recursively.
                    if (iFeatureNode.GetType() == typeof (Category))
                    {
                        result = result | printCategoryNodeAndAllFeatures(iFeatureNode, level + 1);
                    }
                    // Cast all non-category nodes as value nodes
                    else if (chosenRead == readType.Value)
                    {
                        result = result | printValueNode(iFeatureNode, level + 1);
                    }
                    // Cast all non-category nodes as actual types
                    else if (chosenRead == readType.Individual)
                    {
                        if (iFeatureNode.GetType() == typeof (StringNode))
                        {
                            result = result | printStringNode(iFeatureNode, level + 1);
                        }
                        else if (iFeatureNode.GetType() == typeof (Integer))
                        {
                            result = result | printIntegerNode(iFeatureNode, level + 1);
                        }
                        else if (iFeatureNode.GetType() == typeof (Float))
                        {
                            result = result | printFloatNode(iFeatureNode, level + 1);
                        }
                        else if (iFeatureNode.GetType() == typeof (BoolNode))
                        {
                            result = result | printBooleanNode(iFeatureNode, level + 1);
                        }
                        else if (iFeatureNode.GetType() == typeof (Command))
                        {
                            result = result | printCommandNode(iFeatureNode, level + 1);
                        }
                        else if (iFeatureNode.GetType() == typeof (Enumeration))
                        {
                            result = result | printEnumerationNodeAndCurrentEntry(iFeatureNode, level + 1);
                        }
                    }
                }
                Console.WriteLine();
            }
            catch (SpinnakerException ex)
            {
                Console.WriteLine("Error: {0}", ex.Message);
                result = -1;
            }

            return result;
        }

        // This function acts as the body of the example. First, nodes from the
        // transport layer device and stream nodemaps are retrieved and printed.
        // Following this, the camera is initialized and nodes from the
        // GenICam are retrieved and printed.
        int RunSingleCamera(IManagedCamera cam)
        {
            int result = 0;
            int level = 0;

            try
            {
                //
                // Retrieve TL device nodemap
                //
                // *** NOTES ***
                // The TL device nodemap is available on the transport
                // layer. As such, camera initialization is unnecessary. It
                // provides mostly immutable information fundamental to the
                // camera such as the serial number, vendor, and model.
                //
                Console.WriteLine("\n*** PRINTING TL DEVICE NODEMAP ***\n");

                INodeMap genTLNodeMap = cam.GetTLDeviceNodeMap();

                result = printCategoryNodeAndAllFeatures(genTLNodeMap.GetNode<ICategory>("Root"), level);

                //
                // Retrieve TL stream nodemap
                //
                // *** NOTES ***
                // The TL stream nodemap is also available on the transport layer.
                // Camera initialization is again unnecessary. As you can
                // probably guess, it provides information on the camera's
                // streaming performance at any given moment. Having this
                // information available on the transport layer allows the
                // information to be retrieved without affecting camera
                // performance.
                //
                Console.WriteLine("*** PRINTING TL STREAM NODEMAP ***\n");

                INodeMap nodeMapTLStream = cam.GetTLStreamNodeMap();

                result = result | printCategoryNodeAndAllFeatures(nodeMapTLStream.GetNode<ICategory>("Root"), level);

                //
                // Initialize camera
                //
                // *** NOTES ***
                // The camera becomes connected upon initialization. This
                // provides access to configurable options and additional
                // information, accessible through the GenICam nodemap
                // nodemap.
                //
                // *** LATER ***
                // Cameras should be deinitialized when no longer needed.
                //
                Console.WriteLine("*** PRINTING GENICAM NODEMAP ***\n");

                cam.Init();

                //
                // Retrieve GenICam nodemap
                //
                // *** NOTES ***
                // The GenICam nodemap is the primary gateway to customizing
                // and configuring the camera to suit your needs. Configuration
                // options such as image height and width, trigger mode enabling
                // and disabling
                //
                INodeMap appLayerNodeMap = cam.GetNodeMap();

                result = result | printCategoryNodeAndAllFeatures(appLayerNodeMap.GetNode<ICategory>("Root"), level);

                //
                // Deinitialize camera
                //
                // *** NOTES ***
                // Camera deinitialization helps ensure that devices clean up
                // properly and do not need to be power-cycled to maintain
                // integrity.
                //
                cam.DeInit();

                // Dispose of camera
                cam.Dispose();
            }
            catch (SpinnakerException ex)
            {
                Console.WriteLine("Error: {0}", ex.Message);
                result = -1;
            }

            return result;
        }

        // Example entry point; please see Enumeration_CSharp example for more
        // in-depth comments on preparing and cleaning up the system.
        static int Main(string[] args)
        {
            int result = 0;

            Program program = new Program();

            // Retrieve singleton reference to system object
            ManagedSystem system = new ManagedSystem();

            // Print out current library version
            LibraryVersion spinVersion = system.GetLibraryVersion();
            Console.WriteLine(
                "Spinnaker library version: {0}.{1}.{2}.{3}\n\n",
                spinVersion.major,
                spinVersion.minor,
                spinVersion.type,
                spinVersion.build);

            // Retrieve list of cameras from the system
            ManagedCameraList camList = system.GetCameras();

            Console.WriteLine("Number of cameras detected: {0}\n", camList.Count);

            // Finish if there are no cameras
            if (camList.Count == 0)
            {
                // Clear camera list before releasing system
                camList.Clear();

                // Release system
                system.Dispose();

                Console.WriteLine("Not enough cameras!");
                Console.WriteLine("Done! Press Enter to exit...");
                Console.ReadLine();

                return -1;
            }

            // Run example on each camera
            int index = 0;

            foreach(IManagedCamera managedCamera in camList) using(managedCamera)
            {
                Console.WriteLine("Running example for camera {0}...", index);

                try
                {
                    // Run example
                    result = result | program.RunSingleCamera(managedCamera);
                }
                catch (SpinnakerException ex)
                {
                    Console.WriteLine("Error: {0}", ex.Message);
                    result = -1;
                }

                Console.WriteLine("Camera {0} example complete...\n", index++);
            }

            // Clear camera list before releasing system
            camList.Clear();

            // Release system
            system.Dispose();

            Console.WriteLine("\nDone! Press Enter to exit...");
            Console.ReadLine();

            return result;
        }
    }
}