DefectivePixelCorrection#

using Itala;
using Itala.GenApi;

/// <summary>
/// DefectivePixelCorrection" example shows how to detect
/// defective pixels on the sensor given a set of images and how 
/// to correct them via the functionality implemented in the nodemap
/// of the device. The procedure should be performed at max resolution.
/// </summary>
internal class Program
{
  const int ACQ_COUNT = 10;

  private static void CorrectDetectedPixels(List<DefectivePixel> defectivePixels, INodeMap nodeMap)
  {
    IInteger defectivePixelCount = nodeMap.GetNode<IInteger>("oeDefectivePixelCount");
    if (!defectivePixelCount.IsWritable)
      throw new ItalaRuntimeException("Unable to set the number of pixels to be corrected. Aborting.");
    defectivePixelCount.Value = defectivePixels.Count;

    Console.WriteLine("\tCorrection procedure started with " + defectivePixels.Count + " pixels.");

    // Get the pixel selector to iterate over the amount of targeted pixels.
    IInteger defectivePixelSelector = nodeMap.GetNode<IInteger>("oeDefectivePixelSelector");
    if (!defectivePixelSelector.IsWritable)
      throw new ItalaRuntimeException("Unable to set the pixel selector for correction. Aborting.");

    // Get the features which allow to set the X and Y coordinate of the target pixel 
    // identified by the selector.
    IInteger defectivePixelXCoordinate = nodeMap.GetNode<IInteger>("oeDefectivePixelXCoordinate");
    if (!defectivePixelXCoordinate.IsWritable)
      throw new ItalaRuntimeException("Unable to set the X coordinate of the target pixel. Aborting.");
    IInteger defectivePixelYCoordinate = nodeMap.GetNode<IInteger>("oeDefectivePixelYCoordinate");
    if (!defectivePixelYCoordinate.IsWritable)
      throw new ItalaRuntimeException("Unable to set the Y coordinate of the target pixel. Aborting.");

    // Set the coordinates of every targeted pixels.
    for(int i = 0; i < defectivePixels.Count; i++)
    {
      defectivePixelSelector.Value = i;
      defectivePixelXCoordinate.Value = (long)defectivePixels[i].X;
      defectivePixelYCoordinate.Value = (long)defectivePixels[i].Y;

      Console.WriteLine("\tPixel[" + defectivePixels[i].X + "," + defectivePixels[i].Y + "] registered for correction. Was " + defectivePixels[i].TypeString + ".");
    }

    // Once that the pixel map has been set (i.e. the amount of pixels to be corrected
    // and their coordinates) the write function can be called to perform the
    // correction.
    ICommand defectivePixelWriteMap = nodeMap.GetNode<ICommand>("oeDefectivePixelWriteMap");
    if (!defectivePixelWriteMap.IsWritable)
      throw new ItalaRuntimeException("Unable to write the pixel map to device memory. Aborting.");
    defectivePixelWriteMap.Execute();

    Console.WriteLine("\tCorrection command sent, procedure completed.");
  }

  private static void DefectivePixelCorrection_Sample()
  {
    Console.WriteLine("######## DefectivePixelCorrection ########");
    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.");

    // Start by setting a full resolution Mono8 image to perform the
    // correction on the whole sensor. Keep the original values to restore
    // the initial camera state at the end of the program.
    IInteger width = device.GetNodeMap().GetNode<IInteger>("Width");
    if (!width.IsWritable)
      throw new ItalaRuntimeException("Unable to configure the image width. Aborting.");
    Int64 originalWidth = width.Value;
    Int64 maxWidth = width.Max;
    width.Value = maxWidth;
    Console.WriteLine("\tImage width set to " + maxWidth);

    IInteger height = device.GetNodeMap().GetNode<IInteger>("Height");
    if (!height.IsWritable)
      throw new ItalaRuntimeException("Unable to configure the image height. Aborting.");
    Int64 originalHeight = height.Value;
    Int64 maxHeight = height.Max;
    height.Value = maxHeight;
    Console.WriteLine("\tImage height set to " + maxHeight);

    IEnumeration pixelFormat = device.GetNodeMap().GetNode<IEnumeration>("PixelFormat");
    if (!pixelFormat.IsWritable)
      throw new ItalaRuntimeException("Unable to configure the image pixel format. Aborting.");
    Int64 originalPixelFormat = pixelFormat.IntValue;
    IEnumEntry mono8Entry = pixelFormat.GetEntryByName("Mono8");
    Int64 mono8Format = mono8Entry.Value;
    pixelFormat.IntValue = mono8Format;
    Console.WriteLine("\tPixelFormat set to Mono8.");

    // Create a detection interface for the current image size and pixel depth.
    IDefectDetection mono8Detection = DefectDetectionFactory.Create(maxWidth, maxHeight, PixelDepth.d8Bit);

    device.StartAcquisition();
    Console.WriteLine("\tAcquisition started.");

    // Acquire the dark images needed for both leaky and hot/cold 
    // detection. The image data is accumulated thanks to the interface
    // so that each image can be immediately disposed without wasting memory.
    Console.WriteLine("\tAccumulating dark data...");
    for(int i  = 0; i < ACQ_COUNT; i++)
    {
      IImage darkImage = device.GetNextImage(500);

      mono8Detection.AccumulateDark(darkImage.Data);

      Console.WriteLine("\tImage "+(i+1)+" added. \r");
      darkImage.Dispose();
    }

    // Acquire the gray images needed for hot/cold detection.
    Console.WriteLine("\n\tAccumulating grey data...");
    for (int i = 0; i < ACQ_COUNT; i++)
    {
      IImage grayImage = device.GetNextImage(500);

      mono8Detection.AccumulateGray(grayImage.Data);

      Console.WriteLine("\tImage "+(i+1)+" added. \r");
      grayImage.Dispose();
    }

    device.StopAcquisition();
    Console.WriteLine("\n\tAcquisition stopped.");

    // Find and get the leaky pixels of the sensor. 
    List<DefectivePixel> leakyPixels = mono8Detection.FindLeaky(1024, 5);

    //Same for hot/cold pixels.
    List<DefectivePixel> hotNColdPixels = mono8Detection.FindHotNCold(1024, 5);

    Console.WriteLine(leakyPixels.Count+" leaky pixels found.");
    Console.WriteLine(hotNColdPixels.Count+" hot/cold pixels found.");

    // Leaky and hot/cold pixels are equally defective for the purposes of
    // the correction algorithm. Append the two vectors and perform the correction
    // with the dedicated GenICam nodes.
    leakyPixels.AddRange(hotNColdPixels);

    CorrectDetectedPixels(leakyPixels, device.GetNodeMap());

    // Dispose the detection interface when done.
    mono8Detection.Dispose();
    Console.WriteLine("Mono8 detection instance disposed.");

    // Restore the original image size and format.
    width.Value = originalWidth;
    height.Value = originalHeight;
    pixelFormat.IntValue = originalPixelFormat;

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

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