ImageDev

Processing

ImageDev processing features allow the application of computational algorithms on data extracted from images.
ImageDev contains different types of algorithms:

Class and Function programming modes

ImageDev provides two modes for invoking an image processing algorithm: a class and a function programming mode.
Each algorithm documentation exposes two code snippets illustrating the use of both modes.

Function mode

In Function programming mode, the algorithm is directly launched when calling the function.
The result can be obtained either as a returned value, or as the last parameter(s) of the function prototype. This mode is simpler to use for algorithms with few parameters and, in some ways, in languages where parameters can be omitted, like in Python. This mode saves memory by reusing already allocated data which can be, for eligible algorithms, the input data (in situ processing).

With function mode, outputs are returned by the function. When an algorithm generates several outputs: Image outputs also can be returned as parameters of the function. This option is particularly useful for reusing the allocated memory of a temporary image or working in situ when the algorithm is eligible.

Class mode

In Class programming mode, the algorithm is instantiated as a class object and is launched when calling its execute() method.
This mode is simpler to use for algorithms with many parameters, when most of parameters have to keep their default value.
With class mode, a parameter can be: To save memory, it is possible to set already allocated data as output which can be, for eligible algorithms, the input data (in situ processing). If the output data is not set, new data is allocated.

Naming conventions

Capitalization Rules

