Basic Programming Concepts of the Baumer GAPI SDK for C

This document is meant to describe the basics on how to operate a camera using the Baumer GAPI SDK for C.

Physically connect the camera to the system

Obviously, the first step to work with a camera is to physically connect it to the data interface and a power source.

U3V(USB) cameras

All Baumer U3V cameras need to be connected to a free USB3 port on your host system. The USB3 port delivers the necessary power for the camera and provides the data interface. For Windows to recognize the camera it is necessary to install the Baumer USB driver provided in the Baumer GAPI installer. On Linux systems the libusb package is used and no further driver is necessary, however the udev-rules need to be configured to raise the available memory for the USB-system.

When connecting several cameras to one host, it is necessary to think about the USB architecture of your host system. Typically, a host system has several USB3 controllers. Each controller provides the specified bandwidth for USB3, however if more than one device is connected to one controller they have to share the available bandwidth. So if you need the full USB3 bandwidth, you need to ensure each camera is connected to its own USB3 controller.

Troubleshooting tips:

  • Use high-quality USB3 cables as a low quality cable can influence the maximum transfer rate of the camera. Low quality cable might also not be able to deliver the necessary power for the camera.
  • Ensure, that the chosen USB-port does actually deliver the required power of your camera (see the data-sheet of your camera for details on power consumption).
  • When using a USB-hub, ensure that it is specified for the required data speed and power consumption of your camera.

GigE(Ethernet) cameras

Baumer GigE cameras are connected through standard ethernet ports. Standard GigE cameras require a free Gigabit Ethernet port to achieve their full framerate. 10GigE cameras like the LXT-series will need a free 10 Gigabit Ethernet port. On Windows systems, the Baumer filter-driver provided with the Baumer GAPI installer can be installed to reduce the processor load caused by the data-transfer.

When connecting multiple cameras to a host system, it is important to think about the ethernet network topology. When working with switches, it needs to be ensured that the uplink can support the bandwidth requirements of multiple cameras.

Depending on your application, the cameras can be powered via PoE or via an external power supply. Please see the data-sheet of your camera for details.

Troubleshooting tips:

  • Use high-quality Ethernet cables as a low quality cable can influence the maximum transfer rate of the camera. Low quality cable might also not be able to deliver the necessary power for the camera.
  • Ensure, that the chosen power supply does actually deliver the required power of your camera (see the data-sheet of your camera for details on power consumption).
  • When using a switch, ensure that it is specified for the required data speed.

Connect a camera device using the Baumer GAPI SDK for C

The Baumer GAPI SDK for C provides you with a unified interface to all system components of a camera system. It is based on the GenTL and the GenICam API's provided and maintained by the EMVA.

Setup of the project, required headers

For the setup of an example project, please see the Setup and Getting Started page.

The Baumer GAPI model of the camera system

The API has 6 main sets of functions to deal with the different components of the camera system: System, Interface, Device, DataStream, Buffer and Node.

The System

The System module provides access to a GenTL Producer and encapsulates a method of transport such as USB or Ethernet. Use the BGAPI2_UpdateSystemList() function to search for available producers and BGAPI2_GetSystem() to access a system specified by the index. Finally call BGAPI2_System_Open() to open a system to work with it.

See the section System functions for details on each available function.

The Interface

Each (useful) System has one or more Interfaces. An Interface is a specific Ethernet or USB port where a GenICam camera is connected to. Use the BGAPI2_System_UpdateInterfaceList() function to update the list of available interfaces for your system followed by a call to BGAPI2_System_GetInterface() and BGAPI2_Interface_Open() to open the interface specified by the index to work with it.

See the Interface functions for details on each available function.

The Device

Each Interface can have one or more Devices (typically a camera) connected to it. You can use the BGAPI2_Interface_UpdateDeviceList() function to update the list of available Devices followed by a BGAPI2_Interface_GetDevice() and BGAPI2_Device_Open() to open a chosen Device to work with it.

See the Device functions for details on each available function.

The DataStream

Each Device (camera) can have one or more DataStreams where images can be retrieved. You can use the BGAPI2_Device_GetDataStream() function to get a DataStream by index, followed by a BGAPI2_DataStream_Open() to open the DataStream to work with it.

See the DataStream functions for details on each available function.

The Buffer

