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 "itkKappaStatisticImageToImageMetric.h"
20 #include "itkNearestNeighborInterpolateImageFunction.h"
21 #include "itkTranslationTransform.h"
22 #include "itkMath.h"
23 #include "itkTestingMacros.h"
24
25 /**
26 * This test exercised the various methods in the
27 * itkKappaStatisticImageToImageMetric class. Two binary images are
28 * created for testing purposes -- one of a square and another of the
29 * same square translated in both x and y.
30 *
31 */
32
itkKappaStatisticImageToImageMetricTest(int,char * [])33 int itkKappaStatisticImageToImageMetricTest(int, char* [] )
34 {
35
36 constexpr unsigned int Dimension = 2;
37
38 using FixedImagePixelType = unsigned char;
39 using MovingImagePixelType = unsigned char;
40
41 using CoordRepPixelType = double;
42
43 using GradientPixelType = double;
44
45 using FixedImageType = itk::Image< FixedImagePixelType, Dimension >;
46 using MovingImageType = itk::Image< MovingImagePixelType, Dimension >;
47 using GradientImageType = itk::Image< GradientPixelType, Dimension >;
48
49 using MetricType = itk::KappaStatisticImageToImageMetric< FixedImageType, MovingImageType >;
50 using FixedImageIteratorType = itk::ImageRegionIteratorWithIndex< FixedImageType >;
51 using MovingImageIteratorType = itk::ImageRegionIteratorWithIndex< MovingImageType >;
52
53 using GradientImageIteratorType = itk::ImageRegionIteratorWithIndex< GradientImageType >;
54 using TransformType = itk::TranslationTransform< CoordRepPixelType, Dimension >;
55 using InterpolatorType =
56 itk::NearestNeighborInterpolateImageFunction< MovingImageType, CoordRepPixelType >;
57
58
59 double epsilon = 0.000001;
60
61 TransformType::Pointer transform = TransformType::New();
62 InterpolatorType::Pointer interpolator = InterpolatorType::New();
63
64 FixedImageType::SizeType fixedImageSize;
65 fixedImageSize.Fill( 128 );
66
67 // Create fixed image
68 FixedImageType::Pointer fixedImage = FixedImageType::New();
69 fixedImage->SetRegions( fixedImageSize );
70 fixedImage->Allocate( true ); // initialize buffer to zero
71 fixedImage->Update();
72
73 FixedImageIteratorType fixedIt( fixedImage, fixedImage->GetBufferedRegion() );
74 for( fixedIt.GoToBegin(); !fixedIt.IsAtEnd(); ++fixedIt )
75 {
76 FixedImageType::IndexType index = fixedIt.GetIndex();
77 if( index[0] >= 48 && index[0] <= 80 && index[1] >= 48 && index[1] <= 80 )
78 {
79 fixedIt.Set(255);
80 }
81 }
82
83 MovingImageType::SizeType movingImageSize;
84 movingImageSize.Fill( 128 );
85
86 // Create moving image
87 MovingImageType::Pointer movingImage = MovingImageType::New();
88 movingImage->SetRegions( movingImageSize );
89 movingImage->Allocate( true ); // initialize buffer to zero
90 movingImage->Update();
91
92 MovingImageIteratorType movingIt( movingImage, movingImage->GetBufferedRegion() );
93 for( movingIt.GoToBegin(); !movingIt.IsAtEnd(); ++movingIt )
94 {
95 MovingImageType::IndexType index = movingIt.GetIndex();
96 if( index[0] >= 55 && index[0] <= 87 && index[1] >= 55 && index[1] <= 87 )
97 {
98 movingIt.Set(255);
99 }
100 }
101
102 MetricType::Pointer metric = MetricType::New();
103
104 EXERCISE_BASIC_OBJECT_METHODS( metric, KappaStatisticImageToImageMetric,
105 ImageToImageMetric );
106
107 MetricType::RealType foregroundValue = 255;
108 metric->SetForegroundValue( foregroundValue );
109 TEST_SET_GET_VALUE( foregroundValue, metric->GetForegroundValue() );
110
111 bool useComplement = false;
112 metric->SetComplement( useComplement );
113 TEST_SET_GET_VALUE( useComplement, metric->GetComplement() );
114
115 metric->ComplementOff();
116 TEST_SET_GET_VALUE( false, metric->GetComplement() );
117
118 transform->SetIdentity();
119 metric->SetTransform( transform );
120
121 TransformType::ParametersType parameters = transform->GetParameters();
122
123 // Test error conditions
124 //
125 TRY_EXPECT_EXCEPTION( metric->GetValue( parameters ) );
126
127 metric->SetFixedImage( fixedImage );
128
129 TRY_EXPECT_EXCEPTION( metric->GetValue( parameters ) );
130
131 metric->SetMovingImage( movingImage );
132 metric->SetInterpolator( interpolator );
133 metric->SetFixedImageRegion( fixedImage->GetBufferedRegion() );
134
135 MetricType::DerivativeType derivative;
136 TRY_EXPECT_EXCEPTION( metric->GetDerivative( parameters, derivative ) );
137
138 TRY_EXPECT_NO_EXCEPTION( metric->Initialize() );
139
140 metric->SetFixedImage( nullptr );
141 TRY_EXPECT_EXCEPTION( metric->GetDerivative( parameters, derivative ) );
142
143 metric->SetFixedImage( fixedImage );
144
145 // Test the GetValue method
146 //
147
148 // The value 0.620753 was computed by hand for these two images
149 double expectedMatchMeasure = 0.620753;
150 MetricType::MeasureType value = metric->GetValue( parameters );
151 if( !itk::Math::FloatAlmostEqual( (double)value, expectedMatchMeasure, 10, epsilon ) )
152 {
153 std::cerr << "Error !" << std::endl;
154 std::cerr << "Expected: " << expectedMatchMeasure << " but got "
155 << static_cast< double >( value ) << std::endl;
156 std::cerr << "Test failed" << std::endl;
157 return EXIT_FAILURE;
158 }
159
160
161 // Test the ComputeGradient method
162 //
163 metric->ComputeGradient();
164
165 GradientImageType::Pointer xGradImage = GradientImageType::New();
166 xGradImage->SetRegions( movingImageSize );
167 xGradImage->Allocate( true ); // initialize buffer to zero
168 xGradImage->Update();
169
170 GradientImageType::Pointer yGradImage = GradientImageType::New();
171 yGradImage->SetRegions( movingImageSize );
172 yGradImage->Allocate( true ); // initialize buffer to zero
173 yGradImage->Update();
174
175 GradientImageIteratorType xGradIt( xGradImage, xGradImage->GetBufferedRegion() );
176 GradientImageIteratorType yGradIt( yGradImage, yGradImage->GetBufferedRegion() );
177
178 xGradIt.GoToBegin();
179 yGradIt.GoToBegin();
180
181 // Construct the gradient images explicitly based on what we know
182 // they should be and use them to validate metric's version
183 while( !xGradIt.IsAtEnd() )
184 {
185 GradientImageType::IndexType index = xGradIt.GetIndex();
186
187 if( ( index[0] == 54 || index[0] == 55 ) && index[1] >= 55 && index[1] <= 87 )
188 {
189 xGradIt.Set(1);
190 }
191 if( ( index[0] == 87 || index[0] == 88 ) && index[1] >= 55 && index[1] <= 87 )
192 {
193 xGradIt.Set(-1);
194 }
195 if( ( index[1] == 54 || index[1] == 55 ) && index[0] >= 55 && index[0] <= 87 )
196 {
197 yGradIt.Set(1);
198 }
199 if( ( index[1] == 87 || index[1] == 88 ) &&(index[0] >= 55) && index[0] <= 87)
200 {
201 yGradIt.Set(-1);
202 }
203
204 ++xGradIt;
205 ++yGradIt;
206 }
207
208 using GradIteratorType = itk::ImageRegionIteratorWithIndex< const MetricType::GradientImageType >;
209 GradIteratorType gradIt( metric->GetGradientImage(), metric->GetGradientImage()->GetBufferedRegion() );
210 gradIt.GoToBegin();
211 xGradIt.GoToBegin();
212 yGradIt.GoToBegin();
213 while( !gradIt.IsAtEnd() )
214 {
215 if( itk::Math::NotAlmostEquals( ( gradIt.Get())[0], xGradIt.Get() ) ||
216 itk::Math::NotAlmostEquals( ( gradIt.Get())[1], yGradIt.Get() ) )
217 {
218 std::cerr << "Error !" << std::endl;
219 std::cerr << "Expected: [" << static_cast< double >( gradIt.Get()[0] )
220 << ", " << static_cast< double >( gradIt.Get()[1] ) << "], but got ["
221 << static_cast< double >( xGradIt.Get() ) << ", "
222 << static_cast< double >( yGradIt.Get() ) << "]"
223 << std::endl;
224 std::cerr << "Test failed" << std::endl;
225 return EXIT_FAILURE;
226 }
227
228 ++gradIt;
229 ++xGradIt;
230 ++yGradIt;
231 }
232
233
234 // Test the GetDerivative method
235 //
236 metric->GetDerivative( parameters, derivative );
237
238 // The value 0.0477502 was computed by hand
239 double expectedDerivativeMeasure = -0.0477502;
240 for( unsigned int i = 0; i < derivative.size(); ++i )
241 {
242 if( !itk::Math::FloatAlmostEqual( (double)derivative[i], expectedDerivativeMeasure, 10, epsilon ) )
243 {
244 std::cerr << "Error !" << std::endl;
245 std::cerr << "Expected: " << expectedDerivativeMeasure << " but got "
246 << static_cast< double >( derivative[i] )
247 << " at index [" << i << "]" << std::endl;
248 std::cerr << "Test failed" << std::endl;
249 return EXIT_FAILURE;
250 }
251 }
252
253
254 // Test the GetValueAndDerivative method
255 //
256 metric->GetValueAndDerivative( parameters, value, derivative );
257
258 if( !itk::Math::FloatAlmostEqual( (double)value, expectedMatchMeasure, 10, epsilon ) )
259 {
260 std::cerr << "Error !" << std::endl;
261 std::cerr << "Expected: " << expectedMatchMeasure << " but got "
262 << static_cast< double >( value ) << std::endl;
263 std::cerr << "Test failed" << std::endl;
264 return EXIT_FAILURE;
265 }
266 for( unsigned int i = 0; i < derivative.size(); ++i )
267 {
268 if( !itk::Math::FloatAlmostEqual( (double)derivative[i], expectedDerivativeMeasure, 10, epsilon ) )
269 {
270 std::cerr << "Error !" << std::endl;
271 std::cerr << "Expected: " << expectedDerivativeMeasure << " but got "
272 << static_cast< double >( derivative[i] )
273 << " at index [" << i << "]" << std::endl;
274 std::cerr << "Test failed" << std::endl;
275 return EXIT_FAILURE;
276 }
277 }
278
279
280 // Test with Complement set to true
281 //
282 useComplement = true;
283 metric->SetComplement( useComplement );
284 TEST_SET_GET_VALUE( useComplement, metric->GetComplement() );
285
286 metric->ComplementOn();
287 TEST_SET_GET_VALUE( true, metric->GetComplement() );
288
289 // The value 0.379247 was computed by hand
290 expectedMatchMeasure = 0.379247;
291 value = metric->GetValue( parameters );
292 if( !itk::Math::FloatAlmostEqual( (double)value, expectedMatchMeasure, 10, epsilon ) )
293 {
294 std::cerr << "Error !" << std::endl;
295 std::cerr << "Expected: " << expectedMatchMeasure << " but got "
296 << static_cast< double >( value ) << std::endl;
297 std::cerr << "Test failed" << std::endl;
298 return EXIT_FAILURE;
299 }
300
301 return EXIT_SUCCESS;
302 }
303