/***********************************************************************************
*
* Itala API - Copyright (C) 2024 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 Polarization.cpp
*
* @brief "Polarization" example shows how to process images containing light polarization data.
* Polarization images are similar to bayer color images since they need to be demosaiced and
* processed to determine the state of polarized light.
*
* @warning
* The following example shows a complete workflow for monochrome polarization images including
* polarization components and Stokes vector computation. To get images like AoLP, DoLP and
* intensity directly, a dedicated overload set is available.
*/
// Include ItalaApi
#include "ItalaApi/Itala.h"
// Include the GenICam library
#include "GenICam.h"
#define INDENT "\t"
#define PIXEL_FORMAT "Polarized00Mono8"
void Polarization_Sample() {
std::cout << "***** Polarization 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]);
GenApi::INodeMap& deviceNodeMap = pDevice->GetNodeMap();
// Set the pixelformat to Polarized00Mono8 or whatever format is available on the camera.
GenApi::CEnumerationPtr pPixelFormat = deviceNodeMap.GetNode("PixelFormat");
if (!IsWritable(pPixelFormat))
throw GENERIC_EXCEPTION("Unable to configure the pixel format. Aborting.");
uint64_t originalPixelFormat = pPixelFormat->GetIntValue();
pPixelFormat->FromString(PIXEL_FORMAT);
std::cout << "PixelFormat set to " << PIXEL_FORMAT << std::endl;
std::cout << "First device initialized." << std::endl;
pDevice->StartAcquisition();
std::cout << "Acquisition started." << std::endl << std::endl;
Itala::IImage* pImage = pDevice->GetNextImage(1000);
// Clone the grabbed image for convenience so that it can be returned to the library and the
// acquisition can be stopped.
Itala::IImage* pPolarizationImage = pImage->Clone();
pImage->Dispose();
pImage = nullptr;
pDevice->StopAcquisition();
// Extract an image for each component (or angle) of the polarizer filter. Each resulting image
// represents the captured light at 0, 45, 90 and 135 degrees respectively. Depending on the
// demosaicing algorithm used, the pixel format of the resulting images can be of different types.
// NearestNeighbour on Polarized00Mono8 produces Mono8 components.
std::cout << "Extracting all polarization components.. ";
Itala::PolarComponents polarizationComponents = Itala::ExtractAllPolarComponents(
pPolarizationImage, Itala::PolarDemosaicingAlgorithm::NearestNeighbour);
std::cout << "P45 format is "
<< GetPixelFormatDescription(polarizationComponents.P45->GetPixelFormat()) << std::endl;
// display or process polarization components
// Compute all the Stokes vectors to determine the polarization state of the light given the
// intensities of the different polarizers on the sensor. Since we're dealing with linear
// polarization data, only the first three (s0, s1 and s2) components of the vector are available.
// Each resulting image represents the values of that particular component of the Stokes vector
// across the whole sensor. For instance, the S0 image contains the s0 values of each pixel.
std::cout << "Computing all stokes vectors.. ";
Itala::StokesVectors stokesVectors = Itala::ComputeAllStokes(polarizationComponents);
std::cout << "S0 format is " << GetPixelFormatDescription(stokesVectors.S0->GetPixelFormat())
<< std::endl;
// display or process the Stokes vectors
// Given the stokes vectors, compute the linear polarization images.
// The DoLP (Degree of Linear Polarization) image indicates the ratio of the intensity of the
// polarized part of the light to the intensity of the unpolarized one. When the light is totally
// polarized, this corresponds to the total intensity of the light. When the light is unpolarized,
// this corresponds to zero.
// The AoLP (Angle of Linear Polarization) image indicates the polarization direction of the
// incoming light.
// The intensity image simply indicate the total intensity of the incoming light.
std::cout << std::endl << "Computing linear polarization images.." << std::endl;
Itala::IImage* pDolpImage = Itala::ComputeDoLP(stokesVectors);
Itala::IImage* pAolpImage = Itala::ComputeAoLP(stokesVectors);
Itala::IImage* pIntensityImage =
Itala::ComputeIntensity(stokesVectors, pPolarizationImage->GetPixelFormat());
std::cout << "DoLP format is " << GetPixelFormatDescription(pDolpImage->GetPixelFormat())
<< std::endl;
std::cout << "AoLP format is " << GetPixelFormatDescription(pAolpImage->GetPixelFormat())
<< std::endl;
std::cout << "Intensity format is "
<< GetPixelFormatDescription(pIntensityImage->GetPixelFormat()) << std::endl;
// display or process the images
// From the source image, compute an image of the same size divided in four quadrants containing
// the four polarization components.
std::cout << std::endl << "Computing quadrants image.. ";
Itala::IImage* pQuadrantsImage = Itala::ComputePolarQuadrantsImage(pPolarizationImage);
std::cout << "format is " << GetPixelFormatDescription(pQuadrantsImage->GetPixelFormat())
<< std::endl;
// Display or process the quadrants image
// If intermediate data like polar components or stokes vectors is not needed, monochrome AoLP,
// DoLP and intensity can be directly computed with the dedicated functions given the polarized
// image. For instance, DoLP:
std::cout << std::endl << "Computing DoLP without intermediate steps.." << std::endl;
Itala::IImage* pDirectDolp =
Itala::ComputeDoLP(pPolarizationImage, Itala::PolarDemosaicingAlgorithm::NearestNeighbour);
// Display or process DoLP
// Restore the original pixel format value
pPixelFormat->SetIntValue(originalPixelFormat);
// Each image MUST be disposed so that its memory is released. In real scenarios it's a good idea
// to release the images as long as they're no longer required to keep the memory footprint low.
// To prevent leaks, a dedicated set of functions is available in the Smart.h header.
pPolarizationImage->Dispose();
polarizationComponents.P0->Dispose();
polarizationComponents.P45->Dispose();
polarizationComponents.P90->Dispose();
polarizationComponents.P135->Dispose();
stokesVectors.S0->Dispose();
stokesVectors.S1->Dispose();
stokesVectors.S2->Dispose();
pDolpImage->Dispose();
pAolpImage->Dispose();
pIntensityImage->Dispose();
pQuadrantsImage->Dispose();
pDirectDolp->Dispose();
std::cout << std::endl << "Image istances disposed." << std::endl;
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 {
Polarization_Sample();
} catch (GenICam::GenericException& e) {
std::cout << e.what() << std::endl;
}
}