Buffers are required to queue retrieve images from the DataStream. Firstly create some Buffers using the BGAPI2_CreateBuffer() function. Next you need to announce and queue Buffers to the DataStream using BGAPI2_DataStream_AnnounceBuffer() and BGAPI2_DataStream_QueueBuffer(). To retrieve an image the BGAPI2_DataStream_GetFilledBuffer() is used.

See the Buffer functions for details on each available function.

Lifetime of objects

When using the Baumer GAPI SDK for C you have full responsibility for the memory management of your application. You need to ensure that objects which are created are closed once not required anymore.

The Baumer GAPI "objects" are structured hierarchically and each object has an update-list function. Those update functions create the child-objects of a certain type. To close/destroy those objects it is sufficient to call BGAPI2_System_Close() and BGAPI2_ReleaseSystem() on the parent System. If you choose to manually close the object you need to ensure, that you destroy them in the right order.

Objects created as children of objects through functions:

Some objects are created independent and you are attaching them to parent object such as providing Buffers to the DataStream. To close/destroy those objects you need to de-attach them and destroy them manually.

Objects which exists independently from parent objects:

Error handling

As typical for C, the Baumer GAPI SDK for C makes use of return codes to communicate success, failure and errors. The result codes are provided as constants starting with BGAPI2_RESULT_*

Example: Connect a camera

The following example shows how to connect a camera set the exposure time and retrieve one image into a buffer. We print the frame ID, which is a counter the camera will increment and send with each image as a way to check if the image was actually retrieved correctly from the camera.

Attention

For clarity, and to focus on actual functionality the examples provided make assumptions on the system without handling errors. This code is not suitable for production without error-handling! The SDK provides examples, those contain the full error-handling so that they can run on any system without crashes.

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main() {
// Create the system
BGAPI2_UpdateSystemList(); // Update the list of producers (systems)
BGAPI2_System* system = NULL; // Create the pointer for the system
// We expect that GetSystem "1" will be the USB Producer, that should be the case if just the Baumer Producers
// and no additional producers are found on the system
BGAPI2_GetSystem(1, &system); // We want to use the producer with index 1 (second)
BGAPI2_System_Open(system); // Open the system to use it
// Create the interface
bo_bool changed = 0; // Flag for the changed status (not used in this example)
BGAPI2_System_UpdateInterfaceList(system, &changed, 200); // Update list of interfaces with timout of 200 ms
BGAPI2_Interface* iface = NULL; // Create the pointer for the interface
BGAPI2_System_GetInterface(system, 0, &iface); // We want to use the first interface (USB has just one)
BGAPI2_Interface_Open(iface); // Open the interface to use it
// Create the device
BGAPI2_Interface_UpdateDeviceList(iface, &changed, 200); // Update list of devices with timout of 200 ms
BGAPI2_Device* device = NULL; // Create the pointer for the camera
BGAPI2_Interface_GetDevice(iface, 0, &device); // We want to use the first camera
BGAPI2_Device_Open(device); // Open the camera to use it
// Set the ExposureTime feature
BGAPI2_Node* node = NULL; // Create the pointer for the node
BGAPI2_Device_GetRemoteNode(device, SFNC_EXPOSURETIME, &node); // Get the node ExposureTime
bo_double exposuretime = 0;
BGAPI2_Node_GetDouble(node, &exposuretime); // Get the ExposureTime from the camera
printf("The exposure time is set to: %lld micro seconds\n", (long long)exposuretime);
BGAPI2_Node_SetDouble(node, 10000.0); // Set the ExposureTime to 10000 µs
// Open the data stream
BGAPI2_DataStream* datastream = NULL; // Create the pointer for the data stream
BGAPI2_Device_GetDataStream(device, 0, &datastream); // We want to use the first data stream
BGAPI2_DataStream_Open(datastream); // Open the data stream to use it
// Retrieve an image into an buffer
BGAPI2_Buffer* buffer; // Create the pointer for the image buffer
BGAPI2_CreateBuffer(&buffer); // Create a buffer
BGAPI2_DataStream_AnnounceBuffer(datastream, buffer); // Announce the buffer to the datastream
BGAPI2_DataStream_QueueBuffer(datastream, buffer); // Queue the buffer to be used
BGAPI2_DataStream_StartAcquisition(datastream, 1); // Acquire one image from the camera
BGAPI2_Device_GetRemoteNode(device, SFNC_ACQUISITIONSTART, &node); // Get the node "AcquisitionStart"
BGAPI2_Node_Execute(node); // Execute the "AcquisitionStart" feature
BGAPI2_Buffer* bufferfilled = NULL; // Create the pointer for a buffer to reference result image
BGAPI2_DataStream_GetFilledBuffer(datastream, &bufferfilled, 1000); // Get the image from the camera into the buffer provided
bo_uint64 bufferID = 9999; // Set the buffer ID to something arbitary
BGAPI2_Buffer_GetFrameID(bufferfilled, &bufferID); // Get the buffer ID from the buffer to check if we got an image
printf("Frame ID: %lld\n", (long long)bufferID); // Print buffer ID (0 or 1 depending on the camera)
// Start the cleanup process
BGAPI2_DataStream_StopAcquisition(datastream); // Stop the acquisition
BGAPI2_DataStream_DiscardAllBuffers(datastream); // We don't need the buffer data anymore
BGAPI2_DataStream_RevokeBuffer(datastream, buffer, NULL); // Remove buffer from the queue
BGAPI2_DeleteBuffer(buffer, NULL); // Delete the buffer
BGAPI2_DataStream_Close(datastream); // Close the data stream
BGAPI2_Device_Close(device); // Close the device
BGAPI2_Interface_Close(iface); // Close the interface
BGAPI2_System_Close(system); // Close the system
BGAPI2_ReleaseSystem(system); // Release the producer library
}
Example: Connect a camera to retrieve an image

