Interface ITK with NumPy Array#
Synopsis#
This example illustrates interfacing ITK Image data with NumPy array. While doing this, there are two key issues to keep in mind. One, the order of indexes is different between ITK image data class and NumPy array. Second, there are two ways to access ITK image data as a NumPy array. i) Get direct access to memory with the data called”View” functions, or ii) Copy the data using array_from_image function. If the view functions are used, the data can’t be modified.
Results#
The size of the ITK image data read from the input file = itkSize2 ([221, 257])
The size of the NumPy array viewed from itk::Image = (257, 221) The size of the NumPy array copied from itk::Image = (257, 221) ITK image data size after convesion from NumPy = itkSize2 ([221, 257])
ITK image data pixel value at [2,1] = 6 NumPy array pixel value at [2,1] = 8
Code#
Python#
#!/usr/bin/env python
import sys
import itk
import numpy as np
if len(sys.argv) != 3:
print("Usage: " + sys.argv[0] + " <input_image> <output_image>")
sys.exit(1)
# Parse comamnd line arguments
input_file_name = sys.argv[1]
output_file_name = sys.argv[2]
# Read input image
PixelType = itk.ctype("unsigned char")
ImageType = itk.Image[itk.UC, 2]
itk_image = itk.imread(input_file_name, PixelType)
OriginalRegion = itk_image.GetLargestPossibleRegion()
OriginalSize = OriginalRegion.GetSize()
print(f"The size of the ITK image data read from the input file = {OriginalSize}\n")
# There are two ways to bridge the data structures.
# i) Give direct access to memory holding the data called "View" functions for displaying
# purpose. But you can't modify the data
np_view_array = itk.GetArrayViewFromImage(itk_image, ttype=ImageType)
print(f"The size of the NumPy array viewed from itk::Image = {np_view_array.shape}")
# ii) Generate a copy of the data using using array_from_image function.
# You can then freely modify the data as it has no effect on the original ITK image.
# Copy itk.Image pixel data to numpy array
np_array = itk.GetArrayFromImage(itk_image, ttype=ImageType)
print(f"The size of the NumPy array copied from itk::Image = {np_array.shape}")
# Create an ITK image from the numpy array and then write it out
itk_np = itk.GetImageFromArray(np.ascontiguousarray(np_array))
region = itk_np.GetLargestPossibleRegion()
size = region.GetSize()
print(f"ITK image data size after convesion from NumPy = {size}\n")
itk.imwrite(itk_np, output_file_name)
# The order of the indexes is according to the type of object the data is stored in.
# A numpy array is indexed by [row , col ] for 2D data or [slice , row , col ] for 3D data.
# While ITK image data is indexed by (x , y ) for 2D or (x , y , z ) for 3D data.
# To demonstrate here, we create a 2D pixel array data
# and access a pixel with the same indices
np_data = np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]], np.int32)
itk_np_view_data = itk.image_view_from_array(np_data)
print(f"ITK image data pixel value at [2,1] = {itk_np_view_data.GetPixel([2,1])}")
print(f"NumPy array pixel value at [2,1] = {np_data[2,1]}")
Classes demonstrated#
-
template<typename TPixel, unsigned int VImageDimension = 2>
class Image : public itk::ImageBase<VImageDimension> Templated n-dimensional image class.
Images are templated over a pixel type (modeling the dependent variables), and a dimension (number of independent variables). The container for the pixel data is the ImportImageContainer.
Within the pixel container, images are modelled as arrays, defined by a start index and a size.
The superclass of Image, ImageBase, defines the geometry of the image in terms of where the image sits in physical space, how the image is oriented in physical space, the size of a pixel, and the extent of the image itself. ImageBase provides the methods to convert between the index and physical space coordinate frames.
Pixels can be accessed directly using the SetPixel() and GetPixel() methods or can be accessed via iterators that define the region of the image they traverse.
The pixel type may be one of the native types; a Insight-defined class type such as Vector; or a user-defined type. Note that depending on the type of pixel that you use, the process objects (i.e., those filters processing data objects) may not operate on the image and/or pixel type. This becomes apparent at compile-time because operator overloading (for the pixel type) is not supported.
The data in an image is arranged in a 1D array as [][][][slice][row][col] with the column index varying most rapidly. The Index type reverses the order so that with Index[0] = col, Index[1] = row, Index[2] = slice, …
- See
ImageBase
- See
ImageContainerInterface
- ITK Sphinx Examples:
Subclassed by itk::GPUImage< TPixel, VImageDimension >