Programmer's Guide#
Getting Started#
For information when programming for Basler blaze cameras, refer to the pylon Supplementary Package for blaze (available for download on the Basler website). This includes a C++ API and a .NET API as well as sample code.
Common Settings for Building Applications with pylon (Windows)#
This section shows the most common Microsoft Visual Studio build settings for building an application using pylon. Consult the Advanced Topics section for more information, e.g. when a different configuration is required.
Add the following include directories for Release and Debug project configurations (Configuration Properties -> C/C++ -> General -> Additional Include Directories
):
Add the following library directories for Release and Debug project configurations (Configuration Properties -> Linker -> General -> Additional Library Directories
) for 32-Bit:
For 64-Bit configurations add
Enable runtime type info for Release and Debug project configurations (Configuration Properties -> C/C++ -> Language -> Enable Runtime Type Info
).
Enable C++ exceptions for Release and Debug project configurations (Configuration Properties -> C/C++ -> Code Generation -> Enable C++ Exceptions
).
Common Settings for Building Applications with pylon (Linux)#
This section shows the most common Linux build settings for building an application using pylon and the GNU tool chain. Consult the Advanced Topics section for more information.
To collect all the required parameters to build a pylon-based application, we created the pylon-config
utility. It works like pkg-config
and you can call pylon-config \--help
to get a list of supported parameters.
In a typical GNU Make-based project you can add the following lines to your Makefile:
PYLON_ROOT ?= /opt/pylon
CPPFLAGS += $(shell $(PYLON_ROOT)/bin/pylon-config --cflags)
LDFLAGS += $(shell $(PYLON_ROOT)/bin/pylon-config --libs-rpath)
LDLIBS += $(shell $(PYLON_ROOT)/bin/pylon-config --libs)
If needed, you can now overwrite the default installation path using the environment variable <PYLON_ROOT>. E.g.:
Common Settings for Building Applications with pylon (macOS)#
This section shows the most common macOS build settings for building an application using pylon and Apple Xcode. Consult the Advanced Topics section for more information, e.g. when a different configuration is required.
First add the pylon framework to your project, right-click on your project and choose Add files to "\<Projectname\>"...
. Browse to the install location of the pylon framework, typically /Library/Frameworks
and choose pylon.framework
, click Add
button.
Add the following user-defined variable for Release and Debug configurations to your build target (Build Settings -> User-Defined -> PYLON_LIBRARY_DIR
):
Add the following Framework Search Paths for Release and Debug configurations to your build target (Build Settings -> Search Paths -> Framework Search Paths
):
Add the following Header Search Paths for Release and Debug configurations to your build target (Build Settings -> Search Paths -> Header Search Paths
):
Add the following Runpath Search Path for Release and Debug configurations to your build target (Build Settings -> Linking -> Runpath Search Path
):
Building Applications with CMake for pylon#
The pylon SDK Package includes a pylonConfig.cmake module that is used to determine the installation location of pylon. This module exports the pylon::pylon CMake target. Pass this target as argument to target_link_libraries, and CMake will take care of setting the include path, library path, etc. The module is located in the pylon installation folder and will be found by CMake automatically.
A basic CMakeLists.txt CMake file could look like this:
project (grab)
# Locate pylon.
find_package(pylon 7.1.0 REQUIRED)
add_executable(grab Grab.cpp)
target_link_libraries(grab pylon::pylon)
In case pylonConfig.cmake is not found automatically, make sure the path to the pylon runtime binaries and the cmake folder (i.e., C:\Program Files\Basler\pylon 7\Runtime\x64) is set in the Windows PATH environment variable.
Use the CMake command
as a helper in your CMakeLists.txt file before the find_package statement to list all folders where CMake searches for the pylonConfig.cmake file.
If there is no CMake >= 3.14 installed, download a CMake Windows installer from https://cmake.org/download. Launch the .msi installer and follow the instructions.
Debugging pylon Applications Using GigE Cameras#
When debugging a pylon application using GigE cameras you may encounter heartbeat timeouts. The application must send special network packets to the camera in defined intervals. If the camera doesn't receive these heartbeats it will consider the connection as broken and won't accept any commands from the application. This requires setting the heartbeat timeout of a camera to a higher value when debugging. The Advanced Topics section shows how to do this.
Initialization/Uninitialization of the pylon Runtime Library#
The pylon runtime system must be initialized before use. A pylon-based application must call the PylonInitialize() method before using any other functions of the pylon runtime system. Before an application exits, it must call the PylonTerminate() method to free resources allocated by the pylon runtime system.
The Pylon::PylonAutoInitTerm convenience class helps to do the above. The constructor of Pylon::PylonAutoInitTerm calls PylonInitialize(), the destructor calls PylonTerminate(). This ensures that the pylon runtime system is initialized during the lifetime of an object of the Pylon::PylonAutoInitTerm type.
Example:
#include <pylon/PylonIncludes.h>
using namespace Pylon;
int main(int argc, char* argv[])
{
Pylon::PylonAutoInitTerm autoInitTerm; // PylonInitialize() will be called now
// Use pylon
// ..
} // autoInitTerm's destructor calls PylonTerminate() now
The Advanced Topics section contains additional information for MFC users.
Error Handling#
In the case of errors, the methods of pylon classes may throw C++ exceptions. The pylon C++ API throws exceptions of type GenericException or that are subclasses of GenericException. You should guard pylon calls with exception handlers catching GenericException. Example:
try
{
camera.Width.SetValue( 640 );
}
catch (const GenericException & e)
{
cerr << "Failed to set the AOI width. Reason: "
<< e.GetDescription() << endl;
}
Creating a pylon Device#
In pylon, physical camera devices are represented by pylon Devices. The following example shows how to create a pylon Device:
The first found camera device is created, e.g. for a vision system that uses only one camera. The Advanced Topics section shows how to handle multiple camera devices and how to find specific camera devices.
The Instant Camera Classes#
Instant Camera classes make it possible to grab images with a few lines of code reducing the programming effort to a minimum. An Instant Camera class uses a pylon Device internally. The pylon Device needs to be created and attached to the Instant Camera object for operation.
Example:
// Create an instant camera object with the camera device found first.
CInstantCamera camera( CTlFactory::GetInstance().CreateFirstDevice() );
// Print the model name of the camera.
cout << "Using device " << camera.GetDeviceInfo().GetModelName() << endl;
// Start the grabbing of c_countOfImagesToGrab images.
// The camera device is parameterized with a default configuration which
// sets up free-running continuous acquisition.
camera.StartGrabbing( c_countOfImagesToGrab );
// This smart pointer will receive the grab result data.
CGrabResultPtr ptrGrabResult;
// Camera.StopGrabbing() is called automatically by the RetrieveResult() method
// when c_countOfImagesToGrab images have been retrieved.
while (camera.IsGrabbing())
{
// Wait for an image and then retrieve it. A timeout of 5000 ms is used.
camera.RetrieveResult( 5000, ptrGrabResult, TimeoutHandling_ThrowException );
// Image grabbed successfully?
if (ptrGrabResult->GrabSucceeded())
{
// Access the image data.
cout << "SizeX: " << ptrGrabResult->GetWidth() << endl;
cout << "SizeY: " << ptrGrabResult->GetHeight() << endl;
const uint8_t* pImageBuffer = (uint8_t*) ptrGrabResult->GetBuffer();
cout << "Gray value of first pixel: " << (uint32_t) pImageBuffer[0] << endl << endl;
}
else
{
cout << "Error: " << std::hex << ptrGrabResult->GetErrorCode() << std::dec << " " << ptrGrabResult->GetErrorDescription() << endl;
}
}
The above code snippet can be found in the code sample Grab Sample.
The Main Features of an Instant Camera Class#
The Instant Camera classes establish convenient access to a camera device while being highly customizable. The following list shows the main features of an Instant Camera class:
- It serves as single access point for accessing camera functionality.
- It can be used "out of the shelf" without setting any parameters. The camera uses a default configuration for the device. The default configuration can be overridden.
- It handles pylon Device lifetime.
- It opens and closes a pylon Device automatically.
- It handles the creation, reuse and destruction of buffers.
- It provides a grab loop thread if required.
- It detects camera device removal.
- It supports advanced camera features like chunk mode and event reporting (camera events).
- Is extensible using derivation.
- Is extensible by registering additional event handler objects.
Types of Instant Camera Classes#
Before starting to program you need to decide what Instant Camera class to use. The following table shows the available Instant Camera classes:
Name of Class | Usable for Device Type | Device-specific |
---|---|---|
Pylon::CInstantCamera (recommended) | All cameras | No |
Pylon::CBaslerUniversalInstantCamera (recommended for novice users) | All cameras | No |
The CInstantCamera
and the CBaslerUniversalInstantCamera
camera classes allow you to operate camera devices of all types.
The CBaslerUniversalInstantCamera
class is a specialization of the CInstantCamera
class, extending it by a parameter class. The parameter class provides a member for each camera parameter. The additional parameter class provides IDE auto completion (e.g., IntelliSense in Visual Studio) and is helpful when developing an application. It adds a small but neglectable runtime overhead.
Instant Camera Event Handler Basics#
The Instant Camera classes allow to register event handler objects for customizing the behavior of the camera object, for processing grab results, and for handling camera events. The following list shows the available event handler types.
- Configuration event handler - can be used for customizing the behavior of the camera; must be derived from the Pylon::CConfigurationEventHandler base class.
- Image event handler - can be used for processing the grab results; must be derived from the Pylon::CImageEventHandler base class.
- Camera event handler - must be used for processing camera events; must be derived from the Pylon::CCameraEventHandler base class.
Note
For the
CBaslerUniversalInstantCamera
class, separate event handler base classes are available. These classes use the CBaslerUniversalInstantCamera class and the corresponding grab result smart pointer class.
A custom event handler class can override one or more virtual methods of the base class. For instance whenever Pylon::CConfigurationEventHandler::OnOpened is called by an Instant Camera object it is the right time to set up camera parameters. The following code snippet shows an example of a configuration event handler setting the image area of interest (Image AOI) and the pixel format.
class CPixelFormatAndAoiConfiguration : public Pylon::CConfigurationEventHandler
{
public:
void OnOpened( Pylon::CInstantCamera& camera )
{
try
{
// Allow all the names in the namespace GenApi to be used without qualification.
using namespace Pylon;
// Get the camera control object.
GenApi::INodeMap& nodemap = camera.GetNodeMap();
// Get the parameters for setting the image area of interest (Image AOI).
CIntegerParameter width( nodemap, "Width" );
CIntegerParameter height( nodemap, "Height" );
CIntegerParameter offsetX( nodemap, "OffsetX" );
CIntegerParameter offsetY( nodemap, "OffsetY" );
// Maximize the Image AOI.
offsetX.TrySetToMinimum(); // Set to minimum if writable.
offsetY.TrySetToMinimum(); // Set to minimum if writable.
width.SetToMaximum();
height.SetToMaximum();
// Set the pixel data format.
CEnumParameter( nodemap, "PixelFormat" ).SetValue( "Mono8" );
}
catch (const Pylon::GenericException& e)
{
throw RUNTIME_EXCEPTION( "Could not apply configuration. const GenericException caught in OnOpened method msg=%hs", e.what() );
}
}
};
One or more event handler objects can be registered at the Instant Camera object. The following code snippet shows an example of how the above event handler is registered and appended to the configuration event handler list.
// Register an additional configuration handler to set the image format and adjust the AOI.
// By setting the registration mode to RegistrationMode_Append, the configuration handler is added instead of replacing
// the already registered configuration handler.
camera.RegisterConfiguration( new CPixelFormatAndAoiConfiguration, RegistrationMode_Append, Cleanup_Delete );
For more information about registering and deregistering event handlers consult the interface documentation of the Types of Instant Camera Classes used and the codes of the following samples: ParametrizeCamera_Configurations, Grab_UsingGrabLoopThread Sample, and Grab_CameraEvents.
Note
It is possible to use the Instant Camera classes without using event handler objects.
Configurations#
Configuration event handler classes are also just called "configurations" because they encapsulate certain camera configurations. The pylon C++ API comes with the following configuration classes:
- Pylon::CAcquireSingleFrameConfiguration - for single frame acquisition mode.
- Pylon::CAcquireContinuousConfiguration - for continuous frame acquistion mode.
- Pylon::CSoftwareTriggerConfiguration - for software trigger mode.
- Pylon::CActionTriggerConfiguration - for triggers using action commands (applies to GigE Vision only)
These classes are provided as header files. This makes it possible to see what parameters of the camera are changed. The code can be copied and modified for creating own configuration classes. Pylon::CSoftwareTriggerConfiguration for instance can be used as basis for creating a hardware trigger configuration with few modifications. Pylon::CAcquireContinuousConfiguration is already registered when creating an Instant Camera class, providing a default setup that will work for most cameras.
The following example shows how to apply the software trigger configuration:
// Register the standard configuration event handler for enabling software triggering.
// The software trigger configuration handler replaces the default configuration
// as all currently registered configuration handlers are removed by setting the registration mode to RegistrationMode_ReplaceAll.
camera.RegisterConfiguration( new CSoftwareTriggerConfiguration, RegistrationMode_ReplaceAll, Cleanup_Delete );
The code sample ParametrizeCamera_Configurations provides more examples showing the use of configurations.
Handling Multiple Cameras Using Instant Camera Arrays#
The Instant Camera Array classes help managing multiple cameras in a system. An Instant Camera Array represents an array of Instant Camera objects. It provides almost the same interface as an Instant Camera for grabbing. The main purpose of the CInstantCameraArray is to simplify waiting for images and camera events of multiple cameras in one thread. This is done by providing a single RetrieveResult method for all cameras in the array. The following classes are available:
The Grab_MultipleCameras code sample illustrates the use of the CInstantCameraArray
class.
Accessing Parameters#
For camera configuration and for accessing other parameters, the pylon API uses the technologies defined by the GenICam standard. The GenICam specification (http://www.GenICam.org) defines a format for camera parameter description files. These files describe the configuration interface of GenICam compliant cameras. The description files are written in XML (eXtensible Markup Language) and describe camera registers, their interdependencies, and all other information needed to access high-level features such as Gain, Exposure Time, or Image Format by means of low level register read and write operations.
The elements of a camera description file are represented as software objects called Nodes. For example, a node can represent a single camera register, a camera parameter such as Gain, a set of available parameter values, etc. Each node implements the GenApi::INode interface.
The nodes have different types. For example, there are nodes representing integer values and other nodes representing strings. For each type of parameter, there is an interface in GenApi. pylon provides additional interfaces and parameter classes to simplify access to the GenApi interfaces. These interfaces and parameter classes are described in the ParameterTypes section. The AccessModes section introduces the concept of a parameter access mode. An access mode property is used to determine whether a parameter is available, readable, or writable.
The complete set of nodes is stored in a data structure called node map.
Note
Not only camera devices are parameterized using GenICam node maps. Also, most pylon objects provide node maps to provide access to their parameters. Therefore, a common way for accessing parameters is established.
Opening and Closing a Camera#
Before reading or writing parameters of a camera, the drivers involved must be initialized and a connection to the physical camera device must be established. This is done by calling the Open()
method. The camera can be closed using the Close()
method.
Native Parameter Access#
pylon provides programming interface classes that are created from parameter description files using the code generators. These classes are exported by the Universal Instant Camera class. This provides a member for each available parameter. The Pylon::CBaslerUniversalInstantCamera class extends the GenApi interfaces to simplify parameterization. This is the easiest way to access parameters.
Example:
// Maximize the image area of interest (Image AOI).
camera.OffsetX.TrySetToMinimum();
camera.OffsetY.TrySetToMinimum();
camera.Width.SetToMaximum();
camera.Height.SetToMaximum();
// Set the pixel data format.
camera.PixelFormat.SetValue( PixelFormat_Mono8 );
The ParametrizeCamera_NativeParameterAccess code sample shows how to access parameters via the Pylon::CBaslerUniversalInstantCamera class.
Generic Parameter Access#
The complete set of nodes is stored in a data structure called node map. At runtime, a node map is instantiated from an XML description. The parameters or nodes must be accessed using a node map object together with pylon parameter classes based on Pylon::CParameter.
Example (setting the same parameters as in the above example):
// Allow all the names in the namespace GenApi to be used without qualification.
using namespace Pylon;
// Get the camera control object.
GenApi::INodeMap& nodemap = camera.GetNodeMap();
// Get the parameters for setting the image area of interest (Image AOI).
CIntegerParameter width( nodemap, "Width" );
CIntegerParameter height( nodemap, "Height" );
CIntegerParameter offsetX( nodemap, "OffsetX" );
CIntegerParameter offsetY( nodemap, "OffsetY" );
// Maximize the Image AOI.
offsetX.TrySetToMinimum(); // Set to minimum if writable.
offsetY.TrySetToMinimum(); // Set to minimum if writable.
width.SetToMaximum();
height.SetToMaximum();
// Set the pixel data format.
CEnumParameter( nodemap, "PixelFormat" ).SetValue( "Mono8" );
The ParametrizeCamera_GenericParameterAccess code sample shows how to use the generic parameter access.
Where to Find Information About Camera Parameters#
The following sources can be used to get information about camera parameters:
- The Basler Product Documentation
- The interface documentation of the
CBaslerUniversalInstantCamera
class. - The pylon Viewer
- The Parameter Reference
- The pylon samples
Parameter Types#
Integer Parameters#
The GenApi::IInteger interface (optionally extended by Pylon::IIntegerEx and Pylon::CIntegerParameter) is used to access integer parameters. An integer parameter represents a feature that can be set by an integer number, such as a camera's image width or height in pixels. The current value of an integer parameter is augmented by a minimum and a maximum value, defining a range of allowed values for the parameter, and by an increment that acts as a 'step width' for changes to the parameter's value. The set of all allowed values for an integer parameter can hence be expressed as x:={minimum}+N*{increment}, with N=0,1,2…, x<={maximum}. The current value, minimum, maximum, and increment can all be accessed as 64 bit values. The following example prints all valid values for the Width parameter:
camera.Width = camera.Width.GetMin();
int64_t w = camera.Width.GetMin();
while ( w <= camera.Width.GetMax() )
{
cout << w;
w += camera.Width.GetInc();
}
There are two equivalent possibilities for setting a value using the GenApi::IInteger interface:
- Using the assignment operator, e.g.:
- Using the
SetValue()
method, e.g.:
There are also two equivalent ways to get a parameter's current value:
- Using the function call operator, e.g.:
- Using the GetValue() method, e.g.:
Floating Point Parameters#
Floating point parameters are represented by GenApi::IFloat, Pylon::IFloatEx, and Pylon::CFloatParameter objects. A float parameter represents a feature that can be set by a floating-point value, such as a camera's exposure time expressed in seconds. The floating point parameter is similar to the integer parameter with two exceptions: all values are of the 'double' type (double precision floating point numbers as defined by the IEEE 754 standard) and there is no increment value. Hence, a float parameter is allowed to take any value from the interval {minimum} <= x <={maximum}.
Boolean Parameters#
A Boolean parameter represents a binary-valued feature which can be enabled or disabled. It is represented by the GenApi::IBoolean interface and Pylon::IBooleanEx and Pylon::CBooleanParameter objects. Example: Any 'switch' to enable or disable a feature, such as a camera's external trigger input. Set and get operations are similar to the ones used by the GenApi::IInteger interface.
Enumeration Parameters#
The GenApi::IEnumeration interface (optionally extended by Pylon::IEnumerationEx, Pylon::CEnumParameter, and GenApi::IEnumerationT) is used to represent camera parameters that can take any value from a predefined set. Example: Parameters such as PixelFormat or TestImageSelector.
Example:
Command Parameters#
Command parameters (GenApi::ICommand, Pylon::ICommandEx, and Pylon::CCommandParameter) are used for parameters that trigger an action or an operation inside of the camera, e.g., issue a software trigger. The action is issued by calling the GenApi::ICommand::Execute() method. The GenApi::ICommand::IsDone() method can be used to determine whether a running operation has finished.
String Parameters#
The GenApi::IString interface and the Pylon::IStringEx and Pylon::CStringParameter objects provide access to string parameters. The GenICam::gcstring class is used to represent strings. The GenICam::gcstring class is similar to the C++ Standard Library std::string
class. pylon uses GenICam::gcstring by providing the Pylon::String_t type definition.
Access Modes for Parameters#
Each parameter has an access mode that describes whether a feature is implemented, available, readable, and writable. For a given camera, a feature may not be implemented at all. For example, a monochrome camera will not include a white balance feature. Depending on the camera's state, a feature may temporarily not be available. For example, a parameter related to external triggering may not be available when the camera is in free run mode. Available features can be read-only, write-only, or readable and writable.
The current state of a parameter can be queried by calling the parameter's GetAccessMode() method, which returns a GenApi::EAccessMode enumeration value described in the following table:
EAccessMode | Implemented | Available | Readable | Writable |
---|---|---|---|---|
NI | No | No | No | No |
NA | Yes | No | No | No |
WO | Yes | Yes | No | Yes |
RO | Yes | Yes | Yes | No |
RW | Yes | Yes | Yes | Yes |
Typically, it is sufficient to check if a parameter is readable or writable. For this purpose, all pylon parameter interfaces and classes implement the methods IsReadable() and IsWritable().
Handling Differences Between Different Cameras Models#
Most features, e.g., Gain, are named according to the GenICam Standard Feature Naming Convention (SFNC). The SFNC defines a common set of features, their behavior, and the related parameter names. All Basler USB 3.0 and CoaXPress as well as most GigE, e.g., ace 2 GigE, cameras are based on the SFNC version 2.0 or later. Older Basler GigE camera models, however, are based on previous SFNC versions. Accordingly, the behavior of these cameras and some parameter names will be different. The following sections show how to handle this.
Try Methods#
The pylon parameter interfaces and classes provide methods that are prefixed with "Try", e.g., IEnumerationEx::TrySetValue(int64_t). For these methods, the action is executed if the parameter is writable. Sometimes, the value must also be settable.
Example showing how turn GainAuto off if the camera provides GainAuto:
For the exact semantics of a "Try" method, check its documentation.
OrDefault Methods#
Methods that are suffixed with "OrDefault", e.g., GetValueOrDefault(), can be used to read a parameter value if it is readable or otherwise return a default value.
Example:
//code that runs for cameras with and without chunk support.
if (camera.ChunkModeActive.GetValueOrDefault(false))
{
//do something if chunk mode is active
}
Checking the SFNC Version#
If your code has to work with multiple camera device types that are compatible with different SFNC versions, you can use GetSfncVersion() to handle differences in parameter name and behavior.
Example for Generic Parameter Access :
// Check to see which Standard Feature Naming Convention (SFNC) is used by the camera device.
if (camera.GetSfncVersion() >= Sfnc_2_0_0)
{
// Access the Gain float type node. This node is available for USB camera devices.
// USB camera devices are compliant to SFNC version 2.0.
CFloatParameter gain( nodemap, "Gain" );
if (gain.TrySetValuePercentOfRange( 50.0 ))
{
cout << "Gain (50%) : " << gain.GetValue() << " (Min: " << gain.GetMin() << "; Max: " << gain.GetMax() << ")" << endl;
}
}
else
{
// Access the GainRaw integer type node. This node is available for GigE camera devices.
CIntegerParameter gainRaw( nodemap, "GainRaw" );
if (gainRaw.TrySetValuePercentOfRange( 50.0 ))
{
cout << "Gain (50%) : " << gainRaw.GetValue() << " (Min: " << gainRaw.GetMin() << "; Max: " << gainRaw.GetMax() << "; Inc: " << gainRaw.GetInc() << ")" << endl;
}
}
Grabbing Images#
This section shows how to grab images using the Instant Camera class. Before grabbing images the camera parameters must be set up using one or more of the following approaches:
- Registered configuration objects configure the camera.
- The camera is set up using code in the program flow after
Open()
is called. - The camera is preconfigured, e.g. using the pylon Viewer. The settings are stored in a user set in the camera and become active when the camera powers up, provided the user set was selected as the "startup set".
- The parameters are loaded from disk. The Saving and Restoring Camera Features to/from Files section shows how to do this.
Note
Using the latter three approaches may require to remove the default configuration after the Instant Camera object has been created. The following example shows how to do this. The configuration must be removed before calling the Open() method.
// Create a camera object
CInstantCamera camera;
// Remove the default configuration
camera.RegisterConfiguration( (CConfigurationEventHandler*) NULL, RegistrationMode_ReplaceAll, Cleanup_None);
Acquire, Transfer, and Grab Images#
In this document we distinguish between image acquisition, image data transfer, and image grabbing.
We denote the processes inside the camera as image acquisition. When a camera starts image acquisition, the sensor is exposed. When exposure is complete, the image data is read out from the sensor.
The acquired image data is transferred from the camera's memory to the computer using an interface such as USB or Gigabit Ethernet.
The process of writing the image data into the computer's main memory is referred to as "grabbing" an image.
The Grab Result#
The data of a grabbed image is held by a Grab
Result Data object. The Grab Result Data object can't be directly accessed. It is always held by a grab result smart pointer, e.g. the basic grab result smart pointer CGrabResultPtr
. The combination of smart pointer and Grab Result Data object is also referred to as grab result. The smart pointer controls the reuse and the lifetime of the Grab Result Data object and the associated image buffer. When all smart pointers referencing a Grab Result Data object go out of scope, the grab result's image buffer is reused for grabbing. Due to the smart pointer concept, a Grab Result Data object and the associated image buffer can live longer than the camera object used for grabbing the image data. The CBaslerUniversalInstantCamera
class has a specific Grab Result Data object and a specific grab result smart pointer. The specific grab result smart pointer can be converted to or from the basic grab result smart pointer CGrabResultPtr by copying or assigning.
Note
The grabbing will stop with a buffer underrun when the grab results are never released, e.g. when put into a container.
The grab result smart pointer classes provide a cast operator that allows passing a grab result smart pointer directly to functions or methods that take a const
Pylon::IImage&` as parameter, e.g. image saving functions.
Attention
The returned reference to Pylon::IImage is only valid as long the grab result smart pointer it came from is not destroyed.
Buffer Handling#
New buffers are automatically allocated for each grab session starting with StartGrabbing()
. The buffer of a grabbed image is held by the Grab Result Data object. While the grabbing is in progress a buffer is reused when the Grab Result Data object is released by the grab result smart pointer. If the Grab Result Data object is released when the grabbing has stopped then the buffer is freed.
The number of used image data buffers can be set using the MaxNumBuffer
parameter. The default amount of buffers used for grabbing is 10. The buffer size required for grabbing is automatically determined.
The number of allocated buffers is automatically reduced when grabbing a defined number of images smaller than the value of MaxNumBuffer
, e.g. 5.
Note
A buffer factory can be attached to an Instant Camera object for using user provided buffers.
The use of a buffer factory is optional and intended for advanced use cases only. Consult the Instant Camera Class and User Provided Buffers section for more information.
The Grab Engine#
The Instant Camera grab engine consists of an empty buffer queue, an output queue, and a grab thread. The grab engine uses a Low Level API stream grabber to grab images. The empty buffer queue and the output queue can hold the number of buffers defined by the MaxNumBuffer parameter. MaxNumQueuedBuffer buffers are passed to the Low Level API stream grabber at any time. All queues work in FIFO mode (First-In-First-Out). The grab engine thread ensures that the stream grabber does not run out of buffers as long as buffers are available in the empty buffer queue.
The Default Grab Strategy One By One#
The Instant Camera supports different grab strategies. The default strategy is One By One. When the grab strategy One By One is used images are processed in the order of their acquisition.
The Buffer Flow Using Grab Strategy One By One
- The Instant Camera grab engine unqueues buffers from the Empty Buffer Queue and queues the empty buffers at the Low Level API stream grabber (1).
- The camera device is triggered (2). An image is acquired by the camera device, it is transfered to the computer and then grabbed into an empty buffer.
- The Instant Camera grab engine thread is notified that a filled buffer is available. The filled buffer is retrieved by the grab engine thread (3) and is put into the Output Queue.
- The application thread waiting inside the RetrieveResult() method is notified, it stops waiting for a grab result, and it retrieves the filled buffer (4) as part of a grab result data object.
- The grab result data object is held by a grab result smart pointer. After the application has processed the image data the filled buffer is returned to the Empty Buffer Queue (5). This is done by the grab result smart pointer destructor or when the grab result data object is explicitly released. Returned buffers are used again for grabbing.
More information about grab strategies can be found in the Grab Strategies section.
Grabbing Images in a Loop#
The following example shows a simple grab loop:
// Create an instant camera object with the camera device found first.
CInstantCamera camera( CTlFactory::GetInstance().CreateFirstDevice() );
// Print the model name of the camera.
cout << "Using device " << camera.GetDeviceInfo().GetModelName() << endl;
// Start the grabbing of c_countOfImagesToGrab images.
// The camera device is parameterized with a default configuration which
// sets up free-running continuous acquisition.
camera.StartGrabbing( c_countOfImagesToGrab );
// This smart pointer will receive the grab result data.
CGrabResultPtr ptrGrabResult;
// Camera.StopGrabbing() is called automatically by the RetrieveResult() method
// when c_countOfImagesToGrab images have been retrieved.
while (camera.IsGrabbing())
{
// Wait for an image and then retrieve it. A timeout of 5000 ms is used.
camera.RetrieveResult( 5000, ptrGrabResult, TimeoutHandling_ThrowException );
// Image grabbed successfully?
if (ptrGrabResult->GrabSucceeded())
{
// Access the image data.
cout << "SizeX: " << ptrGrabResult->GetWidth() << endl;
cout << "SizeY: " << ptrGrabResult->GetHeight() << endl;
const uint8_t* pImageBuffer = (uint8_t*) ptrGrabResult->GetBuffer();
cout << "Gray value of first pixel: " << (uint32_t) pImageBuffer[0] << endl << endl;
}
else
{
cout << "Error: " << std::hex << ptrGrabResult->GetErrorCode() << std::dec << " " << ptrGrabResult->GetErrorDescription() << endl;
}
}
The camera object is created. The grabbing is started by calling StartGrabbing()
. Since the camera is not open yet, it is automatically opened by the StartGrabbing()
method. The default configuration event handler is called and it applies the default configuration. Images are grabbed continuously by the Instant Camera object and the grab results are placed into the Instant Camera's output queue in the order they are aqcuired by the camera (Grab Strategy One By One). The RetrieveResult()
method is used to wait for a grab result and for retrieving it from the output queue. Some of the grab result data is printed to the screen after it is retrieved. StopGrabbing()
is called automatically by the RetrieveResult()
method when c_countOfImagesToGrab
images have been retrieved. The while statement condition is used to check if the grabbing has been stopped.
It is possible to start grabbing for an unlimited number of images by omitting the maximum number of images to grab in the StartGrabbing()
call and call StopGrabbing()
from inside the grab loop to finish grabbing.
The above code snippet can be found in the Grab Sample code sample.
Grabbing Images Using the Grab Loop Thread Provided by the Instant Camera#
The Instant Camera class can optionally provide a grab loop thread. The thread runs a grab loop calling RetrieveResult()
repeatedly. When using the provided grab loop thread an image event handler is required to process the grab results.
The following image event handler is used:
class CImageEventPrinter : public CImageEventHandler
{
public:
virtual void OnImageGrabbed( CInstantCamera& camera, const CGrabResultPtr& ptrGrabResult )
{
std::cout << "OnImageGrabbed event for device " << camera.GetDeviceInfo().GetModelName() << std::endl;
// Image grabbed successfully?
if (ptrGrabResult->GrabSucceeded())
{
std::cout << "SizeX: " << ptrGrabResult->GetWidth() << std::endl;
std::cout << "SizeY: " << ptrGrabResult->GetHeight() << std::endl;
const uint8_t* pImageBuffer = (uint8_t*) ptrGrabResult->GetBuffer();
std::cout << "Gray value of first pixel: " << (uint32_t) pImageBuffer[0] << std::endl;
std::cout << std::endl;
}
else
{
std::cout << "Error: " << std::hex << ptrGrabResult->GetErrorCode() << std::dec << " " << ptrGrabResult->GetErrorDescription() << std::endl;
}
}
};
The following example shows how to grab using the grab loop thread provided by the Instant Camera object:
// The image event printer serves as sample image processing.
// When using the grab loop thread provided by the Instant Camera object, an image event handler processing the grab
// results must be created and registered.
camera.RegisterImageEventHandler( new CImageEventPrinter, RegistrationMode_Append, Cleanup_Delete );
// Start the grabbing using the grab loop thread, by setting the grabLoopType parameter
// to GrabLoop_ProvidedByInstantCamera. The grab results are delivered to the image event handlers.
// The GrabStrategy_OneByOne default grab strategy is used.
camera.StartGrabbing( GrabStrategy_OneByOne, GrabLoop_ProvidedByInstantCamera );
// Wait for user input to trigger the camera or exit the program.
// The grabbing is stopped, the device is closed and destroyed automatically when the camera object goes out of scope.
bool runLoop = true;
while (runLoop)
{
cout << endl << "Enter \"t\" to trigger the camera or \"e\" to exit and press enter? (t/e) "; cout.flush();
string userInput;
getline(cin, userInput);
for (size_t i = 0; i < userInput.size(); ++i)
{
char key = userInput[i];
if ((key == 't' || key == 'T'))
{
// Execute the software trigger. Wait up to 1000 ms for the camera to be ready for trigger.
if (camera.WaitForFrameTriggerReady( 1000, TimeoutHandling_ThrowException ))
{
camera.ExecuteSoftwareTrigger();
}
}
else if ((key == 'e') || (key == 'E'))
{
runLoop = false;
break;
}
}
// Wait some time to allow the OnImageGrabbed handler print its output,
// so the printed text on the console is in the expected order.
WaitObject::Sleep( 250 );
}
First, the image event handler is registered. It prints a message on the screen for every grabbed image. It serves as image processing in this example. The grabbing is started using StartGrabbing()
for an unlimited number of images and uses the grab loop thread provided by the Instant Camera object by setting the second parameter to GrabLoop_ProvidedByInstantCamera. The main thread can now be used to query the user for input to either trigger an image or to exit the input loop. The grabbing is not explicitly stopped in this example and could be stopped by calling StopGrabbing()
. The above code snippet can be found in the Grab_UsingGrabLoopThread code sample.
Grabbing a Single Image#
For convenience, the GrabOne()
method can be used to grab a single image. The following code shows a simplified version of what is done:
//grab one image
StartGrabbing( 1, GrabStrategy_OneByOne, GrabLoop_ProvidedByUser);
//grab is stopped automatically due to maxImages = 1
return RetrieveResult( timeoutMs, grabResult, timeoutHandling) && grabResult->GrabSucceeded();
Note
Using
GrabOne()
is more efficient if the pylon Device is already open, otherwise the pylon Device is opened and closed automatically for each call. Grabbing single images using Software Trigger (CSoftwareTriggerConfiguration
) is recommended if you want to maximize the frame rate. This is because the overhead per grabbed image is reduced compared to Single Frame Acquisition. The grabbing can be started usingStartGrabbing()
. Images are grabbed using theWaitForFrameTriggerReady()
,ExecuteSoftwareTrigger()
andRetrieveResult()
methods instead of usingGrabOne()
. The grabbing can be stopped usingStopGrabbing()
when done.
Using Advanced Camera Features#
Handling Camera Events#
Basler GigE Vision and USB3 Vision cameras can send event messages. For example, when a sensor exposure has finished, the camera can send an Exposure End event to the computer. Events can be received by registering an image event handler at an Instant Camera class. See the Handling Camera Events section for more information.
Accessing Chunk Features#
Basler Cameras are able to send additional information as so-called data chunks appended to the image data, such as frame counters, time stamps, or CRC checksums. Data chunks are automatically parsed by the Instant Camera class if activated. See the Accessing Chunk Features section for more information.
Getting Informed About Camera Device Removal#
To get informed about camera device removal the method IsCameraDeviceRemoved()
can be queried or a configuration event handler can be registered. The virtual method OnCameraDeviceRemoved()
is called if a camera device is removed. See the Getting Informed About Camera Device Removal section for more information.
Note
The
OnCameraDeviceRemoved()
call is made from a separate thread.
GigE Multicast/Broadcast: Grab Images of One Camera on Multiple Computers#
Basler GigE cameras can be configured to send the image data stream to multiple destinations. Either IP multicasts or IP broadcasts can be used. For more information consult the Grab Images of One Camera on Multiple Computers section.
Image Handling and Image Display#
Besides the Instant Camera classes used for grabbing images pylon offers additional Image Handling Support support for handling grabbed images. There are an image class, Windows bitmap image support, an image format converter, an image window, and the loading and saving of images.
The pylon Image Class#
When working with image data the handling of buffer size and lifetime often involves a lot of coding. The Pylon::CPylonImage class simplifies this. It also allows to attach a buffer of a grab result preventing its reuse as long as required. Additionally, user buffers or buffers provided by third party software packages can be connected. Besides that, the pylon Image class helps when working with image planes or AOIs. The Utility_Image code sample shows the use of the pylon Image class.
The pylon Bitmap Image Class#
The Pylon::CPylonBitmapImage class simplifies the creation of Windows bitmap images for displaying image data. The Utility_Image code sample shows the use of the pylon Bitmap Image class.
The Image Format Converter#
The Pylon::CImageFormatConverter creates new images by converting a source image to a different format. Once the format converter is configured, it can convert almost all image formats supported by Basler camera devices. If you want to use multiple threads to speed up the conversion, specify the desired number of threads via the Pylon::CImageFormatConverter::MaxNumThreads parameter. The Utility_ImageFormatConverter code sample shows the use of the Image Format Converter class.
The AVI Writer#
The Pylon::CAviWriter can be used to create video files in the Audio Video Interleave (AVI) format. The Utility_GrabAvi code sample shows the use of the AVI Writer class.
The Video Writer#
The Pylon::CVideoWriter can be used to create video files in the MP4 format. The Utility_GrabVideo code sample shows the use of the Video Writer class.
Loading and Saving Images#
The Pylon::CImagePersistence class supports loading and saving images to disk. The pylon Image classes use this interface internally and provide methods for loading and saving. The Utility_ImageLoadAndSave code sample shows how to load and save images.
pylon Image Window#
The pylon Image Window allows you to easily display images on the screen using the DisplayImage
or the CPylonImageWindow
class. You can use the CPylonImageWindow
class to inspect the image retrieved from the camera or the results of CPixelFormatConverter.
pylon Image Window
Every pylon image window is addressed by a unique image window index. Valid image window indexes range from 0 to 31.
The DisplayImage() global function provides the easiest way to display an image on the screen. You need to specify the image window index of the image window that will be used for image display and pass the image or grab result. This will create the window if neccessary, set the contents, and display the window on the screen. The image window will create a copy of the image in memory so you can free the image or grab result safely after the function returns.
To clear the window and release the memory needed for the image you can display an empty image.
When the user closes the image window using the mouse or by pressing Alt+F4 the image window will only be hidden. You can call CPylonImageWindow::Show()
to make it visible again.
To actually destroy the window, you must call CPylonImageWindow::Close()
. If you don't close the window yourself pylon will close all existing image windows when PylonTerminate
is called.
Note
All Pylon::CPylonImageWindow functions are fully thread-safe.
If you need more control over an image window you can explicitly call CPylonImageWindow::Create() and pass the position and size of the image window. After calling CPylonImageWindow::Create() the image window is not visible on the screen. To make it visible you must call CPylonImageWindow::Show()
.
When CPylonImageWindow::Create() returns successfully the object will store the image window index passed in CPylonImageWindow::Create() and use it for all other member functions. When a CPylonImageWindow
object is destroyed the destructor will close the image window. If you want to keep the image window, you must call CPylonImageWindow::Detach()
before the object is destroyed.
To use the pylon Image Window you need to include the pylon/PylonGUIIncludes.h header.
See the documentation for DisplayImage() or CPylonImageWindow
for more details.