00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #ifndef __itkTestMainDTI_h
00017 #define __itkTestMainDTI_h
00018
00019
00020
00021
00022
00023
00024 #include "itkWin32Header.h"
00025 #include <map>
00026 #include <string>
00027 #include <iostream>
00028 #include <fstream>
00029 #include "itkNumericTraits.h"
00030 #include "itkMultiThreader.h"
00031 #include "itkImage.h"
00032 #include "itkImageFileReader.h"
00033 #include "itkImageFileWriter.h"
00034 #include "itkImageRegionConstIterator.h"
00035 #include "itkSubtractImageFilter.h"
00036 #include "itkRescaleIntensityImageFilter.h"
00037 #include "itkExtractImageFilter.h"
00038 #include "itkDifferenceImageFilter.h"
00039 #include "itkDifferenceDiffusionTensor3DImageFilter.h"
00040 #include "itkDiffusionTensor3D.h"
00041 #include "itkImageRegion.h"
00042 #include "itksys/SystemTools.hxx"
00043 #include <itkTensorFractionalAnisotropyImageFilter.h>
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 *testImageFilename,
00055 const char *baselineImageFilename,
00056 int reportErrors,
00057 double intensityTolerance = 2.0,
00058 unsigned int numberOfPixelsTolerance = 0,
00059 unsigned int radiusTolerance = 0);
00060
00061 std::map<std::string,int> RegressionTestBaselines (char *);
00062
00063 void RegisterTests();
00064 void PrintAvailableTests()
00065 {
00066 std::cout << "Available tests:\n";
00067 std::map<std::string, MainFuncPointer>::iterator j = StringToTestFunctionMap.begin();
00068 int i = 0;
00069 while(j != StringToTestFunctionMap.end())
00070 {
00071 std::cout << i << ". " << j->first << "\n";
00072 ++i;
00073 ++j;
00074 }
00075 }
00076
00077 int main(int ac, char* av[] )
00078 {
00079 double intensityTolerance = 2.0;
00080 unsigned int numberOfPixelsTolerance = 0;
00081 unsigned int radiusTolerance = 0;
00082
00083 typedef std::pair< char *, char *> ComparePairType;
00084 std::vector< ComparePairType > compareList;
00085
00086 RegisterTests();
00087 std::string testToRun;
00088 if(ac < 2)
00089 {
00090 PrintAvailableTests();
00091 std::cout << "To run a test, enter the test number: ";
00092 int testNum = 0;
00093 std::cin >> testNum;
00094 std::map<std::string, MainFuncPointer>::iterator j = StringToTestFunctionMap.begin();
00095 int i = 0;
00096 while(j != StringToTestFunctionMap.end() && i < testNum)
00097 {
00098 ++i;
00099 ++j;
00100 }
00101 if(j == StringToTestFunctionMap.end())
00102 {
00103 std::cerr << testNum << " is an invalid test number\n";
00104 return -1;
00105 }
00106 testToRun = j->first;
00107 }
00108 else
00109 {
00110 while( ac > 0 && testToRun.empty() )
00111 {
00112 if (strcmp(av[1], "--with-threads") == 0)
00113 {
00114 int numThreads = atoi(av[2]);
00115 itk::MultiThreader::SetGlobalDefaultNumberOfThreads(numThreads);
00116 av += 2;
00117 ac -= 2;
00118 }
00119 else if (strcmp(av[1], "--without-threads") == 0)
00120 {
00121 itk::MultiThreader::SetGlobalDefaultNumberOfThreads(1);
00122 av += 1;
00123 ac -= 1;
00124 }
00125 else if (ac > 3 && strcmp(av[1], "--compare") == 0)
00126 {
00127 compareList.push_back( ComparePairType( av[2], av[3] ) );
00128 av += 3;
00129 ac -= 3;
00130 }
00131 else if (ac > 2 && strcmp(av[1], "--compareNumberOfPixelsTolerance") == 0)
00132 {
00133 numberOfPixelsTolerance = atoi( av[2] );
00134 av += 2;
00135 ac -= 2;
00136 }
00137 else if (ac > 2 && strcmp(av[1], "--compareRadiusTolerance") == 0)
00138 {
00139 radiusTolerance = atoi( av[2] );
00140 av += 2;
00141 ac -= 2;
00142 }
00143 else if (ac > 2 && strcmp(av[1], "--compareIntensityTolerance") == 0)
00144 {
00145 intensityTolerance = atof( av[2] );
00146 av += 2;
00147 ac -= 2;
00148 }
00149 else
00150 {
00151 testToRun = av[1];
00152 }
00153 }
00154 }
00155 std::map<std::string, MainFuncPointer>::iterator j = StringToTestFunctionMap.find(testToRun);
00156 if(j != StringToTestFunctionMap.end())
00157 {
00158 MainFuncPointer f = j->second;
00159 int result;
00160 try
00161 {
00162
00163 result = (*f)(ac-1, av+1);
00164
00165 for( int i=0; i<static_cast<int>(compareList.size()); i++)
00166 {
00167 char * baselineFilename = compareList[i].first;
00168 char * testFilename = compareList[i].second;
00169 std::map<std::string,int> baselines = RegressionTestBaselines(baselineFilename);
00170 std::map<std::string,int>::iterator baseline = baselines.begin();
00171 std::string bestBaseline;
00172 int bestBaselineStatus = itk::NumericTraits<int>::max();
00173 while (baseline != baselines.end())
00174 {
00175 baseline->second = RegressionTestImage(testFilename,
00176 (baseline->first).c_str(),
00177 0,
00178 intensityTolerance,
00179 numberOfPixelsTolerance,
00180 radiusTolerance );
00181 if (baseline->second < bestBaselineStatus)
00182 {
00183 bestBaseline = baseline->first;
00184 bestBaselineStatus = baseline->second;
00185 }
00186 if (baseline->second == 0)
00187 {
00188 break;
00189 }
00190 ++baseline;
00191 }
00192
00193 if (bestBaselineStatus)
00194 {
00195 RegressionTestImage(testFilename,
00196 bestBaseline.c_str(),
00197 1,
00198 intensityTolerance,
00199 numberOfPixelsTolerance,
00200 radiusTolerance );
00201 }
00202
00203
00204 std::cout << "<DartMeasurement name=\"BaselineImageName\" type=\"text/string\">";
00205 std::cout << itksys::SystemTools::GetFilenameName(bestBaseline);
00206 std::cout << "</DartMeasurement>" << std::endl;
00207
00208 result += bestBaselineStatus;
00209 }
00210 }
00211 catch(const itk::ExceptionObject& e)
00212 {
00213 std::cerr << "ITK test driver caught an ITK exception:\n";
00214 e.Print(std::cerr);
00215 result = -1;
00216 }
00217 catch(const std::exception& e)
00218 {
00219 std::cerr << "ITK test driver caught an exception:\n";
00220 std::cerr << e.what() << "\n";
00221 result = -1;
00222 }
00223 catch(...)
00224 {
00225 std::cerr << "ITK test driver caught an unknown exception!!!\n";
00226 result = -1;
00227 }
00228 return result;
00229 }
00230 PrintAvailableTests();
00231 std::cerr << "Failed: " << testToRun << ": No test registered with name " << testToRun << "\n";
00232 return -1;
00233 }
00234
00235
00236
00237
00238
00239
00240
00241 void GetImageType( const char* fileName ,
00242 itk::ImageIOBase::IOPixelType &pixelType ,
00243 itk::ImageIOBase::IOComponentType &componentType )
00244 {
00245 typedef itk::Image< unsigned char , 3 > ImageType ;
00246 itk::ImageFileReader< ImageType >::Pointer imageReader =
00247 itk::ImageFileReader< ImageType >::New();
00248 imageReader->SetFileName( fileName ) ;
00249 imageReader->UpdateOutputInformation() ;
00250 pixelType = imageReader->GetImageIO()->GetPixelType() ;
00251 componentType = imageReader->GetImageIO()->GetComponentType() ;
00252 }
00253
00254 template< class ImageType >
00255 int ReadImages( const char* baselineImageFilename ,
00256 const char* testImageFilename ,
00257 typename ImageType::Pointer &baselineImage ,
00258 typename ImageType::Pointer &testImage
00259 )
00260 {
00261 typedef itk::ImageFileReader< ImageType > ReaderType ;
00262
00263 typename ReaderType::Pointer baselineReader = ReaderType::New() ;
00264 baselineReader->SetFileName( baselineImageFilename ) ;
00265 try
00266 {
00267 baselineReader->UpdateLargestPossibleRegion() ;
00268 }
00269 catch (itk::ExceptionObject& e)
00270 {
00271 std::cerr << "Exception detected while reading " << baselineImageFilename << " : " << e.GetDescription();
00272 return 1000;
00273 }
00274
00275
00276 typename ReaderType::Pointer testReader = ReaderType::New() ;
00277 testReader->SetFileName( testImageFilename ) ;
00278 try
00279 {
00280 testReader->UpdateLargestPossibleRegion() ;
00281 }
00282 catch (itk::ExceptionObject& e)
00283 {
00284 std::cerr << "Exception detected while reading " << testImageFilename << " : " << e.GetDescription() << std::endl;
00285 return 1000;
00286 }
00287
00288 typename ImageType::SizeType baselineSize;
00289 baselineSize = baselineReader->GetOutput()->GetLargestPossibleRegion().GetSize();
00290 typename ImageType::SizeType testSize;
00291 testSize = testReader->GetOutput()->GetLargestPossibleRegion().GetSize();
00292
00293 if (baselineSize != testSize)
00294 {
00295 std::cerr << "The size of the Baseline image and Test image do not match!" << std::endl;
00296 std::cerr << "Baseline image: " << baselineImageFilename
00297 << " has size " << baselineSize << std::endl;
00298 std::cerr << "Test image: " << testImageFilename
00299 << " has size " << testSize << std::endl;
00300 return 1;
00301 }
00302 baselineImage = baselineReader->GetOutput() ;
00303 testImage = testReader->GetOutput() ;
00304 return 0 ;
00305 }
00306
00307 int RegressionTestImage (const char *testImageFilename,
00308 const char *baselineImageFilename,
00309 int reportErrors,
00310 double intensityTolerance,
00311 unsigned int numberOfPixelsTolerance,
00312 unsigned int radiusTolerance )
00313 {
00314
00315 typedef itk::Image<double,ITK_TEST_DIMENSION_MAX> ImageType;
00316 typedef itk::Image<itk::DiffusionTensor3D<double>,ITK_TEST_DIMENSION_MAX> DiffusionImageType;
00317 typedef itk::Image<unsigned char,ITK_TEST_DIMENSION_MAX> OutputType;
00318 typedef itk::Image<unsigned char,2> DiffOutputType;
00319
00320
00321
00322 itk::ImageIOBase::IOPixelType pixelTypeBaseline ;
00323 itk::ImageIOBase::IOComponentType componentTypeBaseline ;
00324 GetImageType( baselineImageFilename , pixelTypeBaseline , componentTypeBaseline ) ;
00325 itk::ImageIOBase::IOPixelType pixelTypeTestImage ;
00326 itk::ImageIOBase::IOComponentType componentTypeTestImage ;
00327 GetImageType( testImageFilename , pixelTypeTestImage , componentTypeTestImage ) ;
00328 bool diffusion = false ;
00329
00330 if( ( pixelTypeBaseline == itk::ImageIOBase::SYMMETRICSECONDRANKTENSOR
00331 || pixelTypeBaseline == itk::ImageIOBase::DIFFUSIONTENSOR3D
00332 )
00333 && ( pixelTypeTestImage == itk::ImageIOBase::SYMMETRICSECONDRANKTENSOR
00334 || pixelTypeTestImage == itk::ImageIOBase::DIFFUSIONTENSOR3D
00335 )
00336 )
00337 {
00338 diffusion = true ;
00339 }
00340 ImageType::Pointer baselineImage ;
00341 ImageType::Pointer testImage ;
00342 DiffusionImageType::Pointer diffusionBaselineImage ;
00343 DiffusionImageType::Pointer diffusionTestImage ;
00344 unsigned long status = 0;
00345 typedef itk::DifferenceImageFilter<ImageType,ImageType> DiffType;
00346 DiffType::Pointer diff ;
00347 typedef itk::DifferenceDiffusionTensor3DImageFilter<DiffusionImageType,ImageType> DiffusionDiffType;
00348 DiffusionDiffType::Pointer diffusiondiff ;
00349 int returnValue ;
00350
00351 if( !diffusion )
00352 {
00353 returnValue = ReadImages< ImageType >( baselineImageFilename ,
00354 testImageFilename ,
00355 baselineImage ,
00356 testImage
00357 ) ;
00358 if( returnValue )
00359 {
00360 return returnValue ;
00361 }
00362
00363 diff = DiffType::New();
00364 diff->SetValidInput( baselineImage ) ;
00365 diff->SetTestInput( testImage ) ;
00366 diff->SetDifferenceThreshold( intensityTolerance );
00367 diff->SetToleranceRadius( radiusTolerance );
00368 diff->UpdateLargestPossibleRegion();
00369 status = diff->GetNumberOfPixelsWithDifferences();
00370
00371 }
00372 else
00373 {
00374 returnValue = ReadImages< DiffusionImageType >( baselineImageFilename ,
00375 testImageFilename ,
00376 diffusionBaselineImage ,
00377 diffusionTestImage
00378 ) ;
00379 if( returnValue )
00380 {
00381 return returnValue ;
00382 }
00383
00384 diffusiondiff = DiffusionDiffType::New();
00385 diffusiondiff->SetValidInput( diffusionBaselineImage ) ;
00386 diffusiondiff->SetTestInput(diffusionTestImage ) ;
00387 diffusiondiff->SetDifferenceThreshold( intensityTolerance );
00388 diffusiondiff->SetToleranceRadius( radiusTolerance );
00389 diffusiondiff->UpdateLargestPossibleRegion();
00390 status = diffusiondiff->GetNumberOfPixelsWithDifferences();
00391 }
00392
00393
00394 if ( (status > numberOfPixelsTolerance) && reportErrors )
00395 {
00396 typedef itk::RescaleIntensityImageFilter<ImageType,OutputType> RescaleType;
00397 typedef itk::ExtractImageFilter<OutputType,DiffOutputType> ExtractType;
00398 typedef itk::ImageFileWriter<DiffOutputType> WriterType;
00399 typedef itk::ImageRegion<ITK_TEST_DIMENSION_MAX> RegionType;
00400 OutputType::SizeType size; size.Fill(0);
00401
00402 RescaleType::Pointer rescale = RescaleType::New();
00403 rescale->SetOutputMinimum(itk::NumericTraits<unsigned char>::NonpositiveMin());
00404 rescale->SetOutputMaximum(itk::NumericTraits<unsigned char>::max());
00405 if( !diffusion )
00406 {
00407 rescale->SetInput(diff->GetOutput());
00408 }
00409 else
00410 {
00411 rescale->SetInput(diffusiondiff->GetOutput());
00412 }
00413 rescale->UpdateLargestPossibleRegion();
00414 size = rescale->GetOutput()->GetLargestPossibleRegion().GetSize();
00415
00416
00417
00418 OutputType::IndexType index; index.Fill(0);
00419 for (unsigned int i = 2; i < ITK_TEST_DIMENSION_MAX; i++)
00420 {
00421 index[i]=size[i]/2;
00422 size[i] = 0;
00423 }
00424
00425 RegionType region;
00426 region.SetIndex(index);
00427
00428 region.SetSize(size);
00429
00430 ExtractType::Pointer extract = ExtractType::New();
00431 extract->SetInput(rescale->GetOutput());
00432 extract->SetExtractionRegion(region);
00433
00434 WriterType::Pointer writer = WriterType::New();
00435 writer->SetInput(extract->GetOutput());
00436
00437 std::cout << "<DartMeasurement name=\"ImageError\" type=\"numeric/double\">";
00438 std::cout << status;
00439 std::cout << "</DartMeasurement>" << std::endl;
00440
00441 ::itk::OStringStream diffName;
00442 diffName << testImageFilename << ".diff.png";
00443 try
00444 {
00445 if( !diffusion )
00446 {
00447 rescale->SetInput(diff->GetOutput());
00448 }
00449 else
00450 {
00451 rescale->SetInput(diffusiondiff->GetOutput());
00452 }
00453 rescale->Update();
00454 }
00455 catch(const std::exception& e)
00456 {
00457 std::cerr << "Error during rescale of " << diffName.str() << std::endl;
00458 std::cerr << e.what() << "\n";
00459 }
00460 catch (...)
00461 {
00462 std::cerr << "Error during rescale of " << diffName.str() << std::endl;
00463 }
00464 writer->SetFileName(diffName.str().c_str());
00465 try
00466 {
00467 writer->Update();
00468 }
00469 catch(const std::exception& e)
00470 {
00471 std::cerr << "Error during write of " << diffName.str() << std::endl;
00472 std::cerr << e.what() << "\n";
00473 }
00474 catch (...)
00475 {
00476 std::cerr << "Error during write of " << diffName.str() << std::endl;
00477 }
00478
00479 std::cout << "<DartMeasurementFile name=\"DifferenceImage\" type=\"image/png\">";
00480 std::cout << diffName.str();
00481 std::cout << "</DartMeasurementFile>" << std::endl;
00482
00483 ImageType::Pointer testFA ;
00484 ImageType::Pointer baselineFA ;
00485
00486
00487 if( diffusion )
00488 {
00489 typedef itk::TensorFractionalAnisotropyImageFilter< DiffusionImageType , ImageType > FAFilterType ;
00490 FAFilterType::Pointer testFAfilter = FAFilterType::New() ;
00491 diffusionTestImage->SetRequestedRegion( region ) ;
00492 testFAfilter->SetInput( diffusionTestImage ) ;
00493 testFAfilter->Update() ;
00494 testFA = testFAfilter->GetOutput() ;
00495
00496 FAFilterType::Pointer baselineFAfilter = FAFilterType::New() ;
00497 diffusionBaselineImage->SetRequestedRegion( region ) ;
00498 baselineFAfilter->SetInput( diffusionBaselineImage ) ;
00499 baselineFAfilter->Update() ;
00500 baselineFA = baselineFAfilter->GetOutput() ;
00501 }
00502
00503 ::itk::OStringStream baseName;
00504 if( !diffusion )
00505 {
00506 baseName << testImageFilename << ".base.png";
00507 }
00508 else
00509 {
00510 baseName << testImageFilename << ".FA.base.png";
00511 }
00512 try
00513 {
00514 if( !diffusion )
00515 {
00516 rescale->SetInput( baselineImage ) ;
00517 }
00518 else
00519 {
00520 rescale->SetInput( baselineFA ) ;
00521 }
00522 rescale->Update();
00523 }
00524 catch(const std::exception& e)
00525 {
00526 std::cerr << "Error during rescale of " << baseName.str() << std::endl;
00527 std::cerr << e.what() << "\n";
00528 }
00529 catch (...)
00530 {
00531 std::cerr << "Error during rescale of " << baseName.str() << std::endl;
00532 }
00533 try
00534 {
00535 writer->SetFileName(baseName.str().c_str());
00536 writer->Update();
00537 }
00538 catch(const std::exception& e)
00539 {
00540 std::cerr << "Error during write of " << baseName.str() << std::endl;
00541 std::cerr << e.what() << "\n";
00542 }
00543 catch (...)
00544 {
00545 std::cerr << "Error during write of " << baseName.str() << std::endl;
00546 }
00547
00548 std::cout << "<DartMeasurementFile name=\"BaselineImage\" type=\"image/png\">";
00549 std::cout << baseName.str();
00550 std::cout << "</DartMeasurementFile>" << std::endl;
00551
00552 ::itk::OStringStream testName;
00553 if( !diffusion )
00554 {
00555 testName << testImageFilename << ".test.png";
00556 }
00557 else
00558 {
00559 testName << testImageFilename << ".FA.test.png";
00560 }
00561 try
00562 {
00563 if( !diffusion )
00564 {
00565 rescale->SetInput( testImage ) ;
00566 }
00567 else
00568 {
00569 rescale->SetInput(testFA);
00570 }
00571 rescale->Update();
00572 }
00573 catch(const std::exception& e)
00574 {
00575 std::cerr << "Error during rescale of " << testName.str() << std::endl;
00576 std::cerr << e.what() << "\n";
00577 }
00578 catch (...)
00579 {
00580 std::cerr << "Error during rescale of " << testName.str() << std::endl;
00581 }
00582 try
00583 {
00584 writer->SetFileName(testName.str().c_str());
00585 writer->Update();
00586 }
00587 catch(const std::exception& e)
00588 {
00589 std::cerr << "Error during write of " << testName.str() << std::endl;
00590 std::cerr << e.what() << "\n";
00591 }
00592 catch (...)
00593 {
00594 std::cerr << "Error during write of " << testName.str() << std::endl;
00595 }
00596
00597 std::cout << "<DartMeasurementFile name=\"TestImage\" type=\"image/png\">";
00598 std::cout << testName.str();
00599 std::cout << "</DartMeasurementFile>" << std::endl;
00600 }
00601
00602 return (status > numberOfPixelsTolerance) ? 1 : 0;
00603 }
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613 std::map<std::string,int> RegressionTestBaselines (char *baselineFilename)
00614 {
00615 std::map<std::string,int> baselines;
00616 baselines[std::string(baselineFilename)] = 0;
00617
00618 std::string originalBaseline(baselineFilename);
00619
00620 int x = 0;
00621 std::string::size_type suffixPos = originalBaseline.rfind(".");
00622 std::string suffix;
00623 if (suffixPos != std::string::npos)
00624 {
00625 suffix = originalBaseline.substr(suffixPos,originalBaseline.length());
00626 originalBaseline.erase(suffixPos,originalBaseline.length());
00627 }
00628 while (++x)
00629 {
00630 ::itk::OStringStream filename;
00631 filename << originalBaseline << "." << x << suffix;
00632 std::ifstream filestream(filename.str().c_str());
00633 if (!filestream)
00634 {
00635 break;
00636 }
00637 baselines[filename.str()] = 0;
00638 filestream.close();
00639 }
00640 return baselines;
00641 }
00642
00643
00644 #include "itkDifferenceImageFilter.txx"
00645 #include "itkDifferenceDiffusionTensor3DImageFilter.txx"
00646
00647 #endif