CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/pypi-simpleitk

SimpleITK is a simplified interface to the Insight Toolkit (ITK) for image registration and segmentation

Pending

Quality

Pending

Does it follow best practices?

Impact

Pending

No eval scenarios have been run

Overview
Eval results
Files

numpy-integration.mddocs/reference/core/

NumPy Integration

SimpleITK provides seamless integration with NumPy, enabling interoperability with the scientific Python ecosystem. Images can be converted to NumPy arrays for processing with NumPy, SciPy, scikit-image, or other array-based libraries, then converted back to SimpleITK images while preserving spatial metadata.

Capabilities

Image to Array Conversion

Convert SimpleITK images to NumPy arrays.

def GetArrayFromImage(image) -> numpy.ndarray:
    """
    Convert SimpleITK Image to NumPy array (deep copy).

    Creates an independent copy of the pixel data. The array's shape is
    reversed compared to SimpleITK's size convention:
    - SimpleITK: (width, height, depth) = (X, Y, Z)
    - NumPy: (depth, height, width) = (Z, Y, X)

    For vector images, the component dimension comes first in NumPy:
    - SimpleITK: size (X, Y, Z), components per pixel = N
    - NumPy: shape (N, Z, Y, X)

    Args:
        image: SimpleITK Image

    Returns:
        NumPy array with reversed dimension order

    Example:
        import SimpleITK as sitk
        import numpy as np

        # 3D image: size (256, 256, 128)
        image = sitk.ReadImage('volume.nii.gz')
        array = sitk.GetArrayFromImage(image)
        # array.shape = (128, 256, 256)

        # Modify array
        array = array * 2.0

        # array and image are independent
        del image  # Safe - array is independent copy
    """

def GetArrayViewFromImage(image) -> numpy.ndarray:
    """
    Get NumPy array view of SimpleITK Image (no copy).

    Returns a view into the image's pixel buffer without copying data.
    More memory efficient than GetArrayFromImage, but the image must
    remain alive while using the array view.

    IMPORTANT: The image object must not be deleted or modified while
    the array view is in use, otherwise the view will point to invalid memory.

    Args:
        image: SimpleITK Image (must remain alive)

    Returns:
        NumPy array view (shares memory with image)

    Example:
        import SimpleITK as sitk
        import numpy as np

        image = sitk.ReadImage('volume.nii.gz')
        array_view = sitk.GetArrayViewFromImage(image)

        # Read operations are safe and efficient
        mean_value = array_view.mean()

        # DANGER: Modifying view modifies image
        array_view *= 2.0  # image is modified too!

        # DANGER: Don't delete image while using view
        # del image  # DON'T DO THIS - array_view becomes invalid
    """

Usage example:

import SimpleITK as sitk
import numpy as np

# Read image
image = sitk.ReadImage('ct_scan.nii.gz')
print(f"Image size: {image.GetSize()}")  # (512, 512, 200)

# Get array (deep copy)
array = sitk.GetArrayFromImage(image)
print(f"Array shape: {array.shape}")  # (200, 512, 512)

# Process with NumPy
array = np.clip(array, 0, 1000)
array = array / 1000.0  # Normalize

# Image is unchanged - array is independent copy

Array to Image Conversion

Create SimpleITK images from NumPy arrays.

def GetImageFromArray(arr: numpy.ndarray, isVector: bool = None):
    """
    Create SimpleITK Image from NumPy array.

    Converts NumPy array to SimpleITK image. The dimension order is reversed:
    - NumPy: (depth, height, width) = (Z, Y, X)
    - SimpleITK: (width, height, depth) = (X, Y, Z)

    For vector images (multi-component pixels like RGB), the first dimension
    is treated as the component dimension if isVector is True:
    - NumPy RGB: shape (3, Z, Y, X) or (3, Y, X)
    - SimpleITK: size (X, Y, Z), 3 components per pixel

    By default, 4D arrays are automatically treated as 3D vector images.

    The resulting image has default metadata (origin at [0,0,0], spacing of
    [1,1,1], and identity direction). Use CopyInformation() to set proper
    spatial metadata.

    Args:
        arr: NumPy array with pixel data
        isVector: If True, first dimension is components. If None, auto-detect
                  (True for 4D non-complex arrays, False otherwise)

    Returns:
        SimpleITK Image (with default metadata)

    Example:
        import SimpleITK as sitk
        import numpy as np

        # Create 3D array
        array = np.random.randn(100, 256, 256).astype(np.float32)

        # Convert to image
        image = sitk.GetImageFromArray(array)
        print(f"Image size: {image.GetSize()}")  # (256, 256, 100)

        # Set proper metadata
        image.SetSpacing((1.0, 1.0, 2.0))
        image.SetOrigin((-127.5, -127.5, -99.0))

        # RGB image (3 components per pixel)
        rgb_array = np.random.randint(0, 256, (3, 256, 256), dtype=np.uint8)
        rgb_image = sitk.GetImageFromArray(rgb_array, isVector=True)
        print(f"Components: {rgb_image.GetNumberOfComponentsPerPixel()}")  # 3
    """

