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

error-handling.mddocs/reference/

Error Handling Reference

Complete guide to error handling, exceptions, and validation in SimpleITK.

Exception Types

RuntimeError

Primary exception type for SimpleITK errors.

import SimpleITK as sitk

try:
    image = sitk.ReadImage('nonexistent.nii')
except RuntimeError as e:
    print(f"SimpleITK error: {e}")

Common RuntimeError Causes

  1. File I/O Errors

    • File not found
    • Unsupported format
    • Corrupted file
    • Permission denied
  2. Type Errors

    • Incompatible pixel types
    • Invalid type conversion
    • Type mismatch in operations
  3. Dimension Errors

    • Mismatched dimensions
    • Invalid dimension for operation
    • Out of bounds access
  4. Parameter Errors

    • Invalid parameter values
    • Out of range parameters
    • Incompatible parameter combinations
  5. Transform Errors

    • Non-invertible transform
    • Invalid transform parameters
    • Transform dimension mismatch

Error Handling Patterns

File I/O Error Handling

import SimpleITK as sitk
import os

def safe_read_image(file_path, default=None):
    """Safely read image with error handling."""
    
    # Check file exists
    if not os.path.exists(file_path):
        print(f"File not found: {file_path}")
        return default
    
    try:
        image = sitk.ReadImage(file_path)
        return image
        
    except RuntimeError as e:
        error_msg = str(e).lower()
        
        if "could not create" in error_msg:
            print(f"Unsupported format: {file_path}")
        elif "could not open" in error_msg:
            print(f"Cannot open file: {file_path}")
        elif "could not read" in error_msg:
            print(f"Corrupted file: {file_path}")
        else:
            print(f"Read error: {e}")
        
        return default

def safe_write_image(image, file_path):
    """Safely write image with error handling."""
    
    try:
        # Create directory if needed
        os.makedirs(os.path.dirname(file_path) or '.', exist_ok=True)
        
        sitk.WriteImage(image, file_path)
        return True
        
    except RuntimeError as e:
        print(f"Write error: {e}")
        return False

Type Validation

def validate_pixel_type(image, expected_types):
    """Validate image pixel type."""
    
    pixel_type = image.GetPixelIDValue()
    
    if pixel_type not in expected_types:
        type_name = image.GetPixelIDTypeAsString()
        raise ValueError(
            f"Invalid pixel type: {type_name}. "
            f"Expected one of: {expected_types}"
        )
    
    return True

# Usage
try:
    validate_pixel_type(image, [sitk.sitkFloat32, sitk.sitkFloat64])
    # Proceed with processing
except ValueError as e:
    print(e)
    # Convert to appropriate type
    image = sitk.Cast(image, sitk.sitkFloat32)

Dimension Validation

def validate_dimension(image, expected_dim):
    """Validate image dimension."""
    
    actual_dim = image.GetDimension()
    
    if actual_dim != expected_dim:
        raise ValueError(
            f"Invalid dimension: {actual_dim}. Expected: {expected_dim}"
        )
    
    return True

def validate_compatible_geometry(image1, image2):
    """Validate images have compatible geometry."""
    
    if not image1.IsCongruentImageGeometry(image2):
        print("Images have incompatible geometry:")
        print(f"  Image1 - Size: {image1.GetSize()}, Spacing: {image1.GetSpacing()}")
        print(f"  Image2 - Size: {image2.GetSize()}, Spacing: {image2.GetSpacing()}")
        return False
    
    return True

Parameter Validation

def validate_parameters(sigma=None, radius=None, iterations=None):
    """Validate common filter parameters."""
    
    errors = []
    
    if sigma is not None:
        if isinstance(sigma, (list, tuple)):
            if any(s < 0 for s in sigma):
                errors.append("Sigma must be non-negative")
        elif sigma < 0:
            errors.append("Sigma must be non-negative")
    
    if radius is not None:
        if isinstance(radius, (list, tuple)):
            if any(r < 0 for r in radius):
                errors.append("Radius must be non-negative")
        elif radius < 0:
            errors.append("Radius must be non-negative")
    
    if iterations is not None:
        if iterations < 1:
            errors.append("Iterations must be positive")
    
    if errors:
        raise ValueError("; ".join(errors))
    
    return True

Validation Functions

Image Validation

def validate_image(image, min_size=None, max_size=None, allowed_types=None):
    """Comprehensive image validation."""
    
    # Check not empty
    if image.GetSize() == ():
        raise ValueError("Image is empty")
    
    # Check size constraints
    if min_size:
        if any(s < min_size for s in image.GetSize()):
            raise ValueError(f"Image too small. Minimum size: {min_size}")
    
    if max_size:
        if any(s > max_size for s in image.GetSize()):
            raise ValueError(f"Image too large. Maximum size: {max_size}")
    
    # Check pixel type
    if allowed_types:
        if image.GetPixelIDValue() not in allowed_types:
            raise ValueError(
                f"Invalid pixel type: {image.GetPixelIDTypeAsString()}"
            )
    
    # Check for invalid values (if float type)
    if image.GetPixelIDValue() in [sitk.sitkFloat32, sitk.sitkFloat64]:
        stats = sitk.StatisticsImageFilter()
        stats.Execute(image)
        
        import numpy as np
        if np.isnan(stats.GetMean()) or np.isinf(stats.GetMean()):
            raise ValueError("Image contains NaN or Inf values")
    
    return True

Transform Validation

