00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef __itkTestMain_h
00021 #define __itkTestMain_h
00022
00023
00024
00025
00026
00027
00028 #include "itkWin32Header.h"
00029 #include <map>
00030 #include <string>
00031 #include <iostream>
00032 #include <fstream>
00033 #include "itkNumericTraits.h"
00034 #include "itkMultiThreader.h"
00035 #include "itkImage.h"
00036 #include "itkImageFileReader.h"
00037 #include "itkImageFileWriter.h"
00038 #include "itkImageRegionConstIterator.h"
00039 #include "itkSubtractImageFilter.h"
00040 #include "itkRescaleIntensityImageFilter.h"
00041 #include "itkExtractImageFilter.h"
00042 #include "itkDifferenceImageFilter.h"
00043 #include "itkImageRegion.h"
00044 #include "itksys/SystemTools.hxx"
00045
00046 #define ITK_TEST_DIMENSION_MAX 6
00047
00048 typedef int (*MainFuncPointer)(int , char* [] );
00049 std::map<std::string, MainFuncPointer> StringToTestFunctionMap;
00050
00051 #define REGISTER_TEST(test) \
00052 extern int test(int, char* [] ); \
00053 StringToTestFunctionMap[#test] = test
00054
00055 int RegressionTestImage (const char *testImageFilename,
00056 const char *baselineImageFilename,
00057 int reportErrors,
00058 double intensityTolerance = 2.0,
00059 unsigned int numberOfPixelsTolerance = 0,
00060 unsigned int radiusTolerance = 0);
00061
00062 std::map<std::string,int> RegressionTestBaselines (char *);
00063
00064 void RegisterTests();
00065 void PrintAvailableTests()
00066 {
00067 std::cout << "Available tests:\n";
00068 std::map<std::string, MainFuncPointer>::iterator j = StringToTestFunctionMap.begin();
00069 int i = 0;
00070 while(j != StringToTestFunctionMap.end())
00071 {
00072 std::cout << i << ". " << j->first << "\n";
00073 ++i;
00074 ++j;
00075 }
00076 }
00077
00078 int main(int ac, char* av[] )
00079 {
00080 double intensityTolerance = 2.0;
00081 unsigned int numberOfPixelsTolerance = 0;
00082 unsigned int radiusTolerance = 0;
00083
00084 typedef std::pair< char *, char *> ComparePairType;
00085 std::vector< ComparePairType > compareList;
00086
00087 RegisterTests();
00088 std::string testToRun;
00089 if(ac < 2)
00090 {
00091 PrintAvailableTests();
00092 std::cout << "To run a test, enter the test number: ";
00093 int testNum = 0;
00094 std::cin >> testNum;
00095 std::map<std::string, MainFuncPointer>::iterator j = StringToTestFunctionMap.begin();
00096 int i = 0;
00097 while(j != StringToTestFunctionMap.end() && i < testNum)
00098 {
00099 ++i;
00100 ++j;
00101 }
00102 if(j == StringToTestFunctionMap.end())
00103 {
00104 std::cerr << testNum << " is an invalid test number\n";
00105 return -1;
00106 }
00107 testToRun = j->first;
00108 }
00109 else
00110 {
00111 while( ac > 0 && testToRun.empty() )
00112 {
00113 if (strcmp(av[1], "--with-threads") == 0)
00114 {
00115 int numThreads = atoi(av[2]);
00116 itk::MultiThreader::SetGlobalDefaultNumberOfThreads(numThreads);
00117 av += 2;
00118 ac -= 2;
00119 }
00120 else if (strcmp(av[1], "--without-threads") == 0)
00121 {
00122 itk::MultiThreader::SetGlobalDefaultNumberOfThreads(1);
00123 av += 1;
00124 ac -= 1;
00125 }
00126 else if (ac > 3 && strcmp(av[1], "--compare") == 0)
00127 {
00128 compareList.push_back( ComparePairType( av[2], av[3] ) );
00129 av += 3;
00130 ac -= 3;
00131 }
00132 else if (ac > 2 && strcmp(av[1], "--compareNumberOfPixelsTolerance") == 0)
00133 {
00134 numberOfPixelsTolerance = atoi( av[2] );
00135 av += 2;
00136 ac -= 2;
00137 }
00138 else if (ac > 2 && strcmp(av[1], "--compareRadiusTolerance") == 0)
00139 {
00140 radiusTolerance = atoi( av[2] );
00141 av += 2;
00142 ac -= 2;
00143 }
00144 else if (ac > 2 && strcmp(av[1], "--compareIntensityTolerance") == 0)
00145 {
00146 intensityTolerance = atof( av[2] );
00147 av += 2;
00148 ac -= 2;
00149 }
00150 else
00151 {
00152 testToRun = av[1];
00153 }
00154 }
00155 }
00156 std::map<std::string, MainFuncPointer>::iterator j = StringToTestFunctionMap.find(testToRun);
00157 if(j != StringToTestFunctionMap.end())
00158 {
00159 MainFuncPointer f = j->second;
00160 int result;
00161 try
00162 {
00163
00164 result = (*f)(ac-1, av+1);
00165
00166
00167 for( int i=0; i<static_cast<int>(compareList.size()); i++)
00168 {
00169 char * baselineFilename = compareList[i].first;
00170 char * testFilename = compareList[i].second;
00171 std::map<std::string,int> baselines = RegressionTestBaselines(baselineFilename);
00172 std::map<std::string,int>::iterator baseline = baselines.begin();
00173 std::string bestBaseline;
00174 int bestBaselineStatus = itk::NumericTraits<int>::max();
00175 while (baseline != baselines.end())
00176 {
00177 baseline->second = RegressionTestImage(testFilename,
00178 (baseline->first).c_str(),
00179 0,
00180 intensityTolerance,
00181 numberOfPixelsTolerance,
00182 radiusTolerance );
00183 if (baseline->second < bestBaselineStatus)
00184 {
00185 bestBaseline = baseline->first;
00186 bestBaselineStatus = baseline->second;
00187 }
00188 if (baseline->second == 0)
00189 {
00190 break;
00191 }
00192 ++baseline;
00193 }
00194
00195 if (bestBaselineStatus)
00196 {
00197 RegressionTestImage(testFilename,
00198 bestBaseline.c_str(),
00199 1,
00200 intensityTolerance,
00201 numberOfPixelsTolerance,
00202 radiusTolerance );
00203 }
00204
00205
00206 std::cout << "<DartMeasurement name=\"BaselineImageName\" type=\"text/string\">";
00207 std::cout << itksys::SystemTools::GetFilenameName(bestBaseline);
00208 std::cout << "</DartMeasurement>" << std::endl;
00209
00210 result += bestBaselineStatus;
00211 }
00212 }
00213 catch(const itk::ExceptionObject& e)
00214 {
00215 std::cerr << "ITK test driver caught an ITK exception:\n";
00216 e.Print(std::cerr);
00217 result = -1;
00218 }
00219 catch(const std::exception& e)
00220 {
00221 std::cerr << "ITK test driver caught an exception:\n";
00222 std::cerr << e.what() << "\n";
00223 result = -1;
00224 }
00225 catch(...)
00226 {
00227 std::cerr << "ITK test driver caught an unknown exception!!!\n";
00228 result = -1;
00229 }
00230 return result;
00231 }
00232 PrintAvailableTests();
00233 std::cerr << "Failed: " << testToRun << ": No test registered with name " << testToRun << "\n";
00234 return -1;
00235 }
00236
00237
00238
00239 int RegressionTestImage (const char *testImageFilename,
00240 const char *baselineImageFilename,
00241 int reportErrors,
00242 double intensityTolerance,
00243 unsigned int numberOfPixelsTolerance,
00244 unsigned int radiusTolerance )
00245 {
00246
00247 typedef itk::Image<double,ITK_TEST_DIMENSION_MAX> ImageType;
00248 typedef itk::Image<unsigned char,ITK_TEST_DIMENSION_MAX> OutputType;
00249 typedef itk::Image<unsigned char,2> DiffOutputType;
00250 typedef itk::ImageFileReader<ImageType> ReaderType;
00251
00252
00253 ReaderType::Pointer baselineReader = ReaderType::New();
00254 baselineReader->SetFileName(baselineImageFilename);
00255 try
00256 {
00257 baselineReader->UpdateLargestPossibleRegion();
00258 }
00259 catch (itk::ExceptionObject& e)
00260 {
00261 std::cerr << "Exception detected while reading " << baselineImageFilename << " : " << e.GetDescription();
00262 return 1000;
00263 }
00264
00265
00266 ReaderType::Pointer testReader = ReaderType::New();
00267 testReader->SetFileName(testImageFilename);
00268 try
00269 {
00270 testReader->UpdateLargestPossibleRegion();
00271 }
00272 catch (itk::ExceptionObject& e)
00273 {
00274 std::cerr << "Exception detected while reading " << testImageFilename << " : " << e.GetDescription() << std::endl;
00275 return 1000;
00276 }
00277
00278
00279 ImageType::SizeType baselineSize;
00280 baselineSize = baselineReader->GetOutput()->GetLargestPossibleRegion().GetSize();
00281 ImageType::SizeType testSize;
00282 testSize = testReader->GetOutput()->GetLargestPossibleRegion().GetSize();
00283
00284 if (baselineSize != testSize)
00285 {
00286 std::cerr << "The size of the Baseline image and Test image do not match!" << std::endl;
00287 std::cerr << "Baseline image: " << baselineImageFilename
00288 << " has size " << baselineSize << std::endl;
00289 std::cerr << "Test image: " << testImageFilename
00290 << " has size " << testSize << std::endl;
00291 return 1;
00292 }
00293
00294
00295 typedef itk::DifferenceImageFilter<ImageType,ImageType> DiffType;
00296 DiffType::Pointer diff = DiffType::New();
00297 diff->SetValidInput(baselineReader->GetOutput());
00298 diff->SetTestInput(testReader->GetOutput());
00299 diff->SetDifferenceThreshold( intensityTolerance );
00300 diff->SetToleranceRadius( radiusTolerance );
00301 diff->UpdateLargestPossibleRegion();
00302
00303 unsigned long status = 0;
00304 status = diff->GetNumberOfPixelsWithDifferences();
00305
00306
00307 if ( (status > numberOfPixelsTolerance) && reportErrors )
00308 {
00309 typedef itk::RescaleIntensityImageFilter<ImageType,OutputType> RescaleType;
00310 typedef itk::ExtractImageFilter<OutputType,DiffOutputType> ExtractType;
00311 typedef itk::ImageFileWriter<DiffOutputType> WriterType;
00312 typedef itk::ImageRegion<ITK_TEST_DIMENSION_MAX> RegionType;
00313 OutputType::SizeType size; size.Fill(0);
00314
00315 RescaleType::Pointer rescale = RescaleType::New();
00316 rescale->SetOutputMinimum(itk::NumericTraits<unsigned char>::NonpositiveMin());
00317 rescale->SetOutputMaximum(itk::NumericTraits<unsigned char>::max());
00318 rescale->SetInput(diff->GetOutput());
00319 rescale->UpdateLargestPossibleRegion();
00320 size = rescale->GetOutput()->GetLargestPossibleRegion().GetSize();
00321
00322
00323
00324 OutputType::IndexType index; index.Fill(0);
00325 for (unsigned int i = 2; i < ITK_TEST_DIMENSION_MAX; i++)
00326 {
00327 index[i]=size[i]/2;
00328 size[i] = 0;
00329 }
00330
00331 RegionType region;
00332 region.SetIndex(index);
00333
00334 region.SetSize(size);
00335
00336 ExtractType::Pointer extract = ExtractType::New();
00337 extract->SetInput(rescale->GetOutput());
00338 extract->SetExtractionRegion(region);
00339
00340 WriterType::Pointer writer = WriterType::New();
00341 writer->SetInput(extract->GetOutput());
00342
00343 std::cout << "<DartMeasurement name=\"ImageError\" type=\"numeric/double\">";
00344 std::cout << status;
00345 std::cout << "</DartMeasurement>" << std::endl;
00346
00347 ::itk::OStringStream diffName;
00348 diffName << testImageFilename << ".diff.png";
00349 try
00350 {
00351 rescale->SetInput(diff->GetOutput());
00352 rescale->Update();
00353 }
00354 catch(const std::exception& e)
00355 {
00356 std::cerr << "Error during rescale of " << diffName.str() << std::endl;
00357 std::cerr << e.what() << "\n";
00358 }
00359 catch (...)
00360 {
00361 std::cerr << "Error during rescale of " << diffName.str() << std::endl;
00362 }
00363 writer->SetFileName(diffName.str().c_str());
00364 try
00365 {
00366 writer->Update();
00367 }
00368 catch(const std::exception& e)
00369 {
00370 std::cerr << "Error during write of " << diffName.str() << std::endl;
00371 std::cerr << e.what() << "\n";
00372 }
00373 catch (...)
00374 {
00375 std::cerr << "Error during write of " << diffName.str() << std::endl;
00376 }
00377
00378 std::cout << "<DartMeasurementFile name=\"DifferenceImage\" type=\"image/png\">";
00379 std::cout << diffName.str();
00380 std::cout << "</DartMeasurementFile>" << std::endl;
00381
00382 ::itk::OStringStream baseName;
00383 baseName << testImageFilename << ".base.png";
00384 try
00385 {
00386 rescale->SetInput(baselineReader->GetOutput());
00387 rescale->Update();
00388 }
00389 catch(const std::exception& e)
00390 {
00391 std::cerr << "Error during rescale of " << baseName.str() << std::endl;
00392 std::cerr << e.what() << "\n";
00393 }
00394 catch (...)
00395 {
00396 std::cerr << "Error during rescale of " << baseName.str() << std::endl;
00397 }
00398 try
00399 {
00400 writer->SetFileName(baseName.str().c_str());
00401 writer->Update();
00402 }
00403 catch(const std::exception& e)
00404 {
00405 std::cerr << "Error during write of " << baseName.str() << std::endl;
00406 std::cerr << e.what() << "\n";
00407 }
00408 catch (...)
00409 {
00410 std::cerr << "Error during write of " << baseName.str() << std::endl;
00411 }
00412
00413 std::cout << "<DartMeasurementFile name=\"BaselineImage\" type=\"image/png\">";
00414 std::cout << baseName.str();
00415 std::cout << "</DartMeasurementFile>" << std::endl;
00416
00417 ::itk::OStringStream testName;
00418 testName << testImageFilename << ".test.png";
00419 try
00420 {
00421 rescale->SetInput(testReader->GetOutput());
00422 rescale->Update();
00423 }
00424 catch(const std::exception& e)
00425 {
00426 std::cerr << "Error during rescale of " << testName.str() << std::endl;
00427 std::cerr << e.what() << "\n";
00428 }
00429 catch (...)
00430 {
00431 std::cerr << "Error during rescale of " << testName.str() << std::endl;
00432 }
00433 try
00434 {
00435 writer->SetFileName(testName.str().c_str());
00436 writer->Update();
00437 }
00438 catch(const std::exception& e)
00439 {
00440 std::cerr << "Error during write of " << testName.str() << std::endl;
00441 std::cerr << e.what() << "\n";
00442 }
00443 catch (...)
00444 {
00445 std::cerr << "Error during write of " << testName.str() << std::endl;
00446 }
00447
00448 std::cout << "<DartMeasurementFile name=\"TestImage\" type=\"image/png\">";
00449 std::cout << testName.str();
00450 std::cout << "</DartMeasurementFile>" << std::endl;
00451
00452
00453 }
00454 return (status > numberOfPixelsTolerance) ? 1 : 0;
00455 }
00456
00457
00458
00459
00460
00461
00462
00463
00464
00465 std::map<std::string,int> RegressionTestBaselines (char *baselineFilename)
00466 {
00467 std::map<std::string,int> baselines;
00468 baselines[std::string(baselineFilename)] = 0;
00469
00470 std::string originalBaseline(baselineFilename);
00471
00472 int x = 0;
00473 std::string::size_type suffixPos = originalBaseline.rfind(".");
00474 std::string suffix;
00475 if (suffixPos != std::string::npos)
00476 {
00477 suffix = originalBaseline.substr(suffixPos,originalBaseline.length());
00478 originalBaseline.erase(suffixPos,originalBaseline.length());
00479 }
00480 while (++x)
00481 {
00482 ::itk::OStringStream filename;
00483 filename << originalBaseline << "." << x << suffix;
00484 std::ifstream filestream(filename.str().c_str());
00485 if (!filestream)
00486 {
00487 break;
00488 }
00489 baselines[filename.str()] = 0;
00490 filestream.close();
00491 }
00492 return baselines;
00493 }
00494
00495
00496 #include "itkDifferenceImageFilter.txx"
00497
00498 #endif
00499