Usage example:

import SimpleITK as sitk
import numpy as np

# Process array
array = np.random.randn(50, 128, 128).astype(np.float32)
array = array * 100 + 500  # Some processing

# Convert to image
image = sitk.GetImageFromArray(array)

# Image has default metadata - set proper values
image.SetSpacing((0.8, 0.8, 2.5))
image.SetOrigin((-51.2, -51.2, -62.5))
image.SetDirection((1, 0, 0, 0, 1, 0, 0, 0, 1))

# Save with metadata
sitk.WriteImage(image, 'output.nii.gz')

Pixel Type Mapping

SimpleITK pixel types map to NumPy dtypes as follows:

Scalar Types

# Integer types
sitkUInt8 <-> numpy.uint8
sitkInt8 <-> numpy.int8
sitkUInt16 <-> numpy.uint16
sitkInt16 <-> numpy.int16
sitkUInt32 <-> numpy.uint32
sitkInt32 <-> numpy.int32
sitkUInt64 <-> numpy.uint64
sitkInt64 <-> numpy.int64

# Floating point types
sitkFloat32 <-> numpy.float32
sitkFloat64 <-> numpy.float64

# Complex types
sitkComplexFloat32 <-> numpy.complex64
sitkComplexFloat64 <-> numpy.complex128

Vector Types

Vector pixel types use the corresponding NumPy dtype with an additional dimension:

sitkVectorUInt8 <-> numpy.uint8 (with component dimension)
sitkVectorInt8 <-> numpy.int8
sitkVectorUInt16 <-> numpy.uint16
sitkVectorInt16 <-> numpy.int16
sitkVectorUInt32 <-> numpy.uint32
sitkVectorInt32 <-> numpy.int32
sitkVectorUInt64 <-> numpy.uint64
sitkVectorInt64 <-> numpy.int64
sitkVectorFloat32 <-> numpy.float32
sitkVectorFloat64 <-> numpy.float64

Label Types

Label types map to unsigned integer types:

sitkLabelUInt8 <-> numpy.uint8
sitkLabelUInt16 <-> numpy.uint16
sitkLabelUInt32 <-> numpy.uint32
sitkLabelUInt64 <-> numpy.uint64

Dimension Order Convention

Understanding the dimension order difference is crucial:

import SimpleITK as sitk
import numpy as np

# SimpleITK uses (X, Y, Z) convention
image = sitk.Image(256, 256, 128, sitk.sitkFloat32)
print(f"SimpleITK size: {image.GetSize()}")  # (256, 256, 128)
# Interpretation: 256 pixels in X, 256 in Y, 128 in Z

# NumPy uses (Z, Y, X) convention
array = sitk.GetArrayFromImage(image)
print(f"NumPy shape: {array.shape}")  # (128, 256, 256)
# Interpretation: 128 slices, 256 rows, 256 columns

# Accessing corresponding elements:
image.SetPixel(10, 20, 5, 100.0)  # Set pixel at (x=10, y=20, z=5)
value = array[5, 20, 10]  # Access same pixel in array [z, y, x]

Common Patterns

Complete Workflow with Metadata Preservation

import SimpleITK as sitk
import numpy as np

# Read image (with metadata)
original_image = sitk.ReadImage('input.nii.gz')

# Convert to NumPy
array = sitk.GetArrayFromImage(original_image)

# Process with NumPy/SciPy
from scipy.ndimage import gaussian_filter
smoothed_array = gaussian_filter(array, sigma=2.0)

# Convert back to SimpleITK
result_image = sitk.GetImageFromArray(smoothed_array)

# IMPORTANT: Copy spatial metadata from original
result_image.CopyInformation(original_image)

# Save with preserved metadata
sitk.WriteImage(result_image, 'output.nii.gz')

Memory-Efficient Processing with Views

import SimpleITK as sitk
import numpy as np

# Read large image
image = sitk.ReadImage('large_volume.nii.gz')

# Get view for read-only operations (no copy)
array_view = sitk.GetArrayViewFromImage(image)

# Compute statistics efficiently
mean = array_view.mean()
std = array_view.std()
max_value = array_view.max()

# For modifications, must use GetArrayFromImage
array = sitk.GetArrayFromImage(image)
array[array < 0] = 0  # Clip negative values
modified_image = sitk.GetImageFromArray(array)
modified_image.CopyInformation(image)

Working with Multi-Component Images

import SimpleITK as sitk
import numpy as np

# Create RGB image from separate channels
r_array = np.random.randint(0, 256, (256, 256), dtype=np.uint8)
g_array = np.random.randint(0, 256, (256, 256), dtype=np.uint8)
b_array = np.random.randint(0, 256, (256, 256), dtype=np.uint8)

