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