mirror of
https://github.com/JulianGro/overte.git
synced 2025-04-25 14:53:01 +02:00
New image comparison method.
This commit is contained in:
parent
346c691f0c
commit
857f2c6880
3 changed files with 20 additions and 73 deletions
|
@ -10,13 +10,8 @@
|
||||||
|
|
||||||
#include "ITKImageComparer.h"
|
#include "ITKImageComparer.h"
|
||||||
|
|
||||||
#include <itkRGBPixel.h>
|
|
||||||
#include <itkImage.h>
|
|
||||||
#include <itkRGBToLuminanceImageFilter.h>
|
#include <itkRGBToLuminanceImageFilter.h>
|
||||||
#include <itkTranslationTransform.h>
|
#include <itkTestingComparisonImageFilter.h>
|
||||||
#include <itkRegularStepGradientDescentOptimizerv4.h>
|
|
||||||
#include <itkMeanSquaresImageToImageMetricv4.h>
|
|
||||||
#include <itkImageRegistrationMethodv4.h>
|
|
||||||
|
|
||||||
ITKImageComparer::ITKImageComparer() {
|
ITKImageComparer::ITKImageComparer() {
|
||||||
// These are smart pointers that do not need to be deleted
|
// These are smart pointers that do not need to be deleted
|
||||||
|
@ -38,73 +33,20 @@ float ITKImageComparer::compareImages(QString resultImageFilename, QString expec
|
||||||
|
|
||||||
resultImageToMonochrome->SetInput(resultImageReader->GetOutput());
|
resultImageToMonochrome->SetInput(resultImageReader->GetOutput());
|
||||||
expectedImageToMonochrome->SetInput(expectedImageReader->GetOutput());
|
expectedImageToMonochrome->SetInput(expectedImageReader->GetOutput());
|
||||||
|
|
||||||
|
using DiffType = itk::Testing::ComparisonImageFilter<MonochromeImageType, MonochromeImageType>;
|
||||||
|
DiffType::Pointer diff = DiffType::New();
|
||||||
|
|
||||||
// Setup registration components
|
diff->SetTestInput(resultImageToMonochrome->GetOutput());
|
||||||
// The transform that will map the fixed image space into the moving image space
|
diff->SetValidInput(expectedImageToMonochrome->GetOutput());
|
||||||
using TransformType = itk::TranslationTransform<double, Dimension>;
|
|
||||||
|
|
||||||
// The optimizer explores the parameter space of the transform in search of optimal values of the metric
|
const double INTENSITY_TOLERANCE = 0.01;
|
||||||
using OptimizerType = itk::RegularStepGradientDescentOptimizerv4<double>;
|
diff->SetDifferenceThreshold(INTENSITY_TOLERANCE);
|
||||||
|
|
||||||
// The metric will compare how well the two images match each other
|
const double RADIUS_TOLERANCE = 2.0;
|
||||||
using MetricType = itk::MeanSquaresImageToImageMetricv4<MonochromeImageType, MonochromeImageType>;
|
diff->SetToleranceRadius(RADIUS_TOLERANCE);
|
||||||
|
|
||||||
//The registration method type is instantiated using the types of the fixed and moving images as well
|
diff->UpdateLargestPossibleRegion();
|
||||||
// as the output transform type.This class is responsible for interconnecting the components
|
|
||||||
using RegistrationType = itk::ImageRegistrationMethodv4<MonochromeImageType, MonochromeImageType, TransformType>;
|
|
||||||
|
|
||||||
// Create registration components (smart pointers, so no need to delete)
|
return (float)diff->GetNumberOfPixelsWithDifferences();
|
||||||
MetricType::Pointer metric = MetricType::New();
|
|
||||||
OptimizerType::Pointer optimizer = OptimizerType::New();
|
|
||||||
RegistrationType::Pointer registration = RegistrationType::New();
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,7 +62,8 @@ void Test::evaluateTests() {
|
||||||
messageBox.critical(0,
|
messageBox.critical(0,
|
||||||
"Test failed",
|
"Test failed",
|
||||||
"Found " + QString::number(resultImages.length()) + " images in directory" +
|
"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);
|
exit(-1);
|
||||||
}
|
}
|
||||||
|
@ -138,11 +139,13 @@ void Test::createRecursiveScript() {
|
||||||
QFileInfo fileInfo(testPathname);
|
QFileInfo fileInfo(testPathname);
|
||||||
if (fileInfo.exists()) {
|
if (fileInfo.exists()) {
|
||||||
// Current folder contains a test
|
// Current folder contains a test
|
||||||
textStream << "Script.include(\"" << testPathname << "/" << " ? raw = true\")" << endl;
|
textStream << "Script.include(\"" << testPathname + "\")" << endl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
allTestsFilename.close();
|
allTestsFilename.close();
|
||||||
|
|
||||||
|
messageBox.information(0, "Success", "Script has been created");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Test::createTest() {
|
void Test::createTest() {
|
||||||
|
@ -166,6 +169,8 @@ void Test::createTest() {
|
||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
messageBox.information(0, "Success", "Test images have been created");
|
||||||
}
|
}
|
||||||
|
|
||||||
void Test::createListOfAllJPEGimagesInDirectory() {
|
void Test::createListOfAllJPEGimagesInDirectory() {
|
||||||
|
|
|
@ -21,7 +21,7 @@ public:
|
||||||
_actualImageFilename = actualImageFilename;
|
_actualImageFilename = actualImageFilename;
|
||||||
}
|
}
|
||||||
|
|
||||||
float _error;
|
double _error;
|
||||||
QString _pathname;
|
QString _pathname;
|
||||||
QString _expectedImageFilename;
|
QString _expectedImageFilename;
|
||||||
QString _actualImageFilename;
|
QString _actualImageFilename;
|
||||||
|
|
Loading…
Reference in a new issue