Thermal Camera SDK 10.0.1
SDK for Optris Thermal Cameras
Loading...
Searching...
No Matches
Start Developing

Contents

Which Language to Choose?

The SDK itself is implemented in C++ but offers bindings to other language like C# and Python 3. One of the first decisions you have to make is to choose the programming language with which you want to interact with the SDK. The bindings offer full access to the exposed C++ API. However, there are some minor omissions due to technical restrictions of the target languages. Their impact on the available feature set is negligible.

The following table lists some use cases as well as some downsides for each language and is by no means exhaustive:

Language Use Case Downsides
C++ Lowest latency and maximum performance Complexity
C# GUI application development Minor performance penalties due to bindings
Python 3 Prototyping and data science Not suitable for high performance demands (slow function calls, global interpreter lock)

The bindings are automatically generated with the help of SWIG and always consist out of the to following parts:

  • A shared library realizing a C-style function based API that is used by the target language wrapper code to access the functionality of the SDK.
  • Wrapper code in the target language that mirrors the C++ API.
Note
All the symbol names of the C++ API carry over to the other languages. Thus, you can easily use the API documentation in the Code section although it was generated from the C++ API.

Toolchains

C++

With C++ you first of all require a compatible compiler to translate your project into an executable or a library. With regards of your operating system the SDK supports the following compilers:

  • Windows: Microsoft Visual C++ Compiler (MSVC)
  • Linux: GNU Compiler Collection with C++ frontend (gcc)
Note
The chosen compiler should support the ISO C++ 17 standard.

In addition to the compiler you need to choose which build system you want to use. The SDK supports the following options out of the box:

  • Windows: CMake and Visual Studio projects
  • Linux: CMake

On Linux the native package manager apt will automatically install the GNU compiler and CMake as dependencies of the SDK package.

On Windows you can easily use either the built-in capabilities of Visual Studio or you can use CMake. Regardless of your choice you need to install the Microsoft Visual C++ compiler. Navigate to the Visual Studio website and download the installer. The following descriptions are based on the freely available Community Edition 2022:

  • Start the installer
  • Choose at least the Workload Desktop development with C++
  • Go to the tab Individual components and scroll down to the section Compiler, Buildtools and Runtimes and select the following additional components:
    • MSVC v143 Buildtools
    • Windows 11 SDK
    • C++-CMake-Tools for Windows (optional)
    • Core Functions of Test Tools - Buildtools
    • C++ AddressSanitizer
    • vcpkg-Package-Manager
    • C++ ATL Support for Buildtools v143
    • C++ Modules for v143 Buildtools
  • Deselect the Visual Studio core editor, if you wish to use another IDE/code editor.

If you want to use CMake as the build system, you have to visit to the CMake website to download their Windows installer. Run it to install CMake on your system.

C Sharp

The C# bindings of the SDK are generated based on the .NET SDK LTS version 8.0. Therefore, you need to install this SDK along with its corresponding runtime. On Linux you can conveniently to do this with the help of the native package manager apt. Just run the following command:

sudo apt install dotnet-sdk-8.0 dotnet8

On Windows you can refer to the Visual Studio installer to get both the .NET SDK and runtime. Navigate to the Visual Studio website and download the installer. The following descriptions are based on the freely available Community Edition 2022:

  • Start the installer
  • Choose the Workload .NET desktop development
  • Deselect the Visual Studio core editor, if you wish to use another IDE/code editor.

Python 3

In order to use the Python 3 bindings of the SDK you require the Python 3 interpreter and the NumPy library.

Linux

On Linux the bindings are compiled against the default Python 3 and NumPy versions provided by the official APT repositories. Therefore, the recommended way to install the required dependencies is the native package manager apt. Run the following command:

sudo apt install python3 python3-numpy
Note
If you use different Python 3 or NumPy versions than the system defaults, then you can run into compatibility issues. They can, for example, manifest through failed imports of the native bindings library _otcsdk_python.

Windows

On Windows the native part of the Python 3 bindings requires at least the following versions of Python 3 and NumPy:

  • Python >= 3.9
  • NumPy >= 2.0.0
Note
If you fail to adhere to these version requirements the import of the binding module will fail with an error message similar to:
ImportError: DLL load failed while importing _otcsdk_python.

Since Windows lacks a central software manager you first have to download the Python 3 installer from its website. After the installation you can use the built-in package manager pip to install NumPy:

pip.exe install numpy

To manipulate and and view false color images you may need an additional library like OpenCV. You can install it with the help of the package managers:

Linux

sudo apt install python3-opencv

Windows

pip.exe install opencv-python

Project Integration

C++

Depending on your chosen build system, CMake or Visual Studio, you have to take a different approach.

CMake

Open your CMakeLists.txt file and add the following find_package() command to instruct CMake to locate the SDK resources:

find_package(otcsdk REQUIRED)

Then add the library target otcsdk::otcsdk to the target_link_library() command for your build target (here named myTarget):

target_link_libraries(
myTarget
PRIVATE
otcsdk::otcsdk
)

In this way you build your target against the shared version of the SDK library. If you wish to link statically, use the library target otcsdk::static instead.

To compile your CMake project go to the root directory of your project, create a build directory and change into it:

mkdir build
cd build

Command CMake to generate the build files and trigger the compilation process:

cmake ..
cmake --build . --config Release
Note
You can use the --parallel option with the second command to speed up the compilation process. Make sure, however, that you have enough memory to support all the resulting compilation processes.

Visual Studio Project

The Windows SDK installer automatically sets up the system wide environment variable OTC_SDK_DIR that holds the path to your chosen installation directory. You can now use this variable to conveniently setup your Visual Studio C++ project.

After you created a C++ project in Visual Studio open the project properties and modify the following settings:

  • General page
    • Set the C++ Language Standard to ISO C++17 Standard (/std:c++17).
  • VC++ Directories page
    • Add the path $(OTC_SDK_DIR)\include to the Include Directories.
    • Add the path $(OTC_SDK_DIR)\lib to the Library Directories.
  • Input page of the Linker category
    • Add otcsdk.lib to the Additional Dependencies.

With this setup you build your project against the dynamic version of the SDK library. If you wish to link statically against the SDK, you will have to adjust the following settings:

  • Input page of the Linker category
    • Set the Additional Dependency to otcsdk_static.lib instead of otcsdk.lib.
  • Preprocessor page of the C/C++ category
    • Add OTC_SDK_STATIC to the Preprocessor Definitions.
Note
The define OTC_SDK_STATIC ensures that the macro OTC_SDK_API controlling the Windows DLL symbol export and import in the SDK headers is empty. For more details on this subject refer to the MSVC documentation.

C Sharp

Create a subfolder classes in your C# project and copy the wrapper C# classes from the SDK install directory to it. They are located in

  • <SDK Installation Directory>\bindings\csharp\classes on Windows and in
  • /usr/share/otcsdk/csharp/classes on Linux

The .NET runtime locates and loads the depended shared libraries automatically.

Python 3

To use the SDK with Python 3 you just need to import the SDK module into your code:

import optris.otcsdk as otc

Nothing more needs to be done.

Public API

Architecture

The following UML diagram illustrates the class structure of the public SDK API. All the details about the class members are omitted to ensure it is clear and easy to understand.

Class diagram detailing the class structure of the public API.

A number of design patterns are employed to make the API easy to use. They include but are not limited to

Observers (red)

The SDK features two Observer structures. The most important one is constituted by the IRImager interface and the IRImagerClient. Each IRImager instance represents a single thermal camera and its interface defines how you can interact with it. By registering a child class of the IRImageClient with the addClient() method you can receive processed thermal frames, flag states and other status information. To process this data implement the corresponding callback methods defined by the IRImagerClient in your child class.

The EnumerationManger uses the same pattern to inform EnumerationClient classes of newly attached or removed devices.

Both client classes feature empty default implementations for the callbacks they define. Therefore, you only need to override the callbacks that you need.

Factories (green)

Factories encapsulate the instantiation of classes. The public API features two such factories: The first one is the IRImagerFactory that creates objects of classes that implement the IRImager interface based on a provided string. By requesting a native instance you get an IRImager implementation that can interact with thermal cameras via USB and Ethernet.

The second factory loads a configuration files from the given path and returns an IRImagerConfig object with the read configuration values.

Iterators (blue)

The iterator classes are designed to offer a uniform and convenient way to iterate over the data values stored in Frame, ThermalFrame, MeasurementField and Image objects. However, they do not offer the best performance for this purpose particularly in programming languages that are supported via bindings.

For more details on efficient ways to access thermal and image data please refer to the sections Retrieving Thermal Data and Creating False Color Images.

Singletons

Both the IRImagerFactory and the EnumerationManager are Singletons. This means there can only be one object per class and per application. To access this object you have to call the static method getInstance().

Static Classes

Apart from the design patterns there is another important class: the static Sdk class. It contains the init() method required to initialize the SDK, methods to manipulate some SDK wide behavior and access to VersionInfo objects holding version and build information.

Retrieving Thermal Data

As illustrated in the previous section, the SDK uses an Observer pattern to relay the latest thermal data to a client. This primarily happens via the following method of the IRImagerClient class (C++):

void onThermalFrame(const ThermalFrame& thermal, const FrameMetadata& meta);

