Image Registration Optimizer Weights
If you are not familiar with the SimpleITK registration framework we recommend that you read the registration overview before continuing with the example.
Overview
The image registration framework allows us to disable subsets of the transformation parameters so that we can use a lower dimensional transformation. In some cases, if we have some better prior knowledge we can weigh the parameters accordingly (this is much harder to utilize to get a desired effect than disabling parameters).
In this example, we work with a 3D rigid transformation using the Euler parameterization, but we only allow rotation around the z axis. As there is no transformation that represents this subspace of rigid transformations, we use the SetOptimizerWeights method to disable rotations around the x and y axes. The order of the weights in the weights parameter matches the order of parameters returned from the transformation GetParameters method. For the Euler3DTransform the order is [angleX, angleY, angleZ, tx, ty, tz], so our weights vector is [0,0,1,1,1,1].
Code
using System;
using itk.simple;
namespace itk.simple.examples
{
class ImageRegistrationOptimizerWeights
{
static void Main(string[] args)
{
if (args.Length < 3)
{
Console.WriteLine("Usage: ImageRegistrationOptimizerWeights <fixedImageFile> <movingImageFile> <outputTransformFile>");
return;
}
Image fixedImage = SimpleITK.ReadImage(args[0], PixelIDValueEnum.sitkFloat32);
Image movingImage = SimpleITK.ReadImage(args[1], PixelIDValueEnum.sitkFloat32);
// initialization
Transform transform = SimpleITK.CenteredTransformInitializer(
fixedImage,
movingImage,
new Euler3DTransform(),
CenteredTransformInitializerFilter.OperationModeType.GEOMETRY);
// registration
ImageRegistrationMethod registrationMethod = new ImageRegistrationMethod();
registrationMethod.SetMetricAsCorrelation();
registrationMethod.SetMetricSamplingStrategy(ImageRegistrationMethod.MetricSamplingStrategyType.NONE);
registrationMethod.SetInterpolator(InterpolatorEnum.sitkLinear);
registrationMethod.SetOptimizerAsGradientDescent(1.0, // learningRate
300, // numberOfIterations
1e-6, // convergenceMinimumValue
10); // convergenceWindowSize
registrationMethod.SetOptimizerScalesFromPhysicalShift();
registrationMethod.SetInitialTransform(transform, true); // inPlace=true
// Set optimizer weights: [0, 0, 1, 1, 1, 1] - disable rotation around x and y axes
VectorDouble weights = new VectorDouble(new double[] { 0, 0, 1, 1, 1, 1 });
registrationMethod.SetOptimizerWeights(weights);
registrationMethod.Execute(fixedImage, movingImage);
Console.WriteLine("-------");
Console.WriteLine("Final transform parameters: " + transform.GetParameters());
Console.WriteLine("Optimizer stop condition: " + registrationMethod.GetOptimizerStopConditionDescription());
Console.WriteLine("Iteration: " + registrationMethod.GetOptimizerIteration());
Console.WriteLine("Metric value: " + registrationMethod.GetMetricValue());
SimpleITK.WriteTransform(transform, args[2]);
}
}
}
#include <SimpleITK.h>
#include <iostream>
#include <stdlib.h>
#include <vector>
namespace sitk = itk::simple;
int
main(int argc, char * argv[])
{
using sitk::operator<<;
if (argc < 4)
{
std::cout << "Usage: " << argv[0] << " <fixedImageFile> <movingImageFile> <outputTransformFile>" << std::endl;
return 1;
}
sitk::Image fixedImage = sitk::ReadImage(argv[1], sitk::sitkFloat32);
sitk::Image movingImage = sitk::ReadImage(argv[2], sitk::sitkFloat32);
// initialization
sitk::Transform transform = sitk::CenteredTransformInitializer(
fixedImage, movingImage, sitk::Euler3DTransform(), sitk::CenteredTransformInitializerFilter::GEOMETRY);
// registration
sitk::ImageRegistrationMethod registrationMethod;
registrationMethod.SetMetricAsCorrelation();
registrationMethod.SetMetricSamplingStrategy(registrationMethod.NONE);
registrationMethod.SetInterpolator(sitk::sitkLinear);
registrationMethod.SetOptimizerAsGradientDescent(1.0, // learningRate
300, // numberOfIterations
1e-6, // convergenceMinimumValue
10); // convergenceWindowSize
registrationMethod.SetOptimizerScalesFromPhysicalShift();
registrationMethod.SetInitialTransform(transform, true); // inPlace=true
// Set optimizer weights: [0, 0, 1, 1, 1, 1] - disable rotation around x and y axes
std::vector<double> weights = { 0, 0, 1, 1, 1, 1 };
registrationMethod.SetOptimizerWeights(weights);
registrationMethod.Execute(fixedImage, movingImage);
std::cout << "-------" << std::endl;
std::cout << "Final transform parameters: " << transform.GetParameters() << std::endl;
std::cout << "Optimizer stop condition: " << registrationMethod.GetOptimizerStopConditionDescription() << std::endl;
std::cout << "Iteration: " << registrationMethod.GetOptimizerIteration() << std::endl;
std::cout << "Metric value: " << registrationMethod.GetMetricValue() << std::endl;
sitk::WriteTransform(transform, argv[3]);
return 0;
}
import org.itk.simple.*;
public class ImageRegistrationOptimizerWeights {
public static void main(String[] args) throws Exception {
if (args.length < 3) {
System.out.println("Usage: ImageRegistrationOptimizerWeights <fixedImageFile> <movingImageFile> <outputTransformFile>");
System.exit(1);
}
Image fixedImage = SimpleITK.readImage(args[0], PixelIDValueEnum.sitkFloat32);
Image movingImage = SimpleITK.readImage(args[1], PixelIDValueEnum.sitkFloat32);
// initialization
Transform transform = SimpleITK.centeredTransformInitializer(
fixedImage,
movingImage,
new Euler3DTransform(),
CenteredTransformInitializerFilter.OperationModeType.GEOMETRY);
// registration
ImageRegistrationMethod registrationMethod = new ImageRegistrationMethod();
registrationMethod.setMetricAsCorrelation();
registrationMethod.setMetricSamplingStrategy(ImageRegistrationMethod.MetricSamplingStrategyType.NONE);
registrationMethod.setInterpolator(InterpolatorEnum.sitkLinear);
registrationMethod.setOptimizerAsGradientDescent(1.0, // learningRate
300, // numberOfIterations
1e-6, // convergenceMinimumValue
10); // convergenceWindowSize
registrationMethod.setOptimizerScalesFromPhysicalShift();
registrationMethod.setInitialTransform(transform, true); // inPlace=true
// Set optimizer weights: [0, 0, 1, 1, 1, 1] - disable rotation around x and y axes
VectorDouble weights = new VectorDouble();
weights.add(0.0); weights.add(0.0); weights.add(1.0);
weights.add(1.0); weights.add(1.0); weights.add(1.0);
registrationMethod.setOptimizerWeights(weights);
registrationMethod.execute(fixedImage, movingImage);
System.out.println("-------");
System.out.println("Final transform parameters: " + transform.getParameters());
System.out.println("Optimizer stop condition: " + registrationMethod.getOptimizerStopConditionDescription());
System.out.println("Iteration: " + registrationMethod.getOptimizerIteration());
System.out.println("Metric value: " + registrationMethod.getMetricValue());
SimpleITK.writeTransform(transform, args[2]);
}
}
#!/usr/bin/env python
import sys
import SimpleITK as sitk
if len(sys.argv) < 4:
print(
"Usage:",
sys.argv[0],
"<fixedImageFile> <movingImageFile>",
"<outputTransformFile>",
)
sys.exit(1)
fixed_image = sitk.ReadImage(sys.argv[1], sitk.sitkFloat32)
moving_image = sitk.ReadImage(sys.argv[2], sitk.sitkFloat32)
# initialization
transform = sitk.CenteredTransformInitializer(
fixed_image,
moving_image,
sitk.Euler3DTransform(),
sitk.CenteredTransformInitializerFilter.GEOMETRY,
)
# registration
registration_method = sitk.ImageRegistrationMethod()
registration_method.SetMetricAsCorrelation()
registration_method.SetMetricSamplingStrategy(registration_method.NONE)
registration_method.SetInterpolator(sitk.sitkLinear)
registration_method.SetOptimizerAsGradientDescent(
learningRate=1.0,
numberOfIterations=300,
convergenceMinimumValue=1e-6,
convergenceWindowSize=10,
)
registration_method.SetOptimizerScalesFromPhysicalShift()
registration_method.SetInitialTransform(transform, inPlace=True)
registration_method.SetOptimizerWeights([0, 0, 1, 1, 1, 1])
registration_method.Execute(fixed_image, moving_image)
print("-------")
print(f"Final transform parameters: {transform.GetParameters()}")
print(
"Optimizer stop condition: "
+ f"{registration_method.GetOptimizerStopConditionDescription()}"
)
print(f"Iteration: {registration_method.GetOptimizerIteration()}")
print(f"Metric value: {registration_method.GetMetricValue()}")
sitk.WriteTransform(transform, sys.argv[3])
library(SimpleITK)
args <- commandArgs( TRUE )
if (length(args) != 3) {
stop("Expected arguments: <fixedImageFile> <movingImageFile> <outputTransformFile>")
}
fixed_image = ReadImage(args[[1]], "sitkFloat32")
moving_image = ReadImage(args[[2]], "sitkFloat32")
# initialization
transform <- CenteredTransformInitializer(fixed_image,
moving_image,
Euler3DTransform(),
"GEOMETRY")
# registration
registration_method <- ImageRegistrationMethod()
registration_method$SetMetricAsCorrelation()
registration_method$SetMetricSamplingStrategy("NONE")
registration_method$SetInterpolator("sitkLinear")
registration_method$SetOptimizerAsGradientDescent(learningRate=1.0,
numberOfIterations=300,
convergenceMinimumValue=1e-6,
convergenceWindowSize=10)
registration_method$SetOptimizerScalesFromPhysicalShift()
registration_method$SetInitialTransform(transform, inPlace=TRUE)
registration_method$SetOptimizerWeights(c(0,0,1,1,1,1))
output_sink_tx<-registration_method$Execute(fixed_image, moving_image)
cat("-------\n")
cat("Final transform parameters: ", transform$GetParameters(), "\n")
cat("Optimizer stop condition: ", registration_method$GetOptimizerStopConditionDescription(), "\n")
cat("Iteration: ", registration_method$GetOptimizerIteration(), "\n")
cat("Metric value:", registration_method$GetMetricValue(), "\n")
WriteTransform(transform, args[[3]])