ifm3d::Buffer- Basic C++ STL container for ifm3d

ifm3d::Buffer is designed to provide a C++ STL container that can hold buffer data of different types provided by ifm3d vision devices. Data is stored in sequential memory layout and ifm3d::Buffer provides a function template to access the pixel. The pixel data type is defined in an enum ifm3d::pixel_format. ifm3d::Buffer class does memory management and the user is free from the memory allocation and deallocation. The assignment operator and the copy constructor only copy the attributes and data is shared across the object.

Creating Buffer Object:

This can be done by calling ifm3d::Buffer() and ifm3d::Buffer(rows, cols, nchannel, ifm3d::pixel_format). The default Constructor only creates the attributes and the allocation of memory is done on create(rows, cols, nchannel, ifm3d::pixel_format) call. ifm3d::Buffer::create(rows, cols, nchannel, ifm3d::pixel_format) will allocate the required memory only if the previous memory is not sufficient to store the buffer data.

//a 100 x 100 Buffer of type 8U

ifm3d::Buffer buffer;
buffer.create(100,100,1,ifm3d::FORMAT_8U)

//OR
//can also be created  with parameter construction

ifm3d::Buffer buffer(100,100,1,ifm3d::FORMAT_8U);
 
//and now turn buffer to a 10 x10 3-channel 8-bit matrix.
// The old content will be deallocated
buffer.create(10,10,3,ifm3d::FORMAT_8U);
	  

Accessing the Pixel

The ifm3d::Buffer provides a template function to access data. Use at<T>(index) or at<T>(i,j) to access the pixel. This functions returns the reference to the pixel. A pixel is defined as a structure of n-channel values of type T at a given index or position in 2D array.

// To access a pixel in ifm3d::Buffer I ( 100,100,1,ifm3d::FORMAT_8U) at  50,50
// position

auto pixel = I.at<uint8_t>(50,50);
// if working as Index array then

auto index = 50*100 + 50 ;
auto pixel = I.at<uint8_t>(index);

// Changing the pixel value can be done as follow :
// Writing 255 at pixel postion 50,50

I.at<uint8_t>(50,50) = 255;
I.at<uint8_t>(index) = 255;

To access a pixel in n-channel ifm3d::Buffer I ( 100,100,3,ifm3d::FORMAT_8U) at (50,50) position, follow the example below (for a 3 channel Buffer), as the pixel is a structure of the values of n-channel at a given position.

// User define struct 
struct pixel{
uint8_t x;
uint8_t y;
uint8_t z;
}pixel_t;

// Accessing the value at 50, 50 position can be done as 

auto pixel = I.at<pixel_t>(50,50);
auto x = pixel.x;
auto y = pixel.y;
auto z = pixel.z;

Buffer Templates

ifm3d::Buffer_<T> extends ifm3d::Buffer where T defines the data type in which the user wants to access the pixel. This removes the need for providing the template type T while using the Buffer functionality and working with std::algorithms.

Compatibility with C++ STL Algorithms

The ifm3d::Buffer provides templated iterator to access data and to work with std::algorithms. The user can use ifm3d::IteratorAdapter<T>(ifm3d::Buffer) which forwards type T to templated iterators of the ifm3d::Buffer.

ifm3d::Buffer buffer(10,10,1,ifm3d::FORMAT_16U);

for (auto value : ifm3d::IteratorAdapter<std::uint16_t>(buffer) )
{
// use value 
}

// For multi channel buffer 
ifm3d::Buffer buffer(10,10,3,ifm3d::FORMAT_16U);

for (auto value : ifm3d::IteratorAdapter<ifm3d::Point3D<uint16_t>>(buffer) )
  {
    std::cout << "(" << value.val[0]  << ",  " << value.val[1] << ", " << value.val[2] << ")" ;
  }
  

The user can convert ifm3d::Buffer to ifm3d::Buffer_<T>, where T will define the type in which the user wants to access the pixel. For ifm3d::Buffer_<T> containers, the ifm3d::pixel_format is deduced internally.

ifm3d::Buffer buffer(10,10,1,ifm3d::FORMAT_16U);
ifm3d::Buffer_<std::uint16_t> buffer_ = buffer;
for (auto value :buffer_ )
{
// use value 
}
// For multi channel buffer 
ifm3d::Buffer buffer(10,10,3,ifm3d::FORMAT_16U);
ifm3d::Buffer_<ifm3d::Point3D<uint16_t>> buffer_ = buffer;
for (auto value : buffer_ )
  {
     std::cout << "(" << value.val[0]  << ",  " << value.val[1] << ", " << value.val[2] << ")" ;
  }

This way, ifm3d::Buffer container can be used with any of the std::algorithm

Example grabbing distance and amplitude in ifm3d::Buffer

#include <iostream>
#include <ifm3d/device.h>
#include <ifm3d/fg.h>
#include <ifm3d/fg/buffer.h>

