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 #include "itkDemonsImageToImageMetricv4.h"
19 #include "itkTranslationTransform.h"
20 #include "itkGaussianSmoothingOnUpdateDisplacementFieldTransform.h"
21 #include "itkTestingMacros.h"
22 #include "itkMath.h"
23
24 /* Simple test to verify that class builds and runs.
25 * Results are not verified. See ImageToImageMetricv4Test
26 * for verification of basic metric functionality.
27 *
28 * TODO Numerical verification.
29 */
30
itkDemonsImageToImageMetricv4Test(int,char ** const)31 int itkDemonsImageToImageMetricv4Test(int, char ** const)
32 {
33
34 constexpr unsigned int imageSize = 5;
35 constexpr unsigned int imageDimensionality = 3;
36 using ImageType = itk::Image< double, imageDimensionality >;
37
38 ImageType::SizeType size;
39 size.Fill( imageSize );
40 ImageType::IndexType index;
41 index.Fill( 0 );
42 ImageType::RegionType region;
43 region.SetSize( size );
44 region.SetIndex( index );
45 ImageType::SpacingType spacing;
46 spacing.Fill(1.0);
47 ImageType::PointType origin;
48 origin.Fill(0);
49 ImageType::DirectionType direction;
50 direction.SetIdentity();
51
52 /* Create simple test images. */
53 ImageType::Pointer fixedImage = ImageType::New();
54 fixedImage->SetRegions( region );
55 fixedImage->SetSpacing( spacing );
56 fixedImage->SetOrigin( origin );
57 fixedImage->SetDirection( direction );
58 fixedImage->Allocate();
59
60 ImageType::Pointer movingImage = ImageType::New();
61 movingImage->SetRegions( region );
62 movingImage->SetSpacing( spacing );
63 movingImage->SetOrigin( origin );
64 movingImage->SetDirection( direction );
65 movingImage->Allocate();
66
67 /* Fill images */
68 itk::ImageRegionIterator<ImageType> itFixed( fixedImage, region );
69 itFixed.GoToBegin();
70 unsigned int count = 1;
71 while( !itFixed.IsAtEnd() )
72 {
73 itFixed.Set( count*count );
74 count++;
75 ++itFixed;
76 }
77
78 itk::ImageRegionIteratorWithIndex<ImageType> itMoving( movingImage, region );
79
80 itMoving.GoToBegin();
81 count = 1;
82
83 while( !itMoving.IsAtEnd() )
84 {
85 itMoving.Set( 1.0/(count*count) );
86 count++;
87 ++itMoving;
88 }
89
90 /* Transforms */
91 using TranslationTransformType = itk::TranslationTransform<double,imageDimensionality>;
92 using DisplacementTransformType = itk::GaussianSmoothingOnUpdateDisplacementFieldTransform< double, imageDimensionality>;
93
94 TranslationTransformType::Pointer translationTransform = TranslationTransformType::New();
95 translationTransform->SetIdentity();
96
97 DisplacementTransformType::Pointer displacementTransform = DisplacementTransformType::New();
98 using DisplacementFieldType = DisplacementTransformType::DisplacementFieldType;
99 DisplacementFieldType::Pointer field = DisplacementFieldType::New();
100 field->SetRegions( fixedImage->GetLargestPossibleRegion() );
101 field->CopyInformation( fixedImage );
102 field->Allocate();
103 DisplacementTransformType::OutputVectorType zeroVector;
104 zeroVector.Fill( 0 );
105 field->FillBuffer( zeroVector );
106 displacementTransform->SetDisplacementField( field );
107 displacementTransform->SetGaussianSmoothingVarianceForTheUpdateField( 5 );
108 displacementTransform->SetGaussianSmoothingVarianceForTheTotalField( 6 );
109
110 /* The metric */
111 using MetricType = itk::DemonsImageToImageMetricv4< ImageType, ImageType, ImageType >;
112
113 MetricType::Pointer metric = MetricType::New();
114
115 /* Assign images and transforms.
116 * By not setting a virtual domain image or virtual domain settings,
117 * the metric will use the fixed image for the virtual domain. */
118 metric->SetFixedImage( fixedImage );
119 metric->SetMovingImage( movingImage );
120 metric->SetFixedTransform( translationTransform );
121 metric->SetMovingTransform( displacementTransform );
122
123 /* Test 1st with fixed image gradient source. This is the default */
124 metric->SetGradientSource( MetricType::GRADIENT_SOURCE_FIXED );
125 if( metric->GetGradientSource() != MetricType::GRADIENT_SOURCE_FIXED )
126 {
127 std::cerr << "Failed setting fixed image gradient source." << std::endl;
128 return EXIT_FAILURE;
129 }
130
131 /* Initialize. */
132 try
133 {
134 std::cout << "Calling Initialize..." << std::endl;
135 metric->Initialize();
136 }
137 catch( itk::ExceptionObject & exc )
138 {
139 std::cerr << "Caught unexpected exception during Initialize: " << exc << std::endl;
140 return EXIT_FAILURE;
141 }
142
143 // Evaluate with GetValueAndDerivative
144 MetricType::MeasureType valueReturn1, valueReturn2;
145 MetricType::DerivativeType derivativeReturn;
146
147 try
148 {
149 std::cout << "Calling GetValueAndDerivative..." << std::endl;
150 metric->GetValueAndDerivative( valueReturn1, derivativeReturn );
151 }
152 catch( itk::ExceptionObject & exc )
153 {
154 std::cout << "Caught unexpected exception during GetValueAndDerivative: "
155 << exc;
156 return EXIT_FAILURE;
157 }
158
159 /* Re-initialize. */
160 try
161 {
162 std::cout << "Calling Initialize..." << std::endl;
163 metric->Initialize();
164 }
165 catch( itk::ExceptionObject & exc )
166 {
167 std::cerr << "Caught unexpected exception during re-initialize: " << exc << std::endl;
168 return EXIT_FAILURE;
169 }
170
171 try
172 {
173 std::cout << "Calling GetValue..." << std::endl;
174 valueReturn2 = metric->GetValue();
175 }
176 catch( itk::ExceptionObject & exc )
177 {
178 std::cout << "Caught unexpected exception during GetValue: "
179 << exc;
180 return EXIT_FAILURE;
181 }
182
183 // Test same value returned by different methods
184 std::cout << "Check Value return values..." << std::endl;
185 if( itk::Math::NotExactlyEquals(valueReturn1, valueReturn2) )
186 {
187 std::cerr << "Results for Value don't match: " << valueReturn1
188 << ", " << valueReturn2 << std::endl;
189 }
190
191 /* Test with moving image as gradient source. The default is
192 * to have the fixed image used for image gradients. */
193 metric->SetFixedTransform( translationTransform );
194 metric->SetMovingTransform( displacementTransform );
195 metric->SetGradientSource( MetricType::GRADIENT_SOURCE_MOVING );
196 if( metric->GetGradientSource() != MetricType::GRADIENT_SOURCE_MOVING )
197 {
198 std::cerr << "Failed setting moving image gradient source." << std::endl;
199 return EXIT_FAILURE;
200 }
201
202 try
203 {
204 std::cout << "Calling Initialize..." << std::endl;
205 metric->Initialize();
206 }
207 catch( itk::ExceptionObject & exc )
208 {
209 std::cerr << "Caught unexpected exception during initialize with moving "
210 << "image gradient source: " << exc << std::endl;
211 return EXIT_FAILURE;
212 }
213
214 // Evaluate with GetValueAndDerivative
215 try
216 {
217 std::cout << "Calling GetValueAndDerivative..." << std::endl;
218 metric->GetValueAndDerivative( valueReturn1, derivativeReturn );
219 }
220 catch( itk::ExceptionObject & exc )
221 {
222 std::cout << "Caught unexpected exception during GetValueAndDerivative: "
223 << exc;
224 return EXIT_FAILURE;
225 }
226
227 /* Re-initialize. */
228 try
229 {
230 std::cout << "Calling Initialize..." << std::endl;
231 metric->Initialize();
232 }
233 catch( itk::ExceptionObject & exc )
234 {
235 std::cerr << "Caught unexpected exception during re-initialize: " << exc << std::endl;
236 return EXIT_FAILURE;
237 }
238
239 try
240 {
241 std::cout << "Calling GetValue..." << std::endl;
242 valueReturn2 = metric->GetValue();
243 }
244 catch( itk::ExceptionObject & exc )
245 {
246 std::cout << "Caught unexpected exception during GetValue: "
247 << exc;
248 return EXIT_FAILURE;
249 }
250
251 // Test same value returned by different methods
252 std::cout << "Check Value return values..." << std::endl;
253 if( itk::Math::NotExactlyEquals(valueReturn1, valueReturn2) )
254 {
255 std::cerr << "Moving image gradient source: results for Value don't match: " << valueReturn1
256 << ", " << valueReturn2 << std::endl;
257 }
258
259 /* Test expected exceptions when transform is not right type */
260 metric->SetMovingTransform( translationTransform );
261 TRY_EXPECT_EXCEPTION( metric->Initialize() );
262
263 /* Exercise accessor method */
264 const auto testValue = static_cast<MetricType::InternalComputationValueType>(0.5);
265 metric->SetIntensityDifferenceThreshold( testValue );
266 if( itk::Math::NotExactlyEquals(metric->GetIntensityDifferenceThreshold(), testValue) )
267 {
268 std::cerr << "Set/GetIntensityDifferenceThreshold failed." << std::endl;
269 return EXIT_FAILURE;
270 }
271
272 /* Print self */
273 metric->Print( std::cout );
274
275 std::cout << "Test passed." << std::endl;
276 return EXIT_SUCCESS;
277 }
278