/*========================================================================= Program: Insight Segmentation & Registration Toolkit Module: $RCSfile: ImageRegistration3-mod.cxx,v $ Language: C++ Date: $Date: 2005/06/10 18:31:25 $ Version: $Revision: 1.33 $ Copyright (c) Insight Software Consortium. All rights reserved. See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #if defined(_MSC_VER) #pragma warning ( disable : 4786 ) #endif // Software Guide : BeginLatex // // This example illustrates the use of the // \doxygen{CommbinedImageToImageMetricAdaptor} class for performing // registration of two $2D$ images. The example code is for // the most part identical to code presented in ImageRegistration3.cxx. // The major difference is that in the example we use a combined // mean squares and normalized correlation metric. // // Software Guide : EndLatex // Software Guide : BeginCodeSnippet #include "itkMeanSquaresImageToImageMetric.h" #include "itkNormalizedCorrelationImageToImageMetric.h" #include "itkCombinedImageToImageMetricAdaptor.h" // Software Guide : EndCodeSnippet #include "itkImageRegistrationMethod.h" #include "itkTranslationTransform.h" #include "itkLinearInterpolateImageFunction.h" #include "itkRegularStepGradientDescentOptimizer.h" #include "itkImage.h" #include "itkImageFileReader.h" #include "itkImageFileWriter.h" #include "itkResampleImageFilter.h" #include "itkCastImageFilter.h" #include "itkCommand.h" class CommandIterationUpdate : public itk::Command { public: typedef CommandIterationUpdate Self; typedef itk::Command Superclass; typedef itk::SmartPointer Pointer; itkNewMacro( Self ); protected: CommandIterationUpdate() {}; public: typedef itk::RegularStepGradientDescentOptimizer OptimizerType; typedef const OptimizerType *OptimizerPointer; void Execute(itk::Object *caller, const itk::EventObject & event) { Execute( (const itk::Object *)caller, event); } void Execute(const itk::Object * object, const itk::EventObject & event) { OptimizerPointer optimizer = dynamic_cast< OptimizerPointer >( object ); if( ! itk::IterationEvent().CheckEvent( &event ) ) { return; } std::cout << optimizer->GetCurrentIteration() << " = "; std::cout << optimizer->GetValue() << " : "; std::cout << optimizer->GetCurrentPosition() << std::endl; } }; int main( int argc, char *argv[] ) { if( argc < 3 ) { std::cerr << "Missing Parameters " << std::endl; std::cerr << "Usage: " << argv[0]; std::cerr << " fixedImageFile movingImageFile "; std::cerr << "outputImagefile [differenceImage]" << std::endl; return 1; } const unsigned int Dimension = 2; typedef unsigned short PixelType; typedef itk::Image< PixelType, Dimension > FixedImageType; typedef itk::Image< PixelType, Dimension > MovingImageType; typedef itk::TranslationTransform< double, Dimension > TransformType; typedef itk::RegularStepGradientDescentOptimizer OptimizerType; typedef itk::LinearInterpolateImageFunction< MovingImageType, double > InterpolatorType; typedef itk::ImageRegistrationMethod< FixedImageType, MovingImageType > RegistrationType; // Software Guide : BeginCodeSnippet typedef itk::MeanSquaresImageToImageMetric< FixedImageType, MovingImageType > Metric1Type; typedef itk::NormalizedCorrelationImageToImageMetric< FixedImageType, MovingImageType > Metric2Type; typedef itk::CombinedImageToImageMetricAdaptor< FixedImageType, MovingImageType > MetricType; // Software Guide : EndCodeSnippet TransformType::Pointer transform = TransformType::New(); OptimizerType::Pointer optimizer = OptimizerType::New(); InterpolatorType::Pointer interpolator = InterpolatorType::New(); RegistrationType::Pointer registration = RegistrationType::New(); registration->SetOptimizer( optimizer ); registration->SetTransform( transform ); registration->SetInterpolator( interpolator ); typedef itk::ImageFileReader< FixedImageType > FixedImageReaderType; typedef itk::ImageFileReader< MovingImageType > MovingImageReaderType; FixedImageReaderType::Pointer fixedImageReader = FixedImageReaderType::New(); MovingImageReaderType::Pointer movingImageReader = MovingImageReaderType::New(); fixedImageReader->SetFileName( argv[1] ); movingImageReader->SetFileName( argv[2] ); registration->SetFixedImage( fixedImageReader->GetOutput() ); registration->SetMovingImage( movingImageReader->GetOutput() ); fixedImageReader->Update(); // This is needed to make the BufferedRegion below valid. registration->SetFixedImageRegion( fixedImageReader->GetOutput()->GetBufferedRegion() ); typedef RegistrationType::ParametersType ParametersType; ParametersType initialParameters( transform->GetNumberOfParameters() ); initialParameters[0] = 0.0; // Initial offset in mm along X initialParameters[1] = 0.0; // Initial offset in mm along Y registration->SetInitialTransformParameters( initialParameters ); optimizer->SetMaximumStepLength( 4.00 ); optimizer->SetMinimumStepLength( 0.01 ); optimizer->SetNumberOfIterations( 200 ); optimizer->MaximizeOff(); //---------------------------------------------------- // Setting up the combined weighted metric //---------------------------------------------------- // Instantiate the each of the underlying metrics Metric1Type::Pointer metric1 = Metric1Type::New(); Metric2Type::Pointer metric2 = Metric2Type::New(); // Instantiate the combined metric MetricType::Pointer metric = MetricType::New(); // We have to manually hook things up to the metric // since we can potentially have metric which is based on // different images and/or masks etc // Setup for metric1: mean squares InterpolatorType::Pointer interpolator1 = InterpolatorType::New(); metric1->SetFixedImage( fixedImageReader->GetOutput() ); metric1->SetMovingImage( movingImageReader->GetOutput() ); metric1->SetFixedImageRegion( fixedImageReader->GetOutput()->GetBufferedRegion() ); metric1->SetInterpolator( interpolator1 ); // Setup for metric2: normalized correlation InterpolatorType::Pointer interpolator2 = InterpolatorType::New(); metric2->SetFixedImage( fixedImageReader->GetOutput() ); metric2->SetMovingImage( movingImageReader->GetOutput() ); metric2->SetFixedImageRegion( fixedImageReader->GetOutput()->GetBufferedRegion() ); metric2->SetInterpolator( interpolator2 ); // Plug the underlying metrics into the adaptor metric->SetMetric( 0, metric1, 0.001 ); metric->SetMetric( 1, metric2, 1.0 ); // Plug adaptor into the registration class registration->SetMetric( metric ); CommandIterationUpdate::Pointer observer = CommandIterationUpdate::New(); optimizer->AddObserver( itk::IterationEvent(), observer ); try { registration->StartRegistration(); } catch( itk::ExceptionObject & err ) { std::cout << "ExceptionObject caught !" << std::endl; std::cout << err << std::endl; return -1; } ParametersType finalParameters = registration->GetLastTransformParameters(); const double TranslationAlongX = finalParameters[0]; const double TranslationAlongY = finalParameters[1]; const unsigned int numberOfIterations = optimizer->GetCurrentIteration(); const double bestValue = optimizer->GetValue(); std::cout << "Registration done !" << std::endl; std::cout << "Number of iterations = " << numberOfIterations << std::endl; std::cout << "Translation along X = " << TranslationAlongX << std::endl; std::cout << "Translation along Y = " << TranslationAlongY << std::endl; std::cout << "Optimal metric value = " << bestValue << std::endl; // Prepare the resampling filter in order to map the moving image. // typedef itk::ResampleImageFilter< MovingImageType, FixedImageType > ResampleFilterType; TransformType::Pointer finalTransform = TransformType::New(); finalTransform->SetParameters( finalParameters ); ResampleFilterType::Pointer resample = ResampleFilterType::New(); resample->SetTransform( finalTransform ); resample->SetInput( movingImageReader->GetOutput() ); FixedImageType::Pointer fixedImage = fixedImageReader->GetOutput(); resample->SetSize( fixedImage->GetLargestPossibleRegion().GetSize() ); resample->SetOutputOrigin( fixedImage->GetOrigin() ); resample->SetOutputSpacing( fixedImage->GetSpacing() ); resample->SetDefaultPixelValue( 100 ); // Prepare a writer and caster filters to send the resampled moving image to // a file // typedef unsigned char OutputPixelType; typedef itk::Image< OutputPixelType, Dimension > OutputImageType; typedef itk::CastImageFilter< FixedImageType, OutputImageType > CastFilterType; typedef itk::ImageFileWriter< OutputImageType > WriterType; WriterType::Pointer writer = WriterType::New(); CastFilterType::Pointer caster = CastFilterType::New(); writer->SetFileName( argv[3] ); caster->SetInput( resample->GetOutput() ); writer->SetInput( caster->GetOutput() ); writer->Update(); return 0; }