1 /*=========================================================================
2  *
3  *  Copyright Insight Software Consortium
4  *
5  *  Licensed under the Apache License, Version 2.0 (the "License");
6  *  you may not use this file except in compliance with the License.
7  *  You may obtain a copy of the License at
8  *
9  *         http://www.apache.org/licenses/LICENSE-2.0.txt
10  *
11  *  Unless required by applicable law or agreed to in writing, software
12  *  distributed under the License is distributed on an "AS IS" BASIS,
13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  *  See the License for the specific language governing permissions and
15  *  limitations under the License.
16  *
17  *=========================================================================*/
18 
19 #include "itkImageRegistrationMethod.h"
20 #include "itkMeanReciprocalSquareDifferenceImageToImageMetric.h"
21 #include "itkLinearInterpolateImageFunction.h"
22 #include "itkRegularStepGradientDescentOptimizer.h"
23 
24 #include "itkImageRegistrationMethodImageSource.h"
25 
26 /**
27  *  This program tests one instantiation of the itk::ImageRegistrationMethod class
28  *
29  *
30  */
31 
itkImageRegistrationMethodTest_10(int argc,char * argv[])32 int itkImageRegistrationMethodTest_10(int argc, char* argv[] )
33 {
34 
35   bool pass = true;
36 
37   constexpr unsigned int dimension = 2;
38 
39   // Fixed Image Type
40   using FixedImageType = itk::Image<float,dimension>;
41 
42   // Moving Image Type
43   using MovingImageType = itk::Image<float,dimension>;
44 
45   // Size Type
46   using SizeType = MovingImageType::SizeType;
47 
48 
49   // ImageSource
50   using ImageSourceType = itk::testhelper::ImageRegistrationMethodImageSource<
51                                   FixedImageType::PixelType,
52                                   MovingImageType::PixelType,
53                                   dimension >;
54   // Transform Type
55   using TransformType = itk::AffineTransform< double, dimension >;
56   using ParametersType = TransformType::ParametersType;
57 
58   // Optimizer Type
59   using OptimizerType = itk::RegularStepGradientDescentOptimizer;
60 
61   // Metric Type
62   using MetricType = itk::MeanReciprocalSquareDifferenceImageToImageMetric<
63                                     FixedImageType,
64                                     MovingImageType >;
65 
66   // Interpolation technique
67   using InterpolatorType = itk:: LinearInterpolateImageFunction<
68                                     MovingImageType,
69                                     double >;
70 
71   // Registration Method
72   using RegistrationType = itk::ImageRegistrationMethod<
73                                     FixedImageType,
74                                     MovingImageType >;
75 
76   using CommandIterationType = itk::CommandIterationUpdate<OptimizerType>;
77 
78 
79   MetricType::Pointer         metric        = MetricType::New();
80   TransformType::Pointer      transform     = TransformType::New();
81   OptimizerType::Pointer      optimizer     = OptimizerType::New();
82   InterpolatorType::Pointer   interpolator  = InterpolatorType::New();
83   RegistrationType::Pointer   registration  = RegistrationType::New();
84 
85   ImageSourceType::Pointer    imageSource   = ImageSourceType::New();
86 
87   SizeType size;
88   size[0] = 100;
89   size[1] = 100;
90 
91   imageSource->GenerateImages( size );
92 
93   FixedImageType::ConstPointer     fixedImage    = imageSource->GetFixedImage();
94   MovingImageType::ConstPointer    movingImage   = imageSource->GetMovingImage();
95 
96   //
97   // Connect all the components required for Registratio
98   //
99   registration->SetMetric(        metric        );
100   registration->SetOptimizer(     optimizer     );
101   registration->SetTransform(     transform     );
102   registration->SetFixedImage(    fixedImage    );
103   registration->SetMovingImage(   movingImage   );
104   registration->SetInterpolator(  interpolator  );
105 
106 
107   // Select the Region of Interest over which the Metric will be computed
108   // Registration time will be proportional to the number of pixels in this region.
109   metric->SetFixedImageRegion( fixedImage->GetBufferedRegion() );
110 
111   // Instantiate an Observer to report the progress of the Optimization
112   CommandIterationType::Pointer iterationCommand = CommandIterationType::New();
113   iterationCommand->SetOptimizer(  optimizer );
114 
115   // Scale the translation components of the Transform in the Optimizer
116   OptimizerType::ScalesType scales( transform->GetNumberOfParameters() );
117   scales.Fill( 1.0 );
118 
119 
120   unsigned long   numberOfIterations =   100;
121   double          translationScale   =  1e-6;
122   double          maximumStepLenght  =  10.0; // no step will be larger than this
123   double          minimumStepLenght  =   0.1; // convergence criterion
124   double          gradientTolerance  =   0.01; // convergence criterion
125 
126   if( argc > 1 )
127     {
128     numberOfIterations = atol( argv[1] );
129     std::cout << "numberOfIterations = " << numberOfIterations << std::endl;
130     }
131   if( argc > 2 )
132     {
133     translationScale = std::stod( argv[2] );
134     std::cout << "translationScale = " << translationScale << std::endl;
135     }
136   if( argc > 3 )
137     {
138     maximumStepLenght = std::stod( argv[3] );
139     std::cout << "maximumStepLenght = " << maximumStepLenght << std::endl;
140     }
141   if( argc > 4 )
142     {
143     minimumStepLenght = std::stod( argv[4] );
144     std::cout << "minimumStepLenght = " << minimumStepLenght << std::endl;
145     }
146   if( argc > 5 )
147     {
148     gradientTolerance = std::stod( argv[5] );
149     std::cout << "gradientTolerance = " << gradientTolerance << std::endl;
150     }
151 
152   for( unsigned int i=0; i<dimension; i++)
153     {
154     scales[ i + dimension * dimension ] = translationScale;
155     }
156 
157   optimizer->SetScales( scales );
158   optimizer->SetMaximize( true );
159   optimizer->SetNumberOfIterations( numberOfIterations );
160   optimizer->SetMinimumStepLength( minimumStepLenght );
161   optimizer->SetMaximumStepLength( maximumStepLenght );
162   optimizer->SetGradientMagnitudeTolerance( gradientTolerance );
163 
164   // Start from an Identity transform (in a normal case, the user
165   // can probably provide a better guess than the identity...
166   transform->SetIdentity();
167   registration->SetInitialTransformParameters( transform->GetParameters() );
168 
169   // Initialize the internal connections of the registration method.
170   // This can potentially throw an exception
171   try
172     {
173     registration->Update();
174     }
175   catch( itk::ExceptionObject & e )
176     {
177     std::cerr << e << std::endl;
178     pass = false;
179     }
180 
181   ParametersType actualParameters = imageSource->GetActualParameters();
182   ParametersType finalParameters  = registration->GetLastTransformParameters();
183 
184   const unsigned int numbeOfParameters = actualParameters.Size();
185 
186   // We know that for the Affine transform the Translation parameters are at
187   // the end of the list of parameters.
188   const unsigned int offsetOrder = finalParameters.Size()-actualParameters.Size();
189   constexpr double tolerance = 1.0;  // equivalent to 1 pixel.
190 
191   for(unsigned int i=0; i<numbeOfParameters; i++)
192     {
193     // the parameters are negated in order to get the inverse transformation.
194     // this only works for comparing translation parameters....
195     std::cout << finalParameters[i+offsetOrder] << " == " << -actualParameters[i] << std::endl;
196     if( itk::Math::abs ( finalParameters[i+offsetOrder] - (-actualParameters[i]) ) > tolerance )
197       {
198       std::cout << "Tolerance exceeded at component " << i << std::endl;
199       pass = false;
200       }
201     }
202 
203 
204   if( !pass )
205     {
206     std::cout << "Test FAILED." << std::endl;
207     return EXIT_FAILURE;
208     }
209 
210   std::cout << "Test PASSED." << std::endl;
211   return EXIT_SUCCESS;
212 }
213