Hello,
I am relatively new ITK user and I am trying to implement affine registration in C++. After going through examples, I was able to put together a reasonable solution. However, when I run it it crashes unexpectedly with the following call stack:
ITK-5.2/itkImageConstIteratorWithIndex.hxx:103:18: runtime error: applying non-zero offset 4194300 to null pointer
::ImageConstIteratorWithIndex ITK-5.2/itkImageConstIteratorWithIndex.hxx:103
::ImageRandomConstIteratorWithIndex ITK-5.2/itkImageRandomConstIteratorWithIndex.hxx:41
::SetMetricSamplePoints() ITK-5.2/itkImageRegistrationMethodv4.hxx:1028
::InitializeRegistrationAtEachLevel(unsigned long) ITK-5.2/itkImageRegistrationMethodv4.hxx:734
Looking through the header files/source code, it appears to me that this is something to do with VirtualDomainImage. I am a little surprised by this, since my understanding was that mapping between fixed image and VirtualDomainImage was identity by default and I don’t have to specify that explicitly. Am I missing something? I would greatly appreciate your help. Thank you, in advance!
For completeness, my source code is listed below.
using ImageType = itk::Image<float, 2>;
using TransformType = itk::AffineTransform<double, 2>;
using MetricType = itk::CorrelationImageToImageMetricv4<ImageType, ImageType>;
using RegistrationType = itk::ImageRegistrationMethodv4<ImageType, ImageType>;
using OptimizerType = itk::RegularStepGradientDescentOptimizerv4<double>;
using TransformInitializerType =
itk::CenteredTransformInitializer<TransformType, ImageType, ImageType>;
using InterpolatorType = itk::LinearInterpolateImageFunction<ImageType, double>;
affine_transform(const ImageType::Pointer fixedImage, const ImageType::Pointer movingImage) {
auto initialTransform = TransformType::New();
auto transformInitializer = TransformInitializerType::New();
transformInitializer->SetFixedImage(fixedImage);
transformInitializer->SetMovingImage(movingImage);
transformInitializer->SetTransform(initialTransform);
transformInitializer->GeometryOn();
transformInitializer->InitializeTransform();
auto optimizer = OptimizerType::New();
optimizer->SetLearningRate(4);
optimizer->SetMinimumStepLength(0.001);
optimizer->SetNumberOfIterations(200);
optimizer->SetRelaxationFactor(0.5);
optimizer->SetGradientMagnitudeTolerance(1e-4);
auto metric = MetricType::New();
auto fixedIinterpolator = InterpolatorType::New();
auto movingInterpolator = InterpolatorType::New();
metric->SetFixedInterpolator(fixedIinterpolator);
metric->SetMovingInterpolator(movingInterpolator);
auto scaleEstimator =
itk::RegistrationParameterScalesFromPhysicalShift<MetricType>::New();
scaleEstimator->SetCentralRegionRadius(5);
scaleEstimator->SetSmallParameterVariation(0.01);
scaleEstimator->SetMetric(metric);
scaleEstimator->SetTransformForward(true);
optimizer->SetScalesEstimator(scaleEstimator);
auto registration = RegistrationType::New();
registration->SetInitialTransform(initialTransform);
registration->SetMovingInitialTransform(initialTransform);
registration->SetMetric(metric);
registration->SetOptimizer(optimizer);
registration->SetFixedImage(fixedImage);
registration->SetMovingImage(movingImage);
registration->SetInPlace(true);
registration->SetNumberOfLevels(1);
registration->SetMetricSamplingStrategy(itk::ImageRegistrationMethodv4Enums::MetricSamplingStrategy::RANDOM);
registration->SetMetricSamplingPercentage(0.01);
auto identityTransform = TransformType::New();
identityTransform->SetIdentity();
registration->SetFixedInitialTransform(identityTransform);
try {
registration->Update();
} catch (const itk::ExceptionObject& err) {
std::cerr << "ExceptionObject caught !" << std::endl;
std::cerr << err << std::endl;
return NULL;
}
initialTransform->Register();
return initialTransform.GetPointer();
}