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

ENH: Added optional masks for MonolithicElastixComponent #143

parent ab5906cb
......@@ -29,6 +29,33 @@ struct PodString
static_assert( StaticErrorMessageRevealT< T >::False, "Please Implement PodString<T> for this T" );
};
template< >
struct PodString< bool >
{
static const char * Get()
{
return "bool";
}
};
template< >
struct PodString< unsigned char >
{
static const char * Get()
{
return "unsigned char";
}
};
template< >
struct PodString< char >
{
static const char * Get()
{
return "char";
}
};
template< >
struct PodString< unsigned int >
{
......
......@@ -38,7 +38,9 @@ class MonolithicElastixComponent :
public SuperElastixComponent<
Accepting<
itkImageFixedInterface< Dimensionality, TPixel >,
itkImageMovingInterface< Dimensionality, TPixel >
itkImageMovingInterface< Dimensionality, TPixel >,
itkImageFixedMaskInterface< Dimensionality, unsigned char >,
itkImageMovingMaskInterface< Dimensionality, unsigned char >
>,
Providing<
elastixTransformParameterObjectInterface< itk::Image< TPixel, Dimensionality >, itk::Image< TPixel, Dimensionality >>,
......@@ -56,7 +58,9 @@ public:
typedef SuperElastixComponent<
Accepting<
itkImageFixedInterface< Dimensionality, TPixel >,
itkImageMovingInterface< Dimensionality, TPixel >
itkImageMovingInterface< Dimensionality, TPixel >,
itkImageFixedMaskInterface< Dimensionality, unsigned char >,
itkImageMovingMaskInterface< Dimensionality, unsigned char >
>,
Providing<
elastixTransformParameterObjectInterface< itk::Image< TPixel, Dimensionality >, itk::Image< TPixel, Dimensionality >>,
......@@ -94,6 +98,10 @@ public:
virtual int Accept( typename itkImageMovingInterface< Dimensionality, TPixel >::Pointer ) override;
virtual int Accept( typename itkImageFixedMaskInterface< Dimensionality, unsigned char >::Pointer ) override;
virtual int Accept( typename itkImageMovingMaskInterface< Dimensionality, unsigned char >::Pointer ) override;
// Providing Interfaces:
virtual elastixTransformParameterObject * GetTransformParameterObject() override;
......@@ -101,8 +109,11 @@ public:
virtual void Update() override;
//Base class methods:
virtual bool MeetsCriterion( const CriterionType & criterion ) override;
virtual bool ConnectionsSatisfied() override;
static const char * GetDescription() { return "MonolithicElastix Component"; }
private:
......
......@@ -67,6 +67,26 @@ MonolithicElastixComponent< Dimensionality, TPixel >::Accept( typename itkImageM
return 0;
}
template< int Dimensionality, class TPixel >
int
MonolithicElastixComponent< Dimensionality, TPixel >::Accept(typename itkImageFixedMaskInterface< Dimensionality, unsigned char >::Pointer component)
{
auto fixedMaskImage = component->GetItkImageFixedMask();
// connect the itk pipeline
this->m_elastixFilter->SetFixedMask(fixedMaskImage);
return 0;
}
template< int Dimensionality, class TPixel >
int
MonolithicElastixComponent< Dimensionality, TPixel >::Accept(typename itkImageMovingMaskInterface< Dimensionality, unsigned char >::Pointer component)
{
auto movingMaskImage = component->GetItkImageMovingMask();
// connect the itk pipeline
this->m_elastixFilter->SetMovingMask(movingMaskImage);
return 0;
}
template< int Dimensionality, class TPixel >
typename MonolithicElastixComponent< Dimensionality, TPixel >::ItkImagePointer
......@@ -146,4 +166,25 @@ MonolithicElastixComponent< Dimensionality, TPixel >
}
return meetsCriteria;
}
template< int Dimensionality, class TPixel >
bool
MonolithicElastixComponent< Dimensionality, TPixel >
::ConnectionsSatisfied()
{
// This function overrides the default behavior, in which all accepting interfaces must be set.
// Only Fixed and Moving images are required
// TODO: see I we can reduce the amount of code with helper (meta-)functions
if (!this->InterfaceAcceptor< itkImageFixedInterface< Dimensionality, TPixel >>::GetAccepted())
{
return false;
}
if (!this->InterfaceAcceptor< itkImageMovingInterface< Dimensionality, TPixel >>::GetAccepted())
{
return false;
}
return true;
}
} //end namespace selx
......@@ -51,12 +51,16 @@ public:
ItkImageSinkComponent< 2, float >,
DisplacementFieldItkImageFilterSinkComponent< 2, float >,
ItkImageSourceComponent< 2, float >,
ItkImageSourceComponent< 2, unsigned char >, //for masks
ItkImageSourceComponent< 3, double >> RegisterComponents;
typedef itk::Image< float, 2 > Image2DType;
typedef itk::ImageFileReader< Image2DType > ImageReader2DType;
typedef itk::ImageFileWriter< Image2DType > ImageWriter2DType;
typedef itk::Image< unsigned char, 2 > Mask2DType;
typedef itk::ImageFileReader< Mask2DType > MaskReader2DType;
typedef itk::Image< itk::Vector< float, 2 >, 2 > DisplacementImage2DType;
typedef itk::ImageFileWriter< DisplacementImage2DType > DisplacementImageWriter2DType;
......@@ -101,6 +105,10 @@ TEST_F( ElastixComponentTest, MonolithicElastixTransformix )
blueprint->SetComponent( "MovingImageSource", { { "NameOfClass", { "ItkImageSourceComponent" } }, { "Dimensionality", { "2" } } } );
blueprint->SetComponent( "FixedMaskImageSource", { { "NameOfClass", { "ItkImageSourceComponent" } }, { "Dimensionality", { "2" } } } );
blueprint->SetComponent( "MovingMaskImageSource", { { "NameOfClass", { "ItkImageSourceComponent" } }, { "Dimensionality", { "2" } } } );
blueprint->SetComponent( "ResultImageSink", { { "NameOfClass", { "ItkImageSinkComponent" } }, { "Dimensionality", { "2" } } } );
blueprint->SetComponent( "ResultDisplacementFieldSink", { { "NameOfClass", { "DisplacementFieldItkImageFilterSinkComponent" } }, { "Dimensionality", { "2" } } });
......@@ -115,19 +123,29 @@ TEST_F( ElastixComponentTest, MonolithicElastixTransformix )
blueprint->SetConnection( "MovingImageSource", "TransformDisplacementField", { { "NameOfInterface", { "itkImageMovingInterface" } } } ); //;
blueprint->SetConnection( "FixedMaskImageSource", "RegistrationMethod", { { "NameOfInterface", { "itkImageFixedMaskInterface" } } } ); // ;
blueprint->SetConnection( "MovingMaskImageSource", "RegistrationMethod", { { "NameOfInterface", { "itkImageMovingMaskInterface" } } } ); //;
blueprint->SetConnection( "TransformDisplacementField", "ResultImageSink", { { "NameOfInterface", { "itkImageInterface" } } } ); // ;
blueprint->SetConnection( "TransformDisplacementField", "ResultDisplacementFieldSink", { { "NameOfInterface", { "DisplacementFieldItkImageSourceInterface" } } }); // ;
// Set up the readers and writers
ImageReader2DType::Pointer fixedImageReader = ImageReader2DType::New();
auto fixedImageReader = ImageReader2DType::New();
fixedImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20.png" ) );
ImageReader2DType::Pointer movingImageReader = ImageReader2DType::New();
auto movingImageReader = ImageReader2DType::New();
movingImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceR10X13Y17.png" ) );
ImageWriter2DType::Pointer resultImageWriter = ImageWriter2DType::New();
auto fixedMaskReader = MaskReader2DType::New();
fixedMaskReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20Mask.png" ) );
auto movingMaskReader = MaskReader2DType::New();
movingMaskReader->SetFileName(dataManager->GetInputFile("BrainProtonDensitySliceBorder20Mask.png")); // same as fixedmask: good enough for unit test, but probably bad practice for registration.
auto resultImageWriter = ImageWriter2DType::New();
resultImageWriter->SetFileName( dataManager->GetOutputFile( "ElastixComponentTest_BrainProtonDensity.mhd" ) );
DisplacementImageWriter2DType::Pointer resultDisplacementWriter = DisplacementImageWriter2DType::New();
......@@ -136,6 +154,9 @@ TEST_F( ElastixComponentTest, MonolithicElastixTransformix )
// Connect SuperElastix in an itk pipeline
superElastixFilter->SetInput( "FixedImageSource", fixedImageReader->GetOutput() );
superElastixFilter->SetInput( "MovingImageSource", movingImageReader->GetOutput() );
superElastixFilter->SetInput( "FixedMaskImageSource", fixedMaskReader->GetOutput() );
superElastixFilter->SetInput( "MovingMaskImageSource", movingMaskReader->GetOutput() );
resultImageWriter->SetInput( superElastixFilter->GetOutput< Image2DType >( "ResultImageSink" ) );
resultDisplacementWriter->SetInput(superElastixFilter->GetOutput< DisplacementImage2DType >("ResultDisplacementFieldSink"));
......
......@@ -37,7 +37,9 @@ class ItkImageSourceComponent :
Providing< SourceInterface, itkImageInterface< Dimensionality, TPixel >,
itkImageFixedInterface< Dimensionality, TPixel >,
itkImageMovingInterface< Dimensionality, TPixel >,
itkImageDomainFixedInterface< Dimensionality >>
itkImageDomainFixedInterface< Dimensionality >,
itkImageMovingMaskInterface< Dimensionality, TPixel >,
itkImageFixedMaskInterface< Dimensionality, TPixel >>
>
{
public:
......@@ -51,7 +53,9 @@ public:
Providing< SourceInterface, itkImageInterface< Dimensionality, TPixel >,
itkImageFixedInterface< Dimensionality, TPixel >,
itkImageMovingInterface< Dimensionality, TPixel >,
itkImageDomainFixedInterface< Dimensionality >>
itkImageDomainFixedInterface< Dimensionality >,
itkImageMovingMaskInterface< Dimensionality, TPixel >,
itkImageFixedMaskInterface< Dimensionality, TPixel >>
> Superclass;
typedef std::shared_ptr< Self > Pointer;
typedef std::shared_ptr< const Self > ConstPointer;
......@@ -74,6 +78,10 @@ public:
virtual typename ItkImageDomainType::Pointer GetItkImageDomainFixed() override;
virtual typename ItkImageType::Pointer GetItkImageFixedMask() override;
virtual typename ItkImageType::Pointer GetItkImageMovingMask() override;
virtual void SetMiniPipelineInput( itk::DataObject::Pointer ) override;
virtual AnyFileReader::Pointer GetInputFileReader( void ) override;
......
......@@ -87,6 +87,30 @@ ItkImageSourceComponent< Dimensionality, TPixel >
return this->m_Image.GetPointer();
}
template< int Dimensionality, class TPixel >
typename ItkImageSourceComponent< Dimensionality, TPixel >::ItkImageType::Pointer
ItkImageSourceComponent< Dimensionality, TPixel >
::GetItkImageFixedMask()
{
if (this->m_Image == nullptr)
{
throw std::runtime_error("SourceComponent needs to be initialized by SetMiniPipelineInput()");
}
return this->m_Image;
}
template< int Dimensionality, class TPixel >
typename ItkImageSourceComponent< Dimensionality, TPixel >::ItkImageType::Pointer
ItkImageSourceComponent< Dimensionality, TPixel >
::GetItkImageMovingMask()
{
if (this->m_Image == nullptr)
{
throw std::runtime_error("SourceComponent needs to be initialized by SetMiniPipelineInput()");
}
return this->m_Image;
}
template< int Dimensionality, class TPixel >
void
......
......@@ -32,6 +32,10 @@ using ModuleSinksAndSourcesComponents = selx::TypeList<
ItkImageSinkComponent< 2, float >,
ItkImageSinkComponent< 3, short >,
ItkImageSourceComponent< 2, float >,
ItkImageSourceComponent< 2, short >
ItkImageSourceComponent< 2, short >,
ItkImageSourceComponent< 2, unsigned char >, // for masks
ItkImageSourceComponent< 3, float >,
ItkImageSourceComponent< 3, short >,
ItkImageSourceComponent< 3, unsigned char > // for masks
>;
}
......@@ -107,6 +107,32 @@ public:
virtual typename ItkImageType::Pointer GetItkImageMoving() = 0;
};
template< int Dimensionality, class TPixel >
class itkImageFixedMaskInterface
{
// An interface that provides the smart pointer to an itk image
public:
using Type = itkImageFixedMaskInterface< Dimensionality, TPixel >;
using Pointer = std::shared_ptr< Type >;
typedef typename itk::Image< TPixel, Dimensionality > ItkImageType;
virtual typename ItkImageType::Pointer GetItkImageFixedMask() = 0;
};
template< int Dimensionality, class TPixel >
class itkImageMovingMaskInterface
{
// An interface that provides the smart pointer to an itk image
public:
using Type = itkImageMovingMaskInterface< Dimensionality, TPixel >;
using Pointer = std::shared_ptr< Type >;
typedef typename itk::Image< TPixel, Dimensionality > ItkImageType;
virtual typename ItkImageType::Pointer GetItkImageMovingMask() = 0;
};
template< int Dimensionality, class TPixel >
class DisplacementFieldItkImageSourceInterface
{
......@@ -157,7 +183,7 @@ struct Properties< itkImageFixedInterface< D, TPixel >>
{
static const std::map< std::string, std::string > Get()
{
return { { keys::NameOfInterface, "itkImageFixedInterface" }, { keys::Dimensionality, std::to_string( D ) }, { keys::PixelType, PodString< TPixel >::Get() }, { "Role", "Fixed" } };
return { { keys::NameOfInterface, "itkImageFixedInterface" }, { keys::Dimensionality, std::to_string( D ) }, { keys::PixelType, PodString< TPixel >::Get() }, { "Role", "Fixed" } };// TODO replace "Role" by "Domain"
}
};
......@@ -175,7 +201,25 @@ struct Properties< itkImageMovingInterface< D, TPixel >>
{
static const std::map< std::string, std::string > Get()
{
return { { keys::NameOfInterface, "itkImageMovingInterface" }, { keys::Dimensionality, std::to_string( D ) }, { keys::PixelType, PodString< TPixel >::Get() }, { "Role", "Moving" } };
return { { keys::NameOfInterface, "itkImageMovingInterface" }, { keys::Dimensionality, std::to_string( D ) }, { keys::PixelType, PodString< TPixel >::Get() }, { "Role", "Moving" } }; // TODO replace "Role" by "Domain"
}
};
template< int D, class TPixel >
struct Properties< itkImageFixedMaskInterface< D, TPixel >>
{
static const std::map< std::string, std::string > Get()
{
return{ { keys::NameOfInterface, "itkImageFixedMaskInterface" }, { keys::Dimensionality, std::to_string(D) }, { keys::PixelType, PodString< TPixel >::Get() } };
}
};
template< int D, class TPixel >
struct Properties< itkImageMovingMaskInterface< D, TPixel >>
{
static const std::map< std::string, std::string > Get()
{
return{ { keys::NameOfInterface, "itkImageMovingMaskInterface" }, { keys::Dimensionality, std::to_string(D) }, { keys::PixelType, PodString< TPixel >::Get() } };
}
};
......
Markdown is supported
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