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

type-system.mddocs/reference/

Type System Reference

Complete reference for SimpleITK's type system, pixel types, and type conversions.

Pixel Type Hierarchy

SimpleITK supports 26 distinct pixel types organized into categories:

Scalar Integer Types

sitkUInt8   # Unsigned 8-bit: 0 to 255
sitkInt8    # Signed 8-bit: -128 to 127
sitkUInt16  # Unsigned 16-bit: 0 to 65,535
sitkInt16   # Signed 16-bit: -32,768 to 32,767
sitkUInt32  # Unsigned 32-bit: 0 to 4,294,967,295
sitkInt32   # Signed 32-bit: -2,147,483,648 to 2,147,483,647
sitkUInt64  # Unsigned 64-bit
sitkInt64   # Signed 64-bit

Scalar Floating Point Types

sitkFloat32  # 32-bit float (single precision): ~7 decimal digits
sitkFloat64  # 64-bit float (double precision): ~15 decimal digits

Complex Types

sitkComplexFloat32  # Complex with 32-bit real and imaginary
sitkComplexFloat64  # Complex with 64-bit real and imaginary

Vector Types

sitkVectorUInt8 = 13    # Vector of UInt8
sitkVectorInt8 = 14
sitkVectorUInt16 = 15
sitkVectorInt16 = 16
sitkVectorUInt32 = 17
sitkVectorInt32 = 18
sitkVectorUInt64 = 19
sitkVectorInt64 = 20
sitkVectorFloat32 = 21  # RGB images, gradient fields
sitkVectorFloat64 = 22

Label Types

sitkLabelUInt8 = 23   # Up to 255 labels
sitkLabelUInt16 = 24  # Up to 65,535 labels
sitkLabelUInt32 = 25  # Up to 4 billion labels
sitkLabelUInt64 = 26  # Extremely large label sets

Unknown Type

sitkUnknown = -1  # Unspecified or error state

Type Selection Guidelines

By Use Case

Use CaseRecommended TypeReason
Binary maskssitkUInt81 byte, values 0-1
CT scanssitkInt16Hounsfield units (-1024 to 3071)
MRIsitkFloat32Arbitrary intensity scale
PETsitkFloat32Continuous values
Segmentation (< 256 labels)sitkLabelUInt8Memory efficient
Segmentation (> 256 labels)sitkLabelUInt16 or sitkLabelUInt32More labels
RGB imagessitkVectorUInt83 components per pixel
Gradient fieldssitkVectorFloat323D vectors
Distance mapssitkFloat32Signed distances
Intermediate processingsitkFloat32Avoid precision loss

By Memory Requirements

TypeBytes/Pixel256³ Volume Memory
UInt8116 MB
UInt16232 MB
Float32464 MB
Float648128 MB
VectorFloat32 (3D)12192 MB

Type Conversion

Casting Between Types

def Cast(image, pixelID: int):
    """
    Cast image to specified pixel type.
    
    Args:
        image: Input image
        pixelID: Target pixel type constant
    
    Returns:
        Image with new pixel type
    """

class CastImageFilter:
    """Object-oriented interface for type casting."""
    
    def SetOutputPixelType(self, pixelID: int) -> None:
        """Set target pixel type."""
    
    def Execute(self, image):
        """Returns: Casted image"""

Conversion Rules

import SimpleITK as sitk

# Integer to integer: Direct conversion
uint8_img = sitk.Cast(int16_img, sitk.sitkUInt8)

# Float to integer: Truncation (not rounding)
int_img = sitk.Cast(float_img, sitk.sitkInt16)
# 42.7 becomes 42, not 43

# Integer to float: Exact conversion
float_img = sitk.Cast(int_img, sitk.sitkFloat32)

# Narrowing conversions: May overflow/clamp
uint8_img = sitk.Cast(uint16_img, sitk.sitkUInt8)
# Values > 255 wrap around or clamp (implementation-dependent)

Safe Conversion Patterns

def safe_cast_to_uint8(image):
    """Safely cast to UInt8 with proper scaling."""
    
    # Rescale to [0, 255] first
    rescaled = sitk.RescaleIntensity(
        image,
        outputMinimum=0,
        outputMaximum=255
    )
    
    # Now safe to cast
    return sitk.Cast(rescaled, sitk.sitkUInt8)

def safe_cast_with_clamping(image, target_type, min_val, max_val):
    """Cast with explicit clamping."""
    
    # Clamp to valid range
    clamped = sitk.Clamp(image, lowerBound=min_val, upperBound=max_val)
    
    # Cast
    return sitk.Cast(clamped, target_type)

NumPy Type Mapping

Scalar Type Mapping

# 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

# Float types
sitkFloat32 <-> numpy.float32
sitkFloat64 <-> numpy.float64

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

Vector Type Handling

import SimpleITK as sitk
import numpy as np

# Vector types add component dimension
# SimpleITK VectorFloat32 (3 components) <-> NumPy float32 with shape (3, ...)

# Create RGB image
rgb_array = np.random.randint(0, 256, (3, 256, 256), dtype=np.uint8)
rgb_image = sitk.GetImageFromArray(rgb_array, isVector=True)

# Type is VectorUInt8 with 3 components
print(f"Type: {rgb_image.GetPixelIDTypeAsString()}")
print(f"Components: {rgb_image.GetNumberOfComponentsPerPixel()}")

Type Compatibility

Filter Type Requirements

# Some filters require specific types

# Morphological filters: Typically require integer types
binary_image = sitk.Cast(image, sitk.sitkUInt8)
eroded = sitk.BinaryErode(binary_image, kernelRadius=[2, 2])

# Statistical filters: Work with any scalar type
stats = sitk.StatisticsImageFilter()
stats.Execute(image)  # Any scalar type OK

# FFT filters: Require float types
float_image = sitk.Cast(image, sitk.sitkFloat32)
fft = sitk.ForwardFFT(float_image)

Binary Operation Type Rules

# Same type: Result has same type
uint8_1 = sitk.Image(100, 100, sitk.sitkUInt8)
uint8_2 = sitk.Image(100, 100, sitk.sitkUInt8)
result = uint8_1 + uint8_2  # Result is sitkUInt8

# Different types: Requires explicit casting
uint8_img = sitk.Image(100, 100, sitk.sitkUInt8)
float_img = sitk.Image(100, 100, sitk.sitkFloat32)
# result = uint8_img + float_img  # ERROR!

# Cast to common type
uint8_as_float = sitk.Cast(uint8_img, sitk.sitkFloat32)
result = uint8_as_float + float_img  # OK

Type Introspection

Query Image Type

# Get pixel type ID
pixel_id = image.GetPixelIDValue()

# Get human-readable type name
type_name = image.GetPixelIDTypeAsString()

# Check for specific type
if pixel_id == sitk.sitkFloat32:
    print("Image is Float32")

# Check type category
if pixel_id in [sitk.sitkFloat32, sitk.sitkFloat64]:
    print("Image is floating point")

# Get component count
num_components = image.GetNumberOfComponentsPerPixel()
if num_components > 1:
    print(f"Vector image with {num_components} components")

Type Checking Functions

def is_integer_type(image):
    """Check if image has integer pixel type."""
    pixel_id = image.GetPixelIDValue()
    integer_types = [
        sitk.sitkUInt8, sitk.sitkInt8,
        sitk.sitkUInt16, sitk.sitkInt16,
        sitk.sitkUInt32, sitk.sitkInt32,
        sitk.sitkUInt64, sitk.sitkInt64
    ]
    return pixel_id in integer_types

def is_float_type(image):
    """Check if image has floating point type."""
    pixel_id = image.GetPixelIDValue()
    return pixel_id in [sitk.sitkFloat32, sitk.sitkFloat64]

def is_vector_type(image):
    """Check if image has vector pixel type."""
    return image.GetNumberOfComponentsPerPixel() > 1

def is_label_type(image):
    """Check if image has label pixel type."""
    pixel_id = image.GetPixelIDValue()
    label_types = [
        sitk.sitkLabelUInt8, sitk.sitkLabelUInt16,
        sitk.sitkLabelUInt32, sitk.sitkLabelUInt64
    ]
    return pixel_id in label_types

Type Conversion Workflows

Preprocessing Type Workflow

def prepare_for_processing(image):
    """Convert to optimal type for processing."""
    
    # Get current type
    current_type = image.GetPixelIDValue()
    
    # Convert to Float32 for processing
    if current_type != sitk.sitkFloat32:
        print(f"Converting from {image.GetPixelIDTypeAsString()} to Float32")
        image = sitk.Cast(image, sitk.sitkFloat32)
    
    return image, current_type

def restore_original_type(image, original_type):
    """Restore original pixel type after processing."""
    
    if image.GetPixelIDValue() != original_type:
        # Rescale if going to integer type
        if original_type in [sitk.sitkUInt8, sitk.sitkUInt16, sitk.sitkInt16]:
            # Rescale to appropriate range
            if original_type == sitk.sitkUInt8:
                image = sitk.RescaleIntensity(image, outputMinimum=0, outputMaximum=255)
            elif original_type == sitk.sitkUInt16:
                image = sitk.RescaleIntensity(image, outputMinimum=0, outputMaximum=65535)
        
        image = sitk.Cast(image, original_type)
    
    return image

