Skip to content

Transformations

This section covers spatial transformations in ZarrNii, including affine transforms and displacement fields.

Overview

ZarrNii provides support for spatial transformations through the AffineTransform and DisplacementTransform classes. These can be used to apply transformations derived from performing ANTS registration on downsampled (e.g. level > 3) images, then applied to higher resolution (e.g. level < 3) images. ZarrNii performs these computations in a block-wise manner using Dask, upsampling the displacement field for a block before applying it. You can also provide a sequence of transforms to perform composition of transformations to resample in a single step.

Affine Transformations

Creating Affine Transformations

from zarrnii import ZarrNii
from zarrnii.transform import AffineTransform
import numpy as np

# Load a dataset
znimg = ZarrNii.from_nifti("path/to/image.nii")

# Create identity transformation
identity_transform = AffineTransform.identity()

# Create transformation from a matrix
matrix = np.array([
    [2.0, 0.0, 0.0, 10.0],  # Scale X by 2, translate by 10
    [0.0, 2.0, 0.0, -5.0],  # Scale Y by 2, translate by -5
    [0.0, 0.0, 1.0, 0.0],   # No change in Z
    [0.0, 0.0, 0.0, 1.0]    # Homogeneous coordinates
])
transform = AffineTransform.from_array(matrix)

# Load transformation from text file
transform_from_file = AffineTransform.from_txt("transform.txt")

Applying Transformations

# Apply transformation (requires reference image)
ref_znimg = ZarrNii.from_nifti("path/to/reference.nii")
transformed = znimg.apply_transform(transform, ref_znimg=ref_znimg)

Working with Displacement Transformations

from zarrnii.transform import DisplacementTransform

# Load displacement field from NIfTI file
disp_transform = DisplacementTransform.from_nifti("displacement_field.nii")

# Apply displacement transformation
deformed = znimg.apply_transform(disp_transform, ref_znimg=ref_znimg)

Multiple Transformations

# Apply multiple transformations in sequence
# Each transformation is applied sequentially
result = znimg.apply_transform(transform1, transform2, ref_znimg=ref_znimg)

Coordinate Transformations

# Transform coordinates using the matrix multiplication operator
voxel_coords = np.array([50, 60, 30])
ras_coords = transform @ voxel_coords

# Transform multiple points
points = np.array([[50, 60, 30], [100, 120, 60]]).T  # 3xN array
transformed_points = transform @ points

Inverting Transformations

# Get the inverse of a transformation
inverse_transform = transform.invert()

# Apply inverse transformation
restored = transformed_znimg.apply_transform(inverse_transform, ref_znimg=znimg)

Coordinate System Handling

# Update transformation for different orientations
updated_transform = transform.update_for_orientation("RPI", "RAS")

Best Practices

  1. Use ref_znimg parameter: Always provide a reference image when applying transformations
  2. Consider coordinate systems: Be aware of voxel vs RAS coordinate conventions
  3. Memory efficiency: Use lazy evaluation with Dask arrays for large datasets
  4. Transformation order: Remember that multiple transforms are applied sequentially

See Also