1 /*
2  * Medical Image Registration ToolKit (MIRTK)
3  *
4  * Copyright 2013-2015 Imperial College London
5  * Copyright 2013-2015 Andreas Schuh
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *     http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 
20 // TODO: Rewrite test using GTest library. -as12312
21 
22 #include "mirtk/GenericImage.h"
23 #include "mirtk/InterpolateImageFunction.h"
24 #include "mirtk/ExtrapolateImageFunction.h"
25 
26 using namespace mirtk;
27 
28 // ===========================================================================
29 // Macros
30 // ===========================================================================
31 
32 // ---------------------------------------------------------------------------
33 #define TEST(id) \
34   const char *_id    = id; \
35   int         _nfail = 0; \
36   cout << "Test case: " << _id << endl
37 
38 // ---------------------------------------------------------------------------
39 #define RESULT _nfail
40 
41 // ---------------------------------------------------------------------------
42 #define NULLPTR(actual, message, exit_if_not) \
43   do { \
44     void *_actual = (actual); \
45     if (_actual != NULL) { \
46       _nfail++; \
47       cerr << message << endl; \
48       cerr << "  Actual:   " << _actual << endl; \
49       cerr << "  Expected: NULL" << endl; \
50       if (exit_if_not) exit(_nfail); \
51     } \
52   }while(false)
53 
54 // ---------------------------------------------------------------------------
55 #define NOT_NULLPTR(actual, message, exit_if_not) \
56   do { \
57     void *_actual = (actual); \
58     if (_actual == NULL) { \
59       _nfail++; \
60       cerr << message << endl; \
61       cerr << "  Actual:   " << _actual << endl; \
62       cerr << "  Expected: !NULL" << endl; \
63       if (exit_if_not) exit(_nfail); \
64     } \
65   }while(false)
66 
67 // ---------------------------------------------------------------------------
68 #define EQUAL(actual, expected, message, exit_if_not) \
69   do { \
70     double _actual   = (actual); \
71     double _expected = (expected); \
72     if (fabs(_actual - _expected) >= 1e-10) { \
73       _nfail++; \
74       cerr << message << endl; \
75       cerr << "  Actual:   " << setprecision(15) << _actual   << endl; \
76       cerr << "  Expected: " << setprecision(15) << _expected << endl; \
77       if (exit_if_not) exit(_nfail); \
78     } \
79   }while(false)
80 
81 // ---------------------------------------------------------------------------
82 #define NOT_EQUAL(actual, expected, message, exit_if_not) \
83   do { \
84     double _actual   = (actual); \
85     double _expected = (expected); \
86     if (fabs(_actual - _expected) < 1e-10) { \
87       _nfail++; \
88       cerr << message << endl; \
89       cerr << "  Actual:   " << setprecision(15) << _actual   << endl; \
90       cerr << "  Expected: " << setprecision(15) << _expected << endl; \
91       if (exit_if_not) exit(_nfail); \
92     } \
93   }while(false)
94 
95 // ---------------------------------------------------------------------------
96 #define STREQUAL(actual, expected, message, exit_if_not) \
97   do { \
98     string _actual   = (actual); \
99     string _expected = (expected); \
100     if (_actual != _expected) { \
101       _nfail++; \
102       cerr << message << endl; \
103       cerr << "  Actual:   " << _actual << endl; \
104       cerr << "  Expected: " << _expected << endl; \
105       if (exit_if_not) exit(_nfail); \
106     } \
107   }while(false)
108 
109 // ---------------------------------------------------------------------------
110 #define EXPECT_NULL(actual, message)                NULLPTR(actual, message, false)
111 #define EXPECT_NOT_NULL(actual, message)            NOT_NULLPTR(actual, message, false)
112 #define EXPECT_EQUAL(actual, expected, message)     EQUAL(actual, expected, message, false)
113 #define EXPECT_NOT_EQUAL(actual, expected, message) NOT_EQUAL(actual, expected, message, false)
114 #define EXPECT_STREQUAL (actual, expected, message) STREQUAL(actual, expected, message, false)
115 
116 // ---------------------------------------------------------------------------
117 #define ASSERT_NULL(actual, message)                NULLPTR(actual, message, true)
118 #define ASSERT_NOT_NULL(actual, message)            NOT_NULLPTR(actual, message, true)
119 #define ASSERT_EQUAL(actual, expected, message)     EQUAL(actual, expected, message, true)
120 #define ASSERT_NOT_EQUAL(actual, expected, message) NOT_EQUAL(actual, expected, message, true)
121 #define ASSERT_STREQUAL(actual, expected, message)  STREQUAL(actual, expected, message, true)
122 
123 // ===========================================================================
124 // Test images
125 // ===========================================================================
126 
127 // ---------------------------------------------------------------------------
128 template <class VoxelType>
create_test_image(int x=16,int y=16,int z=1,int t=1,int n=1)129 GenericImage<VoxelType> *create_test_image(int x = 16, int y = 16, int z = 1, int t = 1, int n = 1)
130 {
131   // Instantiate image
132   GenericImage<VoxelType> *image = new GenericImage<double>(x, y, z, t, n);
133   // Fill test image
134   for (int l = 0; l < image->T(); l++) {
135     for (int k = 0; k < image->Z(); k++) {
136       for (int j = 0; j < image->Y(); j++) {
137         for (int i = 0; i < image->X(); i++) {
138           image->Put(i, j, k, l, static_cast<VoxelType>(image->VoxelToIndex(i, j, k, l)));
139         }
140       }
141     }
142   }
143   return image;
144 }
145 
146 // ===========================================================================
147 // Tests
148 // ===========================================================================
149 
150 // ---------------------------------------------------------------------------
test_Initialize()151 int test_Initialize()
152 {
153   TEST("test_Initialize");
154 
155   GenericImage<double>     *image = create_test_image<double>(16, 16);
156   InterpolateImageFunction *inter = InterpolateImageFunction::New(Interpolation_NN, Extrapolation_Const, image);
157   ExtrapolateImageFunction *extra = inter->Extrapolator();
158 
159   inter->Initialize();
160   extra->Initialize(); // not required, but shall also not hurt (ie., recurse infinitely)
161   inter->Initialize();
162 
163   return RESULT;
164 }
165 
166 // ---------------------------------------------------------------------------
test_IsInsideOutside()167 int test_IsInsideOutside()
168 {
169   TEST("test_IsInsideOutside");
170 
171   GenericImage<double>     *image = NULL;
172   InterpolateImageFunction *inter = NULL;
173   //ExtrapolateImageFunction *extra = NULL;
174 
175   // --------------------------------------------------------------------------
176   // 2D
177   image = create_test_image<double>(16, 16);
178   inter = InterpolateImageFunction::New(Interpolation_NN, Extrapolation_Const, image);
179   //extra = inter->Extrapolator();
180 
181   inter->Initialize();
182 
183   EXPECT_EQUAL(inter->IsInside (3.0, 2.0), true,  "Check if voxel is inside image domain");
184   EXPECT_EQUAL(inter->IsInside (3.4, 2.1), true,  "Check if sub-voxel is inside image domain");
185 
186   EXPECT_EQUAL(inter->IsInside (-3.0, 0.0), false, "Check if voxel is outside image domain");
187   EXPECT_EQUAL(inter->IsInside (-3.4, 2.1), false, "Check if sub-voxel is outside image domain");
188 
189   delete image;
190   delete inter;
191 
192   // --------------------------------------------------------------------------
193   // 3D
194   image = create_test_image<double>(16, 16, 16);
195   inter = InterpolateImageFunction::New(Interpolation_NN, Extrapolation_Const, image);
196   //extra = inter->Extrapolator();
197 
198   inter->Initialize();
199 
200   EXPECT_EQUAL(inter->IsInside (3.0, 2.0, 5.0), true,  "Check if voxel is inside image domain");
201   EXPECT_EQUAL(inter->IsInside (3.4, 2.1, 5.5), true,  "Check if sub-voxel is inside image domain");
202 
203   EXPECT_EQUAL(inter->IsInside (-3.0, 0.0, 1.0), false, "Check if voxel is outside image domain");
204   EXPECT_EQUAL(inter->IsInside (-3.4, 2.1, 1.0), false, "Check if sub-voxel is outside image domain");
205 
206   delete image;
207   delete inter;
208 
209   return RESULT;
210 }
211 
212 // ---------------------------------------------------------------------------
test_Interpolation_NN_Extrapolation_Default()213 int test_Interpolation_NN_Extrapolation_Default()
214 {
215   TEST("test_Interpolation_NN_Extrapolation_Default");
216 
217   GenericImage<double>     *image = create_test_image<double>(16, 16, 16);
218   InterpolateImageFunction *func  = InterpolateImageFunction::New(Interpolation_NN, image);
219 
220   // Initialize image function
221   EXPECT_NULL(func->Extrapolator(), "Extrapolator not instantiated yet");
222 
223   func->Initialize();
224 
225   ASSERT_NOT_NULL(func->Extrapolator(), "Extrapolator initialized");
226 
227   // Check instantiated image function
228   ASSERT_STREQUAL(func->NameOfClass(), "GenericNearestNeighborInterpolateImageFunction", "Type of interpolator");
229   ASSERT_STREQUAL(func->Extrapolator()->NameOfClass(), "GenericConstExtrapolateImageFunction", "Type of extrapolator");
230   EXPECT_EQUAL(func->Extrapolator()->DefaultValue(), 0, "Constant outside value");
231 
232   // Interpolate inside of image domain
233   EXPECT_EQUAL(func->Evaluate(3.0, 2.0, 5.0), image->VoxelToIndex(3, 2, 5), "Interpolate image value at voxel position");
234   EXPECT_EQUAL(func->Evaluate(3.4, 2.1, 5.5), image->VoxelToIndex(3, 2, 6), "Interpolate image value at sub-voxel position");
235 
236   // Extrapolate outside of image domain
237   EXPECT_EQUAL(func->Evaluate(-3.0, 0.0, 1.0), 0, "Extrapolate image value at voxel position");
238   EXPECT_EQUAL(func->Evaluate(-3.4, 2.1, 1.0), 0, "Extrapolate image value at sub-voxel position");
239 
240   // Clean up
241   delete image;
242   delete func;
243 
244   return RESULT;
245 }
246 
247 // ---------------------------------------------------------------------------
test_Interpolation_NN_Extrapolation_Const()248 int test_Interpolation_NN_Extrapolation_Const()
249 {
250   TEST("test_Interpolation_NN_Extrapolation_Const");
251 
252   GenericImage<double>     *image = NULL;
253   InterpolateImageFunction *func  = NULL;
254 
255   // -------------------------------------------------------------------------
256   // 2D
257   image = create_test_image<double>(16, 16);
258   func  = InterpolateImageFunction::New(Interpolation_NN, Extrapolation_Const, image);
259 
260   // Initialize image function
261   func->Initialize();
262 
263   // Check instantiated image function
264   ASSERT_STREQUAL(func->NameOfClass(), "GenericNearestNeighborInterpolateImageFunction", "Type of interpolator");
265   ASSERT_STREQUAL(func->Extrapolator()->NameOfClass(), "GenericConstExtrapolateImageFunction", "Type of extrapolator");
266   EXPECT_EQUAL(func->Extrapolator()->DefaultValue(), 0, "Constant outside value");
267 
268   // Interpolate inside of image domain
269   EXPECT_EQUAL(func->Evaluate(3.0, 2.0), image->VoxelToIndex(3, 2), "Interpolate image value at voxel position");
270   EXPECT_EQUAL(func->Evaluate(3.4, 2.1), image->VoxelToIndex(3, 2), "Interpolate image value at sub-voxel position");
271 
272   // Extrapolate outside of image domain
273   EXPECT_EQUAL(func->Evaluate(-3.0, 0.0), 0, "Extrapolate image value at voxel position");
274   EXPECT_EQUAL(func->Evaluate(-3.4, 2.1), 0, "Extrapolate image value at sub-voxel position");
275 
276   // Clean up
277   delete image;
278   delete func;
279 
280   // -------------------------------------------------------------------------
281   // 3D
282   image = create_test_image<double>(16, 16, 16);
283   func  = InterpolateImageFunction::New(Interpolation_NN, Extrapolation_Const, image);
284 
285   // Initialize image function
286   func->Initialize();
287 
288   // Check instantiated image function
289   ASSERT_STREQUAL(func->NameOfClass(), "GenericNearestNeighborInterpolateImageFunction", "Type of interpolator");
290   ASSERT_STREQUAL(func->Extrapolator()->NameOfClass(), "GenericConstExtrapolateImageFunction", "Type of extrapolator");
291   EXPECT_EQUAL(func->Extrapolator()->DefaultValue(), 0, "Constant outside value");
292 
293   // Interpolate inside of image domain
294   EXPECT_EQUAL(func->Evaluate(3.0, 2.0, 5.0), image->VoxelToIndex(3, 2, 5), "Interpolate image value at voxel position");
295   EXPECT_EQUAL(func->Evaluate(3.4, 2.1, 5.5), image->VoxelToIndex(3, 2, 6), "Interpolate image value at sub-voxel position");
296 
297   // Extrapolate outside of image domain
298   EXPECT_EQUAL(func->Evaluate(-3.0, 0.0, 1.0), 0, "Extrapolate image value at voxel position");
299   EXPECT_EQUAL(func->Evaluate(-3.4, 2.1, 1.0), 0, "Extrapolate image value at sub-voxel position");
300 
301   // Clean up
302   delete image;
303   delete func;
304 
305   return RESULT;
306 }
307 
308 // ---------------------------------------------------------------------------
test_Interpolation_Linear_Extrapolation_Const()309 int test_Interpolation_Linear_Extrapolation_Const()
310 {
311   TEST("test_Interpolation_Linear_Extrapolation_Const");
312 
313   GenericImage<double>     *image = NULL;
314   InterpolateImageFunction *func  = NULL;
315 
316   // -------------------------------------------------------------------------
317   // 2D
318   image = create_test_image<double>(16, 16);
319   func  = InterpolateImageFunction::New(Interpolation_Linear, Extrapolation_Const, image);
320 
321   // Initialize image function
322   func->Initialize();
323   func->Extrapolator()->DefaultValue(-1);
324 
325   // Check instantiated image function
326   ASSERT_STREQUAL(func->NameOfClass(), "GenericLinearInterpolateImageFunction2D", "Type of interpolator");
327   ASSERT_STREQUAL(func->Extrapolator()->NameOfClass(), "GenericConstExtrapolateImageFunction", "Type of extrapolator");
328 
329   // Interpolate inside image domain
330   EXPECT_EQUAL(func->Evaluate(3.0, 2.0), image->VoxelToIndex(3, 2), "Interpolate image value at voxel position");
331   EXPECT_EQUAL(func->Evaluate(3.4, 2.0), 0.6 * image->VoxelToIndex(3, 2) + 0.4 * image->VoxelToIndex(4, 2), "Interpolate image value at sub-voxel position along x");
332   EXPECT_EQUAL(func->Evaluate(3.0, 2.7), 0.3 * image->VoxelToIndex(3, 2) + 0.7 * image->VoxelToIndex(3, 3), "Interpolate image value at sub-voxel position along y");
333 
334   // Extrapolate outside image domain
335   ASSERT_EQUAL(func->Extrapolator()->DefaultValue(), -1, "Default value of extrapolator");
336   EXPECT_EQUAL(func->Evaluate(-0.1, -0.1), -0.19, "Extrapolate image value outside of image domain");
337   EXPECT_EQUAL(func->Evaluate(-1.1,  0.0), -1, "Extrapolate image value outside of image domain in x");
338   EXPECT_EQUAL(func->Evaluate(16.1,  0.0), -1, "Extrapolate image value outside of image domain in x");
339   EXPECT_EQUAL(func->Evaluate( 0.0, -1.1), -1, "Extrapolate image value outside of image domain in y");
340   EXPECT_EQUAL(func->Evaluate( 0.0, 16.1), -1, "Extrapolate image value outside of image domain in y");
341   EXPECT_EQUAL(func->Evaluate(-1.1, -1.1), -1, "Extrapolate image value outside of image domain in x and y");
342   EXPECT_EQUAL(func->Evaluate(16.1, 16.1), -1, "Extrapolate image value outside of image domain in x and y");
343 
344   // Clean up
345   delete image;
346   delete func;
347 
348   // -------------------------------------------------------------------------
349   // 3D
350   image = create_test_image<double>(16, 16, 16);
351   func  = InterpolateImageFunction::New(Interpolation_Linear, Extrapolation_Const, image);
352 
353   // Initialize image function
354   func->Initialize();
355   func->Extrapolator()->DefaultValue(-1);
356 
357   // Check instantiated image function
358   ASSERT_STREQUAL(func->NameOfClass(), "GenericLinearInterpolateImageFunction3D", "Type of interpolator");
359   ASSERT_STREQUAL(func->Extrapolator()->NameOfClass(), "GenericConstExtrapolateImageFunction", "Type of extrapolator");
360 
361   // Interpolate inside image domain
362   EXPECT_EQUAL(func->Evaluate(3.0, 2.0, 5.0), image->VoxelToIndex(3, 2, 5), "Interpolate image value at voxel position");
363   EXPECT_EQUAL(func->Evaluate(3.4, 2.0, 5.0), 0.6 * image->VoxelToIndex(3, 2, 5) + 0.4 * image->VoxelToIndex(4, 2, 5), "Interpolate image value at sub-voxel position along x");
364   EXPECT_EQUAL(func->Evaluate(3.0, 2.7, 5.0), 0.3 * image->VoxelToIndex(3, 2, 5) + 0.7 * image->VoxelToIndex(3, 3, 5), "Interpolate image value at sub-voxel position along y");
365   EXPECT_EQUAL(func->Evaluate(3.0, 2.0, 5.1), 0.9 * image->VoxelToIndex(3, 2, 5) + 0.1 * image->VoxelToIndex(3, 2, 6), "Interpolate image value at sub-voxel position along z");
366 
367   // Extrapolate outside image domain
368   ASSERT_EQUAL(func->Extrapolator()->DefaultValue(), -1, "Default value of extrapolator");
369   EXPECT_EQUAL(func->Evaluate(-1.1,  0.0,  0.0), -1, "Extrapolate image value slightly outside of image domain in x");
370   EXPECT_EQUAL(func->Evaluate(16.1,  0.0,  0.0), -1, "Extrapolate image value slightly outside of image domain in x");
371   EXPECT_EQUAL(func->Evaluate( 0.0, -1.1,  0.0), -1, "Extrapolate image value slightly outside of image domain in y");
372   EXPECT_EQUAL(func->Evaluate( 0.0, 16.1,  0.0), -1, "Extrapolate image value slightly outside of image domain in y");
373   EXPECT_EQUAL(func->Evaluate( 0.0,  0.0, -1.1), -1, "Extrapolate image value slightly outside of image domain in z");
374   EXPECT_EQUAL(func->Evaluate( 0.0,  0.0, 16.1), -1, "Extrapolate image value slightly outside of image domain in z");
375   EXPECT_EQUAL(func->Evaluate(-1.1, -1.1,  0.0), -1, "Extrapolate image value slightly outside of image domain in x and y");
376   EXPECT_EQUAL(func->Evaluate(16.1, 16.1,  0.0), -1, "Extrapolate image value slightly outside of image domain in x and y");
377   EXPECT_EQUAL(func->Evaluate(-1.1,  0.0, -1.1), -1, "Extrapolate image value slightly outside of image domain in x and z");
378   EXPECT_EQUAL(func->Evaluate(16.1,  0.0, 16.1), -1, "Extrapolate image value slightly outside of image domain in x and z");
379   EXPECT_EQUAL(func->Evaluate( 0.0, -1.1, -1.1), -1, "Extrapolate image value slightly outside of image domain in y and z");
380   EXPECT_EQUAL(func->Evaluate( 0.0, 16.1, 16.1), -1, "Extrapolate image value slightly outside of image domain in y and z");
381 
382   // Clean up
383   delete image;
384   delete func;
385 
386   // -------------------------------------------------------------------------
387   // 3D vector field
388   image = create_test_image<double>(16, 16, 16, 1, 3);
389   func  = InterpolateImageFunction::New(Interpolation_Linear, Extrapolation_Const, image);
390 
391   // Initialize image function
392   func->Initialize();
393   func->Extrapolator()->DefaultValue(-1);
394 
395   // Check instantiated image function
396   ASSERT_STREQUAL(func->NameOfClass(), "GenericLinearInterpolateImageFunction3D", "Type of interpolator");
397   ASSERT_STREQUAL(func->Extrapolator()->NameOfClass(), "GenericConstExtrapolateImageFunction", "Type of extrapolator");
398 
399   // Interpolate inside image domain
400   EXPECT_EQUAL(func->Evaluate(3.0, 2.0, 5.0, 0.0), image->VoxelToIndex(3, 2, 5, 0), "Interpolate image value at voxel position");
401   EXPECT_EQUAL(func->Evaluate(3.4, 2.0, 5.0, 0.0), 0.6 * image->VoxelToIndex(3, 2, 5, 0) + 0.4 * image->VoxelToIndex(4, 2, 5, 0), "Interpolate image value at sub-voxel position along x");
402   EXPECT_EQUAL(func->Evaluate(3.0, 2.7, 5.0, 0.0), 0.3 * image->VoxelToIndex(3, 2, 5, 0) + 0.7 * image->VoxelToIndex(3, 3, 5, 0), "Interpolate image value at sub-voxel position along y");
403   EXPECT_EQUAL(func->Evaluate(3.0, 2.0, 5.1, 0.0), 0.9 * image->VoxelToIndex(3, 2, 5, 0) + 0.1 * image->VoxelToIndex(3, 2, 6, 0), "Interpolate image value at sub-voxel position along z");
404 
405   EXPECT_EQUAL(func->Evaluate(3.0, 2.0, 5.0, 1.0), image->VoxelToIndex(3, 2, 5, 1), "Interpolate image value at voxel position");
406   EXPECT_EQUAL(func->Evaluate(3.4, 2.0, 5.0, 1.0), 0.6 * image->VoxelToIndex(3, 2, 5, 1) + 0.4 * image->VoxelToIndex(4, 2, 5, 1), "Interpolate image value at sub-voxel position along x");
407   EXPECT_EQUAL(func->Evaluate(3.0, 2.7, 5.0, 1.0), 0.3 * image->VoxelToIndex(3, 2, 5, 1) + 0.7 * image->VoxelToIndex(3, 3, 5, 1), "Interpolate image value at sub-voxel position along y");
408   EXPECT_EQUAL(func->Evaluate(3.0, 2.0, 5.1, 1.0), 0.9 * image->VoxelToIndex(3, 2, 5, 1) + 0.1 * image->VoxelToIndex(3, 2, 6, 1), "Interpolate image value at sub-voxel position along z");
409 
410   EXPECT_EQUAL(func->Evaluate(3.0, 2.0, 5.0, 2.0), image->VoxelToIndex(3, 2, 5, 2), "Interpolate image value at voxel position");
411   EXPECT_EQUAL(func->Evaluate(3.4, 2.0, 5.0, 2.0), 0.6 * image->VoxelToIndex(3, 2, 5, 2) + 0.4 * image->VoxelToIndex(4, 2, 5, 2), "Interpolate image value at sub-voxel position along x");
412   EXPECT_EQUAL(func->Evaluate(3.0, 2.7, 5.0, 2.0), 0.3 * image->VoxelToIndex(3, 2, 5, 2) + 0.7 * image->VoxelToIndex(3, 3, 5, 2), "Interpolate image value at sub-voxel position along y");
413   EXPECT_EQUAL(func->Evaluate(3.0, 2.0, 5.1, 2.0), 0.9 * image->VoxelToIndex(3, 2, 5, 2) + 0.1 * image->VoxelToIndex(3, 2, 6, 2), "Interpolate image value at sub-voxel position along z");
414 
415   // Clean up
416   delete image;
417   delete func;
418 
419   return RESULT;
420 }
421 
422 // ---------------------------------------------------------------------------
test_Interpolation_Linear_Extrapolation_NN()423 int test_Interpolation_Linear_Extrapolation_NN()
424 {
425   TEST("test_Interpolation_Linear_Extrapolation_NN");
426 
427   GenericImage<double>     *image = NULL;
428   InterpolateImageFunction *func  = NULL;
429 
430   // -------------------------------------------------------------------------
431   // 2D
432   image = create_test_image<double>(16, 16);
433   func  = InterpolateImageFunction::New(Interpolation_Linear, Extrapolation_NN, image);
434 
435   // Initialize image function
436   func->Initialize();
437 
438   // Check instantiated image function
439   ASSERT_STREQUAL(func->NameOfClass(), "GenericLinearInterpolateImageFunction2D", "Type of interpolator");
440   ASSERT_STREQUAL(func->Extrapolator()->NameOfClass(), "GenericNearestNeighborExtrapolateImageFunction", "Type of extrapolator");
441 
442   // Interpolate inside image domain
443   EXPECT_EQUAL(func->Evaluate(3.0, 2.0), image->VoxelToIndex(3, 2), "Interpolate image value at voxel position");
444   EXPECT_EQUAL(func->Evaluate(3.4, 2.0), 0.6 * image->VoxelToIndex(3, 2) + 0.4 * image->VoxelToIndex(4, 2), "Interpolate image value at sub-voxel position along x");
445   EXPECT_EQUAL(func->Evaluate(3.0, 2.7), 0.3 * image->VoxelToIndex(3, 2) + 0.7 * image->VoxelToIndex(3, 3), "Interpolate image value at sub-voxel position along y");
446 
447   // Extrapolate outside image domain
448   EXPECT_EQUAL(func->Evaluate(-0.1,  0.0), image->VoxelToIndex( 0,  0), "Extrapolate image value slightly outside of image domain in x");
449   EXPECT_EQUAL(func->Evaluate(15.1,  0.0), image->VoxelToIndex(15,  0), "Extrapolate image value slightly outside of image domain in x");
450   EXPECT_EQUAL(func->Evaluate( 0.0, -0.1), image->VoxelToIndex( 0,  0), "Extrapolate image value slightly outside of image domain in y");
451   EXPECT_EQUAL(func->Evaluate( 0.0, 15.1), image->VoxelToIndex( 0, 15), "Extrapolate image value slightly outside of image domain in y");
452   EXPECT_EQUAL(func->Evaluate(-0.1, -0.1), image->VoxelToIndex( 0,  0), "Extrapolate image value slightly outside of image domain in x and y");
453   EXPECT_EQUAL(func->Evaluate(15.1, 15.1), image->VoxelToIndex(15, 15), "Extrapolate image value slightly outside of image domain in x and y");
454 
455   // Clean up
456   delete image;
457   delete func;
458 
459   // -------------------------------------------------------------------------
460   // 3D
461   image = create_test_image<double>(16, 16, 16);
462   func  = InterpolateImageFunction::New(Interpolation_Linear, Extrapolation_NN, image);
463 
464   // Initialize image function
465   func->Initialize();
466 
467   // Check instantiated image function
468   ASSERT_STREQUAL(func->NameOfClass(), "GenericLinearInterpolateImageFunction3D", "Type of interpolator");
469   ASSERT_STREQUAL(func->Extrapolator()->NameOfClass(), "GenericNearestNeighborExtrapolateImageFunction", "Type of extrapolator");
470 
471   // Interpolate inside image domain
472   EXPECT_EQUAL(func->Evaluate(3.0, 2.0, 5.0), image->VoxelToIndex(3, 2, 5), "Interpolate image value at voxel position");
473   EXPECT_EQUAL(func->Evaluate(3.4, 2.0, 5.0), 0.6 * image->VoxelToIndex(3, 2, 5) + 0.4 * image->VoxelToIndex(4, 2, 5), "Interpolate image value at sub-voxel position along x");
474   EXPECT_EQUAL(func->Evaluate(3.0, 2.7, 5.0), 0.3 * image->VoxelToIndex(3, 2, 5) + 0.7 * image->VoxelToIndex(3, 3, 5), "Interpolate image value at sub-voxel position along y");
475   EXPECT_EQUAL(func->Evaluate(3.0, 2.0, 5.1), 0.9 * image->VoxelToIndex(3, 2, 5) + 0.1 * image->VoxelToIndex(3, 2, 6), "Interpolate image value at sub-voxel position along z");
476 
477   // Extrapolate outside image domain
478   EXPECT_EQUAL(func->Evaluate(-0.1,  0.0,  0.0), image->VoxelToIndex( 0,  0,  0), "Extrapolate image value slightly outside of image domain in x");
479   EXPECT_EQUAL(func->Evaluate(15.1,  0.0,  0.0), image->VoxelToIndex(15,  0,  0), "Extrapolate image value slightly outside of image domain in x");
480   EXPECT_EQUAL(func->Evaluate( 0.0, -0.1,  0.0), image->VoxelToIndex( 0,  0,  0), "Extrapolate image value slightly outside of image domain in y");
481   EXPECT_EQUAL(func->Evaluate( 0.0, 15.1,  0.0), image->VoxelToIndex( 0, 15,  0), "Extrapolate image value slightly outside of image domain in y");
482   EXPECT_EQUAL(func->Evaluate( 0.0,  0.0, -0.1), image->VoxelToIndex( 0,  0,  0), "Extrapolate image value slightly outside of image domain in z");
483   EXPECT_EQUAL(func->Evaluate( 0.0,  0.0, 15.1), image->VoxelToIndex( 0,  0, 15), "Extrapolate image value slightly outside of image domain in z");
484   EXPECT_EQUAL(func->Evaluate(-0.1, -0.1,  0.0), image->VoxelToIndex( 0,  0,  0), "Extrapolate image value slightly outside of image domain in x and y");
485   EXPECT_EQUAL(func->Evaluate(15.1, 15.1,  0.0), image->VoxelToIndex(15, 15,  0), "Extrapolate image value slightly outside of image domain in x and y");
486   EXPECT_EQUAL(func->Evaluate(-0.1,  0.0, -0.1), image->VoxelToIndex( 0,  0,  0), "Extrapolate image value slightly outside of image domain in x and z");
487   EXPECT_EQUAL(func->Evaluate(15.1,  0.0, 15.1), image->VoxelToIndex(15,  0, 15), "Extrapolate image value slightly outside of image domain in x and z");
488   EXPECT_EQUAL(func->Evaluate( 0.0, -0.1, -0.1), image->VoxelToIndex( 0,  0,  0), "Extrapolate image value slightly outside of image domain in y and z");
489   EXPECT_EQUAL(func->Evaluate( 0.0, 15.1, 15.1), image->VoxelToIndex( 0, 15, 15), "Extrapolate image value slightly outside of image domain in y and z");
490 
491   // Clean up
492   delete image;
493   delete func;
494 
495   return RESULT;
496 }
497 
498 // ===========================================================================
499 // Main
500 // ===========================================================================
501 
502 // ---------------------------------------------------------------------------
InterpolateExtrapolateImageFunctionTest(int,char * [])503 int InterpolateExtrapolateImageFunctionTest(int, char *[])
504 {
505   int retval = 0;
506 
507   retval += test_Initialize();
508   retval += test_IsInsideOutside();
509   retval += test_Interpolation_NN_Extrapolation_Default();
510   retval += test_Interpolation_NN_Extrapolation_Const();
511   retval += test_Interpolation_Linear_Extrapolation_Const();
512   retval += test_Interpolation_Linear_Extrapolation_NN();
513 
514   return retval;
515 }
516