Format-Specific Type Conversion

def prepare_for_png_export(image):
    """Convert image to PNG-compatible type (UInt8 or UInt16)."""
    
    # Rescale to [0, 255]
    rescaled = sitk.RescaleIntensity(image, outputMinimum=0, outputMaximum=255)
    
    # Cast to UInt8
    return sitk.Cast(rescaled, sitk.sitkUInt8)

def prepare_for_dicom_export(image):
    """Convert to DICOM-compatible type (typically Int16)."""
    
    # Cast to Int16
    return sitk.Cast(image, sitk.sitkInt16)

Vector Image Operations

Component Extraction

def extract_rgb_channels(rgb_image):
    """Extract R, G, B channels from RGB image."""
    
    # Convert to NumPy
    array = sitk.GetArrayFromImage(rgb_image)  # Shape: (3, H, W)
    
    # Extract channels
    r_array = array[0, :, :]
    g_array = array[1, :, :]
    b_array = array[2, :, :]
    
    # Convert back to SimpleITK
    r_image = sitk.GetImageFromArray(r_array)
    g_image = sitk.GetImageFromArray(g_array)
    b_image = sitk.GetImageFromArray(b_array)
    
    # Copy metadata
    for img in [r_image, g_image, b_image]:
        img.CopyInformation(rgb_image)
    
    return r_image, g_image, b_image

def compose_rgb_image(r_image, g_image, b_image):
    """Compose R, G, B channels into RGB image."""
    
    # Use Compose filter
    rgb_image = sitk.Compose(r_image, g_image, b_image)
    
    return rgb_image

Vector to Scalar Conversion

# Extract single component
component_0 = sitk.VectorIndexSelectionCast(vector_image, index=0)

# Compute magnitude
magnitude = sitk.VectorMagnitude(vector_image)

# For single-component vectors
scalar = vector_image.ToScalarImage()

Label Image Handling

Label Type Selection

def select_label_type(num_labels):
    """Select appropriate label type for number of labels."""
    
    if num_labels <= 255:
        return sitk.sitkLabelUInt8
    elif num_labels <= 65535:
        return sitk.sitkLabelUInt16
    elif num_labels <= 4294967295:
        return sitk.sitkLabelUInt32
    else:
        return sitk.sitkLabelUInt64

# Usage
num_objects = 1000
label_type = select_label_type(num_objects)
labeled_image = sitk.Cast(labeled_image, label_type)

Label vs Regular Integer Types

# Label types are semantically different from regular integers
# Use label types for segmentation masks

# CORRECT: Use label type
segmentation = sitk.ConnectedComponent(binary)
# Returns sitkLabelUInt* type

# For arithmetic: Convert to regular integer
regular_uint = sitk.Cast(segmentation, sitk.sitkUInt32)

Type Conversion Best Practices

Preserve Precision

# WRONG: Precision loss
float64_image = sitk.ReadImage('precise.nii')  # Float64
float32_image = sitk.Cast(float64_image, sitk.sitkFloat32)  # Loses precision

# CORRECT: Keep Float64 if precision needed
result = sitk.SomeFilter(float64_image)  # Process as Float64

Avoid Overflow

# WRONG: Overflow risk
uint8_img1 = sitk.Image(100, 100, sitk.sitkUInt8)
uint8_img1.SetPixel(50, 50, 200)
uint8_img2 = sitk.Image(100, 100, sitk.sitkUInt8)
uint8_img2.SetPixel(50, 50, 100)

result = uint8_img1 + uint8_img2  # 200 + 100 = 300, overflows UInt8!

# CORRECT: Cast to larger type first
float1 = sitk.Cast(uint8_img1, sitk.sitkFloat32)
float2 = sitk.Cast(uint8_img2, sitk.sitkFloat32)
result = float1 + float2
result = sitk.Clamp(result, lowerBound=0, upperBound=255)
result = sitk.Cast(result, sitk.sitkUInt8)

Rounding vs Truncation

# Truncation (default)
float_img = sitk.Image(100, 100, sitk.sitkFloat32)
float_img.SetPixel(50, 50, 42.7)
int_img = sitk.Cast(float_img, sitk.sitkInt16)
value = int_img.GetPixel(50, 50)  # 42 (truncated)

