New image comparison method.

This commit is contained in:
nissim.hadar 2017-11-23 05:58:00 -08:00
parent 346c691f0c
commit 857f2c6880
3 changed files with 20 additions and 73 deletions

View file

@ -10,13 +10,8 @@
#include "ITKImageComparer.h"
#include <itkRGBPixel.h>
#include <itkImage.h>
#include <itkRGBToLuminanceImageFilter.h>
#include <itkTranslationTransform.h>
#include <itkRegularStepGradientDescentOptimizerv4.h>
#include <itkMeanSquaresImageToImageMetricv4.h>
#include <itkImageRegistrationMethodv4.h>
#include <itkTestingComparisonImageFilter.h>
ITKImageComparer::ITKImageComparer() {
// These are smart pointers that do not need to be deleted
@ -39,72 +34,19 @@ float ITKImageComparer::compareImages(QString resultImageFilename, QString expec
resultImageToMonochrome->SetInput(resultImageReader->GetOutput());
expectedImageToMonochrome->SetInput(expectedImageReader->GetOutput());
// Setup registration components
// The transform that will map the fixed image space into the moving image space
using TransformType = itk::TranslationTransform<double, Dimension>;
using DiffType = itk::Testing::ComparisonImageFilter<MonochromeImageType, MonochromeImageType>;
DiffType::Pointer diff = DiffType::New();
// The optimizer explores the parameter space of the transform in search of optimal values of the metric
using OptimizerType = itk::RegularStepGradientDescentOptimizerv4<double>;
diff->SetTestInput(resultImageToMonochrome->GetOutput());
diff->SetValidInput(expectedImageToMonochrome->GetOutput());
// The metric will compare how well the two images match each other
using MetricType = itk::MeanSquaresImageToImageMetricv4<MonochromeImageType, MonochromeImageType>;
const double INTENSITY_TOLERANCE = 0.01;
diff->SetDifferenceThreshold(INTENSITY_TOLERANCE);
//The registration method type is instantiated using the types of the fixed and moving images as well
// as the output transform type.This class is responsible for interconnecting the components
using RegistrationType = itk::ImageRegistrationMethodv4<MonochromeImageType, MonochromeImageType, TransformType>;
const double RADIUS_TOLERANCE = 2.0;
diff->SetToleranceRadius(RADIUS_TOLERANCE);
// Create registration components (smart pointers, so no need to delete)
MetricType::Pointer metric = MetricType::New();
OptimizerType::Pointer optimizer = OptimizerType::New();
RegistrationType::Pointer registration = RegistrationType::New();
diff->UpdateLargestPossibleRegion();
// The comparison metric needs an interpreter.
// The same interpolator is used for both images
using LinearInterpolatorType = itk::LinearInterpolateImageFunction<MonochromeImageType, double>;
LinearInterpolatorType::Pointer interpolator = LinearInterpolatorType::New();
metric->SetFixedInterpolator(interpolator);
metric->SetMovingInterpolator(interpolator);
// Connect components
registration->SetMetric(metric);
registration->SetOptimizer(optimizer);
registration->SetFixedImage(resultImageToMonochrome->GetOutput());
registration->SetMovingImage(expectedImageToMonochrome->GetOutput());
// Initialization
TransformType::Pointer movingInitialTransform = TransformType::New();
TransformType::ParametersType initialParameters(movingInitialTransform->GetNumberOfParameters());
initialParameters[0] = 0.0; // Initial offset in mm along X
initialParameters[1] = 0.0; // Initial offset in mm along Y
movingInitialTransform->SetParameters(initialParameters);
registration->SetMovingInitialTransform(movingInitialTransform);
// Set optimizer parameters
optimizer->SetLearningRate(4);
optimizer->SetMinimumStepLength(0.001);
optimizer->SetRelaxationFactor(0.5);
optimizer->SetNumberOfIterations(200);
// Define registration criteria
const unsigned int numberOfLevels = 1;
RegistrationType::ShrinkFactorsArrayType shrinkFactorsPerLevel;
shrinkFactorsPerLevel.SetSize(1);
shrinkFactorsPerLevel[0] = 1;
RegistrationType::SmoothingSigmasArrayType smoothingSigmasPerLevel;
smoothingSigmasPerLevel.SetSize(1);
smoothingSigmasPerLevel[0] = 0;
registration->SetNumberOfLevels(numberOfLevels);
registration->SetSmoothingSigmasPerLevel(smoothingSigmasPerLevel);
registration->SetShrinkFactorsPerLevel(shrinkFactorsPerLevel);
// Activate the registration project
try
{
registration->Update();
return 0.0;
} catch (itk::ExceptionObject & err) {
return EXIT_FAILURE;
}
return (float)diff->GetNumberOfPixelsWithDifferences();
}

View file

@ -62,7 +62,8 @@ void Test::evaluateTests() {
messageBox.critical(0,
"Test failed",
"Found " + QString::number(resultImages.length()) + " images in directory" +
"\nExpected to find " + QString::number(expectedImages.length()) + " images");
"\nExpected to find " + QString::number(expectedImages.length()) + " images"
);
exit(-1);
}
@ -138,11 +139,13 @@ void Test::createRecursiveScript() {
QFileInfo fileInfo(testPathname);
if (fileInfo.exists()) {
// Current folder contains a test
textStream << "Script.include(\"" << testPathname << "/" << " ? raw = true\")" << endl;
textStream << "Script.include(\"" << testPathname + "\")" << endl;
}
}
allTestsFilename.close();
messageBox.information(0, "Success", "Script has been created");
}
void Test::createTest() {
@ -166,6 +169,8 @@ void Test::createTest() {
++i;
}
}
messageBox.information(0, "Success", "Test images have been created");
}
void Test::createListOfAllJPEGimagesInDirectory() {

View file

@ -21,7 +21,7 @@ public:
_actualImageFilename = actualImageFilename;
}
float _error;
double _error;
QString _pathname;
QString _expectedImageFilename;
QString _actualImageFilename;