KWStyle - itkTestMain.h
 
Matrix View
Description

1
2 HRD /*=========================================================================
3
4 HRD   Program:   Insight Segmentation & Registration Toolkit
5 HRD   Module:    $RCSfile: itkTestMain.h.html,v $
6 HRD   Language:  C++
7 HRD   Date:      $Date: 2006/01/17 19:15:48 $
8   Version:   $Revision: 1.4 $
9
10 HRD   Copyright (c) Insight Software Consortium. All rights reserved.
11   See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
12
13   Portions of this code are covered under the VTK copyright.
14   See VTKCopyright.txt or http://www.kitware.com/VTKCopyright.htm for details.
15
16      This software is distributed WITHOUT ANY WARRANTY; without even 
17      the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR 
18 IND *****PURPOSE.  See the above copyright notices for more information.
19
20 =========================================================================*/
21
22 // This file is used to create TestDriver executables
23 // These executables are able to register a function pointer to a string name
24 // in a lookup table.   By including this file, it creates a main function
25 // that calls RegisterTests() then looks up the function pointer for the test
26 // specified on the command line.
27 #include "itkWin32Header.h"
28 #include <map>
29 #include <string>
30 #include <iostream>
31 #include <fstream>
32 #include "itkNumericTraits.h"
33 #include "itkMultiThreader.h"
34 #include "itkImage.h"
35 #include "itkImageFileReader.h"
36 #include "itkImageFileWriter.h"
37 #include "itkImageRegionConstIterator.h"
38 #include "itkSubtractImageFilter.h"
39 #include "itkRescaleIntensityImageFilter.h"
40 #include "itkExtractImageFilter.h"
41 #include "itkDifferenceImageFilter.h"
42 #include "itkImageRegion.h"
43 #include "itksys/SystemTools.hxx"
44
45 #define ITK_TEST_DIMENSION_MAX 6
46
47 TDR typedef int (*MainFuncPointer)(int , char* [] );
48 std::map<std::string, MainFuncPointer> StringToTestFunctionMap;
49
50 #define REGISTER_TEST(test) \
51 extern int test(int, char* [] ); \
52 StringToTestFunctionMap[#test] = test
53
54 int RegressionTestImage (const char *, const char *, int);
55 std::map<std::string,int> RegressionTestBaselines (char *);
56
57 void RegisterTests();
58 void PrintAvailableTests()
59 IND {
60   std::cout << "Available tests:\n";
61 LEN   std::map<std::string, MainFuncPointer>::iterator j = StringToTestFunctionMap.begin();
62   int i = 0;
63   while(j != StringToTestFunctionMap.end())
64     {
65     std::cout << i << ". " << j->first << "\n";
66     ++i;
67     ++j;
68     }
69 }
70
71 int main(int ac, char* av[] )
72 {
73   char *baselineFilename = NULL;
74   char *testFilename = NULL;
75
76   RegisterTests();
77   std::string testToRun;
78   if(ac < 2)
79     {
80     PrintAvailableTests();
81     std::cout << "To run a test, enter the test number: ";
82     int testNum = 0;
83     std::cin >> testNum;
84 LEN     std::map<std::string, MainFuncPointer>::iterator j = StringToTestFunctionMap.begin();
85     int i = 0;
86     while(j != StringToTestFunctionMap.end() && i < testNum)
87       {
88       ++i;
89       ++j;
90       }
91     if(j == StringToTestFunctionMap.end())
92       {
93       std::cerr << testNum << " is an invalid test number\n";
94       return -1;
95       }
96     testToRun = j->first;
97     }
98   else
99     {
100     if (strcmp(av[1], "--with-threads") == 0)
101       {
102       int numThreads = atoi(av[2]);
103       itk::MultiThreader::SetGlobalDefaultNumberOfThreads(numThreads);
104       av += 2;
105       ac -= 2;
106       }
107     else if (strcmp(av[1], "--without-threads") == 0)
108       {
109       itk::MultiThreader::SetGlobalDefaultNumberOfThreads(1);
110       av += 1;
111       ac -= 1;
112       }
113     else if (strcmp(av[1], "--compare") == 0)
114       {
115       baselineFilename = av[2];
116       testFilename = av[3];
117       av += 3;
118       ac -= 3;
119       }
120     testToRun = av[1];
121     }
122 LEN   std::map<std::string, MainFuncPointer>::iterator j = StringToTestFunctionMap.find(testToRun);
123   if(j != StringToTestFunctionMap.end())
124     {
125     MainFuncPointer f = j->second;
126     int result;
127     try
128       {
129       // Invoke the test's "main" function.
130       result = (*f)(ac-1, av+1);
131
132       // Make a list of possible baselines
133       if (baselineFilename && testFilename)
134         {
135 LEN         std::map<std::string,int> baselines = RegressionTestBaselines(baselineFilename);
136         std::map<std::string,int>::iterator baseline = baselines.begin();
137         std::string bestBaseline;
138         int bestBaselineStatus = itk::NumericTraits<int>::max();
139         while (baseline != baselines.end())
140           {
141           baseline->second = RegressionTestImage(testFilename,
142                                                  (baseline->first).c_str(),
143 IND *************************************************0);
144           if (baseline->second < bestBaselineStatus)
145             {
146             bestBaseline = baseline->first;
147             bestBaselineStatus = baseline->second;
148             }
149           if (baseline->second == 0)
150             {
151             break;
152             }
153           ++baseline;
154           }
155         // if the best we can do still has errors, generate the error images
156         if (bestBaselineStatus)
157           {
158           baseline->second = RegressionTestImage(testFilename,
159                                                  bestBaseline.c_str(),
160 IND *************************************************1);
161           }
162
163         // output the matching baseline
164 LEN         std::cout << "<DartMeasurement name=\"BaselineImageName\" type=\"text/string\">";
165         std::cout << itksys::SystemTools::GetFilenameName(bestBaseline);
166         std::cout << "</DartMeasurement>" << std::endl;
167         
168         result += bestBaselineStatus;
169         }
170       }
171     catch(const itk::ExceptionObject& e)
172       {
173       std::cerr << "ITK test driver caught an ITK exception:\n";
174       std::cerr << e.GetFile() << ":" << e.GetLine() << ":\n"
175                 << e.GetDescription() << "\n";
176       result = -1;
177       }
178     catch(const std::exception& e)
179       {
180       std::cerr << "ITK test driver caught an exception:\n";
181       std::cerr << e.what() << "\n";
182       result = -1;
183       }
184     catch(...)
185       {
186       std::cerr << "ITK test driver caught an unknown exception!!!\n";
187       result = -1;
188       }
189     return result;
190     }
191   PrintAvailableTests();
192 LEN   std::cerr << "Failed: " << testToRun << ": No test registered with name " << testToRun << "\n";
193   return -1;
194 }
195
196 // Regression Testing Code
197
198 LEN int RegressionTestImage (const char *testImageFilename, const char *baselineImageFilename, int reportErrors)
199 {
200 LEN   // Use the factory mechanism to read the test and baseline files and convert them to double
201   typedef itk::Image<double,ITK_TEST_DIMENSION_MAX> ImageType;
202 TDA   typedef itk::Image<unsigned char,ITK_TEST_DIMENSION_MAX> OutputType;
203 TDA   typedef itk::Image<unsigned char,2> DiffOutputType;
204 TDA   typedef itk::ImageFileReader<ImageType> ReaderType;
205
206   // Read the baseline file
207   ReaderType::Pointer baselineReader = ReaderType::New();
208 IND ****baselineReader->SetFileName(baselineImageFilename);
209   try
210     {
211     baselineReader->UpdateLargestPossibleRegion();
212     }
213   catch (itk::ExceptionObject& e)
214     {
215 LEN     std::cerr << "Exception detected while reading " << baselineImageFilename << " : "  << e.GetDescription();
216     return 1000;
217     }
218
219   // Read the file generated by the test
220   ReaderType::Pointer testReader = ReaderType::New();
221     testReader->SetFileName(testImageFilename);
222   try
223     {
224     testReader->UpdateLargestPossibleRegion();
225     }
226   catch (itk::ExceptionObject& e)
227     {
228 LEN     std::cerr << "Exception detected while reading " << testImageFilename << " : "  << e.GetDescription() << std::endl;
229     return 1000;
230     }
231
232   // The sizes of the baseline and test image must match
233   ImageType::SizeType baselineSize;
234 LEN     baselineSize = baselineReader->GetOutput()->GetLargestPossibleRegion().GetSize();
235   ImageType::SizeType testSize;
236 IND ****testSize = testReader->GetOutput()->GetLargestPossibleRegion().GetSize();
237   
238   if (baselineSize != testSize)
239     {
240 LEN     std::cerr << "The size of the Baseline image and Test image do not match!" << std::endl;
241     std::cerr << "Baseline image: " << baselineImageFilename
242               << " has size " << baselineSize << std::endl;
243     std::cerr << "Test image:     " << testImageFilename
244               << " has size " << testSize << std::endl;
245     return 1;
246     }
247
248   // Now compare the two images
249   typedef itk::DifferenceImageFilter<ImageType,ImageType> DiffType;
250   DiffType::Pointer diff = DiffType::New();
251 IND ****diff->SetValidInput(baselineReader->GetOutput());
252 IND ****diff->SetTestInput(testReader->GetOutput());
253 IND ****diff->SetDifferenceThreshold(2.0);
254 IND ****diff->UpdateLargestPossibleRegion();
255
256   double status = diff->GetTotalDifference();
257
258   // if there are discrepencies, create an diff image
259   if (status && reportErrors)
260     {
261     typedef itk::RescaleIntensityImageFilter<ImageType,OutputType> RescaleType;
262 TDA     typedef itk::ExtractImageFilter<OutputType,DiffOutputType> ExtractType;
263 TDA     typedef itk::ImageFileWriter<DiffOutputType> WriterType;
264 TDA     typedef itk::ImageRegion<ITK_TEST_DIMENSION_MAX> RegionType;
265     OutputType::IndexType index; index.Fill(0);
266     OutputType::SizeType size; size.Fill(0);
267
268     RescaleType::Pointer rescale = RescaleType::New();
269 LEN,IND ******rescale->SetOutputMinimum(itk::NumericTraits<unsigned char>::NonpositiveMin());
270 IND ******rescale->SetOutputMaximum(itk::NumericTraits<unsigned char>::max());
271 IND ******rescale->SetInput(diff->GetOutput());
272 IND ******rescale->UpdateLargestPossibleRegion();
273
274     RegionType region;
275     region.SetIndex(index);
276     
277     size = rescale->GetOutput()->GetLargestPossibleRegion().GetSize();
278     for (unsigned int i = 2; i < ITK_TEST_DIMENSION_MAX; i++)
279       {
280       size[i] = 0;
281       }
282     region.SetSize(size);
283
284     ExtractType::Pointer extract = ExtractType::New();
285       extract->SetInput(rescale->GetOutput());
286 IND ******extract->SetExtractionRegion(region);
287
288     WriterType::Pointer writer = WriterType::New();
289 IND ******writer->SetInput(extract->GetOutput());
290
291 LEN     std::cout << "<DartMeasurement name=\"ImageError\" type=\"numeric/double\">";
292     std::cout << status;
293     std::cout <<  "</DartMeasurement>" << std::endl;
294
295     ::itk::OStringStream diffName;
296       diffName << testImageFilename << ".diff.png";
297     try
298       {
299       rescale->SetInput(diff->GetOutput());
300       rescale->Update();
301       }
302     catch (...)
303       {
304       std::cerr << "Error during rescale of " << diffName.str() << std::endl;
305       }
306     writer->SetFileName(diffName.str().c_str());
307     try
308       {
309       writer->Update();
310       }
311     catch (...)
312       {
313       std::cerr << "Error during write of " << diffName.str() << std::endl;
314       }
315
316 LEN     std::cout << "<DartMeasurementFile name=\"DifferenceImage\" type=\"image/png\">";
317     std::cout << diffName.str();
318     std::cout << "</DartMeasurementFile>" << std::endl;
319
320     ::itk::OStringStream baseName;
321     baseName << testImageFilename << ".base.png";
322     try
323       {
324       rescale->SetInput(baselineReader->GetOutput());
325       rescale->Update();
326       }
327     catch (...)
328       {
329       std::cerr << "Error during rescale of " << baseName.str() << std::endl;
330       }
331     try
332       {
333       writer->SetFileName(baseName.str().c_str());
334       writer->Update();
335       }
336     catch (...)
337       {
338       std::cerr << "Error during write of " << baseName.str() << std::endl;
339       }
340
341 LEN     std::cout << "<DartMeasurementFile name=\"BaselineImage\" type=\"image/png\">";
342     std::cout << baseName.str();
343     std::cout << "</DartMeasurementFile>" << std::endl;
344
345     ::itk::OStringStream testName;
346     testName << testImageFilename << ".test.png";
347     try
348       {
349       rescale->SetInput(testReader->GetOutput());
350       rescale->Update();
351       }
352     catch (...)
353       {
354       std::cerr << "Error during rescale of " << testName.str()
355                 << std::endl;
356       }
357     try
358       {
359       writer->SetFileName(testName.str().c_str());
360       writer->Update();
361       }
362     catch (...)
363       {
364       std::cerr << "Error during write of " << testName.str() << std::endl;
365       }
366
367     std::cout << "<DartMeasurementFile name=\"TestImage\" type=\"image/png\">";
368     std::cout << testName.str();
369     std::cout << "</DartMeasurementFile>" << std::endl;
370
371
372     }
373   return (status != 0) ? 1 : 0;
374 }
375
376 //
377 // Generate all of the possible baselines
378 LEN // The possible baselines are generated fromn the baselineFilename using the following algorithm:
379 // 1) strip the suffix
380 // 2) append a digit .x
381 // 3) append the original suffix.
382 // It the file exists, increment x and continue
383 //
384 std::map<std::string,int> RegressionTestBaselines (char *baselineFilename)
385 IND {
386   std::map<std::string,int> baselines;
387   baselines[std::string(baselineFilename)] = 0;
388
389   std::string originalBaseline(baselineFilename);
390
391   int x = 0;
392   std::string::size_type suffixPos = originalBaseline.rfind(".");
393   std::string suffix;
394   if (suffixPos != std::string::npos)
395     {
396     suffix = originalBaseline.substr(suffixPos,originalBaseline.length());
397     originalBaseline.erase(suffixPos,originalBaseline.length());
398     }
399   while (++x)
400     {
401     ::itk::OStringStream filename;
402     filename << originalBaseline << "." << x << suffix;
403     std::ifstream filestream(filename.str().c_str());
404     if (!filestream)
405       {
406 IND ********break;
407       }
408     baselines[filename.str()] = 0;
409     filestream.close();
410     }
411   return baselines;
412 IND }
413

Generated by KWStyle 1.0b on Tuesday January,17 at 02:14:49PM
© Kitware Inc.