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