Convert between itk and napari data structures.
pip install itk-napari-conversionConvert an itk.Image to a napari.layers.Image:
from itk_napari_conversion import image_layer_from_image
image_layer = image_layer_from_image(image)Features:
- Automatically detects and handles RGB/RGBA images
- Preserves image metadata (spacing, origin, direction, custom metadata)
- Converts ITK's physical space information to napari's layer transformations:
spacing→scaleorigin→translatedirection→rotate
Example:
import itk
import napari
from itk_napari_conversion import image_layer_from_image
# Read an image
image = itk.imread('path/to/image.nrrd')
# Add custom metadata
image['units'] = 'mm'
image['patient_id'] = '12345'
# Convert to napari layer
image_layer = image_layer_from_image(image)
# The layer will have:
# - image_layer.scale = image spacing (in reverse order for NumPy)
# - image_layer.translate = image origin (in reverse order for NumPy)
# - image_layer.rotate = image direction matrix (in reverse order for NumPy)
# - image_layer.metadata = all custom metadataConvert a napari.layers.Image to an itk.Image:
from itk_napari_conversion import image_from_image_layer
image = image_from_image_layer(image_layer)Features:
- Automatically handles RGB/RGBA layers
- Converts napari layer transformations back to ITK physical space:
scale→spacingtranslate→originrotate→direction
- Preserves all metadata from the layer
Example:
import numpy as np
import napari
from itk_napari_conversion import image_from_image_layer
# Create a napari image layer with transformations
viewer = napari.Viewer()
data = np.random.rand(100, 100, 100)
# 45 degree rotation around z-axis
angle = np.radians(45)
rotate = np.array([
[np.cos(angle), -np.sin(angle), 0],
[np.sin(angle), np.cos(angle), 0],
[0, 0, 1]
], dtype=np.float64)
layer = viewer.add_image(
data,
scale=[2.0, 1.5, 1.5], # anisotropic spacing
rotate=rotate,
translate=[10.0, 20.0, 30.0],
metadata={'description': 'My volume'}
)
# Convert to ITK
image = image_from_image_layer(layer)
# The ITK image will have:
# - spacing: coordinates in ITK order, so reversed from napari `scale`: [1.5, 1.5, 2.0]
# - origin: coordinates in ITK order, so reversed from napari `translate`: [30.0, 20.0, 10.0]
# The ITK image will have:
# - spacing: coordinates in ITK order, so reversed from napari `scale`: [1.5, 1.5, 2.0]
# - origin: coordinates in ITK order, so reversed from napari `translate`: [30.0, 20.0, 10.0]
# - direction: transpose of napari `rotate` matrix
# Access the direction matrix via dictionary access (recommended):
direction = image["direction"]
print(direction)
# [[0.70710678 0.70710678 0. ]
# [-0.70710678 0.70710678 0. ]
# [0. 0. 1. ]]
# This is the transpose of napari's rotate matrix:
# [[cos(45°), sin(45°), 0],
# [-sin(45°), cos(45°), 0],
# [0, 0, 1]]
# Note: image.GetDirection() may return a different matrix because it accesses
# the underlying ITK image metadata differently. Use dictionary access for
# consistency with how the direction was set.Convert an itk.PointSet to a napari.layers.Points:
from itk_napari_conversion import points_layer_from_point_set
points_layer = points_layer_from_point_set(point_set)Features:
- Extracts point coordinates from ITK PointSet using
itk.array_from_vector_container() - Converts point data (if present) to napari features dictionary
- Uses the first component as the 'feature' key
- Returns a
napari.layers.Pointsobject
Example:
import itk
import numpy as np
from itk_napari_conversion import points_layer_from_point_set
# Create ITK PointSet
PointSetType = itk.PointSet[itk.F, 3]
point_set = PointSetType.New()
# Add points
points_data = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]], dtype=np.float32)
points = itk.vector_container_from_array(points_data.flatten())
point_set.SetPoints(points)
# Add point data (features)
feature_data = np.array([10.0, 20.0], dtype=np.float32)
point_data = itk.vector_container_from_array(feature_data)
point_set.SetPointData(point_data)
# Convert to napari
points_layer = points_layer_from_point_set(point_set)
# points_layer.features['feature'] will contain [10.0, 20.0]Convert a napari.layers.Points to an itk.PointSet:
from itk_napari_conversion import point_set_from_points_layer
point_set = point_set_from_points_layer(points_layer)Features:
- Applies napari transformations (scale, rotate, translate) to point coordinates before conversion
- Extracts points from napari layer data
- Converts the first feature column (if present) to ITK point data
- Returns an
itk.PointSetobject with dimension determined from the data
Example:
import napari
import numpy as np
from itk_napari_conversion import point_set_from_points_layer
# Create napari Points layer with transformations
data = np.array([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
features = {'intensity': np.array([10.0, 20.0])}
scale = np.array([2.0, 2.0, 2.0])
translate = np.array([100.0, 200.0, 300.0])
# Optional: add rotation (90 degrees around z-axis)
angle = np.radians(90)
rotate = np.array([
[np.cos(angle), -np.sin(angle), 0],
[np.sin(angle), np.cos(angle), 0],
[0, 0, 1]
])
points_layer = napari.layers.Points(
data,
features=features,
scale=scale,
rotate=rotate,
translate=translate
)
# Convert to ITK PointSet
point_set = point_set_from_points_layer(points_layer)
# The points in the ITK PointSet will be in world coordinates:
# ((data * scale) @ rotate.T) + translate
# Point data will be stored from the 'intensity' feature- ITK → napari: Physical space metadata (spacing, origin, direction) is converted to napari layer transformations
- napari → ITK: Layer transformations are converted back to ITK physical space metadata
- ITK → napari: Points are copied as-is without transformations (identity transform assumed)
- napari → ITK: Layer transformations (scale, rotate, translate) are applied to points to convert them to world coordinates
- Transformations are applied in order: scale → rotate → translate
Images:
- Supports 2D, 3D, and multi-dimensional images
- RGB and RGBA images are automatically detected and handled
- Axis order is automatically reversed between ITK (x, y, z) and NumPy/napari (z, y, x)
- Metadata is preserved bidirectionally
Points:
- Point data in ITK is stored as float32
- Only the first feature column from napari is used for ITK point data
- Empty point sets are handled gracefully
- Dimension is automatically determined from the point data shape
- Metadata conversion is not currently supported for point sets
Contributions are welcome!
To test locally:
git clone https://github.com/InsightSoftwareConsortium/itk-napari-conversion.git
cd itk-napari-conversation
pip install flit pytest
flit install --symlink
pytest tests.py
Follow the itk contributing guidelines and the itk code of conduct.