Working with camera features

Every camera project requires configuring at least some basic settings of the camera. GenICam compatible devices use the SFNC naming convention to standardize how features are named see here for details about the machine vision standards.

Using the Baumer GAPI SDK each feature is presented as a node. A node has functions to get and set feature values and read additional information about the feature such as name, type, min/max values, etc.

Additionally, there are functions to check availability and access status of features using the nodes.

Feature types

The GenICam describes 6 different feature types:

  • IInteger, IFloat, IBool, IString — Those are simple features, the take a value which will have some influence on the camera.
  • IEnumeration — Those features are used in two ways. Firstly, like in “PixelFormat” they can behave like an enum, the feature can only take a set amount of values. The second use case for IEnumeration features are “Selector features” here the feature is used to switch one or more other features. A good example is the “GainSelector” which selects which color-channel the “Gain” feature represents for reading or writing a value.
  • ICommand — These are features which will execute something on the camera, good examples are the “AcquisitionStart” or the “TriggerSoftware” features.

Is the feature implemented and available?

The Standard Feature Naming Convention (SFNC) describes many features a camera can implement, however not all features are implemented on all cameras. That means, before you can access a feature, you need to check if the feature is available on a camera using the BGAPI2_Node_GetImplemented() method.

// [...] includes and main() omitted, device is a valid, opened camera device pointer
BGAPI2_Node* node = NULL;
bo_bool flag = 0;
if (BGAPI2_Device_GetRemoteNode(device, "ExposureTime", &node) == BGAPI2_RESULT_SUCCESS) {
if (flag)
printf("Feature ExposureTime is implemented\n");
else
printf("Feature ExposureTime is not implemented\n");
}
else
printf("Feature ExposureTime does not exists\n");
Example: Check if a feature is implemented

Some features can change depending on other features set on the camera. So for example the availability of feature ExposureTime depends on the value of feature ExposureAuto. ExposureTime will only be available if the ExposureAuto is switched off. You can use the BGAPI2_Node_GetAvailable() method to get the current status.

// [...] includes and main() omitted, device is a valid, opened camera device pointer
BGAPI2_Node* node = NULL;
bo_bool flag = 0;
if (BGAPI2_Device_GetRemoteNode(device, "ExposureTime", &node) == BGAPI2_RESULT_SUCCESS) {
if (flag)
printf("Feature ExposureTime is available\n");
else
printf("Feature ExposureTime is not available\n");
}
else
printf("Feature ExposureTime does not exists\n");
}
Example: Check if a feature is accessible

Is the feature available for reading or writing?