def validate_transform(transform, expected_dimension=None):
    """Validate transform."""
    
    # Check dimension
    if expected_dimension:
        if transform.GetDimension() != expected_dimension:
            raise ValueError(
                f"Transform dimension {transform.GetDimension()} "
                f"does not match expected {expected_dimension}"
            )
    
    # Check invertibility if needed
    try:
        inverse = transform.GetInverse()
    except RuntimeError:
        print("WARNING: Transform is not invertible")
    
    return True

Error Recovery Strategies

Automatic Type Conversion

def robust_filter_application(image, filter_func, required_type=sitk.sitkFloat32):
    """Apply filter with automatic type conversion."""
    
    original_type = image.GetPixelIDValue()
    
    # Convert if needed
    if original_type != required_type:
        print(f"Converting from {image.GetPixelIDTypeAsString()} to Float32")
        image = sitk.Cast(image, required_type)
    
    # Apply filter
    result = filter_func(image)
    
    # Convert back if needed
    if original_type != required_type:
        result = sitk.Cast(result, original_type)
    
    return result

Automatic Resampling

def robust_binary_operation(image1, image2, operation):
    """Binary operation with automatic geometry matching."""
    
    # Check if compatible
    if not image1.IsCongruentImageGeometry(image2):
        print("Resampling image2 to match image1 geometry")
        
        image2 = sitk.Resample(
            image2,
            image1,  # Use image1 as reference
            sitk.Transform(),
            sitk.sitkLinear,
            0.0,
            image2.GetPixelID()
        )
    
    # Now can operate
    return operation(image1, image2)

# Usage
result = robust_binary_operation(img1, img2, sitk.Add)

Fallback Strategies

def robust_segmentation(image, seeds, lower, upper):
    """Segmentation with fallback strategies."""
    
    try:
        # Try confidence connected
        result = sitk.ConfidenceConnected(
            image,
            seedList=seeds,
            numberOfIterations=5,
            multiplier=2.5
        )
        
        # Check if result is non-empty
        stats = sitk.StatisticsImageFilter()
        stats.Execute(result)
        
        if stats.GetSum() == 0:
            raise ValueError("Segmentation produced empty result")
        
        return result
        
    except (RuntimeError, ValueError) as e:
        print(f"Confidence connected failed: {e}")
        print("Falling back to simple threshold")
        
        # Fallback to threshold
        return sitk.BinaryThreshold(
            image,
            lowerThreshold=lower,
            upperThreshold=upper
        )

Debugging

Enable Debug Output

# Global debug
sitk.ProcessObject.SetGlobalDefaultDebug(True)

# Per-filter debug
filter = sitk.DiscreteGaussianImageFilter()
filter.DebugOn()
result = filter.Execute(image)

Verbose Error Messages

import SimpleITK as sitk
import traceback

def verbose_error_handling():
    """Detailed error reporting."""
    
    try:
        image = sitk.ReadImage('input.nii')
        result = sitk.SomeFilter(image)
        
    except RuntimeError as e:
        print("=" * 60)
        print("SimpleITK ERROR")
        print("=" * 60)
        print(f"Error message: {e}")
        print(f"\nFull traceback:")
        traceback.print_exc()
        print("=" * 60)

Validation Utilities

Pre-Flight Checks

def preflight_check(image, operation_name):
    """Run pre-flight checks before expensive operation."""
    
    checks = []
    
    # Check 1: Image not empty
    if image.GetSize() == ():
        checks.append("Image is empty")
    
    # Check 2: Reasonable size
    num_pixels = image.GetNumberOfPixels()
    if num_pixels > 1e9:  # 1 billion pixels
        checks.append(f"Image very large ({num_pixels} pixels)")
    
    # Check 3: Valid pixel type
    pixel_type = image.GetPixelIDValue()
    if pixel_type == sitk.sitkUnknown:
        checks.append("Unknown pixel type")
    
    # Check 4: Valid spacing
    spacing = image.GetSpacing()
    if any(s <= 0 for s in spacing):
        checks.append(f"Invalid spacing: {spacing}")
    
    if checks:
        print(f"Pre-flight warnings for {operation_name}:")
        for check in checks:
            print(f"  ⚠️  {check}")
        
        response = input("Continue anyway? (y/n): ")
        return response.lower() == 'y'
    
    return True

Common Error Messages

"Could not create IO object"

Cause: Unsupported file format Solution: Check file extension, try specifying ImageIO explicitly

"Images do not occupy the same physical space"

Cause: Mismatched geometry (size, spacing, origin, direction) Solution: Resample to common geometry

"Pixel type mismatch"

Cause: Incompatible pixel types in operation Solution: Cast to common type

"Index out of bounds"

Cause: Accessing pixel outside image Solution: Validate indices before access

"Transform is not invertible"

Cause: Singular matrix or non-invertible transform type Solution: Check transform parameters, use different transform type

Best Practices

DO:

  • ✅ Validate inputs before expensive operations
  • ✅ Use try-except for file I/O
  • ✅ Check image geometry before binary operations
  • ✅ Validate parameter ranges
  • ✅ Test with small datasets first
  • ✅ Add progress callbacks for long operations
  • ✅ Log errors with context

DON'T:

  • ❌ Assume files exist or are readable
  • ❌ Ignore geometry mismatches
  • ❌ Skip parameter validation
  • ❌ Suppress errors without logging
  • ❌ Use bare except clauses
  • ❌ Proceed with invalid data

See Also

  • Edge Cases - Handling special cases
  • Quick Start Guide - Getting started
  • Architecture Reference - System architecture

Install with Tessl CLI

npx tessl i tessl/pypi-simpleitk@2.5.1

docs

index.md

tile.json