The thermal data is encapsulated in an object of the ThermalFrame class while a FrameMetadata object holds its corresponding metadata. There are a few important things to note:

  • The method does only provide references (&) to these objects. Those will remain valid while the IRImager instance is connected to a device. In other words, the ThermalFrame and FrameMetadata objects remain the same while a connection is active. Their content, however, will be constantly updated and will only remain the same while the method is called.
    If you wish to use the ThermalFrame data or the FrameMetadata later on or in a different thread, you will have to make an explicit copy.

    Attention
    In C++ a simple assignment is enough. In any other language you have to use the clone() methods of the ThermalFrame and FrameMetadata classes to ensure an explicit copy is created.
  • The provided references are const. This means you can not manipulate the objects to which they are pointing to. You have only read access.

    Attention
    The const qualifier is typically not mirrored in the bindings of the other supported programming languages. Thus, it may appear that you can manipulate these objects but this will certainly lead to errors.
  • Keep your method implementation short because no further frames are processed while it is active.
Note
These observations also apply to the onMeasurementField() and onThermalFrameEvent() methods of the IRImagerClient class.

The ThermalFrame object contains the measured temperatures for each pixel in an internal format. These values are represented by unsigned 16 bit integers. You can convert the internal values into degree Celsius with the help of an TemperatureConverter object. Retrieve it for every ThermalFrame with the getConverter() method.

Attention
Do not use TemperatureConverter objects that you instantiated yourself but retrieve them from every ThermalFrame you process. This is necessary because the internal values differ depending which TemperaturePrecision is currently active.

You have multiple ways to access the thermal data that is internally stored in a one-dimensional array:

  • Use the getValue() methods to access the internal temperature values for individual pixels.
  • Use the getTemperature() methods to access the temperature in degree Celsius for individual pixels.
  • Use the getConstIterator() method to get an iterator that allows you iterate over the entire frame.

The iterator is convenient but does not offer the best performance particularly in programming languages that are supported via bindings. The most efficient ways to access the thermal data are:

  • C++
    Use the getData() method to acquire a const pointer to the internal temperature value of the first pixel. All the values are stored in one continuous section of the memory like they would in a standard C array.
  • C#
    Use the copyDataTo() method to copy the internal temperature values to a ushort[] array. Make sure it has at least the size returned by the getSize() method.
  • Python 3
    Use the copyDataTo() method to copy the internal temperature values to a two-dimensional NumPy array with the shape (getWidth(), getHeight()) and the data type uint16.
Note
These remarks also apply to the thermal data stored in MeasurementField objects.

Creating False Color Images

You can easily convert a ThermalFrame into a false color image with the help of an ImageBuilder object. The resulting images have three channels: red, blue and green. Each channel has a color depth of 8 bits. The color values are stored in a continuous one-dimensional array. When setting up the ImageBuilder there are few things to consider:

  • The ColorFormat defines the sequence in which the individual color values for each pixel are stored in the image array. If set to RGB, the value for red will have the lowest index and the value for blue will have the highest. With BGR things are the other way around.

    Note
    Not all libraries or programming languages may interpret RGB and BGR this way.
  • The WidthAlignment specifies whether the size of each row/line in the resulting image should adhere to a specific alignment. For example the FourBytes alignment ensures that the size of every row/line in bytes is a multiple of four. If this is not the case out of the box, padding bytes will be added at the end of each line. Some libraries depend on a certain alignment to efficiently read image data.
  • The ColorPalette defines with what set of colors the different temperatures are represented. Refer to the API documentation of the ColorPalette enum to get an idea what options are available.
  • The PaletteScalingMethod specifies how the ColorPalette gets applied to the temperature spectrum found in a ThermalFrame.

Once the ImageBuilder object is set up you can set the ThermalFrame to convert with the setThermalFrame() method. Trigger the conversion with convertTemperatureToPaletteImage() and access the result with getImage(). The image data is encapsulated in an Image object.

Attention
The getImage() method returns only a reference to the Image object that grants read access. If you want to retain a copy in languages other than C++, use the clone() method to force an explicit copy. Keep in mind that you can not manipulate the referenced Image object even if the API of the bindings may suggest it.

You can access the image data in different ways:

  • Use the getPixel() methods to get a Pixel object containing the color values.
  • Use the getConstIterator() method to get an iterator that enables you to iterate over the image pixel by pixel.

The iterator is more convenient than the ones for the thermal data because you do not need to worry about the order of the color values and potential padding bytes. It shares, however, the same downsides. Therefore, the SDK provides more efficient ways to access the image data:

  • C++
    Use the getData() method to acquire a const pointer to the color value array. All the values are stored in one continuous section of the memory like they would in a standard C array.
  • C#
    Use the copyDataTo() method to copy the color values to a byte[] array. Make sure it has at least the size returned by the getSizeInBytes() method.
  • Python 3
    Use the copyDataTo() method to copy the color values to a three-dimensional NumPy array with the shape (getWidth(), getHeight(), 3) and the data type uint8.
Attention
A downside of these more efficient ways is that you have to take care of the color value order and of potential padding bytes at the end of every image row/line yourself.
Note
The ImageBuilder offers the shortcut methods copyImageDataTo() and getImageSizeInBytes() that allow you direct access the data of the Image object.