To check if a feature is readable or writable the methods BGAPI2_Node_IsReadable() and BGAPI2_Node_IsWriteable() are implemented. Some features will never be writable such as the device serial number or the model name. Other features might change their access status depending on the value of another feature. As an example, if the feature “ExposureAuto” is switched on, the feature “ExposureTime” will be set to read-only thereby ensuring nobody does interfere with the AutoExposure algorithm.

// [...] includes and main() omitted, device is a valid, opened camera device pointer
BGAPI2_Node* node = NULL;
bo_bool flag = 0;
if (BGAPI2_Device_GetRemoteNode(device, "ExposureTime", &node) == BGAPI2_RESULT_SUCCESS) {
if (BGAPI2_Node_IsReadable(node, &flag) == BGAPI2_RESULT_SUCCESS && flag)
printf("Feature ExposureTime is readable\n");
if (BGAPI2_Node_IsWriteable(node, &flag) == BGAPI2_RESULT_SUCCESS && flag)
printf("Feature ExposureTime is writable\n");
}
else
printf("Feature ExposureTime does not exists\n");
Example: Check if a feature is readable or writable

Read and write feature values

Once the feature is checked for availability and read/write-ability, reading and writing a value is trivial. There are getters and setters for different data types.

// [...] includes and main() omitted, device is a valid, opened camera device pointer
BGAPI2_Node* node = NULL;
bo_double value = 0;
if (BGAPI2_Device_GetRemoteNode(device, "ExposureTime", &node) == BGAPI2_RESULT_SUCCESS) {
printf("ExposureTime is set to: %lld.\n", (long long)value);
printf("Exposure Time is set to 10000 micro seconds\n");
}
else
printf("Feature ExposureTime does not exists\n");
Example: Read and write features

Handling features with a set increment

Features can have a minimum, maximum or increment for the allowed values set. This means it is not possible to set the full range of numbers but only a subset. A good example are the features to set a region or area of interest (ROI/AOI). The features “Width”, “Height”, “OffsetX” and “OffsetY” can typically only take values which are multiples of 2, 4, 8 or 16 and which have a maximum/minimum depending on the sensor of the camera. If an increment is set for a feature, you can check the increment using BGAPI2_Node_GetIntInc() and BGAPI2_Node_GetDoubleInc() functions.

// [...] includes and main() omitted, device is a valid, opened camera device pointer
BGAPI2_Node* node = NULL;
BGAPI2_Node* node2 = NULL;
bo_uint64 value = 0;
if (BGAPI2_Device_GetRemoteNode(device, "Width", &node) == BGAPI2_RESULT_SUCCESS) {
printf("The minimum width is: %lld\n", (long long)value);
printf("The maximum width is: %lld\n", (long long)value);
printf("The increment for the width is: %lld\n", (long long)value);
// Stop the Acquisition so we can set the Width
BGAPI2_Device_GetRemoteNode(device, "AcquisitionStop", &node2);
// Set the width to a valid value close to 300 (just smaller)
bo_uint64 width = (300 / value) * value;
printf("Width is set to: %lld\n", (long long)width);
else
printf("Width not writable, was the acquisition stopped before?\n", (long long)width);
}
Example: min, max, increment feature values


Attention

Some features do not have an increment but are rounded inside of a camera so writing 2.2 to the Gain feature will result in a value like 2.1877 when read back from the camera.

When do changed feature settings become active?

If you change the value of a feature, this might not be honored by the next image you retrieve from the camera. This can be for two reasons. Firstly, the changed feature must be written to the camera before start of the exposure, otherwise the image will be taken using the old settings. Secondly, because there is a buffer queue on the host it might be that the next image you request is already in a buffer and therefore will also be taken with older settings.

This behavior can especially be observed when triggering very fast or in free running mode. If this is an issue, you can avoid this firstly by executing "AcquisitionAbort" after changing the feature, this will ensure the camera does not deliver any image taking with old settings. Secondly you need to remove all buffers which might hold data taken before a feature change.

