Skip to content

Commit

Permalink
ENH: Add SetInitialTransformParameterObject to ElastixRegistrationMethod
Browse files Browse the repository at this point in the history
Internally added `ElastixMain::RunWithInitialTransformParameterMaps`, and extended `elx::TransformBase<TElastix>::BeforeRegistrationBase()` to implement this feature.

Tested by GoogleTest `itkElastixRegistrationMethod.SetInitialTransformParameterObject`.
  • Loading branch information
N-Dekker committed Mar 23, 2023
1 parent b261946 commit 48c6458
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 3 deletions.
19 changes: 18 additions & 1 deletion Core/ComponentBaseClasses/elxTransformBase.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,24 @@ TransformBase<TElastix>::BeforeRegistrationBase()
else
{
std::string fileName = configuration.GetCommandLineArgument("-t0");
if (!fileName.empty())
if (fileName.empty())
{
const ElastixBase & elastixBase = Deref(Superclass::GetElastix());

const auto numberOfConfigurations = elastixBase.GetNumberOfTransformConfigurations();

if ((numberOfConfigurations > 0) && (&configuration != elastixBase.GetTransformConfiguration(0)))
{
const Configuration::ConstPointer previousTransformConfiguration =
elastixBase.GetPreviousTransformConfiguration(configuration);
const Configuration::ConstPointer lastTransformConfiguration =
elastixBase.GetTransformConfiguration(numberOfConfigurations - 1);

this->ReadInitialTransformFromConfiguration(previousTransformConfiguration ? previousTransformConfiguration
: lastTransformConfiguration);
}
}
else
{
if (itksys::SystemTools::FileExists(fileName.c_str()))
{
Expand Down
35 changes: 35 additions & 0 deletions Core/Kernel/elxElastixMain.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,7 @@ ElastixMain::Run()

/** Set some information in the ElastixBase. */
elastixBase.SetConfiguration(MainBase::GetConfiguration());
elastixBase.SetTransformConfigurations(this->m_TransformConfigurations);
elastixBase.SetDBIndex(this->m_DBIndex);

/** Populate the component containers. ImageSampler is not mandatory.
Expand Down Expand Up @@ -207,6 +208,40 @@ ElastixMain::Run()

} // end Run()

int
ElastixMain::RunWithInitialTransformParameterMaps(const ArgumentMapType & argmap,
const ParameterMapType & inputMap,
const std::vector<ParameterMapType> & initialTransformParameterMaps)
{
Configuration & configuration = Deref(MainBase::GetConfiguration());

if (configuration.Initialize(argmap, inputMap) != 0)
{
log::error("ERROR: Something went wrong during initialization of the configuration object.");
}

const auto numberOfTransformParameterMaps = initialTransformParameterMaps.size();
m_TransformConfigurations.clear();
m_TransformConfigurations.resize(numberOfTransformParameterMaps);

for (size_t i = 0; i < numberOfTransformParameterMaps; ++i)
{
/** Initialize the configuration object with the
* command line parameters entered by the user.
*/
const auto configuration = Configuration::New();
int dummy = configuration->Initialize(argmap, initialTransformParameterMaps[i]);
m_TransformConfigurations[i] = configuration;
if (dummy)
{
log::error(std::ostringstream{} << "ERROR: Something went wrong during initialization of configuration object "
<< i << ".");
}
}

return ElastixMain::Run();
}


/**
* ************************** InitDBIndex ***********************
Expand Down
5 changes: 5 additions & 0 deletions Core/Kernel/elxElastixMain.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,11 @@ class ElastixMain : public MainBase
int
Run() override;

int
RunWithInitialTransformParameterMaps(const ArgumentMapType & argmap,
const ParameterMapType & inputMap,
const std::vector<ParameterMapType> & initialTransformParameterMaps);

/** GetTransformParametersMap */
virtual ParameterMapType
GetTransformParametersMap() const;
Expand Down
69 changes: 69 additions & 0 deletions Core/Main/GTesting/itkElastixRegistrationMethodGTest.cxx
Original file line number Diff line number Diff line change
Expand Up @@ -582,6 +582,75 @@ GTEST_TEST(itkElastixRegistrationMethod, InitialTransformParameterFile)
}


GTEST_TEST(itkElastixRegistrationMethod, SetInitialTransformParameterObject)
{
using PixelType = float;
constexpr auto ImageDimension = 2U;
using ImageType = itk::Image<PixelType, ImageDimension>;
using SizeType = itk::Size<ImageDimension>;
using IndexType = itk::Index<ImageDimension>;
using OffsetType = itk::Offset<ImageDimension>;

const OffsetType initialTranslation{ { 1, -2 } };
const auto regionSize = SizeType::Filled(2);
const SizeType imageSize{ { 5, 6 } };
const IndexType fixedImageRegionIndex{ { 1, 3 } };

const auto fixedImage = CreateImage<PixelType>(imageSize);
FillImageRegion(*fixedImage, fixedImageRegionIndex, regionSize);

const auto movingImage = CreateImage<PixelType>(imageSize);

elx::DefaultConstruct<elx::ParameterObject> transformParameterObject{};

DefaultConstructibleElastixRegistrationMethod<ImageType, ImageType> registration;

registration.SetFixedImage(fixedImage);
registration.SetInitialTransformParameterObject(&transformParameterObject);
registration.SetParameterObject(CreateParameterObject({ // Parameters in alphabetic order:
{ "ImageSampler", "Full" },
{ "MaximumNumberOfIterations", "2" },
{ "Metric", "AdvancedNormalizedCorrelation" },
{ "Optimizer", "AdaptiveStochasticGradientDescent" },
{ "Transform", "TranslationTransform" } }));

const auto toOffset = [](const IndexType & index) { return index - IndexType(); };

using ParameterMapVectorType = elx::ParameterObject::ParameterMapVectorType;

// Test both one and two transform parameter maps.
for (const auto & transformParameterMaps : { ParameterMapVectorType{ { { "NumberOfParameters", { "2" } },
{ "Transform", { "TranslationTransform" } },
{ "TransformParameters", { "1", "-2" } } } },
ParameterMapVectorType{ { { "NumberOfParameters", { "2" } },
{ "Transform", { "TranslationTransform" } },
{ "TransformParameters", { "1", "0" } } },
{ { "NumberOfParameters", { "2" } },
{ "Transform", { "TranslationTransform" } },
{ "TransformParameters", { "0", "-2" } } } } })
{
transformParameterObject.SetParameterMaps(transformParameterMaps);

for (const auto index :
itk::ImageRegionIndexRange<ImageDimension>(itk::ImageRegion<ImageDimension>({ 0, -2 }, { 2, 3 })))
{
movingImage->FillBuffer(0);
FillImageRegion(*movingImage, fixedImageRegionIndex + toOffset(index), regionSize);
registration.SetMovingImage(movingImage);
registration.Update();

const auto transformParameters = GetTransformParametersFromFilter(registration);
ASSERT_EQ(transformParameters.size(), ImageDimension);

for (unsigned i{}; i < ImageDimension; ++i)
{
EXPECT_EQ(std::round(transformParameters[i]), index[i] - initialTranslation[i]);
}
}
}
}


GTEST_TEST(itkElastixRegistrationMethod, InitialTransformParameterFileLinkToTransformFile)
{
using PixelType = float;
Expand Down
7 changes: 6 additions & 1 deletion Core/Main/itkElastixRegistrationMethod.h
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,9 @@ class ITK_TEMPLATE_EXPORT ElastixRegistrationMethod : public itk::ImageSource<TF
this->SetInitialTransformParameterFileName("");
}

/** Set initial transform parameter object. */
itkSetConstObjectMacro(InitialTransformParameterObject, elx::ParameterObject);

/** Set/Get/Remove fixed point set filename. */
itkSetMacro(FixedPointSetFileName, std::string);
itkGetConstMacro(FixedPointSetFileName, std::string);
Expand Down Expand Up @@ -311,7 +314,9 @@ class ITK_TEMPLATE_EXPORT ElastixRegistrationMethod : public itk::ImageSource<TF

SmartPointer<const elx::ElastixMain> m_ElastixMain{ nullptr };

std::string m_InitialTransformParameterFileName{};
std::string m_InitialTransformParameterFileName{};
elx::ParameterObject::ConstPointer m_InitialTransformParameterObject{};

std::string m_FixedPointSetFileName{};
std::string m_MovingPointSetFileName{};

Expand Down
5 changes: 4 additions & 1 deletion Core/Main/itkElastixRegistrationMethod.hxx
Original file line number Diff line number Diff line change
Expand Up @@ -232,7 +232,10 @@ ElastixRegistrationMethod<TFixedImage, TMovingImage>::GenerateData()
unsigned int isError = 0;
try
{
isError = elastixMain->Run(argumentMap, parameterMap);
isError = m_InitialTransformParameterObject
? elastixMain->RunWithInitialTransformParameterMaps(
argumentMap, parameterMap, m_InitialTransformParameterObject->GetParameterMap())
: elastixMain->Run(argumentMap, parameterMap);
}
catch (const itk::ExceptionObject & e)
{
Expand Down

0 comments on commit 48c6458

Please sign in to comment.