IOLink  IOL_v1.6.1_release
Getting started

Introduction

First of all, IOLink does not allow to open and decode files. It is not its purpose. See IOFormat component for this need.

IOLink defines a set of interfaces, mainly inheriting from View, to enable better inter-libraries communication. It also provides some common implementations of these interfaces, like the memory ImageView for example.

Creation of your first ImageView

You can use IOFormat to open a view onto a specific encoded file, if the format is supported. Or you can implement your own reader, that we call extractors, using the ImageView interface.

But, to simply create an in-memory view, from scratch, you can use ImageViewFactory.

The common interfaces implementations, like the in-memory ImageView, are defined in factories. There is a factory for each kind of view in IOLink, with each method outputting a view of this specific interface. Thus, to create an in-memory ImageView, you will use ImageViewFactory as follows:

std::shared_ptr<ImageView> image = ImageViewFactory::allocate(VectorXu64{100, 200}, DataTypeId::UINT8);

With this line of code, you requested to create an empty 2-dimensional ImageView whose size is 100 x 200, and each pixel is a 8 bits unsigned value.

As you can see, views are stored through shared pointers (from C++ standard library), and it ensures that the view's memory will be automatically handled. A memory buffer is allocated to store that image's data, and will only be released when last shared pointer on the view is freed.

You could also request for more complex formats, such as a three-dimensional image, by passing a higher dimension vector as the first parameter.

std::shared_ptr<ImageView> image = ImageViewFactory::allocate(VectorXu64{100, 200, 15}, DataTypeId::UINT16);

This time, a larger memory area (100 x 200 x 15 x 2 bytes) is allocated.

This new image could be a video or a volume. In fact, it could be any kind of three-dimensional image. Currently, it does not matter.

Access to image content

Capabilities

ImageView instances support a set of capabilities, that are needed to call some of its methods.

An ImageView capabilities can be tested in different ways:

// tests if this image support the READ capability
image->capabilities().has(ImageCapability::READ);
// shorter version
image->support(ImageCapability::READ);

Useful image properties

From your ImageView instance, you have access to basic information about the image: shape, data type, properties, and metadata.

You can access this information directly with an ImageView object:

std::shared_ptr<ImageView> image = ImageViewFactory::allocate(VectorXu64{100, 200}, DataTypeId::UINT8);
VectorXu64 shape = image->shape();
// shape is {100,200}
DataType dtype = image->dataType();
// type is datatype::UINT8
std::shared_ptr<const ImageProperties> properties = image->properties();
// a collection of properties of the image
std::shared_ptr<const MetadataNode> metadata = image->metadata();
// the metadata tree of the image

Read pixels

When an ImageView instance supports the READ capability, you can read its pixels. Most of ImageView instances returned by ImageViewFactory support that capability.

You can read one pixel at a time:

std::shared_ptr<ImageView> image = ImageViewFactory::allocate(VectorXu64{100, 200}, DataTypeId::UINT8);
uint8_t pixelValue;
VectorXu64 index{16, 32};
image->read(index, &pixelValue);

With this code, you read the pixel value at position (16,32). The pixelValue variable is of unsigned 8 bits type as in the ImageView data type information.

You also can read a region of your image, as follows:

// create a small region in the image
RegionXu64 region(VectorXu64{0, 0}, VectorXu64{16, 32});
// allocate a memory buffer of region size
size_t bufferSize = region.elementCount() * image->dataType().byteCount();
std::vector<uint8_t> buffer(bufferSize);
// read the region content into the buffer
image->readRegion(region, buffer.data());

Here we read a region defined by its origin and its size in the original image. A memory buffer correctly allocated is needed before calling the method. The RegionXu64 provides a method to get the number of elements in this region.

Write pixels

The WRITE capability of ImageView provides support for methods to write data into the image.

We can write a pixel:

uint8_t pixelValue = 15;
VectorXu64 index{16, 32};
image->write(index, &pixelValue);

Here we wrote the pixel value 15 at position (16, 32) in our image.

Same thing to write a region of the image:

RegionXu64 region(VectorXu64{0, 0}, VectorXu64{16, 32});
size_t bufferSize = region.elementCount() * image->dataType().byteCount();
std::vector<uint8_t> buffer(bufferSize);
// write data into buffer...
image->writeRegion(region, buffer.data());

Conclusion

Now, with these examples, you can apply basic Image modifications in memory. See the How To section for more details.