// [...] includes and main() omitted, device is a valid, opened camera device pointer
BGAPI2_DataStream* datastream = NULL;
BGAPI2_Buffer* buffer[5];
BGAPI2_Node* node = NULL;
bo_uint index = 0;
// Get the first data stream, most cameras have just one
if (BGAPI2_Device_GetDataStream(device, 0, &datastream) == BGAPI2_RESULT_SUCCESS) {
// Open the datastream and provide 5 buffers to it
for (index = 0; index < 5; index++) {
BGAPI2_CreateBuffer(&buffer[index]);
BGAPI2_DataStream_AnnounceBuffer(datastream, buffer[index]);
BGAPI2_DataStream_QueueBuffer(datastream, buffer[index]);
}
// Start the acquisition of the camera
BGAPI2_Device_GetRemoteNode(device, "AcquisitionStart", &node);
// [...] Take some images and do feature changes
// Now ensure that the next image comes with the settings required
if (BGAPI2_Device_GetRemoteNode(device, "AcquisitionAbort", &node) == BGAPI2_RESULT_SUCCESS) {
BGAPI2_Node_Execute(node); // Abort the current image in the camera
BGAPI2_DataStream_FlushAllToInputQueue(datastream); // Abort the current image in the camera
// Re-start the acquisition of the camera
BGAPI2_Device_GetRemoteNode(device, "AcquisitionStart", &node);
}
// [...] Take new images with new settings
}
Example: Feature setting to image synchronization

Execute ICommand features

One special category are features which execute something on the camera. Examples are the software trigger or the acquisition start/stop features.

// [...] includes and main() omitted, device is a valid, opened camera device pointer
BGAPI2_DataStream* datastream = NULL; // Create the pointer for the data stream
BGAPI2_Buffer* buffer; // Create the pointer for the image buffer
BGAPI2_Node* node = NULL;
bo_bool flag = 0;
// Open the data stream
BGAPI2_Device_GetDataStream(device, 0, &datastream); // We want to use the first data stream
BGAPI2_DataStream_Open(datastream); // Open the data stream to use it
// Create and queue buffer
BGAPI2_CreateBuffer(&buffer); // Create a buffer
BGAPI2_DataStream_AnnounceBuffer(datastream, buffer); // Announce the buffer to the datastream
BGAPI2_DataStream_QueueBuffer(datastream, buffer); // Queue the buffer to be used
// Start the acquisition of the camera
BGAPI2_Device_GetRemoteNode(device, "AcquisitionStart", &node); // Get a executable feature
BGAPI2_Node_Execute(node); // Execute the feature
while (!flag) // Wait for the execution to finish
{
BGAPI2_Node_IsDone(node, &flag);
printf(".");
}
Example: Working with an executable feature

Using IEnumeration features

Another special case are enumeration features. They can be two different things, either a “selector feature” such as the “GainSelector” which is used to change other features on the camera, or an enumeration like the “PixelFormat” which can only be assigned a set number of values.

The example below shows, how to loop through the possible values of the PixelFormat feature. With the call BGAPI2_Node_IsReadable() we check two things, firstly if the feature PixelFormat is not locked, that could be the case if the Acquisition is not stopped. Secondly we check if a value allowed, meaning that the camera implements the functionality behind it.

// [...] includes and main() omitted, device is a valid, opened camera device pointer
BGAPI2_Node* node = NULL;
BGAPI2_NodeMap* nodemap = NULL;
bo_uint64 mapsize = 0;
bo_uint64 stringsize = 0;
char* stringvalue = NULL;
bo_bool flag = 0;
bo_uint index = 0;
// Get the PixelFormat feature and its value as a string
BGAPI2_Device_GetRemoteNode(device, "PixelFormat", &node);
BGAPI2_Node_GetString(node, NULL, &stringsize); // Get string size so we can reserve required memory
printf("PixelFormat string size: %lld", (long long)stringsize);
stringvalue = malloc(stringsize); // Now allocate the memory
BGAPI2_Node_GetString(node, stringvalue, &stringsize); // Get the value of the feature
printf(", value: %s.\n", stringvalue);
free(stringvalue);
BGAPI2_Node_GetEnumNodeList(node, &nodemap); // Get the list of possible enums
BGAPI2_NodeMap_GetNodeCount(nodemap, &mapsize); // Get the enum count
// Loop through the enum list and check which ones are readable, meaning which can be applied.
// If the enum is not readable, it could be that the PixelFormat feature is locked, or that
// the specific enum is not implemented on the camera
for (index = 0; index < mapsize; index++) {
BGAPI2_NodeMap_GetNodeByIndex(nodemap, index, &node);
BGAPI2_Node_GetString(node, NULL, &stringsize);
printf("String size: %lld", (long long)stringsize);
stringvalue = malloc(stringsize);
BGAPI2_Node_GetString(node, stringvalue, &stringsize);
// Check if the feature is implemented and readable
BGAPI2_Node_IsReadable(node, &flag);
if (flag)
printf(", value: %s.\n", stringvalue);
else
printf(", value: %s is not available.\n", stringvalue);
free(stringvalue);
}
Example: Working with the PixelFormat feature (enumeration feature)

