GrabChunks#

/***********************************************************************************
 *
 * Itala API - Copyright (C) 2022 Opto Engineering
 *
 * THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS
 * FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT
 * HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY SUFFERED BY LICENSE AS
 * A RESULT OF USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES.
 *
 ***********************************************************************************/

/**
 * @example GrabChunks.cpp
 *
 * @brief "GrabChunks" is an extension of the simple Grab example which introduces
 * the chunk data functionality. Along with the image data itself, images can
 * be shipped along with additional information. This additional data is arranged in
 * "chunks". For instance, an image can contain two chunks: its timestamp and the
 * temperature of the device at the moment of the acquisition. Chunks can be read
 * as GenICam features returned by the IImage interface.
 *
 * Suggested examples:
 * @see GrabTrigger.cpp
 * @see Events.cpp
 */

// Include Itala API
#include "ItalaApi/Itala.h"

// Include the GenICam library
#include "GenICam.h"

#define INDENT "\t"
#define ACQUIRE_COUNT 10

void GrabChunks_Sample() {
  std::cout << "***** Grab chunks example started. *****" << std::endl << std::endl;

  Itala::ISystem* pSystem = Itala::CreateSystem();
  Itala::DeviceInfoList deviceInfos = pSystem->EnumerateDevices(700);

  if (deviceInfos.size() == 0) throw GENERIC_EXCEPTION("No devices found. Example canceled.");

  if (deviceInfos[0].AccessStatus() != Itala::DeviceAccessStatus::AvailableReadWrite)
    throw GENERIC_EXCEPTION("Target device is unaccessible in RW mode. Example canceled.");

  Itala::IDevice* pDevice = pSystem->CreateDevice(deviceInfos[0]);

  std::cout << "First device found is initialized." << std::endl;
  std::cout << "Enabling chunk data.." << std::endl;

  // Enable the auto exposure time functionality to cause changes in the exposure
  // time value when the scene changes or the camera itself is moved.
  GenApi::CEnumerationPtr ptrExposureAuto = pDevice->GetNodeMap().GetNode("ExposureAuto");
  if (!IsWritable(ptrExposureAuto))
    throw GENERIC_EXCEPTION("Unable to activate auto exposure time mode. Aborting.");
  int64_t originalExposureAuto = ptrExposureAuto->GetIntValue();
  ptrExposureAuto->FromString("Continuous");

  // The chunk data functionality is enabled via the "ChunkModeActive" feature.
  GenApi::CBooleanPtr ptrChunkModeActive = pDevice->GetNodeMap().GetNode("ChunkModeActive");
  if (!IsWritable(ptrChunkModeActive))
    throw GENERIC_EXCEPTION("Unable to activate chunk mode. Aborting.");
  bool originalChunkModeActive = ptrChunkModeActive->GetValue();
  ptrChunkModeActive->SetValue(true);

  // Each chunk data available can be enabled individually. In this case, exposure
  // time, pixel format and frame timestamp chunks are activated.
  // First select the exposure time chunk via the selector and enable it via the
  // "ChunkEnable" feature.
  GenApi::CEnumerationPtr ptrChunkSelector = pDevice->GetNodeMap().GetNode("ChunkSelector");
  if (!IsReadable(ptrChunkSelector))
    throw GENERIC_EXCEPTION("Unable to retrieve chunk selector. Aborting.");

  ptrChunkSelector->FromString("ExposureTime");
  GenApi::CBooleanPtr ptrChunkEnable = pDevice->GetNodeMap().GetNode("ChunkEnable");
  bool originalExposureTimeChunkEnabled = ptrChunkEnable->GetValue();
  ptrChunkEnable->SetValue(true);

  // Do the same for frame ID chunk.
  ptrChunkSelector->FromString("FrameID");
  bool originalFrameIDChunkEnabled = ptrChunkEnable->GetValue();
  ptrChunkEnable->SetValue(true);

  // And again for timestamp chunk.
  ptrChunkSelector->FromString("Timestamp");
  bool originalTimestampChunkEnabled = ptrChunkEnable->GetValue();
  ptrChunkEnable->SetValue(true);

  std::cout << std::endl;

  pDevice->StartAcquisition();

  std::cout << "Acquisition started with chunk functionality enabled." << std::endl;
  std::cout << std::endl;

  std::vector<Itala::IImage*> images;
  for (size_t i = 0; i < ACQUIRE_COUNT; i++) {
    Itala::IImage* pImage = pDevice->GetNextImage(1000);

    if (pImage->IsIncomplete()) {
      // Report some info if the image is partially filled.
      std::cout << i << " is a incomplete image." << std::endl;
      std::cout << INDENT << "Bytes filled: " << pImage->GetBytesFilled() << "/"
                << pImage->GetPayloadSize() << std::endl;
    } else {
      std::cout << "Image " << i << " grabbed." << std::endl;
    }

    // Add the image to the acquired frames list so that image chunks can be
    // retrieved and displayed after che grab.
    images.push_back(pImage);

    // The image IS NOT disposed here since it's needed afterwards to get and
    // display the attached chunk data.
  }

  std::cout << std::endl;

  // The chunks embedded in the available images are ready to be read.
  for (size_t i = 0; i < images.size(); i++) {
    Itala::IImage* pImage = images[i];

    std::cout << "Retrieving chunks for image " << i << ".." << std::endl;

    // Check if the acquired image has embedded chunk data.
    if (pImage->HasChunkData()) {
      // Chunk data is exposed as a set GenICam features which names ar
      // regulated by the SFNC specification. In general, the names of
      // chunk features are defined by prepending the "Chunk" prefix
      // (e.g. ChunkExposureTime) to the equivalent standard feature
      // (e.g. ExposureTime).
      GenApi::CFloatPtr pChunkExposureTime = pImage->GetChunkNode("ChunkExposureTime");
      GenApi::CIntegerPtr pChunkFrameId = pImage->GetChunkNode("ChunkFrameID");
      GenApi::CIntegerPtr pChunkTimestamp = pImage->GetChunkNode("ChunkTimestamp");

      std::cout << INDENT << "ChunkExposureTime: " << pChunkExposureTime->GetValue() << std::endl;
      std::cout << INDENT << "ChunkFrameID: " << pChunkFrameId->GetValue() << std::endl;
      std::cout << INDENT << "ChunkTimestamp: " << pChunkTimestamp->GetValue() << std::endl;
    } else {
      std::cout << INDENT << "No chunk data attached." << std::endl;
    }

    // The image can now be disposed: it's not required anymore.
    pImage->Dispose();
    pImage = nullptr;

    std::cout << std::endl;
  }

  // The acquisition must be stopped AFTER the acquired images have been used
  // (to display chunk data, in this case). If the acquisition was stopped
  // prematurely, errors may have occurred when accessing the image data (released
  // by the library).
  pDevice->StopAcquisition();

  // Restore the original features state.
  ptrExposureAuto->SetIntValue(originalExposureAuto);

  ptrChunkSelector->FromString("ExposureTime");
  ptrChunkEnable->SetValue(originalExposureTimeChunkEnabled);

  ptrChunkSelector->FromString("FrameID");
  ptrChunkEnable->SetValue(originalFrameIDChunkEnabled);

  ptrChunkSelector->FromString("Timestamp");
  ptrChunkEnable->SetValue(originalTimestampChunkEnabled);

  ptrChunkModeActive->SetValue(originalChunkModeActive);

  pDevice->Dispose();
  pDevice = nullptr;
  std::cout << "Device instance disposed." << std::endl;
  pSystem->Dispose();
  pSystem = nullptr;
  std::cout << "System instance disposed." << std::endl;
}

int main(int /*argc*/, char** /*argv*/) {
  try {
    GrabChunks_Sample();
  } catch (GenICam::GenericException& e) {
    std::cout << e.what() << std::endl;
  }
}