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