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-workflow.mddocs/guides/

NumPy Integration Workflow

Complete guide to working with SimpleITK and NumPy together.

Overview

SimpleITK provides seamless integration with NumPy for interoperability with the scientific Python ecosystem. Understanding dimension ordering and metadata preservation is crucial for correct implementation.

Dimension Ordering

Critical: SimpleITK and NumPy use opposite dimension conventions.

import SimpleITK as sitk
import numpy as np

# SimpleITK: (X, Y, Z) = (width, height, depth)
image = sitk.Image(256, 256, 128, sitk.sitkFloat32)
print(f"SimpleITK size: {image.GetSize()}")  # (256, 256, 128)

# NumPy: (Z, Y, X) = (depth, height, width)
array = sitk.GetArrayFromImage(image)
print(f"NumPy shape: {array.shape}")  # (128, 256, 256)

# Accessing corresponding elements:
image.SetPixel(10, 20, 5, 100.0)  # (x=10, y=20, z=5)
value = array[5, 20, 10]           # [z, y, x]

Conversion Functions

Image to Array (Deep Copy)

import SimpleITK as sitk
import numpy as np

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

# Convert to NumPy array (creates copy)
array = sitk.GetArrayFromImage(image)

# Modify array
array = array * 2.0
array = np.clip(array, 0, 1000)

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

Image to Array (View - No Copy)

# Get view (no copy, shares memory)
image = sitk.ReadImage('large_volume.nii.gz')
array_view = sitk.GetArrayViewFromImage(image)

# Read-only operations are efficient
mean = array_view.mean()
std = array_view.std()
max_val = array_view.max()

# WARNING: Image must stay alive
# del image  # DON'T DO THIS - array_view becomes invalid

# WARNING: Modifying view modifies image
# array_view *= 2.0  # This modifies the original image!

Array to Image

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

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

# Image has default metadata - set proper values
image.SetSpacing((1.0, 1.0, 2.0))
image.SetOrigin((-127.5, -127.5, -99.0))
image.SetDirection((1, 0, 0, 0, 1, 0, 0, 0, 1))

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

Complete Workflow with Metadata Preservation

import SimpleITK as sitk
import numpy as np

def process_with_numpy(input_path, output_path):
    """Complete workflow preserving spatial metadata."""
    
    # 1. Read image (with metadata)
    original_image = sitk.ReadImage(input_path)
    
    # 2. Convert to NumPy
    array = sitk.GetArrayFromImage(original_image)
    
    # 3. Process with NumPy/SciPy
    from scipy.ndimage import gaussian_filter, median_filter
    
    # Apply filters
    array = gaussian_filter(array, sigma=2.0)
    array = median_filter(array, size=3)
    
    # Normalize
    array = (array - array.min()) / (array.max() - array.min())
    array = array * 1000
    
    # 4. Convert back to SimpleITK
    result_image = sitk.GetImageFromArray(array)
    
    # 5. CRITICAL: Copy spatial metadata from original
    result_image.CopyInformation(original_image)
    
    # 6. Save with preserved metadata
    sitk.WriteImage(result_image, output_path)
    
    return result_image

Type Conversion

NumPy to SimpleITK Type Mapping

import SimpleITK as sitk
import numpy as np

# Integer types
array_uint8 = np.random.randint(0, 256, (100, 100), dtype=np.uint8)
image_uint8 = sitk.GetImageFromArray(array_uint8)
# Result: sitkUInt8

array_int16 = np.random.randint(-1000, 1000, (100, 100), dtype=np.int16)
image_int16 = sitk.GetImageFromArray(array_int16)
# Result: sitkInt16

# Float types
array_float32 = np.random.randn(100, 100).astype(np.float32)
image_float32 = sitk.GetImageFromArray(array_float32)
# Result: sitkFloat32

# Convert between types
image_converted = sitk.Cast(image_uint8, sitk.sitkFloat32)

Vector Images (Multi-Component)

RGB Images

import SimpleITK as sitk
import numpy as np

# Create RGB array (3 components)
r = np.random.randint(0, 256, (256, 256), dtype=np.uint8)
g = np.random.randint(0, 256, (256, 256), dtype=np.uint8)
b = np.random.randint(0, 256, (256, 256), dtype=np.uint8)

# Stack into (3, 256, 256)
rgb_array = np.stack([r, g, b], axis=0)

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

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

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

Slice-Wise Processing

def process_slices(volume_path, output_path):
    """Process 3D volume slice by slice."""
    
    # Read volume
    volume = sitk.ReadImage(volume_path)
    array = sitk.GetArrayFromImage(volume)  # Shape: (depth, height, width)
    
    # Process each slice
    processed = np.zeros_like(array)
    for z in range(array.shape[0]):
        slice_2d = array[z, :, :]
        
        # 2D processing
        slice_2d = slice_2d * 2.0
        slice_2d = np.clip(slice_2d, 0, 1000)
        
        processed[z, :, :] = slice_2d
    
    # Convert back
    result = sitk.GetImageFromArray(processed)
    result.CopyInformation(volume)
    
    sitk.WriteImage(result, output_path)
    return result

Integration with SciPy

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