The next example shows how a selector feature is used to access a set of similar features. A camera can have more than one GPIO line, each of the lines has a set of attributes. To access them for one of the GPIO lines we set the LineSelector to this line and can than read or write the attributes of this line.

// [...] includes and main() omitted, device is a valid, opened camera device pointer
BGAPI2_Node* node = NULL;
BGAPI2_Node* node2 = NULL;
BGAPI2_NodeMap* nodemap = NULL;
char value[256] = "";
bo_int length = 256;
bo_int nodecount = 0;
bo_int index = 0;
bo_bool flag = 0;
BGAPI2_Device_GetRemoteNode(device, "LineSelector", &node);
length = sizeof(value);
BGAPI2_Node_GetString(node, value, &length);
printf("Current value of the LineSelector is: %s\n\n", value);
BGAPI2_Node_SetString(node, "Line1");
BGAPI2_Node_GetEnumNodeList(node, &nodemap); // Get the list of available values
BGAPI2_NodeMap_GetNodeCount(nodemap, &nodecount); // Get the count of values
for (index = 0; index < nodecount; index++) { // Loop through the values
BGAPI2_NodeMap_GetNodeByIndex(nodemap, index, &node2);
length = sizeof(value);
BGAPI2_Node_GetString(node2, value, &length);
BGAPI2_Node_IsReadable(node2, &flag); // Check if the feature is implemented and readable
if (flag)
printf("Available value: %s.\n", value);
else
printf("Value: %s is not available.\n", value);
}
BGAPI2_Node_GetSelectedFeatures(node, &nodemap); // Get the list of connected features
BGAPI2_NodeMap_GetNodeCount(nodemap, &nodecount);
for (index = 0; index < nodecount; index++) { // Loop through the features
BGAPI2_NodeMap_GetNodeByIndex(nodemap, index, &node2);
length = sizeof(value);
BGAPI2_Node_GetDisplayname(node2, value, &length); // Print the display name for the feature
printf("Connected feature: %s.\n", value);
}
Example: Working with a selector feature (GainSelector)

Further feature attributes

Each feature has a set of methods which should make it easy to use them for calculations or in a GUI. The available methods do depend on the type of the feature.

