ITK 2D image rigid registration

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"
Fixed Image
Moving Image

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;
}

Output results

##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;
}

Guess you like

Origin blog.csdn.net/Gastby_/article/details/126732551