def scipy_processing(image):
    """Use SciPy filters on SimpleITK image."""
    
    # Convert to NumPy
    array = sitk.GetArrayFromImage(image)
    
    # SciPy operations
    smoothed = ndimage.gaussian_filter(array, sigma=2.0)
    edges = ndimage.sobel(smoothed)
    labeled, num_features = ndimage.label(edges > 0.5)
    
    # Convert back
    result = sitk.GetImageFromArray(labeled.astype(np.uint32))
    result.CopyInformation(image)
    
    return result, num_features

Integration with Scikit-Image

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

def skimage_processing(image):
    """Use scikit-image on SimpleITK image."""
    
    # Convert to NumPy
    array = sitk.GetArrayFromImage(image)
    
    # Scikit-image operations
    threshold = filters.threshold_otsu(array)
    binary = array > threshold
    
    # Remove small objects
    cleaned = morphology.remove_small_objects(binary, min_size=64)
    
    # Label and measure
    labeled = measure.label(cleaned)
    regions = measure.regionprops(labeled)
    
    print(f"Found {len(regions)} objects")
    for region in regions:
        print(f"  Area: {region.area}, Centroid: {region.centroid}")
    
    # Convert back
    result = sitk.GetImageFromArray(labeled.astype(np.uint32))
    result.CopyInformation(image)
    
    return result

Hybrid Processing Pipeline

def hybrid_pipeline(input_path, output_path):
    """Combine SimpleITK and NumPy/SciPy processing."""
    
    # Start with SimpleITK
    image = sitk.ReadImage(input_path)
    
    # SimpleITK preprocessing
    image = sitk.RescaleIntensity(image, outputMinimum=0, outputMaximum=1000)
    image = sitk.SmoothingRecursiveGaussian(image, sigma=[1.0, 1.0, 1.0])
    
    # NumPy/SciPy processing
    array = sitk.GetArrayFromImage(image)
    from scipy.ndimage import median_filter
    array = median_filter(array, size=3)
    
    # Back to SimpleITK
    image = sitk.GetImageFromArray(array)
    image.CopyInformation(sitk.ReadImage(input_path))
    
    # SimpleITK postprocessing
    image = sitk.Cast(image, sitk.sitkUInt16)
    
    sitk.WriteImage(image, output_path)
    return image

Performance Patterns

Memory-Efficient Statistics

# Use view for read-only operations
image = sitk.ReadImage('huge_volume.nii.gz')
array_view = sitk.GetArrayViewFromImage(image)

# Compute statistics without copying
mean = array_view.mean()
std = array_view.std()
percentiles = np.percentile(array_view, [25, 50, 75])

Chunked Processing

def process_large_volume_chunked(volume_path):
    """Process very large volumes in chunks."""
    
    volume = sitk.ReadImage(volume_path)
    array = sitk.GetArrayFromImage(volume)
    
    # Process in chunks to reduce memory
    chunk_size = 10
    for z_start in range(0, array.shape[0], chunk_size):
        z_end = min(z_start + chunk_size, array.shape[0])
        
        # Process chunk
        chunk = array[z_start:z_end, :, :]
        chunk = chunk * 2.0  # Some operation
        array[z_start:z_end, :, :] = chunk
    
    # Convert back
    result = sitk.GetImageFromArray(array)
    result.CopyInformation(volume)
    
    return result

Common Pitfalls and Solutions

Pitfall 1: Forgetting CopyInformation

# WRONG: Metadata lost
array = sitk.GetArrayFromImage(image)
result = sitk.GetImageFromArray(array * 2.0)
# result has default metadata (origin=0, spacing=1)

# CORRECT: Metadata preserved
array = sitk.GetArrayFromImage(image)
result = sitk.GetImageFromArray(array * 2.0)
result.CopyInformation(image)  # Preserve spatial metadata

Pitfall 2: Dimension Order Confusion

# WRONG: Dimension mismatch
image_size = image.GetSize()  # (256, 256, 128)
array = sitk.GetArrayFromImage(image)
# Trying to use image_size with array indexing fails

# CORRECT: Use array.shape
array_shape = array.shape  # (128, 256, 256)
# Use array_shape for array operations

Pitfall 3: Modifying Views

# WRONG: Unexpected side effects
array_view = sitk.GetArrayViewFromImage(image)
array_view *= 2.0  # Modifies original image!

# CORRECT: Use copy for modifications
array = sitk.GetArrayFromImage(image)  # Deep copy
array *= 2.0  # Safe modification

Pitfall 4: Deleting Image with Active View

# WRONG: View becomes invalid
image = sitk.ReadImage('data.nii')
array_view = sitk.GetArrayViewFromImage(image)
del image  # array_view now points to invalid memory!

# CORRECT: Keep image alive
image = sitk.ReadImage('data.nii')
array_view = sitk.GetArrayViewFromImage(image)
# Use array_view while image is alive
result = array_view.mean()
# Now safe to delete image

See Also

  • NumPy Integration Reference - Complete NumPy API
  • Image API Reference - Image class details
  • Performance Guide - Optimization techniques

Install with Tessl CLI

npx tessl i tessl/pypi-simpleitk@2.5.1

docs

index.md

tile.json