// [...] includes and main() omitted, device is a valid, opened camera device pointer
BGAPI2_Node* node = NULL;
bo_int64 intvalue = 0;
bo_bool flag = 0;
bo_int64 strsize = 0;
char strvalue[1024] = "";
// IString feature functions
BGAPI2_Device_GetRemoteNode(device, "DeviceUserID", &node);
BGAPI2_Node_SetString(node, "MyCamera"); // Set the DeviceUserID to "MyCamera"
strsize = sizeof(strvalue);
BGAPI2_Node_GetString(node, strvalue, &strsize); // Get the value back as a String
printf("String value: %s\n", strvalue);
BGAPI2_Node_GetMaxStringLength(node, &strsize); // Get the maximum length of the string
printf("Max String size: %lld\n", (long long)strsize);
// IInteger, IFloat or IBool feature methods
BGAPI2_Device_GetRemoteNode(device, "Width", &node);
BGAPI2_Node_GetInt(node, &intvalue); // Get the value as an Integer
printf("Integer value: %lld\n", (long long)intvalue);
BGAPI2_Node_GetIntMin(node, &intvalue); // Get the smallest possible value
printf("Minimum Integer value: %lld\n", (long long)intvalue);
BGAPI2_Node_GetIntMax(node, &intvalue); // Get the largest possible value
printf("Maximum Integer value: %lld\n", (long long)intvalue);
BGAPI2_Node_GetIntInc(node, &intvalue); // Get the increment to the next possible value
printf("Increment Integer value: %lld\n", (long long)intvalue);
flag = 0;
BGAPI2_Node_HasUnit(node, &flag); // Check if the feature has a unit
if (flag) {
strsize = sizeof(strvalue);
BGAPI2_Node_GetUnit(node, strvalue, &strsize); // Get a string with the unit to be displayed
printf("Unit: %s\n", strvalue);
}
strsize = sizeof(strvalue);
BGAPI2_Node_GetRepresentation(node, strvalue, &strsize); // How should the data be presented (linear, logarithmic, number)
printf("Representation: %s\n", strvalue);
// Feature attributes available for all feature types
strsize = sizeof(strvalue);
BGAPI2_Node_GetString(node, strvalue, &strsize); // Get the value back as a String
printf("Value as string: %s\n", strvalue);
strsize = sizeof(strvalue);
BGAPI2_Node_GetName(node, strvalue, &strsize); // Get the name of the feature (CamelCase)
printf("Name: %s\n", strvalue);
strsize = sizeof(strvalue);
BGAPI2_Node_GetDisplayname(node, strvalue, &strsize); // Get the name as it should be displayed (with spaces)
printf("Displayname: %s\n", strvalue);
strsize = sizeof(strvalue);
BGAPI2_Node_GetToolTip(node, strvalue, &strsize); // Get a short description of the feature
printf("Tool Tip: %s\n", strvalue);
strsize = sizeof(strvalue);
BGAPI2_Node_GetDescription(node, strvalue, &strsize); // Get a longer description of the feature
printf("Description: %s\n", strvalue);
// Check the access mode
flag = 0;
if (flag) printf("Feature is available\n");
flag = 0;
if (flag) printf("Feature is implemented\n");
flag = 0;
if (flag) printf("Feature is readable\n");
flag = 0;
if (flag) printf("Feature is writable\n");
strsize = sizeof(strvalue);
BGAPI2_Node_GetInterface(node, strvalue, &strsize); // Get the GenICam interface (type) of the current feature
printf("Interface: %s\n", strvalue);
strsize = sizeof(strvalue);
BGAPI2_Node_GetVisibility(node, strvalue, &strsize); // Get the GenICam recommended level (beginner, expert, guru)
printf("Interface: %s\n", strvalue);
Example: Working with a additional feature methods

Images and buffers

Now that you have a camera connected and know how to change camera settings via the features, it is time to get some images. To get to your first image is straight forward. Please be aware, that the Baumer GAPI does not provide functionality to display or save images. Please use your preferred framework (like OpenCV) for those tasks.

// [...] includes and main() omitted, device is a valid, opened camera device pointer
BGAPI2_DataStream* datastream = NULL;
BGAPI2_Buffer* buffer = NULL;
BGAPI2_Node* node = NULL;
BGAPI2_Device_GetDataStream(device, 0, &datastream); // We want to use the first data stream
BGAPI2_DataStream_Open(datastream); // Open the data stream to use it
BGAPI2_CreateBuffer(&buffer); // Create a buffer
BGAPI2_DataStream_AnnounceBuffer(datastream, buffer); // Announce the buffer to the datastream
BGAPI2_DataStream_QueueBuffer(datastream, buffer); // Queue the buffer to be used
BGAPI2_DataStream_StartAcquisition(datastream, 1); // Acquire one image from the camera
BGAPI2_Device_GetRemoteNode(device, "AcquisitionStart", &node); // Get the node "AcquisitionStart"
BGAPI2_Node_Execute(node); // Execute the node
BGAPI2_Buffer* bufferfilled = NULL; // Create the pointer for the buffer to fill
BGAPI2_DataStream_GetFilledBuffer(datastream, &bufferfilled, 1000); // Get the image into the buffer provided
bo_uint64 frameID = 9999; // Set the frameID to something arbitary
BGAPI2_Buffer_GetFrameID(bufferfilled, &frameID); // Get the frame counter from the camera to check
// if the buffer holds an image.
printf("Frame ID: %lld", (long long)frameID); // Print bufferID (0 or 1 depending on the camera)
Example: Retrieve an image into an buffer

How are images transferred to the application?

Firstly, there are two different modes a GenICam camera can be operated in. The camera can either be in “free-run” mode, where the camera will constantly supply images. Secondly, there is the trigger mode where you need to tell the camera to take an image either via software command feature “TriggerSoftware” or via a hardware trigger impulse where the source is set via the feature “TriggerSource”.

