BASIS  version 1.2.3 (revision 2104)
testdriver-itk.hxx
Go to the documentation of this file.
00001 /**
00002  * @file  testdriver-itk.hxx
00003  * @brief ITK-based implementation of test driver.
00004  *
00005  * This implementation of the test driver utilizes the ITK.
00006  *
00007  * This file is in parts a modified version of the itkTestDriverInclude.h
00008  * file which is part of the TestKernel module of the ITK 4 project and
00009  * in other parts contains code from the ImageCompareCommand.cxx file
00010  * which is part of the ITK 3.20 release.
00011  *
00012  * Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen<br />
00013  * Copyright (c) Insight Software Consortium.<br />
00014  * Copyright (c) 2011 University of Pennsylvania.
00015  *
00016  * Portions of this file are subject to the VTK Toolkit Version 3 copyright.
00017  *
00018  * For complete copyright, license and disclaimer of warranty information
00019  * please refer to the COPYRIGHT file.
00020  *
00021  * Contact: SBIA Group <sbia-software at uphs.upenn.edu>
00022  */
00023 
00024  /*=========================================================================
00025  *
00026  *  Copyright Insight Software Consortium
00027  *
00028  *  Licensed under the Apache License, Version 2.0 (the "License");
00029  *  you may not use this file except in compliance with the License.
00030  *  You may obtain a copy of the License at
00031  *
00032  *         http://www.apache.org/licenses/LICENSE-2.0.txt
00033  *
00034  *  Unless required by applicable law or agreed to in writing, software
00035  *  distributed under the License is distributed on an "AS IS" BASIS,
00036  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00037  *  See the License for the specific language governing permissions and
00038  *  limitations under the License.
00039  *
00040  *=========================================================================*/
00041 /*=========================================================================
00042  *
00043  *  Portions of this file are subject to the VTK Toolkit Version 3 copyright.
00044  *
00045  *  Copyright (c) Ken Martin, Will Schroeder, Bill Lorensen
00046  *
00047  *  For complete copyright, license and disclaimer of warranty information
00048  *  please refer to the NOTICE file at the top of the ITK source tree.
00049  *
00050  *=========================================================================*/
00051 
00052 #pragma once
00053 #ifndef _SBIA_BASIS_TESTDRIVER_ITK_HXX
00054 #define _SBIA_BASIS_TESTDRIVER_ITK_HXX
00055 
00056 
00057 // avoid dependency on all IO libraries which are commonly used
00058 // has to be undefined before including the reader or writer
00059 #ifdef ITK_IO_FACTORY_REGISTER_MANAGER
00060 #  undef ITK_IO_FACTORY_REGISTER_MANAGER
00061 #endif
00062 
00063 
00064 #if ITK_VERSION_MAJOR >= 4
00065 // Disable warning: 'std::copy': Function call with parameters that may be unsafe
00066 //                  - this call relies on the caller to check that the passed
00067 //                  values are correct.
00068 #  pragma warning (disable: 4996)
00069 #  include <itkTestDriverInclude.h>
00070 #else
00071 #  include <itkImage.h>
00072 #  include <itkImageFileReader.h>
00073 #  include <itkImageFileWriter.h>
00074 #  include <itkRescaleIntensityImageFilter.h>
00075 #  include <itkExtractImageFilter.h>
00076 #  include <itkDifferenceImageFilter.h>
00077 #endif
00078 
00079 #include <itkGDCMImageIOFactory.h>
00080 #include <itkMetaImageIOFactory.h>
00081 #include <itkJPEGImageIOFactory.h>
00082 #include <itkPNGImageIOFactory.h>
00083 #include <itkTIFFImageIOFactory.h>
00084 #include <itkBMPImageIOFactory.h>
00085 #include <itkVTKImageIOFactory.h>
00086 #include <itkNrrdImageIOFactory.h>
00087 #include <itkGiplImageIOFactory.h>
00088 #include <itkNiftiImageIOFactory.h>
00089 #include <itkObjectFactoryBase.h>
00090 
00091 
00092 // maximum number of dimensions of test and baseline images
00093 // Note: We cannot redefine the macro used by the ITK 4.
00094 #if ITK_VERSION_MAJOR < 4
00095 #  define ITK_TEST_DIMENSION_MAX BASIS_MAX_TEST_IMAGE_DIMENSION
00096 #endif
00097 
00098 
00099 // ---------------------------------------------------------------------------
00100 void RegisterRequiredFactories()
00101 {
00102     itk::ObjectFactoryBase::RegisterFactory(itk::MetaImageIOFactory::New());
00103     itk::ObjectFactoryBase::RegisterFactory(itk::GDCMImageIOFactory::New());
00104     itk::ObjectFactoryBase::RegisterFactory(itk::JPEGImageIOFactory::New());
00105     itk::ObjectFactoryBase::RegisterFactory(itk::VTKImageIOFactory::New());
00106     itk::ObjectFactoryBase::RegisterFactory(itk::PNGImageIOFactory::New());
00107     itk::ObjectFactoryBase::RegisterFactory(itk::TIFFImageIOFactory::New());
00108     itk::ObjectFactoryBase::RegisterFactory(itk::BMPImageIOFactory::New());
00109     itk::ObjectFactoryBase::RegisterFactory(itk::NrrdImageIOFactory::New());
00110     itk::ObjectFactoryBase::RegisterFactory(itk::GiplImageIOFactory::New());
00111     itk::ObjectFactoryBase::RegisterFactory(itk::NiftiImageIOFactory::New());
00112 }
00113 
00114 
00115 #if ITK_VERSION_MAJOR < 4
00116 
00117 
00118 // ---------------------------------------------------------------------------
00119 // This implementation of the image regression test was copied from the
00120 // Testing/Code/IO/ImageCompareCommand.cxx file of the ITK 3.20 release.
00121 // Then the function has been modified such that first of all the function
00122 // prototype matches the one of the corresponding function of the ITK 4
00123 // TestKernel module and furthermore the generation of the reports is
00124 // identical as well. This includes the extraction of the center slice instead
00125 // of the first slice to generate PNG images for inclusion in the report.
00126 int RegressionTestImage (const char* testImageFilename,
00127                          const char* baselineImageFilename,
00128                          int reportErrors,
00129                          double intensityTolerance,
00130                          unsigned int numberOfPixelsTolerance,
00131                          unsigned int radiusTolerance)
00132 {
00133   // Use the factory mechanism to read the test and baseline files and convert them to double
00134   typedef itk::Image<double,ITK_TEST_DIMENSION_MAX>         ImageType;
00135   typedef itk::Image<unsigned char,ITK_TEST_DIMENSION_MAX>  OutputType;
00136   typedef itk::Image<unsigned char,2>                       DiffOutputType;
00137   typedef itk::ImageFileReader<ImageType>                   ReaderType;
00138 
00139   // Read the baseline file
00140   ReaderType::Pointer baselineReader = ReaderType::New();
00141     baselineReader->SetFileName(baselineImageFilename);
00142   try
00143     {
00144     baselineReader->UpdateLargestPossibleRegion();
00145     }
00146   catch (itk::ExceptionObject& e)
00147     {
00148     std::cerr << "Exception detected while reading " << baselineImageFilename << " : "  << e;
00149     return 1000;
00150     }
00151 
00152   // Read the file generated by the test
00153   ReaderType::Pointer testReader = ReaderType::New();
00154     testReader->SetFileName(testImageFilename);
00155   try
00156     {
00157     testReader->UpdateLargestPossibleRegion();
00158     }
00159   catch (itk::ExceptionObject& e)
00160     {
00161     std::cerr << "Exception detected while reading " << testImageFilename << " : "  << e << std::endl;
00162     return 1000;
00163     }
00164 
00165   // The sizes of the baseline and test image must match
00166   ImageType::SizeType baselineSize;
00167     baselineSize = baselineReader->GetOutput()->GetLargestPossibleRegion().GetSize();
00168   ImageType::SizeType testSize;
00169     testSize = testReader->GetOutput()->GetLargestPossibleRegion().GetSize();
00170   
00171   if (baselineSize != testSize)
00172     {
00173     std::cerr << "The size of the Baseline image and Test image do not match!" << std::endl;
00174     std::cerr << "Baseline image: " << baselineImageFilename
00175               << " has size " << baselineSize << std::endl;
00176     std::cerr << "Test image:     " << testImageFilename
00177               << " has size " << testSize << std::endl;
00178     return 1;
00179     }
00180 
00181   // Now compare the two images
00182   typedef itk::DifferenceImageFilter<ImageType,ImageType> DiffType;
00183   DiffType::Pointer diff = DiffType::New();
00184     diff->SetValidInput(baselineReader->GetOutput());
00185     diff->SetTestInput(testReader->GetOutput());
00186     
00187     diff->SetDifferenceThreshold( intensityTolerance );
00188     diff->SetToleranceRadius( radiusTolerance );
00189 
00190     diff->UpdateLargestPossibleRegion();
00191 
00192   bool differenceFailed = false;
00193   
00194   double averageIntensityDifference = diff->GetTotalDifference();
00195 
00196   unsigned long numberOfPixelsWithDifferences = 
00197                         diff->GetNumberOfPixelsWithDifferences();
00198 
00199   //The measurement errors should be reported for both success and errors
00200   //to facilitate setting tight tolerances of tests.
00201   std::cout << "<DartMeasurement name=\"ImageError\" type=\"numeric/double\">";
00202   std::cout << numberOfPixelsWithDifferences;
00203   std::cout <<  "</DartMeasurement>" << std::endl;
00204 
00205   if( averageIntensityDifference > 0.0 )
00206     {
00207     if( numberOfPixelsWithDifferences > numberOfPixelsTolerance )
00208       {
00209       differenceFailed = true;
00210       }
00211     else
00212       {
00213       differenceFailed = false;
00214       }
00215     }
00216   else
00217     {
00218     differenceFailed = false; 
00219     }
00220   
00221   if (differenceFailed && reportErrors)
00222     {
00223     typedef itk::RescaleIntensityImageFilter<ImageType,OutputType>    RescaleType;
00224     typedef itk::ExtractImageFilter<OutputType,DiffOutputType>        ExtractType;
00225     typedef itk::ImageFileWriter<DiffOutputType>                      WriterType;
00226     typedef itk::ImageRegion<ITK_TEST_DIMENSION_MAX>                  RegionType;
00227 
00228     OutputType::IndexType index; index.Fill(0);
00229     OutputType::SizeType size; size.Fill(0);
00230 
00231     RescaleType::Pointer rescale = RescaleType::New();
00232 
00233     rescale->SetOutputMinimum(itk::NumericTraits<unsigned char>::NonpositiveMin());
00234     rescale->SetOutputMaximum(itk::NumericTraits<unsigned char>::max());
00235     rescale->SetInput(diff->GetOutput());
00236     rescale->UpdateLargestPossibleRegion();
00237 
00238     //Note: This modification has been applied to the ImageCompareCommand
00239     //      implementation of the ITK 3.18 vs. ITK 4.0
00240     //
00241     //Get the center slice of the image,  In 3D, the first slice
00242     //is often a black slice with little debugging information.
00243     size = rescale->GetOutput()->GetLargestPossibleRegion().GetSize();
00244     for (unsigned int i = 2; i < ITK_TEST_DIMENSION_MAX; i++)
00245       {
00246       index[i] = size[i] / 2; //NOTE: Integer Divide used to get approximately
00247                               // the center slice
00248       size[i] = 0;
00249       }
00250 
00251     RegionType region;
00252     region.SetIndex(index);
00253     region.SetSize(size);
00254 
00255     ExtractType::Pointer extract = ExtractType::New();
00256 
00257     extract->SetInput(rescale->GetOutput());
00258     extract->SetExtractionRegion(region);
00259 
00260     WriterType::Pointer writer = WriterType::New();
00261     writer->SetInput(extract->GetOutput());
00262 
00263     itksys_ios::ostringstream diffName;
00264     diffName << testImageFilename << ".diff.png";
00265     try
00266       {
00267       rescale->SetInput(diff->GetOutput());
00268       rescale->Update();
00269       }
00270     catch(const std::exception& e)
00271       {
00272       std::cerr << "Error during rescale of " << diffName.str() << std::endl;
00273       std::cerr << e.what() << "\n";
00274       }
00275     catch (...)
00276       {
00277       std::cerr << "Error during rescale of " << diffName.str() << std::endl;
00278       }
00279     writer->SetFileName(diffName.str().c_str());
00280     try
00281       {
00282       writer->Update();
00283       }
00284     catch(const std::exception& e)
00285       {
00286       std::cerr << "Error during write of " << diffName.str() << std::endl;
00287       std::cerr << e.what() << "\n";
00288       }
00289     catch (...)
00290       {
00291       std::cerr << "Error during write of " << diffName.str() << std::endl;
00292       }
00293 
00294     std::cout << "<DartMeasurementFile name=\"DifferenceImage\" type=\"image/png\">";
00295     std::cout << diffName.str();
00296     std::cout << "</DartMeasurementFile>" << std::endl;
00297 
00298     itksys_ios::ostringstream baseName;
00299     baseName << testImageFilename << ".base.png";
00300     try
00301       {
00302       rescale->SetInput(baselineReader->GetOutput());
00303       rescale->Update();
00304       }
00305     catch(const std::exception& e)
00306       {
00307       std::cerr << "Error during rescale of " << baseName.str() << std::endl;
00308       std::cerr << e.what() << "\n";
00309       }
00310     catch (...)
00311       {
00312       std::cerr << "Error during rescale of " << baseName.str() << std::endl;
00313       }
00314     try
00315       {
00316       writer->SetFileName(baseName.str().c_str());
00317       writer->Update();
00318       }
00319     catch(const std::exception& e)
00320       {
00321       std::cerr << "Error during write of " << baseName.str() << std::endl;
00322       std::cerr << e.what() << "\n";
00323       }
00324     catch (...)
00325       {
00326       std::cerr << "Error during write of " << baseName.str() << std::endl;
00327       }
00328 
00329     std::cout << "<DartMeasurementFile name=\"BaselineImage\" type=\"image/png\">";
00330     std::cout << baseName.str();
00331     std::cout << "</DartMeasurementFile>" << std::endl;
00332 
00333     itksys_ios::ostringstream testName;
00334     testName << testImageFilename << ".test.png";
00335     try
00336       {
00337       rescale->SetInput(testReader->GetOutput());
00338       rescale->Update();
00339       }
00340     catch(const std::exception& e)
00341       {
00342       std::cerr << "Error during rescale of " << testName.str() << std::endl;
00343       std::cerr << e.what() << "\n";
00344       }
00345     catch (...)
00346       {
00347       std::cerr << "Error during rescale of " << testName.str() << std::endl;
00348       }
00349     try
00350       {
00351       writer->SetFileName(testName.str().c_str());
00352       writer->Update();
00353       }
00354     catch(const std::exception& e)
00355       {
00356       std::cerr << "Error during write of " << testName.str() << std::endl;
00357       std::cerr << e.what() << "\n";
00358       }
00359     catch (...)
00360       {
00361       std::cerr << "Error during write of " << testName.str() << std::endl;
00362       }
00363 
00364     std::cout << "<DartMeasurementFile name=\"TestImage\" type=\"image/png\">";
00365     std::cout << testName.str();
00366     std::cout << "</DartMeasurementFile>" << std::endl;
00367 
00368     }
00369   return differenceFailed;
00370 }
00371 
00372 
00373 #endif // ITK_VERSION_MAJOR < 4
00374 
00375 
00376 #endif // _SBIA_BASIS_TESTDRIVER_ITK_HXX