IOLink Python IOL_v1.8.0_release
All Classes Functions Pages
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:

imgView = ImageViewFactory.allocate((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.

imgView = ImageViewFactory.allocate((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:

image = ImageViewFactory.allocate((100, 200), DataTypeId.UINT8)
shape = image.shape
# shape is {100,200}
dtype = image.data_type
# type is datatype::UINT8
properties = image.properties
# a collection of properties of the image
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:

image = ImageViewFactory.allocate((100, 200), DataTypeId.UINT8)
index = VectorXu64(16, 32)
# using bytearray to retrieve read value (best performances)
pixelValue = bytearray(1)
image.read(index, pixelValue)
# using list or tuple to retrieve read value
pixelValue = [0]
image.read(index, pixelValue)
# directly retrieving the value from read method
pixelValue = image.read(index)

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
region = RegionXu64((0, 0), (16, 32))
# allocate a bytearray taking into account region and type sizes
bufferSize = region.element_count * image.data_type.byte_count()
buffer = bytearray(bufferSize)
# read the region content into the bytearray (best performances)
image.read_region(region, buffer)
# or region content is directly returned by read_region
buffer = image.read_region(region)
# or give a correctly sized mutable sequence to read_region to retrieve region content
buffer = [0] * region.element_count * image.data_type.element_count
image.read_region(region, buffer)
# or give an empty mutable sequence to read_region to retrieve region content
buffer = []
image.read_region(region, buffer)
# You can make the method returning an array by removing the last argument
data = image.read_region(region)

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:

# using bytearray
buffer = bytearray([15])
index = VectorXu64(16, 32)
imgView.write(index, buffer)
# or list
buffer = [15]
index = VectorXu64(16, 32)
imgView.write(index, buffer)
# or tuple/value
buffer = (15)
index = VectorXu64(16, 32)
imgView.write(index, buffer)

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

Same thing to write a region of the image:

region = RegionXu64((0, 0), (16, 32))
# Fill a bytearray and write it into the region
bufferSize = region.element_count * image.data_type.byte_count()
buffer = bytearray(bufferSize)
// write data into buffer...
image.write_region(region, buffer)
# Fill a tuple/list/array and write it into the region
buffer = [0] * region.element_count * image.data_type.element_count
image.write_region(region, buffer)

Conclusion

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