Landmark Registration
This example demonstrates the use of point based registration. This form of registration is often used to initialize an intensity based registration that refines the results of the point base method, hence the “initializer” in the class name. The example uses a 2D rigid transformation, though the LandmarkBasedTransformInitializerFilter class supports other transformation types including VersorRigid3DTransform, AffineTransform and BSplineTransform.
If you are not familiar with the SimpleITK registration framework we recommend that you read the registration overview before continuing with the example.
Overview
Code
#include <SimpleITK.h>
#include <iostream>
#include <vector>
namespace sitk = itk::simple;
int
main(int argc, char * argv[])
{
using sitk::operator<<;
// Black image with a small white square in it.
sitk::Image fixedImage(100, 100, sitk::sitkUInt8);
// Paste a white square (9x9 pixels with value 200) at position [11, 11]
sitk::PasteImageFilter pasteFilter;
pasteFilter.SetSourceSize({ 9, 9 });
pasteFilter.SetSourceIndex({ 0, 0 });
pasteFilter.SetDestinationIndex({ 11, 11 });
fixedImage = pasteFilter.Execute(fixedImage, 200);
// Black image with a small grey square at a different location.
sitk::Image movingImage(100, 100, sitk::sitkUInt8);
// Paste a grey square (9x9 pixels with value 69) at position [51, 51]
pasteFilter.SetDestinationIndex({ 51, 51 });
movingImage = pasteFilter.Execute(movingImage, 69);
// Landmarks are 3 corners of the squares.
// 3 (X, Y) pairs are flattened into 1-d lists.
std::vector<double> fixedLandmarks = { 10, 10, 20, 10, 20, 20 };
std::vector<double> movingLandmarks = { 50, 50, 60, 50, 60, 60 };
// Set up the LandmarkBasedTransformInitializerFilter.
sitk::LandmarkBasedTransformInitializerFilter landmarkInitializer;
landmarkInitializer.SetFixedLandmarks(fixedLandmarks);
landmarkInitializer.SetMovingLandmarks(movingLandmarks);
sitk::Transform transform = sitk::Euler2DTransform();
// Compute the transform.
sitk::Transform outputTransform = landmarkInitializer.Execute(transform);
std::cout << outputTransform.ToString() << std::endl;
// Resample the transformed moving image onto the fixed image.
sitk::Image outputImage = sitk::Resample(movingImage, fixedImage, outputTransform, sitk::sitkLinear, 150);
// Write the resampled image.
sitk::WriteImage(outputImage, "landmark_example.png");
// Write the transform.
std::string outName;
if (argc > 1)
{
outName = argv[1];
}
else
{
outName = "landmark_transform.tfm";
}
sitk::WriteTransform(outputTransform, outName);
return 0;
}
using System;
using itk.simple;
namespace itk.simple.examples
{
class LandmarkRegistration
{
static void Main(string[] args)
{
// Black image with a small white square in it.
Image fixedImage = new Image(100, 100, PixelIDValueEnum.sitkUInt8);
// Paste a white square (9x9 pixels with value 200) at position [11, 11]
PasteImageFilter pasteFilter = new PasteImageFilter();
pasteFilter.SetSourceSize(new VectorUInt32(new uint[] {9, 9}));
pasteFilter.SetSourceIndex(new VectorInt32(new int[] {0, 0}));
pasteFilter.SetDestinationIndex(new VectorInt32(new int[] {11, 11}));
fixedImage = pasteFilter.Execute(fixedImage, 200);
// Black image with a small grey square at a different location.
Image movingImage = new Image(100, 100, PixelIDValueEnum.sitkUInt8);
// Paste a grey square (9x9 pixels with value 69) at position [51, 51]
pasteFilter.SetDestinationIndex(new VectorInt32(new int[] {51, 51}));
movingImage = pasteFilter.Execute(movingImage, 69);
// Landmarks are 3 corners of the squares.
// 3 (X, Y) pairs are flattened into 1-d lists.
VectorDouble fixedLandmarks = new VectorDouble(new double[] {10, 10, 20, 10, 20, 20});
VectorDouble movingLandmarks = new VectorDouble(new double[] {50, 50, 60, 50, 60, 60});
// Set up the LandmarkBasedTransformInitializerFilter.
LandmarkBasedTransformInitializerFilter landmarkInitializer = new LandmarkBasedTransformInitializerFilter();
landmarkInitializer.SetFixedLandmarks(fixedLandmarks);
landmarkInitializer.SetMovingLandmarks(movingLandmarks);
Transform transform = new Euler2DTransform();
// Compute the transform.
Transform outputTransform = landmarkInitializer.Execute(transform);
Console.WriteLine(outputTransform.ToString());
// Resample the transformed moving image onto the fixed image.
Image outputImage = SimpleITK.Resample(movingImage, fixedImage, outputTransform, InterpolatorEnum.sitkLinear, 150);
// Write the resampled image.
SimpleITK.WriteImage(outputImage, "landmark_example.png");
// Write the transform.
string outName;
if (args.Length > 0)
{
outName = args[0];
}
else
{
outName = "landmark_transform.tfm";
}
SimpleITK.WriteTransform(outputTransform, outName);
}
}
}
import org.itk.simple.*;
public class LandmarkRegistration {
public static void main(String[] args) throws Exception {
// Black image with a small white square in it.
Image fixedImage = new Image(100, 100, PixelIDValueEnum.sitkUInt8);
// Set pixels in rectangle [11:20, 11:20] to 200
for (long x = 11; x < 20; ++x) {
for (long y = 11; y < 20; ++y) {
VectorUInt32 idx = new VectorUInt32();
idx.add(x);
idx.add(y);
fixedImage.setPixelAsUInt8(idx, (short)200);
}
}
// Black image with a small grey square at a different location.
Image movingImage = new Image(100, 100, PixelIDValueEnum.sitkUInt8);
// Set pixels in rectangle [51:60, 51:60] to 69
for (long x = 51; x < 60; ++x) {
for (long y = 51; y < 60; ++y) {
VectorUInt32 idx = new VectorUInt32();
idx.add(x);
idx.add(y);
movingImage.setPixelAsUInt8(idx, (short)69);
}
}
// Landmarks are 3 corners of the squares.
// 3 (X, Y) pairs are flattened into 1-d lists.
VectorDouble fixedLandmarks = new VectorDouble();
fixedLandmarks.add(10.0); fixedLandmarks.add(10.0);
fixedLandmarks.add(20.0); fixedLandmarks.add(10.0);
fixedLandmarks.add(20.0); fixedLandmarks.add(20.0);
VectorDouble movingLandmarks = new VectorDouble();
movingLandmarks.add(50.0); movingLandmarks.add(50.0);
movingLandmarks.add(60.0); movingLandmarks.add(50.0);
movingLandmarks.add(60.0); movingLandmarks.add(60.0);
// Set up the LandmarkBasedTransformInitializerFilter.
LandmarkBasedTransformInitializerFilter landmarkInitializer = new LandmarkBasedTransformInitializerFilter();
landmarkInitializer.setFixedLandmarks(fixedLandmarks);
landmarkInitializer.setMovingLandmarks(movingLandmarks);
Transform transform = new Euler2DTransform();
// Compute the transform.
Transform outputTransform = landmarkInitializer.execute(transform);
System.out.println(outputTransform.toString());
// Resample the transformed moving image onto the fixed image.
Image outputImage = SimpleITK.resample(movingImage, fixedImage, outputTransform, InterpolatorEnum.sitkLinear, 150);
// Write the resampled image.
SimpleITK.writeImage(outputImage, "landmark_example.png");
// Write the transform.
String outName;
if (args.length > 0) {
outName = args[0];
} else {
outName = "landmark_transform.tfm";
}
SimpleITK.writeTransform(outputTransform, outName);
}
}
#!/usr/bin/env python
import sys
import SimpleITK as sitk
# Black image with a small white square in it.
fixed_image = sitk.Image(100, 100, sitk.sitkUInt8)
fixed_image[11:20, 11:20] = 200
# Black image with a small grey square at a different location.
moving_image = sitk.Image(100, 100, sitk.sitkUInt8)
moving_image[51:60, 51:60] = 69
# Landmarks are 3 corners of the squares.
# 3 (X, Y) pairs are flattened into 1-d lists.
fixed_landmarks = [10, 10, 20, 10, 20, 20]
moving_landmarks = [50, 50, 60, 50, 60, 60]
# Set up the LandmarkBasedTransformInitializerFilter.
landmark_initializer = sitk.LandmarkBasedTransformInitializerFilter()
landmark_initializer.SetFixedLandmarks(fixed_landmarks)
landmark_initializer.SetMovingLandmarks(moving_landmarks)
transform = sitk.Euler2DTransform()
# Compute the transform.
output_transform = landmark_initializer.Execute(transform)
print(output_transform)
# Resample the transformed moving image onto the fixed image.
output_image = sitk.Resample(
moving_image, fixed_image, transform=output_transform, defaultPixelValue=150
)
# Write the resampled image.
sitk.WriteImage(output_image, "landmark_example.png")
# Write the transform.
if len(sys.argv) > 1:
out_name = sys.argv[1]
else:
out_name = "landmark_transform.tfm"
sitk.WriteTransform(output_transform, out_name)
library(SimpleITK)
args <- commandArgs(TRUE)
# Black image with a small white square in it.
fixedImage <- Image(100, 100, 'sitkUInt8')
# Set pixels in rectangle [11:20, 11:20] to 200
for (x in 11:19) {
for (y in 11:19) {
fixedImage$SetPixel(c(x, y), 200)
}
}
# Black image with a small grey square at a different location.
movingImage <- Image(100, 100, 'sitkUInt8')
# Set pixels in rectangle [51:60, 51:60] to 69
for (x in 51:59) {
for (y in 51:59) {
movingImage$SetPixel(c(x, y), 69)
}
}
# Landmarks are 3 corners of the squares.
# 3 (X, Y) pairs are flattened into 1-d lists.
fixedLandmarks <- c(10, 10, 20, 10, 20, 20)
movingLandmarks <- c(50, 50, 60, 50, 60, 60)
# Set up the LandmarkBasedTransformInitializerFilter.
landmarkInitializer <- LandmarkBasedTransformInitializerFilter()
landmarkInitializer$SetFixedLandmarks(fixedLandmarks)
landmarkInitializer$SetMovingLandmarks(movingLandmarks)
transform <- Euler2DTransform()
# Compute the transform.
outputTransform <- landmarkInitializer$Execute(transform)
cat(outputTransform$ToString())
# Resample the transformed moving image onto the fixed image.
outputImage <- Resample(movingImage, fixedImage, outputTransform, 'sitkLinear', 150)
# Write the resampled image.
WriteImage(outputImage, "landmark_example.png")
# Write the transform.
if (length(args) > 0) {
outName <- args[1]
} else {
outName <- "landmark_transform.tfm"
}
WriteTransform(outputTransform, outName)