// [...] includes and main() omitted, device is a valid, opened camera device pointer
BGAPI2_Node* node = NULL;
// Set the camera to triggered mode
BGAPI2_Device_GetRemoteNode(device, "TriggerMode", &node);
BGAPI2_Device_GetRemoteNode(device, "TriggerSource", &node);
BGAPI2_Node_SetString(node, "All"); // Alternatively use "Software" or "Line 0"
BGAPI2_Device_GetRemoteNode(device, "TriggerSoftware", &node);
// Set the camera to free running mode (default)
BGAPI2_Device_GetRemoteNode(device, "TriggerMode", &node);
BGAPI2_Node_SetString(node, "Off");
BGAPI2_Device_GetRemoteNode(device, "AcquisitionFrameRateEnable", &node); // Optional to fix the frame rate
BGAPI2_Device_GetRemoteNode(device, "AcquisitionFrameRate", &node); // Optional, the fixed frame rate
Example: Change the camera behavior from triggered to free-run

The transfer of the images from the camera is the most critical process. It needs to be reliable so no image gets lost. It also needs to be really quick, as a single camera can already deliver up to 10 GBits of data per second to the host. Furthermore, the mechanics of the image transfer needs some flexibility as the host operating system is not a real-time OS, which means, we don't know exactly when the application will be scheduled next for work. And finally, to be able to process the data at high speeds, it is necessary to enable parallel execution of image processing.

To deal with those issues, a buffer queue is implemented. In the beginning, all those buffers are empty. Calling BGAPI2_DataStream_GetFilledBuffer() on an empty buffer queue will result in an empty image. For the camera to deliver an image to the host, an empty buffer must be lined up to receive an image. If no empty buffer is available, the camera will produce so called under-runs and will drop the image. Once the camera can deliver an image to a buffer, it will be placed in the queue of filled buffers. On calling BGAPI2_DataStream_GetFilledBuffer(), one of the filled buffers is given to the user.

At this point, the buffer is delivered directly to you, to be used in your application without further copying (copying of large data blocks is slow!). The buffer is owned by you and is not available for the Baumer GAPI to store a new image. Therefore, you need to ensure that you always return buffers back to the buffer queue using the BGAPI2_DataStream_QueueBuffer() function.

You need to setup the required buffers and provide them to the DataStream for usage. Depending on your application you might change the amount of buffers to use, especially if working with high frame-rates. The example below will fail with an NoImageBufferException after 8 images as the example code never returns any buffer back to the Baumer GAPI.

// [...] includes and main() omitted, device is a valid, opened camera device pointer
BGAPI2_DataStream* datastream = NULL;
BGAPI2_Buffer* buffer[5];
BGAPI2_Buffer* bufferfilled[10];
BGAPI2_Node* node = NULL;
bo_uint index = 0;
bo_int64 frameID = 9999;
bo_bool flag = 0;
BGAPI2_Device_GetDataStream(device, 0, &datastream);
for (index = 0; index < 5; index++) {
BGAPI2_CreateBuffer(&buffer[index]);
BGAPI2_DataStream_AnnounceBuffer(datastream, buffer[index]);
BGAPI2_DataStream_QueueBuffer(datastream, buffer[index]);
}
BGAPI2_Device_GetRemoteNode(device, "AcquisitionStart", &node); // Get the AcquisitionStart feature
BGAPI2_Node_Execute(node); // Execute the feature
for (index = 0; index < 10; index++) {
// Get the image from the camera into the buffer provided
if (BGAPI2_DataStream_GetFilledBuffer(datastream, &bufferfilled[index], 1000) == BGAPI2_RESULT_SUCCESS) {
BGAPI2_Buffer_GetIsIncomplete(bufferfilled[index], &flag);
if (flag)
printf("Buffer incomplete\n");
else {
bo_uint64 frameID = 9999; // Set the frame ID to something arbitary
BGAPI2_Buffer_GetFrameID(bufferfilled[index], &frameID); // Get the frame ID from the image to check if we got an image
printf("Buffer with buffer ID %lld received\n", (long long)frameID);
}
}
else
printf("no buffer received\n");
}
Example: Bad! You must return the buffer to the Baumer GAPI