SimpleITK is a simplified interface to the Insight Toolkit (ITK) for image registration and segmentation
—
Quality
Pending
Does it follow best practices?
Impact
Pending
No eval scenarios have been run
Image registration filters and the ImageRegistrationMethod framework for aligning images through optimization. Includes deformable registration using demons algorithms, displacement fields, and the flexible metric-based registration framework.
class ImageRegistrationMethod:
"""
Flexible framework for metric-based image registration.
Combines similarity metrics, optimizers, and transforms for aligning
fixed and moving images through iterative optimization.
"""
def SetInitialTransform(self, transform, inPlace: bool = False) -> None:
"""
Set initial transform.
Args:
transform: Initial transformation
inPlace: If True, optimize transform in-place (modify original)
"""
def GetInitialTransform(self):
"""Get initial transform."""
def SetMetricAsANTSNeighborhoodCorrelation(self, radius: int) -> None:
"""Use ANTs neighborhood correlation metric."""
def SetMetricAsCorrelation(self) -> None:
"""Use correlation metric."""
def SetMetricAsDemons(self, intensityDifferenceThreshold: float = 0.001) -> None:
"""Use demons metric."""
def SetMetricAsJointHistogramMutualInformation(self, numberOfHistogramBins: int = 20,
varianceForJointPDFSmoothing: float = 1.5) -> None:
"""Use joint histogram mutual information."""
def SetMetricAsMeanSquares(self) -> None:
"""Use mean squares metric (sum of squared differences)."""
def SetMetricAsMattesMutualInformation(self, numberOfHistogramBins: int = 50) -> None:
"""Use Mattes mutual information (recommended for multimodal registration)."""
def SetOptimizerAsGradientDescent(self, learningRate: float,
numberOfIterations: int,
convergenceMinimumValue: float = 1e-6,
convergenceWindowSize: int = 10,
estimateLearningRate: int = 0) -> None:
"""
Configure gradient descent optimizer.
Args:
learningRate: Step size for gradient descent
numberOfIterations: Maximum iterations
convergenceMinimumValue: Convergence tolerance
convergenceWindowSize: Window for convergence check
estimateLearningRate: Learning rate estimation method
"""
def SetOptimizerAsGradientDescentLineSearch(self, learningRate: float,
numberOfIterations: int,
convergenceMinimumValue: float = 1e-6,
convergenceWindowSize: int = 10,
lineSearchLowerLimit: float = 0,
lineSearchUpperLimit: float = 5.0,
lineSearchEpsilon: float = 0.01,
lineSearchMaximumIterations: int = 20) -> None:
"""Configure gradient descent with line search."""
def SetOptimizerAsLBFGSB(self, gradientConvergenceTolerance: float = 1e-5,
numberOfIterations: int = 500,
maximumNumberOfCorrections: int = 5,
maximumNumberOfFunctionEvaluations: int = 2000,
costFunctionConvergenceFactor: float = 1e7) -> None:
"""Configure L-BFGS-B optimizer (limited memory BFGS)."""
def SetOptimizerAsLBFGS2(self, solutionAccuracy: float = 1e-5,
numberOfIterations: int = 0,
hessianApproximateAccuracy: int = 6,
deltaConvergenceDistance: int = 0,
deltaConvergenceTolerance: float = 1e-5,
lineSearchMaximumEvaluations: int = 40,
lineSearchMinimumStep: float = 1e-20,
lineSearchMaximumStep: float = 1e20,
lineSearchAccuracy: float = 1e-4) -> None:
"""Configure L-BFGS2 optimizer."""
def SetOptimizerAsConjugateGradient(self, learningRate: float,
numberOfIterations: int,
convergenceMinimumValue: float = 1e-6,
convergenceWindowSize: int = 10) -> None:
"""Configure conjugate gradient optimizer."""
def SetOptimizerAsRegularStepGradientDescent(self, learningRate: float,
minStep: float,
numberOfIterations: int,
relaxationFactor: float = 0.5,
gradientMagnitudeTolerance: float = 1e-4) -> None:
"""Configure regular step gradient descent."""
def SetOptimizerAsPowell(self, numberOfIterations: int = 100,
maximumLineIterations: int = 100,
stepLength: float = 1,
stepTolerance: float = 1e-6,
valueTolerance: float = 1e-6) -> None:
"""Configure Powell optimizer (derivative-free)."""
def SetOptimizerAsAmoeba(self, numberOfIterations: int = 100,
parametersConvergenceTolerance: float = 1e-8,
functionConvergenceTolerance: float = 1e-4,
withRestarts: bool = False) -> None:
"""Configure Amoeba (Nelder-Mead simplex) optimizer."""
def SetOptimizerAsExhaustive(self, numberOfSteps: list[int],
stepLength: float = 1.0) -> None:
"""
Configure exhaustive search optimizer.
Args:
numberOfSteps: Number of steps for each parameter
stepLength: Step size
"""
def SetInterpolator(self, interpolator: int) -> None:
"""
Set interpolator for moving image.
Args:
interpolator: Interpolator type (sitkLinear, sitkNearestNeighbor, etc.)
"""
def SetShrinkFactorsPerLevel(self, factors: list[int]) -> None:
"""
Set shrink factors for multi-resolution pyramid.
Args:
factors: Shrink factor for each level (e.g., [4, 2, 1])
"""
def SetSmoothingSigmasPerLevel(self, sigmas: list[float]) -> None:
"""
Set smoothing sigmas for each pyramid level.
Args:
sigmas: Sigma values for Gaussian smoothing
"""
def SetSmoothingSigmasAreSpecifiedInPhysicalUnits(self, inPhysical: bool) -> None:
"""Specify if sigmas are in physical units."""
def SetMetricSamplingStrategy(self, strategy: int) -> None:
"""Set metric sampling strategy."""
def SetMetricSamplingPercentage(self, percentage: float) -> None:
"""Set percentage of pixels to sample for metric."""
def SetMetricFixedMask(self, mask) -> None:
"""Set mask for fixed image."""
def SetMetricMovingMask(self, mask) -> None:
"""Set mask for moving image."""
def AddCommand(self, event: int, callback) -> None:
"""
Add observer callback for events.
Args:
event: Event type (sitkIterationEvent, sitkStartEvent, etc.)
callback: Callback function
"""
def Execute(self, fixedImage, movingImage):
"""
Run registration.
Args:
fixedImage: Fixed (reference) image
movingImage: Moving (target) image
Returns:
Optimized transform
"""
def GetOptimizerPosition(self) -> tuple[float, ...]:
"""Get current optimizer position."""
def GetOptimizerLearningRate(self) -> float:
"""Get optimizer learning rate."""
def GetOptimizerIteration(self) -> int:
"""Get current iteration."""
def GetMetricValue(self) -> float:
"""Get current metric value."""
def GetOptimizerStopConditionDescription(self) -> str:
"""Get optimizer stop reason."""class DemonsRegistrationFilter:
"""Demons deformable registration."""
def SetNumberOfIterations(self, iterations: int) -> None:
"""Set number of iterations."""
def SetStandardDeviations(self, sigma: float) -> None:
"""Set standard deviation for Gaussian smoothing of displacement field."""
def SetUseImageSpacing(self, useSpacing: bool) -> None:
"""Account for image spacing."""
def Execute(self, fixedImage, movingImage):
"""
Run demons registration.
Returns:
Displacement field (vector image)
"""
def GetMetric(self) -> list[float]:
"""Get metric values per iteration."""
# Note: No procedural DemonsRegistration() function exists.
# Use DemonsRegistrationFilter (OOP interface) instead.
class DiffeomorphicDemonsRegistrationFilter:
"""Diffeomorphic demons (ensures invertible deformations)."""
def SetNumberOfIterations(self, iterations: int) -> None:
"""Set iterations."""
def SetStandardDeviations(self, sigma: float) -> None:
"""Set smoothing standard deviation."""
def SetUseImageSpacing(self, useSpacing: bool) -> None:
"""Account for image spacing."""
def Execute(self, fixedImage, movingImage):
"""Returns: displacement field"""
class SymmetricForcesDemonsRegistrationFilter:
"""Symmetric forces demons registration."""
def SetNumberOfIterations(self, iterations: int) -> None:
"""Set iterations."""
def SetStandardDeviations(self, sigma: float) -> None:
"""Set smoothing."""
def SetUseImageSpacing(self, useSpacing: bool) -> None:
"""Account for spacing."""
def Execute(self, fixedImage, movingImage):
"""Returns: displacement field"""
class FastSymmetricForcesDemonsRegistrationFilter:
"""Fast symmetric forces demons."""
def SetNumberOfIterations(self, iterations: int) -> None:
"""Set iterations."""
def SetStandardDeviations(self, sigma: float) -> None:
"""Set smoothing."""
def Execute(self, fixedImage, movingImage):
"""Returns: displacement field"""class WarpImageFilter:
"""Warp image using displacement field."""
def SetOutputParametersFromImage(self, referenceImage) -> None:
"""Set output geometry from reference image."""
def SetInterpolator(self, interpolator: int) -> None:
"""Set interpolator."""
def SetEdgePaddingValue(self, value: float) -> None:
"""Set value for pixels outside input."""
def Execute(self, image, displacementField):
"""
Warp image.
Args:
image: Image to warp
displacementField: Displacement field (vector image)
Returns:
Warped image
"""
def Warp(image, displacementField, outputParametersFromImage = None,
interpolator: int = sitkLinear, edgePaddingValue: float = 0):
"""Procedural: warp image."""
class InverseDisplacementFieldImageFilter:
"""Compute inverse of displacement field."""
def SetOutputOrigin(self, origin: tuple[float, ...]) -> None:
"""Set output origin."""
def SetOutputSpacing(self, spacing: tuple[float, ...]) -> None:
"""Set output spacing."""
def SetSize(self, size: tuple[int, ...]) -> None:
"""Set output size."""
def SetNumberOfIterations(self, iterations: int) -> None:
"""Set iterations for inverse computation."""
def Execute(self, displacementField):
"""
Compute inverse displacement field.
Returns:
Inverse displacement field
"""import SimpleITK as sitk
# Initialize rigid transform
initial_transform = sitk.CenteredTransformInitializer(
fixed_image,
moving_image,
sitk.Euler3DTransform(),
sitk.CenteredTransformInitializerFilter.GEOMETRY
)
# Configure registration
registration = sitk.ImageRegistrationMethod()
registration.SetMetricAsMattesMutualInformation(numberOfHistogramBins=50)
registration.SetMetricSamplingStrategy(registration.RANDOM)
registration.SetMetricSamplingPercentage(0.01)
registration.SetInterpolator(sitk.sitkLinear)
registration.SetOptimizerAsGradientDescent(
learningRate=1.0,
numberOfIterations=100,
convergenceMinimumValue=1e-6,
convergenceWindowSize=10
)
registration.SetOptimizerScalesFromPhysicalShift()
registration.SetInitialTransform(initial_transform, inPlace=False)
# Run registration
final_transform = registration.Execute(fixed_image, moving_image)
# Apply transform
resampled = sitk.Resample(moving_image, fixed_image, final_transform,
sitk.sitkLinear, 0.0, moving_image.GetPixelID())import SimpleITK as sitk
registration = sitk.ImageRegistrationMethod()
registration.SetMetricAsMattesMutualInformation(50)
registration.SetOptimizerAsGradientDescent(
learningRate=1.0,
numberOfIterations=100
)
registration.SetInterpolator(sitk.sitkLinear)
# Multi-resolution pyramid
registration.SetShrinkFactorsPerLevel([4, 2, 1])
registration.SetSmoothingSigmasPerLevel([2.0, 1.0, 0.0])
registration.SetSmoothingSigmasAreSpecifiedInPhysicalUnits(True)
# Initialize transform
initial_transform = sitk.Euler3DTransform()
registration.SetInitialTransform(initial_transform)
final_transform = registration.Execute(fixed, moving)import SimpleITK as sitk
# Run demons registration using OOP interface
demons = sitk.DemonsRegistrationFilter()
demons.SetNumberOfIterations(50)
demons.SetStandardDeviations(1.0)
displacement = demons.Execute(fixed_image, moving_image)
# Warp moving image
warped = sitk.Warp(moving_image, displacement, outputParametersFromImage=fixed_image)Install with Tessl CLI
npx tessl i tessl/pypi-simpleitk