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