Development environment: VS 2022, Windows 10, ITK5.3
The usage data is BrainProtonDensitySliceBorder20.png and BrainProtonDensitySliceR10X13Y17.png under "D:\Windows\ITK-5.2.1\Examples\Data"
1. Import the required header files
#include "itkImageRegistrationMethodv4.h" //包含配准方法
#include "itkTranslationTransform.h" //空间变换
#include "itkMeanSquaresImageToImageMetricv4.h" //损失函数
#include "itkRegularStepGradientDescentOptimizerv4.h"//优化算法
#include "itkImageFileReader.h"//读取图像
#include "itkImageFileWriter.h"//写入结果
#include "itkPNGImageIOFactory.h" //读取PNG图像所需
using namespace std;
2. Instantiate the required objects
Define the dimensions and pixel type of the read image
constexpr unsigned int Dimension = 2;
using PixelType = float;
instantiate object
//参考和浮动图像的类型在实例化的时候需要指定
using FixedImageType = itk::Image<PixelType, Dimension>;
using MovingImageType = itk::Image<PixelType, Dimension>;
// 空间变换类型和维度
using TransformType = itk::TranslationTransform<double, Dimension>;
//优化算法处理数据的类型
using OptimizerType = itk::RegularStepGradientDescentOptimizerv4<double>;
//计算损失函数的对象,需要指定参考和浮动图像
using MetricType =
itk::MeanSquaresImageToImageMetricv4<FixedImageType, MovingImageType>;
//配准方法实例化,需要指定参考和浮动图像
using RegistrationType = itk::
ImageRegistrationMethodv4<FixedImageType, MovingImageType, TransformType>;
3.Create some objects
Created through New() and assigned through itk::SmartPointer
MetricType::Pointer metric = MetricType::New();
OptimizerType::Pointer optimizer = OptimizerType::New();
RegistrationType::Pointer registration = RegistrationType::New();
4. Configure registration method
Assign the declared partial objects to the registration method (such as optimizer, loss function)
registration->SetMetric(metric);
registration->SetOptimizer(optimizer);
5. Configure the loss function
//配置之前需要用到插值方法,因此需要实例化和创建参考和浮动图像的插值对象
using FixedLinearInterpolatorType =
itk::LinearInterpolateImageFunction<FixedImageType, double>;
using MovingLinearInterpolatorType =
itk::LinearInterpolateImageFunction<MovingImageType, double>;
FixedLinearInterpolatorType::Pointer fixedInterpolator =
FixedLinearInterpolatorType::New();
MovingLinearInterpolatorType::Pointer movingInterpolator =
MovingLinearInterpolatorType::New();
metric->SetFixedInterpolator(fixedInterpolator);
metric->SetMovingInterpolator(movingInterpolator);
6. Read the image and put it into the registration method
typedef itk::ImageFileReader< FixedImageType > FixedImageReaderType;
typedef itk::ImageFileReader< MovingImageType > MovingImageReaderType;
FixedImageReaderType::Pointer fixedImageReader = FixedImageReaderType::New();
MovingImageReaderType::Pointer movingImageReader = MovingImageReaderType::New();
itk::PNGImageIOFactory::RegisterOneFactory();
fixedImageReader->SetFileName(R"(C:\Users\Richard\Desktop\BrainProtonDensitySliceBorder20.png)");
movingImageReader->SetFileName(R"(C:\Users\Richard\Desktop\BrainProtonDensitySliceR10X13Y17.png)");
registration->SetFixedImage(fixedImageReader->GetOutput());
registration->SetMovingImage(movingImageReader->GetOutput());
7. Configure space transformation matrix
TransformType::Pointer movingInitialTransform = TransformType::New();
TransformType::ParametersType initialParameters(
movingInitialTransform->GetNumberOfParameters());
initialParameters[0] = 0.0; // Initial offset in mm along X
initialParameters[1] = 0.0; // Initial offset in mm along Y
movingInitialTransform->SetParameters(initialParameters);
registration->SetMovingInitialTransform(movingInitialTransform);
TransformType::Pointer identityTransform = TransformType::New();
identityTransform->SetIdentity();
registration->SetFixedInitialTransform(identityTransform);
8. Configure optimizer parameters
optimizer->SetLearningRate(4);
optimizer->SetMinimumStepLength(0.001);
optimizer->SetRelaxationFactor(0.5);
optimizer->SetNumberOfIterations(200);
constexpr unsigned int numberOfLevels = 1;
RegistrationType::ShrinkFactorsArrayType shrinkFactorsPerLevel;
shrinkFactorsPerLevel.SetSize(1);
shrinkFactorsPerLevel[0] = 1;
RegistrationType::SmoothingSigmasArrayType smoothingSigmasPerLevel;
smoothingSigmasPerLevel.SetSize(1);
smoothingSigmasPerLevel[0] = 0;
registration->SetNumberOfLevels(numberOfLevels);
registration->SetSmoothingSigmasPerLevel(smoothingSigmasPerLevel);
9. Start registration and output final results
try
{
registration->Update();
std::cout << "Optimizer stop condition: "
<< registration->GetOptimizer()->GetStopConditionDescription()
<< std::endl;
}
catch (const itk::ExceptionObject& err)
{
std::cerr << "ExceptionObject caught !" << std::endl;
std::cerr << err << std::endl;
return EXIT_FAILURE;
}
TransformType::ConstPointer transform = registration->GetTransform();
TransformType::ParametersType finalParameters = transform->GetParameters();
const double TranslationAlongX = finalParameters[0];
const double TranslationAlongY = finalParameters[1];
const unsigned int numberOfIterations = optimizer->GetCurrentIteration();
const double bestValue = optimizer->GetValue();
cout << bestValue<<endl;
cout << TranslationAlongX << endl;
cout << TranslationAlongY << endl;
}
##Complete code
#include "itkImageRegistrationMethodv4.h"
#include "itkTranslationTransform.h"
#include "itkMeanSquaresImageToImageMetricv4.h"
#include "itkRegularStepGradientDescentOptimizerv4.h"
#include "itkImageFileReader.h"
#include "itkImageFileWriter.h"
#include "itkPNGImageIOFactory.h"
using namespace std;
int main()
{
constexpr unsigned int Dimension = 2;
using PixelType = float;
using FixedImageType = itk::Image<PixelType, Dimension>;
using MovingImageType = itk::Image<PixelType, Dimension>;
using TransformType = itk::TranslationTransform<double, Dimension>;
using OptimizerType = itk::RegularStepGradientDescentOptimizerv4<double>;
using MetricType =
itk::MeanSquaresImageToImageMetricv4<FixedImageType, MovingImageType>;
using RegistrationType = itk::
ImageRegistrationMethodv4<FixedImageType, MovingImageType, TransformType>;
MetricType::Pointer metric = MetricType::New();
OptimizerType::Pointer optimizer = OptimizerType::New();
RegistrationType::Pointer registration = RegistrationType::New();
registration->SetMetric(metric);
registration->SetOptimizer(optimizer);
using FixedLinearInterpolatorType =
itk::LinearInterpolateImageFunction<FixedImageType, double>;
using MovingLinearInterpolatorType =
itk::LinearInterpolateImageFunction<MovingImageType, double>;
FixedLinearInterpolatorType::Pointer fixedInterpolator =
FixedLinearInterpolatorType::New();
MovingLinearInterpolatorType::Pointer movingInterpolator =
MovingLinearInterpolatorType::New();
metric->SetFixedInterpolator(fixedInterpolator);
metric->SetMovingInterpolator(movingInterpolator);
typedef itk::ImageFileReader< FixedImageType > FixedImageReaderType;
typedef itk::ImageFileReader< MovingImageType > MovingImageReaderType;
FixedImageReaderType::Pointer fixedImageReader = FixedImageReaderType::New();
MovingImageReaderType::Pointer movingImageReader = MovingImageReaderType::New();
itk::PNGImageIOFactory::RegisterOneFactory();
fixedImageReader->SetFileName(R"(C:\Users\Richard\Desktop\BrainProtonDensitySliceBorder20.png)");
movingImageReader->SetFileName(R"(C:\Users\Richard\Desktop\BrainProtonDensitySliceR10X13Y17.png)");
registration->SetFixedImage(fixedImageReader->GetOutput());
registration->SetMovingImage(movingImageReader->GetOutput());
TransformType::Pointer movingInitialTransform = TransformType::New();
TransformType::ParametersType initialParameters(
movingInitialTransform->GetNumberOfParameters());
initialParameters[0] = 0.0; // Initial offset in mm along X
initialParameters[1] = 0.0; // Initial offset in mm along Y
movingInitialTransform->SetParameters(initialParameters);
registration->SetMovingInitialTransform(movingInitialTransform);
TransformType::Pointer identityTransform = TransformType::New();
identityTransform->SetIdentity();
registration->SetFixedInitialTransform(identityTransform);
optimizer->SetLearningRate(4);
optimizer->SetMinimumStepLength(0.001);
optimizer->SetRelaxationFactor(0.5);
optimizer->SetNumberOfIterations(200);
constexpr unsigned int numberOfLevels = 1;
RegistrationType::ShrinkFactorsArrayType shrinkFactorsPerLevel;
shrinkFactorsPerLevel.SetSize(1);
shrinkFactorsPerLevel[0] = 1;
RegistrationType::SmoothingSigmasArrayType smoothingSigmasPerLevel;
smoothingSigmasPerLevel.SetSize(1);
smoothingSigmasPerLevel[0] = 0;
registration->SetNumberOfLevels(numberOfLevels);
registration->SetSmoothingSigmasPerLevel(smoothingSigmasPerLevel);
try
{
registration->Update();
std::cout << "Optimizer stop condition: "
<< registration->GetOptimizer()->GetStopConditionDescription()
<< std::endl;
}
catch (const itk::ExceptionObject& err)
{
std::cerr << "ExceptionObject caught !" << std::endl;
std::cerr << err << std::endl;
return EXIT_FAILURE;
}
TransformType::ConstPointer transform = registration->GetTransform();
TransformType::ParametersType finalParameters = transform->GetParameters();
const double TranslationAlongX = finalParameters[0];
const double TranslationAlongY = finalParameters[1];
const unsigned int numberOfIterations = optimizer->GetCurrentIteration();
const double bestValue = optimizer->GetValue();
cout << bestValue<<endl;
cout << TranslationAlongX << endl;
cout << TranslationAlongY << endl;
}