# Stack into (3, 256, 256) array
rgb_array = np.stack([r_array, g_array, b_array], axis=0)

# Convert to vector image
rgb_image = sitk.GetImageFromArray(rgb_array, isVector=True)
print(f"Components per pixel: {rgb_image.GetNumberOfComponentsPerPixel()}")  # 3

# Convert back to NumPy
array = sitk.GetArrayFromImage(rgb_image)
print(f"Array shape: {array.shape}")  # (3, 256, 256)

# Extract individual channels
r_channel = array[0, :, :]
g_channel = array[1, :, :]
b_channel = array[2, :, :]

Slice-wise Processing

import SimpleITK as sitk
import numpy as np

# Read 3D volume
volume = sitk.ReadImage('volume.nii.gz')
array = sitk.GetArrayFromImage(volume)  # Shape: (depth, height, width)

# Process each slice
processed_array = np.zeros_like(array)
for z in range(array.shape[0]):
    slice_2d = array[z, :, :]
    # Apply 2D processing
    processed_slice = slice_2d * 2.0  # Example operation
    processed_array[z, :, :] = processed_slice

# Convert back
result = sitk.GetImageFromArray(processed_array)
result.CopyInformation(volume)

Type Conversion

import SimpleITK as sitk
import numpy as np

# Read image
image = sitk.ReadImage('input.png')  # Often UInt8

# Convert to float for processing
array = sitk.GetArrayFromImage(image).astype(np.float32)
array = array / 255.0  # Normalize to [0, 1]

# Process
array = array * 2.0 - 1.0  # Scale to [-1, 1]

# Convert back to appropriate type
array = np.clip(array, 0, 1) * 255.0
array = array.astype(np.uint8)

result = sitk.GetImageFromArray(array)
result.CopyInformation(image)
sitk.WriteImage(result, 'output.png')

Integration with Scikit-Image

import SimpleITK as sitk
import numpy as np
from skimage import filters, measure

# Read image
image = sitk.ReadImage('cells.tif')
array = sitk.GetArrayFromImage(image)

# Use scikit-image for processing
threshold = filters.threshold_otsu(array)
binary = array > threshold

# Label connected components
labeled = measure.label(binary)

# Find region properties
regions = measure.regionprops(labeled)
print(f"Found {len(regions)} objects")

# Convert back to SimpleITK
result = sitk.GetImageFromArray(labeled.astype(np.uint32))
result.CopyInformation(image)
sitk.WriteImage(result, 'segmentation.nii.gz')

Hybrid Processing Pipeline

import SimpleITK as sitk
import numpy as np
from scipy.ndimage import median_filter

# Start with SimpleITK
image = sitk.ReadImage('noisy.nii.gz')

# SimpleITK pre-processing
image = sitk.RescaleIntensity(image, outputMinimum=0, outputMaximum=1000)

# NumPy/SciPy processing
array = sitk.GetArrayFromImage(image)
array = median_filter(array, size=3)

# Back to SimpleITK
image = sitk.GetImageFromArray(array)
image.CopyInformation(sitk.ReadImage('noisy.nii.gz'))

# SimpleITK post-processing
image = sitk.SmoothingRecursiveGaussian(image, sigma=[1.0, 1.0, 1.0])
image = sitk.Cast(image, sitk.sitkUInt16)

sitk.WriteImage(image, 'processed.nii.gz')

Performance Considerations

When to Use GetArrayViewFromImage

Use GetArrayViewFromImage for:

  • Read-only operations (statistics, visualization)
  • Large images where copying is expensive
  • Temporary array access
import SimpleITK as sitk

image = sitk.ReadImage('huge_volume.nii.gz')

# Good: Read-only statistics
array_view = sitk.GetArrayViewFromImage(image)
mean = array_view.mean()

# Bad: Modifications (use GetArrayFromImage instead)
# array_view *= 2.0  # Dangerous!

When to Use GetArrayFromImage

Use GetArrayFromImage for:

  • Modifications to pixel data
  • When image object lifetime is uncertain
  • Passing arrays to functions that may modify them
import SimpleITK as sitk

image = sitk.ReadImage('input.nii.gz')

# Good: Creating modified copy
array = sitk.GetArrayFromImage(image)
array = array * 2.0
result = sitk.GetImageFromArray(array)
result.CopyInformation(image)

Memory Efficiency Tips

import SimpleITK as sitk
import numpy as np

# For large images, process in chunks
image = sitk.ReadImage('very_large.nii.gz')
array = sitk.GetArrayFromImage(image)

# Process slice by slice to reduce memory
for z in range(array.shape[0]):
    array[z, :, :] = process_slice(array[z, :, :])

# Cleanup
del image  # Free original image memory
result = sitk.GetImageFromArray(array)

Install with Tessl CLI

npx tessl i tessl/pypi-simpleitk@2.5.1

docs

index.md

tile.json