# Rounding (add 0.5 before casting)
rounded = float_img + 0.5
int_rounded = sitk.Cast(rounded, sitk.sitkInt16)
value = int_rounded.GetPixel(50, 50)  # 43 (rounded)

Type-Specific Operations

Integer-Only Operations

# Modulus requires integer types
int_img = sitk.Cast(image, sitk.sitkInt32)
result = int_img % 10

# Bitwise operations require integer types
binary1 = sitk.Cast(binary1, sitk.sitkUInt8)
binary2 = sitk.Cast(binary2, sitk.sitkUInt8)
result = binary1 & binary2

Float-Only Operations

# Logarithm requires float types
float_img = sitk.Cast(image, sitk.sitkFloat32)
log_img = sitk.Log(float_img)

# Trigonometric functions require float
sin_img = sitk.Sin(float_img)
cos_img = sitk.Cos(float_img)

Complex Operations

# FFT produces complex images
float_img = sitk.Cast(image, sitk.sitkFloat32)
fft = sitk.ForwardFFT(float_img)  # Returns sitkComplexFloat32

# Extract components
real_part = sitk.ComplexToReal(fft)
imag_part = sitk.ComplexToImaginary(fft)
magnitude = sitk.ComplexToModulus(fft)
phase = sitk.ComplexToPhase(fft)

# Reconstruct
complex_img = sitk.RealAndImaginaryToComplex(real_part, imag_part)

Type Conversion Utilities

Automatic Type Selection

def select_processing_type(image):
    """Select appropriate type for processing."""
    
    pixel_id = image.GetPixelIDValue()
    
    # Already float: Keep as is
    if pixel_id in [sitk.sitkFloat32, sitk.sitkFloat64]:
        return image, pixel_id
    
    # Integer: Convert to Float32
    if pixel_id in [sitk.sitkUInt8, sitk.sitkInt8, sitk.sitkUInt16, sitk.sitkInt16]:
        return sitk.Cast(image, sitk.sitkFloat32), pixel_id
    
    # Large integers: Convert to Float64
    if pixel_id in [sitk.sitkUInt32, sitk.sitkInt32, sitk.sitkUInt64, sitk.sitkInt64]:
        return sitk.Cast(image, sitk.sitkFloat64), pixel_id
    
    # Default: Float32
    return sitk.Cast(image, sitk.sitkFloat32), pixel_id

Type Conversion Pipeline

class TypeConverter:
    """Utility class for type conversions."""
    
    @staticmethod
    def to_float32(image):
        """Convert any type to Float32."""
        if image.GetPixelIDValue() != sitk.sitkFloat32:
            return sitk.Cast(image, sitk.sitkFloat32)
        return image
    
    @staticmethod
    def to_uint8_normalized(image):
        """Convert to UInt8 with normalization."""
        rescaled = sitk.RescaleIntensity(image, outputMinimum=0, outputMaximum=255)
        return sitk.Cast(rescaled, sitk.sitkUInt8)
    
    @staticmethod
    def to_label_uint16(image):
        """Convert to label type."""
        # Ensure non-negative integers
        if image.GetPixelIDValue() not in [sitk.sitkUInt8, sitk.sitkUInt16, sitk.sitkUInt32]:
            image = sitk.Cast(image, sitk.sitkUInt16)
        return sitk.Cast(image, sitk.sitkLabelUInt16)

Type-Related Errors

Common Type Errors

# Error 1: Type mismatch in binary operation
try:
    result = uint8_image + float_image
except RuntimeError as e:
    print("Type mismatch - cast to common type")
    float_uint8 = sitk.Cast(uint8_image, sitk.sitkFloat32)
    result = float_uint8 + float_image

# Error 2: Invalid type for filter
try:
    fft = sitk.ForwardFFT(uint8_image)
except RuntimeError as e:
    print("FFT requires float type")
    float_image = sitk.Cast(uint8_image, sitk.sitkFloat32)
    fft = sitk.ForwardFFT(float_image)

# Error 3: Overflow in arithmetic
uint8_img = sitk.Image(100, 100, sitk.sitkUInt8)
uint8_img.SetPixel(50, 50, 250)
# result = uint8_img + 10  # May overflow
float_img = sitk.Cast(uint8_img, sitk.sitkFloat32)
result = float_img + 10  # Safe

See Also

  • Image API Reference - Image class details
  • Architecture Reference - System architecture
  • Error Handling Reference - Exception handling

Install with Tessl CLI

npx tessl i tessl/pypi-simpleitk

docs

index.md

tile.json