GrabChunks#

using Itala;
using Itala.GenApi;

/// <summary>
/// "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.
/// </summary>
internal class Program
{
  const int ACQUIRE_COUNT = 10;

  private static void GrabChunks_Sample()
  {
    Console.WriteLine("######## GrabChunks ########");
    ISystem system = SystemFactory.Create();
    List<DeviceInfo> deviceInfos = system.EnumerateDevices();

    if (deviceInfos.Count == 0)
      throw new ItalaRuntimeException("No devices found. Example canceled.");
    if (deviceInfos[0].AccessStatus != DeviceAccessStatus.AvailableReadWrite)
      throw new ItalaRuntimeException("Target device is unaccessible in RW mode. Example canceled.");
    IDevice device = system.CreateDevice(deviceInfos[0]);
    Console.WriteLine("First device initialized.");
    Console.WriteLine("Enabling chunk data...");

    // Enable the auto exposure time functionality to cause changes in the exposure
    // time value when the scene changes or the camera itself is moved.
    IEnumeration exposureAuto = device.GetNodeMap().GetNode<IEnumeration>("ExposureAuto");
    if (!exposureAuto.IsWritable)
      throw new ItalaRuntimeException("Unable to activate auto exposure time mode. Aborting.");
    Int64 originalExposureAuto = exposureAuto.IntValue;
    exposureAuto.FromString("Continuous");

    // The chunk data functionality is enabled via the "ChunkModeActive" feature. 
    IBoolean chunkModeActive = device.GetNodeMap().GetNode<IBoolean>("ChunkModeActive");
    if (!chunkModeActive.IsWritable)
      throw new ItalaRuntimeException("Unable to activate chunk mode. Aborting.");
    bool originalChunkModeActive = chunkModeActive.Value;
    chunkModeActive.Value = 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.
    IEnumeration chunkSelector = device.GetNodeMap().GetNode<IEnumeration>("ChunkSelector");
    if (!chunkSelector.IsWritable)
      throw new ItalaRuntimeException("Unable to  retrieve chunk selector. Aborting.");
    chunkSelector.FromString("ExposureTime");

    IBoolean chunkEnable = device.GetNodeMap().GetNode<IBoolean>("ChunkEnable");
    bool originalExposureTimeChunkEnabled = chunkEnable.Value;
    chunkEnable.Value = true;

    // Do the same for frame ID chunk.
    chunkSelector.FromString("FrameID");
    bool originalFrameIDChunkEnabled = chunkEnable.Value;
    chunkEnable.Value = true;

    // And again for timestamp chunk.
    chunkSelector.FromString("Timestamp");
    bool originalTimestampChunkEnabled = chunkEnable.Value;
    chunkEnable.Value = true;

    Console.WriteLine();

    device.StartAcquisition();
    Console.WriteLine("Acquisition started with chunk functionality enabled.\n");

    List<IImage> images = new List<IImage>();
    for(int  i = 0; i < ACQUIRE_COUNT; i++)
    {
      IImage image = device.GetNextImage(1000);

      if(image.IsIncomplete)
      {
        // Report some info if the image is partially filled.
        Console.WriteLine("Icomplete image.");
        Console.WriteLine("\tBytes filled: "+ image.BytesFilled+"/"+image.PayloadSize);
      }
      else
      {
        Console.WriteLine("Image grabbed.");
      }

      // Add the image to the acquired frames list so that image chunks can be
      // retrieved and displayed after che grab.
      images.Add(image);
      // The image IS NOT disposed here since it's needed afterwards to get and
      // display the attached chunk data.
    }

    Console.WriteLine();

    // The chunks embedded in the available images are ready to be read.
    foreach(var (img, i) in images.Select((value, index)=>(value, index)))
    {
      Console.WriteLine("Retrieving chunks for image " + i + "...");

      // Check if the acquired image has embedded chunk data.
      if(img.HasChunckData)
      {
        // 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).
        IFloat chunkExposureTime = img.GetChunkNode<IFloat>("ChunkExposureTime");
        IInteger chunkFrameId = img.GetChunkNode<IInteger>("ChunkFrameID");
        IInteger chunkTimestamp = img.GetChunkNode<IInteger>("ChunkTimestamp");

        Console.WriteLine("\tChunkExposureTime: " + chunkExposureTime.Value);
        Console.WriteLine("\tChunkFrameID: " + chunkFrameId.Value);
        Console.WriteLine("\tChunkTimestamp: " + chunkTimestamp.Value);
      }
      else
      {
        Console.WriteLine("\tNo chunk data attached.");
      }
      // The image can now be disposed: it's not required anymore.
      img.Dispose();
      Console.WriteLine();
    }

    // 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).
    device.StopAcquisition();

    // Restore the original features state.
    exposureAuto.IntValue = originalExposureAuto;

    chunkSelector.FromString("ExposureTime");
    chunkEnable.Value = originalExposureTimeChunkEnabled;

    chunkSelector.FromString("FrameID");
    chunkEnable.Value = originalFrameIDChunkEnabled;

    chunkSelector.FromString("Timestamp");
    chunkEnable.Value = originalTimestampChunkEnabled;

    chunkModeActive.Value = originalChunkModeActive;

    device.Dispose();
    Console.WriteLine("Device instance disposed.");
    system.Dispose();
    Console.WriteLine("System instance disposed.");
  }

  private static void Main(string[] args)
  {
    try
    {
      GrabChunks_Sample();
    }
    catch (Exception ex)
    {
      Console.WriteLine(ex.ToString());
    }
  }
}