Commit dc04c2d8 authored by Floris Berendsen's avatar Floris Berendsen
Browse files

ENH: solved various issues in SuperElastixFilter/Overlord

parent eb6b5cee
......@@ -34,6 +34,12 @@ namespace selx
Providing < RegistrationControllerStartInterface >
>
{
// RegistrationControllerComponent is a work-around for broken itk-pipelines.
// Both the elastix and itkv4 require to connect their transforms *after* execution of the registration.
// This controller explicitly performs these steps
// TODO: see if signals-and-slots paradigm is appropriate here.
public:
selxNewMacro(RegistrationControllerComponent, ComponentBase);
......
......@@ -63,10 +63,10 @@ namespace selx
{
reconnectTransformInterface->ReconnectTransform();
}
for (auto && afterRegistrationInterface : this->m_AfterRegistrationInterfaces)
{
afterRegistrationInterface->AfterRegistration();
}
//for (auto && afterRegistrationInterface : this->m_AfterRegistrationInterfaces)
//{
// afterRegistrationInterface->AfterRegistration();
//}
}
template<bool dummy>
......
......@@ -18,6 +18,7 @@
*=========================================================================*/
#include "selxMonolithicTransformix.h"
#include <string>
namespace selx
{
......@@ -33,11 +34,11 @@ namespace selx
m_transformixFilter->SetOutputDirectory(".");
//TODO m_elastixFilter returns a nullptr GetTransformParameterObject instead of a valid object. However, we need this object to satisfy the input conditions of m_transformixFilter
elxParameterObjectPointer elxParameterObject = elxParameterObjectType::New();
typename elxParameterObjectType::ParameterMapType defaultParameters = elxParameterObject->GetDefaultParameterMap("rigid");
elxParameterObject->SetParameterMap(defaultParameters);
elxParameterObjectPointer trxParameterObject = elxParameterObjectType::New();
//typename elxParameterObjectType::ParameterMapType defaultParameters = elxParameterObject->GetDefaultParameterMap("rigid");
//elxParameterObject->SetParameterMap(defaultParameters);
//m_transformixFilter->SetTransformParameterObject(m_elastixFilter->GetTransformParameterObject());
m_transformixFilter->SetTransformParameterObject(elxParameterObject); // supply a dummy object
m_transformixFilter->SetTransformParameterObject(trxParameterObject); // supply a dummy object
//TODO: instantiating the filter in the constructor might be heavy for the use in component selector factory, since all components of the database are created during the selection process.
// we could choose to keep the component light weighted (for checking criteria such as names and connections) until the settings are passed to the filter, but this requires an additional initialization step.
......@@ -51,9 +52,51 @@ namespace selx
template<int Dimensionality, class TPixel>
int MonolithicTransformixComponent< Dimensionality, TPixel>::Set(itkImageDomainFixedInterface<Dimensionality>* component)
{
auto fixedImageDomain = component->GetItkImageDomainFixed();
// TODO: this is not finished and tested. Make this component use the provided domain
// Currently, the fixed image domain is part of the transformParameter map, which will be set by elastix.
// TODO: make this component use the provided domain
auto fixedImageDomain = component->GetItkImageDomainFixed();
auto size = fixedImageDomain->GetLargestPossibleRegion().GetSize();
TransformixFilterType::ParameterValueVectorType sizeParameters;
auto spacing = fixedImageDomain->GetSpacing();
TransformixFilterType::ParameterValueVectorType spacingParameters;
auto index = fixedImageDomain->GetLargestPossibleRegion().GetIndex();
TransformixFilterType::ParameterValueVectorType indexParameters;
auto origin = fixedImageDomain->GetOrigin();
TransformixFilterType::ParameterValueVectorType originParameters;
//auto direction = fixedImageDomain->GetDirectionCosines();
//TransformixFilterType::ParameterValueVectorType DirectionParameters;
for (int d = 0; d < Dimensionality; ++d)
{
sizeParameters.push_back(std::to_string(size[d]));
spacingParameters.push_back(std::to_string(spacing[d]));
indexParameters.push_back(std::to_string(index[d]));
originParameters.push_back(std::to_string(origin[d]));
}
elxParameterObjectPointer trxParameterObject = elxParameterObjectType::New();
TransformixFilterType::ParameterMapType trxParameterMap = {
{ "FixedImageDimension", { std::to_string(Dimensionality) } },
{ "MovingImageDimension", { std::to_string(Dimensionality) } },
{ "FixedInternalImagePixelType", { "float" } },
{ "MovingInternalImagePixelType", { "float" } },
{ "Size", sizeParameters },
{ "Index", indexParameters },
{ "Spacing", spacingParameters },
{ "Origin", originParameters },
//{ "Direction", { "1", "0", "0", "1" } },
{ "UseDirectionCosines", { "true" } } };
trxParameterObject->SetParameterMap(trxParameterMap);
this->m_transformixFilter->SetTransformParameterObject(trxParameterObject);
return 0;
}
......
......@@ -503,6 +503,8 @@ TEST_F(RegistrationItkv4Test, FullyConfigured3d)
// Update call on the writers triggers SuperElastix to configure and execute
EXPECT_NO_THROW(resultImageWriter->Update());
EXPECT_NO_THROW(resultDisplacementWriter->Update());
blueprint->WriteBlueprint(dataManager->GetOutputFile("RegistrationItkv4Test_DisplacementField_network.dot"));
......
......@@ -204,18 +204,18 @@ TEST_F(WBIRDemoTest, itkv4_SVF_ANTSCC)
ImageReader2DType::Pointer movingImageReader = ImageReader2DType::New();
movingImageReader->SetFileName(dataManager->GetInputFile("coneB2d64.mhd"));
//ImageWriter2DType::Pointer resultImageWriter = ImageWriter2DType::New();
//resultImageWriter->SetFileName(dataManager->GetOutputFile("itkv4_SVF_ANTSCC_Image.mhd"));
ImageWriter2DType::Pointer resultImageWriter = ImageWriter2DType::New();
resultImageWriter->SetFileName(dataManager->GetOutputFile("itkv4_SVF_ANTSCC_Image.mhd"));
//VectorImageWriter2DType::Pointer vectorImageWriter = VectorImageWriter2DType::New();
//vectorImageWriter->SetFileName(dataManager->GetOutputFile("itkv4_SVF_ANTSCC_Displacement.mhd"));
VectorImageWriter2DType::Pointer vectorImageWriter = VectorImageWriter2DType::New();
vectorImageWriter->SetFileName(dataManager->GetOutputFile("itkv4_SVF_ANTSCC_Displacement.mhd"));
// Connect SuperElastix in an itk pipeline
superElastixFilter->SetInput("FixedImageSource", fixedImageReader->GetOutput());
superElastixFilter->SetInput("MovingImageSource", movingImageReader->GetOutput());
//resultImageWriter->SetInput(superElastixFilter->GetOutput<Image2DType>("ResultImageSink"));
//vectorImageWriter->SetInput(superElastixFilter->GetOutput<VectorImage2DType>("ResultDisplacementFieldSink"));
resultImageWriter->SetInput(superElastixFilter->GetOutput<Image2DType>("ResultImageSink"));
vectorImageWriter->SetInput(superElastixFilter->GetOutput<VectorImage2DType>("ResultDisplacementFieldSink"));
baselineImageReader->SetFileName(dataManager->GetBaselineFile("itkv4_SVF_ANTSCC_Image.mhd"));
baselineVectorImageReader->SetFileName(dataManager->GetBaselineFile("itkv4_SVF_ANTSCC_Displacement.mhd"));
......@@ -229,8 +229,8 @@ TEST_F(WBIRDemoTest, itkv4_SVF_ANTSCC)
//superElastixFilter->Update();
// Update call on the writers triggers SuperElastix to configure and execute
//EXPECT_NO_THROW(resultImageWriter->Update());
//EXPECT_NO_THROW(vectorImageWriter->Update());
EXPECT_NO_THROW(resultImageWriter->Update());
EXPECT_NO_THROW(vectorImageWriter->Update());
EXPECT_NO_THROW(compareImageFilter->Update());
EXPECT_NO_THROW(statisticsImageFilter->Update());
......@@ -313,18 +313,18 @@ TEST_F(WBIRDemoTest, itkv4_SVF_MSD)
ImageReader2DType::Pointer movingImageReader = ImageReader2DType::New();
movingImageReader->SetFileName(dataManager->GetInputFile("coneB2d64.mhd"));
//ImageWriter2DType::Pointer resultImageWriter = ImageWriter2DType::New();
//resultImageWriter->SetFileName(dataManager->GetOutputFile("itkv4_SVF_MSD_Image.mhd"));
ImageWriter2DType::Pointer resultImageWriter = ImageWriter2DType::New();
resultImageWriter->SetFileName(dataManager->GetOutputFile("itkv4_SVF_MSD_Image.mhd"));
//VectorImageWriter2DType::Pointer vectorImageWriter = VectorImageWriter2DType::New();
//vectorImageWriter->SetFileName(dataManager->GetOutputFile("itkv4_SVF_MSD_Displacement.mhd"));
VectorImageWriter2DType::Pointer vectorImageWriter = VectorImageWriter2DType::New();
vectorImageWriter->SetFileName(dataManager->GetOutputFile("itkv4_SVF_MSD_Displacement.mhd"));
// Connect SuperElastix in an itk pipeline
superElastixFilter->SetInput("FixedImageSource", fixedImageReader->GetOutput());
superElastixFilter->SetInput("MovingImageSource", movingImageReader->GetOutput());
//resultImageWriter->SetInput(superElastixFilter->GetOutput<Image2DType>("ResultImageSink"));
//vectorImageWriter->SetInput(superElastixFilter->GetOutput<VectorImage2DType>("ResultDisplacementFieldSink"));
resultImageWriter->SetInput(superElastixFilter->GetOutput<Image2DType>("ResultImageSink"));
vectorImageWriter->SetInput(superElastixFilter->GetOutput<VectorImage2DType>("ResultDisplacementFieldSink"));
baselineImageReader->SetFileName(dataManager->GetBaselineFile("itkv4_SVF_MSD_Image.mhd"));
baselineVectorImageReader->SetFileName(dataManager->GetBaselineFile("itkv4_SVF_MSD_Displacement.mhd"));
......@@ -338,8 +338,8 @@ TEST_F(WBIRDemoTest, itkv4_SVF_MSD)
//superElastixFilter->Update();
// Update call on the writers triggers SuperElastix to configure and execute
//EXPECT_NO_THROW(resultImageWriter->Update());
//EXPECT_NO_THROW(vectorImageWriter->Update());
EXPECT_NO_THROW(resultImageWriter->Update());
EXPECT_NO_THROW(vectorImageWriter->Update());
EXPECT_NO_THROW(compareImageFilter->Update());
EXPECT_NO_THROW(statisticsImageFilter->Update());
......@@ -403,11 +403,11 @@ TEST_F(WBIRDemoTest, elastix_BS_NCC)
ImageReader2DType::Pointer movingImageReader = ImageReader2DType::New();
movingImageReader->SetFileName(dataManager->GetInputFile("coneB2d64.mhd"));
//ImageWriter2DType::Pointer resultImageWriter = ImageWriter2DType::New();
//resultImageWriter->SetFileName(dataManager->GetOutputFile("elastix_BS_NCC_Image.mhd"));
ImageWriter2DType::Pointer resultImageWriter = ImageWriter2DType::New();
resultImageWriter->SetFileName(dataManager->GetOutputFile("elastix_BS_NCC_Image.mhd"));
//VectorImageWriter2DType::Pointer vectorImageWriter = VectorImageWriter2DType::New();
//vectorImageWriter->SetFileName(dataManager->GetOutputFile("elastix_BS_NCC_Displacement.mhd"));
VectorImageWriter2DType::Pointer vectorImageWriter = VectorImageWriter2DType::New();
vectorImageWriter->SetFileName(dataManager->GetOutputFile("elastix_BS_NCC_Displacement.mhd"));
// Connect SuperElastix in an itk pipeline
superElastixFilter->SetInput("FixedImageSource", fixedImageReader->GetOutput());
......@@ -498,18 +498,18 @@ TEST_F(WBIRDemoTest, elastix_BS_MSD)
ImageReader2DType::Pointer movingImageReader = ImageReader2DType::New();
movingImageReader->SetFileName(dataManager->GetInputFile("coneB2d64.mhd"));
//ImageWriter2DType::Pointer resultImageWriter = ImageWriter2DType::New();
//resultImageWriter->SetFileName(dataManager->GetOutputFile("elastix_BS_MSD_Image.mhd"));
ImageWriter2DType::Pointer resultImageWriter = ImageWriter2DType::New();
resultImageWriter->SetFileName(dataManager->GetOutputFile("elastix_BS_MSD_Image.mhd"));
//VectorImageWriter2DType::Pointer vectorImageWriter = VectorImageWriter2DType::New();
//vectorImageWriter->SetFileName(dataManager->GetOutputFile("elastix_BS_MSD_Displacement.mhd"));
VectorImageWriter2DType::Pointer vectorImageWriter = VectorImageWriter2DType::New();
vectorImageWriter->SetFileName(dataManager->GetOutputFile("elastix_BS_MSD_Displacement.mhd"));
// Connect SuperElastix in an itk pipeline
superElastixFilter->SetInput("FixedImageSource", fixedImageReader->GetOutput());
superElastixFilter->SetInput("MovingImageSource", movingImageReader->GetOutput());
//resultImageWriter->SetInput(superElastixFilter->GetOutput<Image2DType>("ResultImageSink"));
//vectorImageWriter->SetInput(superElastixFilter->GetOutput<VectorImage2DType>("ResultDisplacementFieldSink"));
resultImageWriter->SetInput(superElastixFilter->GetOutput<Image2DType>("ResultImageSink"));
vectorImageWriter->SetInput(superElastixFilter->GetOutput<VectorImage2DType>("ResultDisplacementFieldSink"));
baselineImageReader->SetFileName(dataManager->GetBaselineFile("elastix_BS_MSD_Image.mhd"));
baselineVectorImageReader->SetFileName(dataManager->GetBaselineFile("elastix_BS_MSD_Displacement.mhd"));
......
......@@ -324,22 +324,7 @@ namespace selx
void Overlord::Execute()
{
// TODO make one "update button" for the overlord
//this->FindRunRegistration();
//this->FindAfterRegistration();
// RunRegistrations is a simple execution model
// E.g.if the components are true itk Process Object, the don't need an 'Update' call.
// The container of RunRegistrationsInterfaces will therefore be empty, since they will not be added if they don't expose this interface.
// If components need RunIterations() or RunResolution() we can explicitly 'Update' them here and control the flow.
// TODO: see if signals-and-slots paradigm is appropriate here.
//this->RunRegistrations();
//this->ReconnectTransforms();
//this->AfterRegistrations();
//update all writers...
/** Scans all Components to find those with RegistrationControllerStart capability and call them */
const CriterionType criterion = CriterionType(keys::HasProvidingInterface, { keys::RegistrationControllerStartInterface });
......
......@@ -41,8 +41,8 @@ SuperElastixFilter< ComponentTypeList >
*/
// TODO this method should be revised together with overlord->Configure(). A functionality
// that is foreseen in which the user may provide a minimalistic configuration (blueprint)
// and that other criteria to select a component may be derived from neighboring components.
// is foreseen in which the user may provide a minimalistic configuration (blueprint) and in
// which other criteria to select a component are derived from neighboring components.
// E.g. we could implement source nodes that provides ImageReaders of multiple dimensions.
// At connecting these reader, the dimensionality is known from the data and the source
// component can pass the dimensionality as an additional criterion to the component selectors
......@@ -97,6 +97,8 @@ SuperElastixFilter< ComponentTypeList >
Overlord::SinkInterfaceMapType sinks = this->m_Overlord->GetSinkInterfaces();
for (const auto & nameAndInterface : sinks)
{
// TODO this Update seems needed, but I would expect that UpdateOutputInformation should be enough
//nameAndInterface.second->GetMiniPipelineOutput()->Update();
nameAndInterface.second->GetMiniPipelineOutput()->UpdateOutputInformation();
this->GetOutput(nameAndInterface.first)->Graft(nameAndInterface.second->GetMiniPipelineOutput());
}
......@@ -116,12 +118,15 @@ void
SuperElastixFilter< ComponentTypeList >
::GenerateData(void)
{
this->m_Overlord->Execute(); // calls updates of sink filters
// This calls controller components that take over the control flow if the itk pipeline is broken.
this->m_Overlord->Execute();
Overlord::SinkInterfaceMapType sinks = this->m_Overlord->GetSinkInterfaces();
for (const auto & nameAndInterface : sinks)
{
// Here we force all output to be updated.
// TODO: it might be desirable to leave parts of the mini pipeline 'outdated' for memory/speed reasons and only update if requested downsteam.
nameAndInterface.second->GetMiniPipelineOutput()->Update();
this->GetOutput(nameAndInterface.first)->Graft(nameAndInterface.second->GetMiniPipelineOutput());
}
......@@ -210,6 +215,16 @@ ReturnType*
SuperElastixFilter< ComponentTypeList >
::GetOutput(const DataObjectIdentifierType& outputName)
{
OutputDataType* output = Superclass::GetOutput(outputName);
if (output != nullptr) // if an output already exists, return it
{
ReturnType* returnOutput = dynamic_cast<ReturnType*>(output);
if (returnOutput != nullptr) // if it is of the same type as requested before
{
return returnOutput;
}
itkExceptionMacro(<< "Output """ << outputName << """ was requested before, but the ReturnTypes do not match")
}
// Purposely not checking the outputName, but just create the requested&named data object in the filter.
// When connecting the Sinks the selxFilter names and data types are checked.
typename ReturnType::Pointer newOutput = ReturnType::New();
......
......@@ -25,6 +25,7 @@
#include "selxItkImageSource.h"
#include "selxItkMeshSink.h"
#include "selxItkMeshSource.h"
#include "selxRegistrationController.h"
#include "itkImage.h"
#include "itkImageFileReader.h"
......@@ -32,6 +33,7 @@
#include "itkDisplacementFieldTransform.h"
#include "itkComposeDisplacementFieldsImageFilter.h"
#include "itkCompositeTransform.h"
#include "itkVector.h"
#include "itkPoint.h"
......@@ -86,7 +88,8 @@ namespace selx {
ComponentFactory<ItkImageSinkComponent<3, double>>::RegisterOneFactory();
ComponentFactory<ItkImageSourceComponent<3, double>>::RegisterOneFactory();
ComponentFactory<ItkSmoothingRecursiveGaussianImageFilterComponent<3, double>>::RegisterOneFactory();
ComponentFactory<RegistrationControllerComponent<>>::RegisterOneFactory();
SuperElastixFilterType::Pointer mySuperElastix;
Blueprint::Pointer blueprint = Blueprint::New();
......@@ -94,8 +97,8 @@ namespace selx {
blueprint->AddComponent("InputImage", { { "NameOfClass", { "ItkImageSourceComponent" } } });
blueprint->AddComponent("ImageFilter", { { "NameOfClass", { "ItkSmoothingRecursiveGaussianImageFilterComponent" } } });
blueprint->AddComponent("OutputImage", { { "NameOfClass", { "ItkImageSinkComponent" } } });
blueprint->AddConnection("InputImage", "ImageFilter", Blueprint::ParameterMapType()); //
blueprint->AddConnection("ImageFilter", "OutputImage", Blueprint::ParameterMapType());
blueprint->AddConnection("InputImage", "ImageFilter", { {} }); //
blueprint->AddConnection("ImageFilter", "OutputImage", { {} });
EXPECT_NO_THROW(mySuperElastix = SuperElastixFilterType::New());
mySuperElastix->SetBlueprint(blueprint);
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment