ImageDev

Data Transfer

This example illustrates how to create a data buffer corresponding to a 3D image, and transfer it in an object connectable to an ImageDev algorithm, without duplicating the data.
To invoke an ImageDev algorithm, the data to process needs to be previously imported into an ImageView object of the IOLink library.

The two previous examples show how to create an ImageView from an existing buffer by copying the data. This way to proceed is safe and prevents conflicts of data ownership. However, when handling large data, it may be preferable to make the ImageView object directly point to the buffer without duplicating its content.

The first part of this example simply creates a buffer representing a 220x192x128 pixel image with a filled sphere drawn inside. This step is for demonstration purposes only. In practice, you should already have the content of the image to process in a buffer stored in the data model used by your application.

Then some IOLink instructions create a new ImageView object. The buffer previously created is set in this image with the fromBuffer method of the ImageViewFactory class. This method does not duplicate the data, thus optimizing the memory usage.

Two ImageDev algorithms are applied afterward to show that it is now possible to process this image with ImageDev.
<b>Figure 1.</b> The 3D volume generated by this example visualized with Open Inventor
Figure 1. The 3D volume generated by this example visualized with Open Inventor

Note:
The last operator adds the values of an 8-bit signed integer image to those of an 8-bit unsigned integer image. The result is a 16-bit signed integer image, as explained in the Basic Rule table of the Rules for Arithmetic Image Type section.

#include <ImageDev/ImageDev.h>
#include <ioformat/IOFormat.h>
#include <iolink/view/ImageViewFactory.h>
#include <iolink/view/ImageViewProvider.h>
#include <string.h>

using namespace imagedev;
using namespace ioformat;
using namespace iolink;

int
main( int argc, char* argv[] )
{
    int status = 0;

    try
    {
        // ImageDev library initialization
        if ( imagedev::isInitialized() == false )
            imagedev::init();

        // Initialize an unsigned 8-bit array storing data of a 3D image
        const uint64_t rowCount = 220;
        const uint64_t colCount = 192;
        const uint64_t sliCount = 128;
        std::vector< uint8_t > imageData( rowCount * colCount * sliCount );

        // Define a synthetic sphere in this array
        const int squareRadius = ( sliCount / 2 - 10 ) * ( sliCount / 2 - 10 ); // Radius of the sphere to draw
        int distToCenter;

        // Loop on image slices
        for ( int k = 0; k < sliCount; ++k )
        {
            // Loop on image rows
            for ( int i = 0; i < rowCount; ++i )
            {
                // Loop on image columns
                for ( int j = 0; j < colCount; ++j )
                {
                    distToCenter = ( i - rowCount / 2 ) * ( i - rowCount / 2 ) +
                                   ( j - colCount / 2 ) * ( j - colCount / 2 ) +
                                   ( k - sliCount / 2 ) * ( k - sliCount / 2 );
                    if ( distToCenter <= squareRadius )
                        imageData[k * rowCount * colCount + i * colCount + j] = 200; // Value inside the sphere
                    else
                        imageData[k * rowCount * colCount + i * colCount + j] = 0; // Background value
                }
            }
        }

        // Create an image view of same dimensions directly from this buffer
        VectorXu64 imageShape{ colCount, rowCount, sliCount };
        auto image = ImageViewFactory::fromBuffer(
            imageShape, DataTypeId::UINT8, imageData.data(), rowCount * colCount * sliCount * sizeof( uint8_t ) );
        image->setAxesInterpretation( ImageTypeId::VOLUME );

        // This image can now be processed by any ImageDev algorithm, for instance to add a Gaussian noise inside
        auto imageNoise = randomGaussianImage3d(
            RandomGaussianImage3d::OutputType::SIGNED_INTEGER_8_BIT, colCount, rowCount, sliCount, 0.0f, 20.0f );
        auto imageOut =
            arithmeticOperationWithImage( image, imageNoise, ArithmeticOperationWithImage::ArithmeticOperator::ADD );

        // Save the created image with IOFormat
        writeView( imageOut, "T02_03_output.tif" );

        std::cout << "This example ran successfully." << std::endl;
    }
    catch ( const imagedev::Exception& error )
    {
        // Print potential exception in the standard output
        std::cerr << "ImageDev exception: " << error.what() << std::endl;
        status = -1;
    }

    // ImageDev library finalization
    imagedev::finish();

    // Check if we must ask for an enter key to close the program
    if ( !( ( argc == 2 ) && strcmp( argv[1], "--no-stop-at-end" ) == 0 ) )
        std::cout << "Press Enter key to close this window." << std::endl, getchar();

    return status;
}


See also