int main(int argc, const char** argv)
{

  auto dev = ifm3d::Device::MakeShared();

  uint16_t pcic_port = (dev->WhoAmI() == ifm3d::Device::device_family::O3R) ? 50012 : 50010;

  auto fg = std::make_shared<ifm3d::FrameGrabber>(
    dev, pcic_port); // 50012 for O3R use default value for other devices

  fg->Start({ ifm3d::buffer_id::AMPLITUDE,ifm3d::buffer_id::XYZ, ifm3d::buffer_id::RADIAL_DISTANCE });

  //polling the device 
  auto frame = fg->WaitForFrame().get();
  
  ifm3d::Buffer amp_buffer = frame->GetBuffer(ifm3d::buffer_id::AMPLITUDE);
  ifm3d::Buffer dist_buffer = frame->GetBuffer(ifm3d::buffer_id::RADIAL_DISTANCE);

  // Accessing the pixels from ifm3d::Buffer 
  // Query the data format and channel.
  std::cout << amp_buffer.nchannels() << std::endl;
  std::cout << static_cast<int>(amp_buffer.dataFormat()) << std::endl;

  // For O3D devices Amplitude and Distance data is `ifm3d::FORMAT_16U`
  // whereas for O3X and O3R Device, the Amplitude buffer type is `ifm3d::FORMAT_32F`
  // Refer to the section below for the full list of data types. 

  // With a 1 channel and float type buffer, 
  // the user can access data:
  ifm3d::Buffer_<float> amp = amp_buffer;

  for (auto& val : amp) {

    //do something with val value
  }
  return 0;
}

Example grabbing XYZ or n-channel ifm3d::Buffer

#include <iostream>
#include <ifm3d/device.h>
#include <ifm3d/fg.h>
#include <ifm3d/fg/buffer.h>

int main(int argc, const char** argv)
{
  auto dev = ifm3d::Device::MakeShared();

  uint16_t pcic_port = (dev->WhoAmI() == ifm3d::Device::device_family::O3R) ? 50012 : 50010;

  auto fg = std::make_shared<ifm3d::FrameGrabber>(
    dev, pcic_port); // 50012 for O3R use default value for other devices

  fg->Start({ ifm3d::buffer_id::AMPLITUDE,ifm3d::buffer_id::XYZ, ifm3d::buffer_id::RADIAL_DISTANCE });

  //polling the device 
  auto frame = fg->WaitForFrame().get();

  ifm3d::Buffer xyz = frame->GetBuffer(ifm3d::buffer_id::XYZ);

  // Accessing the pixels from ifm3d::Buffer 
  // Query the data format and channel.
  std::cout << xyz.nchannels() << std::endl;
  std::cout << static_cast<int>(xyz.dataFormat()) << std::endl;

  // For O3D devices XYZ data is`ifm3d::FORMAT_16S`
  // whereas for O3X,O3R device XYZ buffer type is `ifm3d::FORMAT_32F
  // Refer to the section below for the full list of data types.

  // With 3 channel and float type
  // using point3D_32F
  ifm3d::Buffer_< ifm3d::Point3D_32F>  xyz_data = xyz; // no copy of data 

  // With a range based `for` loop
  for (const auto& point : xyz_data)
  {
    std::cout << "(" << point.val[1] << "," << point.val[2] << "," << point.val[0] << ")";
  }

  // With a pointer 
  for (int i = 0; i < xyz.height(); i++)
  {
    for (int j = 0; j < xyz.width(); j++)
    {
      auto ptr = xyz.ptr<float>(i, j);
      auto z = ptr[0];
      auto x = ptr[1];
      auto y = ptr[2];

      std::cout << "(" << x << "," << y << "," << z << ")";

    }
  }
  return 0;
}

Device, Schema and data types for ifm3d::Buffer

ifm3d supports multiple devices. These devices support multiple buffers/data types which can have different data formats on different devices. The following table summarizes the buffers formats, along with their ifm3d::buffer_id, so a std::set<ifm3d::buffer_id> needs to be pass in FrameGrabber::Start method to enable the corresponding buffer for grabbing.

Data/Image

ifm3d schema

O3D3XX

O3X

O3R

Radial distance image

ifm3d::buffer_id::RADIAL_DISTANCE

std::uint16_t

float

float

Amplitude image

ifm3d::buffer_id::AMPLITUDE

std::uint16_t

float

float

Raw amplitude image

ifm3d::buffer_id::RAW_AMPLITUDE

std::uint16_t

float

NA

Cartesian coordinate

ifm3d::buffer_id::XYZ

std::int16_t

float

float

Unit vector

ifm3d::buffer_id::UNIT_VECTOR_ALL

float

float

NA

Image grayscale

ifm3d::buffer_id::GRAY

std::uint16_t

float

NA

Distance Noise Image

ifm3d::buffer_id::DISTANCE_NOISE

NA

std::uint16_t

std::uint16_t

Confidence Image

ifm3d::buffer_id::CONFIDENCE

std::uint8_t

std::uint8_t

std::unit16_t

JPEG

ifm3d::buffer_id::IMG_JPEG

NA

NA

std::unit8_t

Along with above data ifm3d also supports ifm3d::buffer_id values, which is used to obtain data that are obtained in standard STL containers or C++ default types.

Data/Image

ifm3d schema

O3D3XX

O3X

O3R

JSON Model Data

ifm3d::buffer_id::JSON_MODEL

std::string

NA

NA

JSON Model Data

ifm3d::buffer_id::JSON_MODEL

std::string

NA

NA

Intrinsic calibration parameter

ifm3d::buffer_id::INTRINSIC_CALIBRATION

std::vector

NA

std::vector

inverse Intrinsic calibration parameter

ifm3d::buffer_id::INVERSE_INTRINSIC_CALIBRATION

std::vector

NA

std::vector

Illumination temperature

ifm3d::buffer_id::ILLUMINATION_TEMP

float

NA

NA

Exposure time

ifm3d::buffer_id::EXPOSURE_TIME

std::vector<ifm3d::TimePointT>

std::vector<ifm3d::TimePointT>

std::vector<ifm3d::TimePointT>