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