For a given type of identifier, ImageDev uses the recommended case in each language. $$ \begin{array}{|l|l|l|l|} \hline \textbf{Type of Identifier} & \textbf{C++ Case} & \textbf{Python Case} & \textbf{C# Case}\\ \hline \textbf{Class} & \mbox{PascalCase} & \mbox{PascalCase} & \mbox{PascalCase}\\ \hline \textbf{Function} & \mbox{camelCase} & \mbox{snake_case} & \mbox{PascalCase}\\ \hline \textbf{Class method} & \mbox{camelCase} & \mbox{snake_case} & \mbox{PascalCase}\\ \hline \textbf{Argument} & \mbox{camelCase} & \mbox{snake_case} & \mbox{camelCase}\\ \hline \textbf{Enumerate Type} & \mbox{PascalCase} & \mbox{PascalCase} & \mbox{PascalCase}\\ \hline \textbf{Enumerate Value} & \mbox{SCREAMING_SNAKE_CASE} & \mbox{SCREAMING_SNAKE_CASE} & \mbox{SCREAMING_SNAKE_CASE}\\ \hline \end{array} $$

Dimensional compatibility

ImageDev algorithm names may end with 2d or 3d:

Parameter naming

Input and output data

An algorithm parameter (a function argument or a class member) can be: By convention: A parameter name beginning with input or output represents data. A key-word specifies the type of data:

Kernel size parameters

In many ImageDev processing filters, a parameter represents the size of a moving window applied on the input image to compute the output image. Generally, this window is a square in 2D and a cube in 3D which must have an odd side length in pixels, but, in some cases, it also can be a disk or a ball.
By convention:

Disk processing

ImageDev disk processing features allow the application of computational algorithms on data stored on disk.
To access an image stored on disk without loading the whole data set into memory, the "ioformat::openView" function should be used rather than the "ioformat::readImage" function.
To create temporary images on disk, the "iolink::ImageViewFactory::allocateOnDisk" function should be used. The associated file is automatically deleted when the image is no longer used.
The following example illustrates the use of disk images.

Example

// ImageDev library initialization
imagedev::init();
// Open a tif file
auto viewInput = ioformat::openView( std::string( IMAGEDEVDATA_IMAGES_FOLDER ) + "hello_imagedev.tif" );
auto imageInput = iolink::ImageViewProvider::toImage( viewInput );
// Create the temporary image to store the result of the normalization
auto imageNorm =
    iolink::ImageViewFactory::allocateOnDisk( "tmp_norm.raw", { 1, 1 }, iolink::DataTypeId::UINT8 );
// Apply a normalization of its graylevels using function coding style
imagedev::rescaleIntensity( imageInput,
                            imagedev::RescaleIntensity::OutputType::SAME_AS_INPUT,
                            imagedev::RescaleIntensity::RangeMode::PERCENTILE,
                            { 2, 98 },
                            { 0, 255 },
                            { 0, 255 },
                            imageNorm );
// Create the temporary image to store the result of the median filter
auto imageMedian =
    iolink::ImageViewFactory::allocateOnDisk( "tmp_median.raw", { 1, 1 }, iolink::DataTypeId::UINT8 );
// Apply a median filter processing using class coding style
{
    imagedev::MedianFilter2d processMedian;
    processMedian.setInputImage( imageNorm );
    processMedian.setKernelMode( imagedev::MedianFilter2d::KernelMode::DISK );
    processMedian.setKernelRadius( 1 );
    processMedian.setOutputImage( imageMedian );
    processMedian.execute();
}
// Force the free of the temporary image; The temporary file will be deleted.
// Without it, the temporary image will be freed when it will be no longer used (at the end of the scope).
imageNorm.reset();
// Export the resulting image as a png file
ioformat::writeView( iolink::ImageViewProvider::toRead( imageMedian ),
                     "hello_imagedev_output.png" );
// Free the temporary image; The temporary file will be deleted.
imageMedian.reset();
// ImageDev library finalization
imagedev::finish();
      
import imagedev as id
import imagedev_data
import ioformat
import iolink
# ImageDev library initialization
id.init()
# Open and display a tif file
image_input = ioformat.open_view(imagedev_data.get_image_path("hello_imagedev.tif"))
# Create the temporary image to store the result of the normalization
image_norm = iolink.ImageViewFactory.allocate_on_disk("tmp_norm.raw",
                                                      iolink.VectorXu64(1, 1), iolink.DataTypeId_UINT8,
                                                      None, None)
# Apply a normalization of its graylevels using function coding style
image_norm = id.rescale_intensity(image_input, range_mode=id.RescaleIntensity.RangeMode.PERCENTILE,
                                  output_image=image_norm)
# Create the temporary image to store the result of the median filter
image_median = iolink.ImageViewFactory.allocate_on_disk("tmp_median.raw",
                                                        iolink.VectorXu64(1, 1), iolink.DataTypeId_UINT8,
                                                        None, None)
# Apply a median filter processing using class coding style
process_median = id.MedianFilter2d()
process_median.input_image = image_norm
process_median.kernel_mode = id.MedianFilter2d.KernelMode.DISK
process_median.kernel_radius = 1
process_median.output_image = image_median
process_median.execute()
# Force the free of the processing class; This removes the links between the class and the input and output images.
process_median = None
# Force the free of the temporary image; The temporary file will be deleted.
# Without it, the temporary image will be freed when it will be no longer used (at the end of the scope).
image_norm = None
# Export the resulting image as a png file
ioformat.write_view(image_median, "hello_imagedev_output.png")
# Free the temporary image; The temporary file will be deleted.
image_median = None
# ImageDev library finalization
id.finish()
      
// ImageDev library initialization
Initialization.Init();
// Open a tif file
View viewInput = IOFormat.ViewIO.OpenView(@"Data/images/hello_imagedev.tif");
ImageView imageInput = IOLink.ImageViewProvider.ToImage(viewInput);
// Create the temporary image to store the result of the normalization
ReadImageView imageNorm = IOLink.ImageViewFactory.AllocateOnDisk(@"Data/images/tmp_norm.raw",
                                                                 new VectorXu64(1, 1),
                                                                 IOLink.DataTypeId.UINT8);
// Apply a normalization of its graylevels using function coding style
Processing.RescaleIntensity(imageInput, RescaleIntensity.OutputType.SAME_AS_INPUT,
                            RescaleIntensity.RangeMode.PERCENTILE,
                            new double[] { 2, 98 }, new double[] { 0, 255 },
                            new double[] { 10, 228 }, imageNorm);
// Create the temporary image to store the result of the median filter
ReadImageView imageMedian = IOLink.ImageViewFactory.AllocateOnDisk(@"Data/images/tmp_median.raw",
                                                                   new VectorXu64(1, 1),
                                                                   IOLink.DataTypeId.UINT8);
// Apply a median filter processing using class coding style
MedianFilter2d processMedian = new MedianFilter2d
{
    inputImage = imageNorm,
    kernelMode = MedianFilter2d.KernelMode.DISK,
    kernelRadius = 1,
    outputImage = imageMedian
};
processMedian.Execute();
// Notify the garbage collector that the class can be freed and remove links with input and output images.
processMedian.Dispose();
// Notify the garbage collector that the intermediate image can be freed
// The temporary file will be deleted
imageNorm.Dispose();
// Export the resulting image as a png file
IOFormat.ViewIO.WriteView(imageMedian, @"Data/images/hello_imagedev_output.png");
// Notify the garbage collector that the intermediate image can be freed
// The temporary file will be deleted
imageMedian.Dispose();
// ImageDev library finalization
Initialization.Finish();