DefectivePixelCorrection#

#include <stdio.h>
#include <stdlib.h>
#include "ItalaApiC/ItalaC.h"

#define ACQ_COUNT 10
#define MAX_PIXEL_DETECTED 1024

ItalaError ErrorManager(ItalaError e) {
  size_t sizeMessage = 255;
  char* message = (char*)malloc(sizeof(char) * sizeMessage);
  ERR_GetLastErrorMessage(message, &sizeMessage);
  printf("\nITALA ERROR (%d):\t%s, %zu char", ERR_GetLastErrorCode(), message, sizeMessage);
  free(message);
  return e;
}

ItalaError CorrectDetectedPixels(DefectivePixel* defectivePixel, size_t size, H_NODEMAP hNodeMap) {
  ItalaError error = ItalaErrorSuccess;
  // Start by setting the amount of pixel targeted for correction.
  H_NODE hNodeOEDefectivePixelCount = NULL;
  error = NODEMAP_GetNode(hNodeMap, "oeDefectivePixelCount", &hNodeOEDefectivePixelCount);
  if (error) return ErrorManager(error);
  bool isWritable = false;
  error = IsNodeWritable(hNodeOEDefectivePixelCount, &isWritable);
  if (error) return ErrorManager(error);
  if (!isWritable) {
    printf("Unable to set the number of pixels to be corrected. Aborting.\n");
    return ItalaErrorError;
  }
  error = NODE_IntegerSetValue(hNodeOEDefectivePixelCount, size);
  if (error) return ErrorManager(error);
  printf("\tCorrection procedure started with %zu pixels.\n", size);

  // Get the pixel selector to iterate over the amount of targeted pixels.
  H_NODE hNodeOEDefectivePixelSelector = NULL;
  error = NODEMAP_GetNode(hNodeMap, "oeDefectivePixelSelector", &hNodeOEDefectivePixelSelector);
  if (error) return ErrorManager(error);
  error = IsNodeWritable(hNodeOEDefectivePixelCount, &isWritable);
  if (error) return ErrorManager(error);
  if (!isWritable) {
    printf("Unable to set the pixel selector for correction. Aborting.\n");
    return ItalaErrorError;
  }

  // Get the features which allow to set the X and Y coordinate of the target pixel
  // identified by the selector.
  H_NODE hNodeOEDefectivePixelXCoordinate = NULL;
  error =
      NODEMAP_GetNode(hNodeMap, "oeDefectivePixelXCoordinate", &hNodeOEDefectivePixelXCoordinate);
  if (error) return ErrorManager(error);
  error = IsNodeWritable(hNodeOEDefectivePixelXCoordinate, &isWritable);
  if (error) return ErrorManager(error);
  if (!isWritable) {
    printf("Unable to set the X coordinate of the target pixel. Aborting.\n");
    return ItalaErrorError;
  }
  H_NODE hNodeOEDefectivePixelYCoordinate = NULL;
  error =
      NODEMAP_GetNode(hNodeMap, "oeDefectivePixelYCoordinate", &hNodeOEDefectivePixelYCoordinate);
  if (error) return ErrorManager(error);
  error = IsNodeWritable(hNodeOEDefectivePixelYCoordinate, &isWritable);
  if (error) return ErrorManager(error);
  if (!isWritable) {
    printf("Unable to set the Y coordinate of the target pixel. Aborting.\n");
    return ItalaErrorError;
  }

  // Set the coordinates of every targeted pixels.
  for (size_t i = 0; i < size; i++) {
    error = NODE_IntegerSetValue(hNodeOEDefectivePixelSelector, i);
    if (error) return ErrorManager(error);
    error = NODE_IntegerSetValue(hNodeOEDefectivePixelXCoordinate, defectivePixel[i].X);
    if (error) return ErrorManager(error);
    error = NODE_IntegerSetValue(hNodeOEDefectivePixelYCoordinate, defectivePixel[i].Y);
    if (error) return ErrorManager(error);
    printf("\tPixel [%jd, %jd] registered for correction. Was %s.\n", defectivePixel[i].X,
           defectivePixel[i].Y, defectivePixel[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.
  H_NODE hNodeOEDefectivePixelWriteMap = NULL;
  error = NODEMAP_GetNode(hNodeMap, "oeDefectivePixelWriteMap", &hNodeOEDefectivePixelWriteMap);
  if (error) return ErrorManager(error);
  error = IsNodeWritable(hNodeOEDefectivePixelWriteMap, &isWritable);
  if (error) return ErrorManager(error);
  if (!isWritable) {
    printf("Unable to write the pixel map to device memory. Aborting.\n");
    return ItalaErrorError;
  }
  error = NODE_CommandExecute(hNodeOEDefectivePixelWriteMap);
  if (error) return ErrorManager(error);
  printf("\n\tCorrection command sent, procedure completed.\n");
  return ItalaErrorSuccess;
}

int main(int argc, char** argv) {
  printf("***** DefectivePixelCorrection example started. *****\n");
  ItalaError error = ItalaErrorSuccess;

  error = SYS_Initialize();
  if (error) return ErrorManager(error);

  size_t devicesInfoSize = 0;
  error = SYS_EnumerateDevices(700);
  if (error) return ErrorManager(error);
  error = SYS_GetDeviceCount(&devicesInfoSize);
  if (devicesInfoSize == 0) {
    printf("No devices found. Example canceled.\n");
    return ItalaErrorError;
  }
  DeviceInfo deviceInfo;
  error = SYS_GetDeviceByIndex(0, &deviceInfo);
  if (error) return ErrorManager(error);
  if (deviceInfo.AccessStatus != AvailableReadWrite) {
    printf("Target device is unaccessible in RW mode. Example canceled.\n");
    return ItalaErrorError;
  }

  H_DEVICE hDevice = NULL;
  error = SYS_CreateDevice(deviceInfo, &hDevice);
  if (error) return ErrorManager(error);
  printf("First device initialized.\n");

  H_NODEMAP hNodeMap = NULL;
  error = DEV_GetNodeMap(hDevice, &hNodeMap);
  if (error) return ErrorManager(error);

  // Start by setting a full resolution Mono8 image to perform the
  // to perform the correction on the whole sensor. Keep the original
  // values to restore the initial camera state at the end of the program.
  // Width
  H_NODE hNodeWidth = NULL;
  NODEMAP_GetNode(hNodeMap, "Width", &hNodeWidth);
  if (error) return ErrorManager(error);
  bool isWritable = false;
  error = IsNodeWritable(hNodeWidth, &isWritable);
  if (error) return ErrorManager(error);
  if (!isWritable) {
    printf("Unable to configure the image width. Aborting.\n");
    return ItalaErrorError;
  }
  int64_t originalWidth = 0;
  error = NODE_IntegerGetValue(hNodeWidth, &originalWidth);
  if (error) return ErrorManager(error);
  int64_t maxWidth = 0;
  error = NODE_IntegerGetMax(hNodeWidth, &maxWidth);
  if (error) return ErrorManager(error);
  error = NODE_IntegerSetValue(hNodeWidth, maxWidth);
  if (error) return ErrorManager(error);
  printf("\tImage width set to %jd\n", maxWidth);

  // Height
  H_NODE hNodeHeight = NULL;
  NODEMAP_GetNode(hNodeMap, "Height", &hNodeHeight);
  if (error) return ErrorManager(error);
  isWritable = false;
  error = IsNodeWritable(hNodeHeight, &isWritable);
  if (error) return ErrorManager(error);
  if (!isWritable) {
    printf("Unable to configure the image height. Aborting.\n");
    return ItalaErrorError;
  }
  int64_t originalHeight = 0;
  error = NODE_IntegerGetValue(hNodeHeight, &originalHeight);
  if (error) return ErrorManager(error);
  int64_t maxHeight = 0;
  error = NODE_IntegerGetMax(hNodeHeight, &maxHeight);
  if (error) return ErrorManager(error);
  error = NODE_IntegerSetValue(hNodeHeight, maxHeight);
  if (error) return ErrorManager(error);
  printf("\tImage height set to %jd\n", maxHeight);

  // Pixel Format
  H_NODE hNodePixelFormat = NULL;
  NODEMAP_GetNode(hNodeMap, "PixelFormat", &hNodePixelFormat);
  if (error) return ErrorManager(error);
  isWritable = false;
  error = IsNodeWritable(hNodePixelFormat, &isWritable);
  if (error) return ErrorManager(error);
  if (!isWritable) {
    printf("Unable to configure the pixel format. Aborting.\n");
    return ItalaErrorError;
  }
  int64_t originalPixelFormat = 0;
  error = NODE_EnumerationGetIntValue(hNodePixelFormat, &originalPixelFormat);
  if (error) return ErrorManager(error);
  H_NODE hNodeEntryMono8 = NULL;
  error = NODE_EnumerationGetEntryByName(hNodePixelFormat, "Mono8", &hNodeEntryMono8);
  if (error) return ErrorManager(error);
  int64_t mono8Format = 0;
  error = NODE_EnumEntryGetValue(hNodeEntryMono8, &mono8Format);
  if (error) return ErrorManager(error);
  error = NODE_EnumerationSetIntValue(hNodePixelFormat, mono8Format);
  if (error) return ErrorManager(error);
  printf("\tPixelFormat set to Mono8.\n");

  H_DEFECTDETECTION hDefDetMono8 = NULL;
  error = CreateDefectDetection(maxWidth, maxHeight, D8Bit, &hDefDetMono8);
  if (error) return ErrorManager(error);

  error = DEV_StartAcquisition(hDevice);
  if (error) return ErrorManager(error);
  printf("\tAcquisition started.\n");

  // 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.
  printf("\tAccumulating dark data..\n");
  H_IMAGE hImage = NULL;
  for (int i = 0; i < ACQ_COUNT; i++) {
    error = DEV_GetNextImage(hDevice, 500, &hImage);
    if (error) return ErrorManager(error);
    void* dataImg;
    error = IMG_GetData(hImage, &dataImg);
    if (error) return ErrorManager(error);

    // Accumulate the new dark image. Note that the function requires
    // the raw data pointer, not the IImage itself!
    error = DD_AccumulateDark(hDefDetMono8, (uint8_t*)dataImg);
    if (error) return ErrorManager(error);
    printf("\tImage %d added\n", i + 1);
    error = IMG_Dispose(hImage);
    hImage = NULL;
    if (error) return ErrorManager(error);
  }

  // Acquire the gray images needed for hot/cold detection.
  printf("\tAccumulating gray data..\n");
  hImage = NULL;
  for (int i = 0; i < ACQ_COUNT; i++) {
    error = DEV_GetNextImage(hDevice, 500, &hImage);
    if (error) return ErrorManager(error);
    void* dataImg;
    error = IMG_GetData(hImage, &dataImg);
    if (error) return ErrorManager(error);

    // Accumulate the new gray image. Note that the function requires
    // the raw data pointer, not the IImage itself!
    error = DD_AccumulateGray(hDefDetMono8, (uint8_t*)dataImg);
    if (error) return ErrorManager(error);
    printf("\tImage %d added\n", i + 1);
    error = IMG_Dispose(hImage);
    hImage = NULL;
    if (error) return ErrorManager(error);
  }

  error = DEV_StopAcquisition(hDevice);
  if (error) return ErrorManager(error);
  printf("\tAcquisition stopped.\n");

  // Find the leaky pixels of the sensor.
  size_t leakyPixelSize = 0;
  error = DD_FindLeaky(hDefDetMono8, MAX_PIXEL_DETECTED, 5);
  if (error) return ErrorManager(error);
  error = DD_GetLeakyCount(&leakyPixelSize);
  if (error) return ErrorManager(error);

  // Same for hot/cold pixels.
  size_t hotNColdPixelSize = 0;
  error = DD_FindHotNCold(hDefDetMono8, MAX_PIXEL_DETECTED, 5);
  if (error) return ErrorManager(error);
  error = DD_GetHotNColdCount(&hotNColdPixelSize);
  if (error) return ErrorManager(error);

  printf("%zu leaky pixels found.\n", leakyPixelSize);
  printf("%zu hot/cold pixels found.\n", hotNColdPixelSize);

  // Leaky and hot/cold pixels are equally defective for the purposes of
  // the correction algorithm. Create a unique array and retrive the pixels.
  // Perform the correction with the dedicated GenICam nodes.
  size_t totDefectPixel = leakyPixelSize + hotNColdPixelSize;
  DefectivePixel* defectivePixels =
      (DefectivePixel*)malloc(sizeof(DefectivePixel) * totDefectPixel);
  for (size_t i = 0; i < leakyPixelSize; i++) {
    error = DD_GetLeakyByIndex(i, &defectivePixels[i]);
    if (error) return ErrorManager(error);
  }
  for (size_t i = 0; i < hotNColdPixelSize; i++) {
    error = DD_GetHotNColdByIndex(i, &defectivePixels[leakyPixelSize + i]);
    if (error) return ErrorManager(error);
  }
  error = CorrectDetectedPixels(defectivePixels, totDefectPixel, hNodeMap);
  if (error) return ErrorManager(error);

  error = DD_Dispose(hDefDetMono8);
  hDefDetMono8 = NULL;
  if (error) return ErrorManager(error);
  printf("\nMono8 detection instance disposed.\n");

  error = NODE_IntegerSetValue(hNodeWidth, originalWidth);
  if (error) return ErrorManager(error);
  error = NODE_IntegerSetValue(hNodeHeight, originalHeight);
  if (error) return ErrorManager(error);
  error = NODE_EnumerationSetIntValue(hNodePixelFormat, originalPixelFormat);
  if (error) return ErrorManager(error);

  error = DEV_Dispose(hDevice);
  hDevice = NULL;
  if (error) return ErrorManager(error);
  printf("Device instance disposed.\n");

  error = SYS_Dispose();
  if (error) return ErrorManager(error);
  printf("System instance disposed.\n");
  return 0;
}