Both ITK (python package) and SimpleITK (python package) are bindings of ITK C++ library providing a number of verified utilities for medical image processing, especially 3D volumetric image processing.
ITK python package provides both C++ style bindings ( functions and classes in UpperCamelCase ) and pythonic bindings ( in snake_case ). C++ style bindings keeps the original pipeline structure and template programming style in ITK and the pythoic bindings provides somewhat procedural interface. For example, in C++ style bindings, you need to specify the datatype when instantiating filters, an example is as following. Refer to the tutorial for more information.
InputType = itk.Image[itk.F,3]
OutputType = itk.Image[itk.F,3]
median = itk.MedianImageFilter[InputType, OutputType].New()SimpleITK is a procedural interface for ITK. Everything in SimpleITK is wrapped ITK filters in procedural interfaces so you have a consistent interface for nearly all filters and image datatypes.
Env: Linux Mint 22.2, Python 3.11
| ITK | SimpleITK | |
|---|---|---|
| Version | 5.4.4.post1 | 2.5.1 |
| Total size | 266M | 51M |
| Instantiation time (mean (sd)) | 0.36 (0.09)s | 0.16 (0.01)s |
| Resample (100 * 100 * 100 float32) | 0.032s | 0.021s |
| FastMarching (50 * 50 * 50 float32) | 0.046s | 0.044s |
for i in {0..10}; do python -c 'import time; st_time=time.time(); import itk; print( time.time() - st_time)'; done
for i in {0..10}; do python -c 'import time; st_time=time.time(); import SimpleITK; print( time.time() - st_time)'; done
pip download itk -d /tmp/itk_download && rm /tmp/itk_download/numpy* && du -sh /tmp/itk_download && rm -rf /tmp/itk_download
#!/usr/bin/env python3
"""
Performance comparison between ITK and SimpleITK resample filters.
This script creates a synthetic 3D image and compares the performance
of resampling operations using both libraries.
"""
import time
import numpy as np
import sys
def test_itk_resample():
"""Test ITK resample filter performance"""
try:
import itk
print("Testing ITK resample filter...")
# Create a synthetic 3D image (100x100x100 voxels)
image_size = (100, 100, 100)
image_spacing = (1.0, 1.0, 1.0)
image_origin = (0.0, 0.0, 0.0)
# Create synthetic image data
image_array = np.random.rand(*image_size).astype(np.float32) * 1000
# Convert to ITK image
itk_image = itk.GetImageFromArray(image_array)
itk_image.SetSpacing(image_spacing)
itk_image.SetOrigin(image_origin)
# Set up resample filter
resample_filter = itk.ResampleImageFilter.New(itk_image)
# Set output parameters (downsample by factor of 2)
output_spacing = (2.0, 2.0, 2.0)
output_size = (50, 50, 50)
output_origin = image_origin
resample_filter.SetOutputSpacing(output_spacing)
resample_filter.SetSize(output_size)
resample_filter.SetOutputOrigin(output_origin)
# Use linear interpolator
interpolator = itk.LinearInterpolateImageFunction.New(itk_image)
resample_filter.SetInterpolator(interpolator)
# Time the resampling operation
start_time = time.time()
resample_filter.Update()
resampled_image = resample_filter.GetOutput()
# Force computation by accessing image data
resampled_array = itk.GetArrayFromImage(resampled_image)
itk_time = time.time() - start_time
print(".3f")
# Get shape from the resampled image directly
shape = (resampled_image.GetLargestPossibleRegion().GetSize()[0],
resampled_image.GetLargestPossibleRegion().GetSize()[1],
resampled_image.GetLargestPossibleRegion().GetSize()[2])
return itk_time, shape
except ImportError:
print("ITK not available")
return None, None
except Exception as e:
print(f"ITK test failed: {e}")
return None, None
def test_simpleitk_resample():
"""Test SimpleITK resample filter performance"""
try:
import SimpleITK as sitk
print("Testing SimpleITK resample filter...")
# Create a synthetic 3D image (100x100x100 voxels)
image_size = (100, 100, 100)
image_spacing = (1.0, 1.0, 1.0)
image_origin = (0.0, 0.0, 0.0)
# Create synthetic image data
image_array = np.random.rand(*image_size).astype(np.float32) * 1000
# Convert to SimpleITK image
sitk_image = sitk.GetImageFromArray(image_array)
sitk_image.SetSpacing(image_spacing)
sitk_image.SetOrigin(image_origin)
# Set up resample filter
resample = sitk.ResampleImageFilter()
resample.SetReferenceImage(sitk_image)
# Set output parameters (downsample by factor of 2)
output_spacing = (2.0, 2.0, 2.0)
output_size = (50, 50, 50)
output_origin = image_origin
resample.SetOutputSpacing(output_spacing)
resample.SetSize(output_size)
resample.SetOutputOrigin(output_origin)
# Use linear interpolator
resample.SetInterpolator(sitk.sitkLinear)
# Time the resampling operation
start_time = time.time()
resampled_image = resample.Execute(sitk_image)
# Force computation by accessing image data
resampled_array = sitk.GetArrayFromImage(resampled_image)
simpleitk_time = time.time() - start_time
print(".3f")
return simpleitk_time, np.array(resampled_array).shape
except ImportError:
print("SimpleITK not available")
return None, None
except Exception as e:
print(f"SimpleITK test failed: {e}")
return None, None
def main():
print("ITK vs SimpleITK Resample Filter Performance Comparison")
print("=" * 55)
# Set random seed for reproducible results
np.random.seed(42)
# Test ITK
itk_time, itk_shape = test_itk_resample()
print()
# Test SimpleITK
simpleitk_time, simpleitk_shape = test_simpleitk_resample()
print()
# Compare results
if itk_time is not None and simpleitk_time is not None:
print("Performance Comparison:")
print(".3f")
print(".3f")
if itk_time < simpleitk_time:
speedup = simpleitk_time / itk_time
print(".2f")
else:
speedup = itk_time / simpleitk_time
print(".2f")
print(f"Output shapes: ITK={itk_shape}, SimpleITK={simpleitk_shape}")
else:
print("Unable to compare both libraries - one or both failed")
if __name__ == "__main__":
main()#!/usr/bin/env python3
"""
Performance comparison between ITK and SimpleITK FastMarchingImageFilter.
This script creates a synthetic 3D image with seed points and compares
the performance of FastMarching operations using both libraries.
"""
import time
import numpy as np
import sys
def test_itk_fastmarching():
"""Test ITK FastMarchingImageFilter performance"""
try:
import itk
print("Testing ITK FastMarchingImageFilter...")
# Create a 3D speed image (50x50x50 voxels)
image_size = (50, 50, 50)
image_spacing = (1.0, 1.0, 1.0)
image_origin = (0.0, 0.0, 0.0)
# Create speed image: uniform speed of 1.0 everywhere
speed_array = np.ones(image_size, dtype=np.float32)
# Convert to ITK image
speed_image = itk.GetImageFromArray(speed_array)
speed_image.SetSpacing(image_spacing)
speed_image.SetOrigin(image_origin)
# Try using the specific 3D float filter as suggested
fastmarching_filter = itk.FastMarchingImageFilter.IF3IF3.New(speed_image)
# Create seed points using NodeContainer
# Use the available D3 node type
nodes = itk.VectorContainer[itk.UI, itk.LevelSetNode.F3].New()
# Add seed point at center
node = itk.LevelSetNode.F3()
node.SetValue(0.0) # Initial distance
node.SetIndex([25, 25, 25]) # Center point
nodes.InsertElement(0, node)
fastmarching_filter.SetTrialPoints(nodes)
fastmarching_filter.SetStoppingValue(25.0)
# Time the FastMarching operation
start_time = time.time()
fastmarching_filter.Update()
result_image = fastmarching_filter.GetOutput()
# Force computation
result_array = itk.GetArrayFromImage(result_image)
itk_time = time.time() - start_time
print(f"{itk_time:.3f}")
# Get shape from the result image directly
shape = (result_image.GetLargestPossibleRegion().GetSize()[0],
result_image.GetLargestPossibleRegion().GetSize()[1],
result_image.GetLargestPossibleRegion().GetSize()[2])
return itk_time, shape
except ImportError:
print("ITK not available")
return None, None
except Exception as e:
print(f"ITK test failed: {e}")
return None, None
def test_simpleitk_fastmarching():
"""Test SimpleITK FastMarchingImageFilter performance"""
try:
import SimpleITK as sitk
print("Testing SimpleITK FastMarchingImageFilter...")
# Create a 3D speed image (50x50x50 voxels)
image_size = (50, 50, 50)
image_spacing = (1.0, 1.0, 1.0)
image_origin = (0.0, 0.0, 0.0)
# Create speed image: uniform speed of 1.0 everywhere
speed_array = np.ones(image_size, dtype=np.float32)
# Convert to SimpleITK image
speed_image = sitk.GetImageFromArray(speed_array)
speed_image.SetSpacing(image_spacing)
speed_image.SetOrigin(image_origin)
# Set up FastMarchingImageFilter
fastmarching_filter = sitk.FastMarchingImageFilter()
# Set seed point
fastmarching_filter.AddTrialPoint([25, 25, 25]) # Center point (integers)
# Set stopping value (maximum distance to compute)
fastmarching_filter.SetStoppingValue(25.0)
# Time the FastMarching operation
start_time = time.time()
result_image = fastmarching_filter.Execute(speed_image)
# Force computation
result_array = sitk.GetArrayFromImage(result_image)
simpleitk_time = time.time() - start_time
print(f"{simpleitk_time:.3f}")
return simpleitk_time, np.array(result_array).shape
except ImportError:
print("SimpleITK not available")
return None, None
except Exception as e:
print(f"SimpleITK test failed: {e}")
return None, None
def main():
print("ITK vs SimpleITK FastMarchingImageFilter Performance Comparison (3D)")
print("=" * 68)
# Set random seed for reproducible results
np.random.seed(42)
# Test ITK
itk_time, itk_shape = test_itk_fastmarching()
print()
# Test SimpleITK
simpleitk_time, simpleitk_shape = test_simpleitk_fastmarching()
print()
# Compare results
if itk_time is not None and simpleitk_time is not None:
print("Performance Comparison:")
print(f"ITK time: {itk_time:.3f} seconds")
print(f"SimpleITK time: {simpleitk_time:.3f} seconds")
if itk_time < simpleitk_time:
speedup = simpleitk_time / itk_time
print(f"ITK was {speedup:.2f}x faster than SimpleITK")
else:
speedup = itk_time / simpleitk_time
print(f"SimpleITK was {speedup:.2f}x faster than ITK")
print(f"Output shapes: ITK={itk_shape}, SimpleITK={simpleitk_shape}")
elif simpleitk_time is not None:
print("Only SimpleITK test completed successfully:")
print(f"SimpleITK time: {simpleitk_time:.3f} seconds")
print(f"Output shape: {simpleitk_shape}")
print("Note: ITK FastMarching requires specific template instantiations not available in this Python build")
else:
print("Unable to run tests - both libraries failed")
if __name__ == "__main__":
main()