Skip to content

Commit

Permalink
ENH: Add ElastixFilter unit tests UpdateSerially and UpdateInParallel
Browse files Browse the repository at this point in the history
Originally based on a code snippet by Konstantinos Ntatsis at pull request #389 ("ENH: Make ElastixMain database creation + loading components thread safe"):
#389 (comment)
  • Loading branch information
N-Dekker committed Feb 5, 2021
1 parent 0c84c5b commit 0e0fd13
Showing 1 changed file with 123 additions and 0 deletions.
123 changes: 123 additions & 0 deletions Core/Main/GTesting/ElastixFilterGTest.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,117 @@
#include <utility> // For pair


namespace
{
template <typename TImage>
std::vector<std::string>
GetTransformParameters(const elx::ElastixFilter<TImage, TImage> & filter)
{
const auto transformParameterObject = filter.GetTransformParameterObject();

if (transformParameterObject != nullptr)
{
const auto & transformParameterMaps = transformParameterObject->GetParameterMap();

if (transformParameterMaps.size() == 1)
{
const auto & transformParameterMap = transformParameterMaps.front();
const auto found = transformParameterMap.find("TransformParameters");

if (found != transformParameterMap.cend())
{
return found->second;
}
}
}
return {};
}


void
UpdateFiltersInForLoop(const bool inParallel)
{
constexpr auto ImageDimension = 2;
using ImageType = itk::Image<float, ImageDimension>;
using SizeType = itk::Size<ImageDimension>;

const auto imageSizeValue = 8;
const itk::ImageRegion<ImageDimension> imageRegion{ itk::Index<ImageDimension>::Filled(imageSizeValue / 2),
SizeType::Filled(2) };

const auto numberOfImages = 10;
ImageType::Pointer images[numberOfImages];
std::vector<std::string> transformParameters[numberOfImages - 1];

const auto parameterObject = elx::ParameterObject::New();
parameterObject->SetParameterMap(
elx::ParameterObject::ParameterMapType{ // Parameters in alphabetic order:
{ "ImageSampler", { "Full" } },
{ "MaximumNumberOfIterations", { "2" } },
{ "Metric", { "AdvancedNormalizedCorrelation" } },
{ "Optimizer", { "AdaptiveStochasticGradientDescent" } },
{ "Transform", { "TranslationTransform" } },
{ "WriteFinalTransformParameters", { "false" } } });
for (auto & image : images)
{
image = ImageType::New();
image->SetRegions(SizeType::Filled(imageSizeValue));
image->Allocate(true);

const itk::Experimental::ImageRegionRange<ImageType> imageRegionRange{ *image, imageRegion };
std::fill(std::begin(imageRegionRange), std::end(imageRegionRange), 1.0f);
}

itk::SmartPointer<elx::ElastixFilter<ImageType, ImageType>> filters[numberOfImages - 1];
std::generate_n(filters, numberOfImages - 1, [] { return elx::ElastixFilter<ImageType, ImageType>::New(); });

for (auto i = 0; i < (numberOfImages - 1); ++i)
{
const auto & filter = filters[i];
filter->LogToConsoleOff();
filter->LogToFileOff();
filter->SetFixedImage(images[i]);
filter->SetMovingImage(images[i + std::size_t{ 1 }]);
filter->SetParameterObject(parameterObject);
}

if (inParallel)
{
// Note: The OpenMP implementation of GCC (including GCC 5.5 and GCC 10.2)
// does not seem to support value-initialization of a for-loop index by
// empty pair of braces, as in `for (int i{}; i < n; ++i)`.
#pragma omp parallel for
for (auto i = 0; i < (numberOfImages - 1); ++i)
{
const auto & filter = filters[i];
filter->Update();
transformParameters[i] = GetTransformParameters(*filter);
}
}
else
{
for (auto i = 0; i < (numberOfImages - 1); ++i)
{
const auto & filter = filters[i];
filter->Update();
transformParameters[i] = GetTransformParameters(*filter);
}
}

// Test the resulting TransformParameters after the parallel for loop.
for (std::size_t i{}; i < (numberOfImages - 1); ++i)
{
EXPECT_EQ(transformParameters[i].size(), ImageDimension);

for (const auto & transformParameter : transformParameters[i])
{
EXPECT_EQ(transformParameter, "0");
}
}
}

} // namespace

// Tests registering two small (5x6) binary images, which are translated with respect to each other.
GTEST_TEST(ElastixFilter, Translation)
{
Expand Down Expand Up @@ -108,3 +219,15 @@ GTEST_TEST(ElastixFilter, Translation)
EXPECT_EQ(std::round(std::stod(transformParameters[i])), translationOffset[i]);
}
}


GTEST_TEST(ElastixFilter, UpdateSerially)
{
UpdateFiltersInForLoop(false);
}


GTEST_TEST(ElastixFilter, UpdateInParallel)
{
UpdateFiltersInForLoop(true);
}

0 comments on commit 0e0fd13

Please sign in to comment.