/***********************************************************************************
*
* 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 DefectivePixelCorrection.cpp
*
* @brief "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.
*
* @see LiquidLens.cpp
*/
// Include Itala API
#include "ItalaApi/Itala.h"
// Include the GenICam library
#include "GenICam.h"
#define INDENT "\t"
#define ACQ_COUNT 10
// Pixel correction process enclosed in a separate function for
// better example readability.
void CorrectDetectedPixels(Itala::DefectivePixelList defectivePixels, GenApi::INodeMap& nodemap)
{
// Start by setting the amount of pixel targeted for correction.
GenApi::CIntegerPtr pDefectivePixelCount = nodemap.GetNode("oeDefectivePixelCount");
if (!IsWritable(pDefectivePixelCount))
throw GENERIC_EXCEPTION("Unable to set the number of pixels to be corrected. Aborting.");
pDefectivePixelCount->SetValue(defectivePixels.size());
std::cout << INDENT << "Correction procedure started with " << defectivePixels.size() << " pixels." << std::endl;
// Get the pixel selector to iterate over the amount of targeted pixels.
GenApi::CIntegerPtr pDefectivePixelSelector = nodemap.GetNode("oeDefectivePixelSelector");
if (!IsWritable(pDefectivePixelSelector))
throw GENERIC_EXCEPTION("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.
GenApi::CIntegerPtr pDefectivePixelXCoordinate = nodemap.GetNode("oeDefectivePixelXCoordinate");
if (!IsWritable(pDefectivePixelXCoordinate))
throw GENERIC_EXCEPTION("Unable to set the X coordinate of the target pixel. Aborting.");
GenApi::CIntegerPtr pDefectivePixelYCoordinate = nodemap.GetNode("oeDefectivePixelYCoordinate");
if (!IsWritable(pDefectivePixelYCoordinate))
throw GENERIC_EXCEPTION("Unable to set the Y coordinate of the target pixel. Aborting.");
// Set the coordinates of every targeted pixels.
for (size_t i = 0; i < defectivePixels.size(); i++)
{
pDefectivePixelSelector->SetValue(i);
pDefectivePixelXCoordinate->SetValue(defectivePixels[i].X());
pDefectivePixelYCoordinate->SetValue(defectivePixels[i].Y());
std::cout << INDENT << "Pixel [" << defectivePixels[i].X() << ","
<< defectivePixels[i].Y() << "]" << " registered for correction. Was " <<
defectivePixels[i].TypeString() << "." << std::endl;
}
// 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.
GenApi::CCommandPtr pDefectivePixelWriteMap = nodemap.GetNode("oeDefectivePixelWriteMap");
if (!IsWritable(pDefectivePixelWriteMap))
throw GENERIC_EXCEPTION("Unable to write the pixel map to device memory. Aborting.");
pDefectivePixelWriteMap->Execute();
std::cout << std::endl << INDENT << "Correction command sent, procedure completed." << std::endl;
}
void DefectivePixelCorrection_Sample()
{
std::cout << "***** DefectivePixelCorrection 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 initialized." << std::endl;
// 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.
GenApi::CIntegerPtr pWidth = pDevice->GetNodeMap().GetNode("Width");
if (!IsWritable(pWidth))
throw GENERIC_EXCEPTION("Unable to configure the image width. Aborting.");
int64_t originalWidth = pWidth->GetValue();
int64_t maxWidth = pWidth->GetMax();
pWidth->SetValue(maxWidth);
std::cout << std::endl << INDENT << "Image width set to " << maxWidth << std::endl;
GenApi::CIntegerPtr pHeight = pDevice->GetNodeMap().GetNode("Height");
if (!IsWritable(pHeight))
throw GENERIC_EXCEPTION("Unable to configure the image height. Aborting.");
int64_t originalHeight = pHeight->GetValue();
int64_t maxHeight = pHeight->GetMax();
pHeight->SetValue(maxHeight);
std::cout << INDENT << "Image height set to " << maxHeight << std::endl;
GenApi::CEnumerationPtr pPixelFormat = pDevice->GetNodeMap().GetNode("PixelFormat");
if (!IsWritable(pHeight))
throw GENERIC_EXCEPTION("Unable to configure the image pixel format. Aborting.");
int64_t originalPixelFormat = pPixelFormat->GetIntValue();
GenApi::CEnumEntryPtr pMono8Entry = pPixelFormat->GetEntryByName("Mono8");
int64_t mono8Format = pMono8Entry->GetValue();
pPixelFormat->SetIntValue(mono8Format);
std::cout << INDENT << "PixelFormat set to Mono8." << std::endl;
// Create a detection interface for the current image size and pixel depth.
Itala::IDefectDetection* mono8Detection =
Itala::CreateDefectDetection(maxWidth, maxHeight, Itala::PixelDepth::d8Bit);
pDevice->StartAcquisition();
std::cout << std::endl << INDENT << "Acquisition started." << std::endl;
// 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.
std::cout << INDENT << "Accumulating dark data.." << std::endl;
for (int i = 0; i < ACQ_COUNT; i++)
{
Itala::IImage* dark_image = pDevice->GetNextImage(500);
// Accumulate the new dark image. Note that the function requires
// the raw data pointer, not the IImage itself!
mono8Detection->AccumulateDark((uint8_t*)dark_image->GetData());
std::cout << INDENT << "Image " << i + 1 << " added." << " \r";
std::cout.flush();
dark_image->Dispose();
}
// Acquire the gray images needed for hot/cold detection.
std::cout << std::endl << INDENT << "Accumulating gray data.." << std::endl;
for (int i = 0; i < ACQ_COUNT; i++)
{
Itala::IImage* gray_image = pDevice->GetNextImage(500);
// Accumulate the new gray image. Note that the function requires
// the raw data pointer, not the IImage itself!
mono8Detection->AccumulateGray((uint8_t*)gray_image->GetData());
std::cout << INDENT << "Image " << i + 1 << " added." << " \r";
std::cout.flush();
gray_image->Dispose();
}
pDevice->StopAcquisition();
std::cout << std::endl << INDENT << "Acquisition stopped." << std::endl;
// Find and get the leaky pixels of the sensor.
Itala::DefectivePixelList leakyPixels = mono8Detection->FindLeaky(1024, 5);
// Same for hot/cold pixels.
Itala::DefectivePixelList hotNColdPixels = mono8Detection->FindHotNCold(1024, 5);
std::cout << leakyPixels.size() << " leaky pixels found." << std::endl;
std::cout << hotNColdPixels.size() << " hot/cold pixels found." << std::endl << std::endl;
// 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.insert(leakyPixels.end(), hotNColdPixels.begin(), hotNColdPixels.end());
CorrectDetectedPixels(leakyPixels, pDevice->GetNodeMap());
// Dispose the detection interface when done.
mono8Detection->Dispose();
mono8Detection = nullptr;
std::cout << std::endl << "Mono8 detection instance disposed." << std::endl;
// Restore the original image size and format.
pWidth->SetValue(originalWidth);
pHeight->SetValue(originalHeight);
pPixelFormat->SetIntValue(originalPixelFormat);
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
{
DefectivePixelCorrection_Sample();
}
catch (GenICam::GenericException& e)
{
std::cout << e.what() << std::endl;
}
}