diff --git a/CMake/elxModules.cmake b/CMake/elxModules.cmake index 5cc11cd58dd02129e7b9591c53a2f7221917bc4e..c3ea62004d852b823a794e25498d2548cd8df42f 100644 --- a/CMake/elxModules.cmake +++ b/CMake/elxModules.cmake @@ -16,7 +16,7 @@ macro( _elxmodule_enable MODULE_NAME ) _elxmodule_check_name( ${MODULE_NAME} ) if( NOT ${MODULE_NAME}_ENABLED ) - set( USE_${MODULE_NAME} ON ) + set( ${MODULE_NAME}_ENABLED ON ) include( ${${MODULE_NAME}_FILE} ) @@ -29,6 +29,10 @@ macro( _elxmodule_enable MODULE_NAME ) list( APPEND SUPERELASTIX_LIBRARIES ${${MODULE_NAME}_LIBRARIES} ) endif() + if( ${MODULE_NAME}_TESTS ) + list( APPEND SUPERELASTIX_TESTS ${${MODULE_NAME}_TESTS} ) + endif() + # TODO: Add support for indicating dependencies between modules and recursive enabling of these dependencies endif() @@ -39,8 +43,9 @@ macro( _elxmodule_disable MODULE_NAME ) endmacro() macro( _elxmodules_initialize ) - set( SUPERELASTIX_LIBRARIES ) set( SUPERELASTIX_MODULES ) + set( SUPERELASTIX_LIBRARIES ) + set( SUPERELASTIX_TESTS ) file( GLOB_RECURSE MODULE_FILES RELATIVE "${CMAKE_SOURCE_DIR}" "${CMAKE_SOURCE_DIR}/Modules/*/Module*.cmake" @@ -64,7 +69,7 @@ macro( _elxmodules_initialize ) set( ${MODULE_NAME}_LIBRARY_DIRS ) set( ${MODULE_NAME}_LIBRARIES ) - list(APPEND SUPERELASTIX_MODULES ${MODULE_NAME} ) + list( APPEND SUPERELASTIX_MODULES ${MODULE_NAME} ) endforeach() endmacro() diff --git a/CMakeLists.txt b/CMakeLists.txt index 5166656282880a9012c86bf9235fa7effefc3504..b3f6a08a5a13c8e8931ba9ebfef71a9f75730376 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -63,16 +63,6 @@ include("${CMAKE_CURRENT_SOURCE_DIR}/CMake/elxRequiredITKModules.cmake") find_package( Boost REQUIRED ) include_directories( ${Boost_INCLUDE_DIRS} ) -# --------------------------------------------------------------------- -# OpenMP Library -# Required for ElastixComponent -# gcc needs the appropriate flags to support OpenMP -find_package(OpenMP) -if (OPENMP_FOUND) - set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}") - set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") -endif() - # --------------------------------------------------------------------- # Build SuperElastix diff --git a/Modules/Components/Elastix/ModuleElastix.cmake b/Modules/Components/Elastix/ModuleElastix.cmake index 4d54550cce7922242e43706778cd745a47d29829..6fc59d6eae1e615162c042bcae519415ea0dc72d 100644 --- a/Modules/Components/Elastix/ModuleElastix.cmake +++ b/Modules/Components/Elastix/ModuleElastix.cmake @@ -1,28 +1,35 @@ # Module that exposes old elastix as an ITK filter set( MODULE ModuleElastix ) -if( NOT EXISTS ${ELASTIX_USE_FILE} ) - set( ELASTIX_USE_FILE ) - message( FATAL_ERROR "${MODULE} could not find ELASTIX_USE_FILE. Use the SuperBuild or manually point the ELASTIX_USE_FILE CMake variable to the UseElastix.cmake file in the root of your elastix build tree." ) -endif() - -include( ${ELASTIX_USE_FILE} ) - -# If OpenMP is supported by this machine, elastix will be compiled with +# If OpenMP is supported, elastix will have beeen compiled with # OpenMP flags, and we need to add them here as well find_package( OpenMP ) -if (OPENMP_FOUND) +if( OPENMP_FOUND ) set( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${OpenMP_CXX_FLAGS}" ) set( CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${OpenMP_C_FLAGS}" ) endif() +# Find UseElastix.cmake +if( NOT EXISTS ${ELASTIX_USE_FILE} ) + set( ELASTIX_USE_FILE ${ELASTIX_DIR}/UseElastix.cmake ) +endif() + +if( NOT EXISTS ${ELASTIX_USE_FILE} ) + set( ELASTIX_DIR "" CACHE PATH "Path to elastix build folder" ) + message(FATAL_ERROR "Could not find UseElastix.cmake. Point ELASTIX_DIR to folder containing UseElastix.cmake or use SuperBuild.") +endif() + # Export include files -set( ${MODULE}_INCLUDE_DIRS - ${${MODULE}_SOURCE_DIR}/include -) +include( ${ELASTIX_USE_FILE} ) # Export libraries set( ${MODULE}_LIBRARIES elastix transformix ) + +# Export tests +set( ${MODULE}_TESTS + elxElastixFilterTest.cxx + elxTransformixFilterTest.cxx +) diff --git a/Modules/Components/Elastix/include/elxElastixFilter.h b/Modules/Components/Elastix/include/elxElastixFilter.h deleted file mode 100644 index 5283a74c4f6f30542c0fa34250f82a01b07298a7..0000000000000000000000000000000000000000 --- a/Modules/Components/Elastix/include/elxElastixFilter.h +++ /dev/null @@ -1,156 +0,0 @@ -#ifndef ElastixFilter_h -#define ElastixFilter_h - -// ITK -#include "itkImageSource.h" - -// Elastix -#include "elxElastixMain.h" - -// SuperElastix -#include "elxMacro.h" -#include "elxParameterObject.h" - -/** - * Elastix registration library exposed as an ITK filter. - * - * We have to do some additional bookeeping on input images so that they can - * be split into separate containers fixed and moving images at a later stage. - * This is because ITK filters uses a single input container to drive the - * pipeline while elastix use seperate containers for fixed and moving images. - * - */ - -namespace selx { - -template< typename TFixedImage, - typename TMovingImage > -class ElastixFilter : public itk::ImageSource< TFixedImage > -{ -public: - - elxNewMacro( ElastixFilter, itk::ImageSource ); - - typedef elastix::ElastixMain ElastixMainType; - typedef ElastixMainType::Pointer ElastixMainPointer; - typedef std::vector< ElastixMainPointer > ElastixMainVectorType; - typedef ElastixMainType::ObjectPointer ElastixMainObjectPointer; - - typedef ElastixMainType::FlatDirectionCosinesType FlatDirectionCosinesType; - - typedef ElastixMainType::ArgumentMapType ArgumentMapType; - typedef ArgumentMapType::value_type ArgumentMapEntryType; - - typedef itk::ProcessObject::DataObjectIdentifierType DataObjectIdentifierType; - typedef itk::ProcessObject::DataObjectPointerArraySizeType DataObjectPointerArraySizeType; - typedef itk::ProcessObject::NameArray InputNameArrayType; - - typedef ElastixMainType::DataObjectContainerType DataObjectContainerType; - typedef ElastixMainType::DataObjectContainerPointer DataObjectContainerPointer; - typedef DataObjectContainerType::Iterator DataObjectContainerIterator; - - typedef ParameterObject::ParameterMapListType ParameterMapListType; - typedef ParameterObject::ParameterMapType ParameterMapType; - typedef ParameterObject::ParameterVectorType ParameterVectorType; - typedef ParameterObject::Pointer ParameterObjectPointer; - typedef ParameterObject::ConstPointer ParameterObjectConstPointer; - - typedef typename TFixedImage::Pointer FixedImagePointer; - typedef typename TMovingImage::Pointer MovingImagePointer; - - void SetFixedImage( FixedImagePointer fixedImage ); - void SetFixedImage( DataObjectContainerPointer fixedImages ); - void AddFixedImage( FixedImagePointer fixedImage ); - - void SetMovingImage( MovingImagePointer movingImages ); - void SetMovingImage( DataObjectContainerPointer movingImage ); - void AddMovingImage( MovingImagePointer movingImage ); - - void SetFixedMask( FixedImagePointer fixedMask ); - void SetMovingMask( MovingImagePointer movingMask ); - - void SetParameterObject( ParameterObjectPointer parameterObject ); - ParameterObjectPointer GetTransformParameters( void ); - - itkSetMacro( FixedMeshFileName, std::string ); - itkGetConstMacro( FixedMeshFileName, std::string ); - void RemoveFixedMeshFileName( void ) { this->SetFixedMeshFileName( std::string() ); }; - - itkSetMacro( MovingMeshFileName, std::string ); - itkGetConstMacro( MovingMeshFileName, std::string ); - void RemoveMovingMeshFileName( void ) { this->SetMovingMeshFileName( std::string() ); }; - - itkSetMacro( OutputDirectory, std::string ); - itkGetConstMacro( OutputDirectory, std::string ); - void RemoveOutputDirectory() { this->m_OutputDirectory = std::string(); }; - - void SetLogFileName( std::string logFileName ) - { - this->m_LogFileName = logFileName; - this->LogToFileOn(); - this->Modified(); - } - - itkGetConstMacro( LogFileName, std::string ); - - void RemoveLogFileName( void ) { - this->m_LogFileName = std::string(); - this->LogToFileOff(); - }; - - itkSetMacro( LogToConsole, bool ); - itkGetConstMacro( LogToConsole, bool ); - itkBooleanMacro( LogToConsole ); - - itkSetMacro( LogToFile, bool ); - itkGetConstMacro( LogToFile, bool ); - itkBooleanMacro( LogToFile ); - - // TODO: Superclass GetOutput() does not trigger an Update() as it should - TFixedImage* GetOutput() - { - this->Update(); - return static_cast< TFixedImage* >( itk::ProcessObject::GetPrimaryOutput() ); - } - -protected: - - void GenerateData( void ) ITK_OVERRIDE; - -private: - - ElastixFilter(); - - void AddInputAutoIncrementName( DataObjectIdentifierType key, itk::DataObject* input ); - - bool IsFixedImage( DataObjectIdentifierType key ); - bool IsMovingImage( DataObjectIdentifierType key ); - - void RemoveFixedImages( void ); - void RemoveMovingImages( void ); - - // TODO: When set to true, ReleaseDataFlag should also touch these containers - DataObjectContainerPointer m_FixedImageContainer; - DataObjectContainerPointer m_MovingImageContainer; - DataObjectContainerPointer m_FixedMaskContainer; - DataObjectContainerPointer m_MovingMaskContainer; - - std::string m_FixedMeshFileName; - std::string m_MovingMeshFileName; - - std::string m_OutputDirectory; - std::string m_LogFileName; - - bool m_LogToConsole; - bool m_LogToFile; - - -}; - -} // namespace selx - -#ifndef ITK_MANUAL_INSTANTIATION -#include "elxElastixFilter.hxx" -#endif - -#endif // ElastixFilter_h \ No newline at end of file diff --git a/Modules/Components/Elastix/include/elxElastixFilter.hxx b/Modules/Components/Elastix/include/elxElastixFilter.hxx deleted file mode 100644 index c49adeab48bc9d148fa43abcaf45f023951b5af7..0000000000000000000000000000000000000000 --- a/Modules/Components/Elastix/include/elxElastixFilter.hxx +++ /dev/null @@ -1,428 +0,0 @@ -#ifndef ElastixFilter_hxx -#define ElastixFilter_hxx - -namespace selx { - -template< typename TFixedImage, typename TMovingImage > -ElastixFilter< TFixedImage, TMovingImage > -::ElastixFilter( void ) -{ - this->AddRequiredInputName( "FixedImage" ); - this->AddRequiredInputName( "MovingImage" ); - this->AddRequiredInputName( "ParameterObject"); - - this->SetPrimaryInputName( "FixedImage" ); - this->SetPrimaryOutputName( "ResultImage" ); - - this->m_FixedImageContainer = DataObjectContainerType::New(); - this->m_MovingImageContainer = DataObjectContainerType::New(); - - this->m_FixedMeshFileName = std::string(); - this->m_MovingMeshFileName = std::string(); - - this->m_OutputDirectory = std::string(); - this->m_LogFileName = std::string(); - - this->LogToConsoleOff(); - this->LogToFileOff(); -} - -template< typename TFixedImage, typename TMovingImage > -void -ElastixFilter< TFixedImage, TMovingImage > -::GenerateData( void ) -{ - // Initialize variables here so they don't go out of scope between iterations of the main loop - ElastixMainObjectPointer transform = 0; - DataObjectContainerPointer fixedImageContainer = DataObjectContainerType::New(); - DataObjectContainerPointer movingImageContainer = DataObjectContainerType::New(); - DataObjectContainerPointer fixedMaskContainer = 0; - DataObjectContainerPointer movingMaskContainer = 0; - DataObjectContainerPointer resultImageContainer = 0; - ParameterMapListType TransformParameterMapList; - FlatDirectionCosinesType fixedImageOriginalDirection; - - // Split input images into two seperate fixed and moving image containers - InputNameArrayType inputNames = this->GetInputNames(); - for( unsigned int i = 0; i < inputNames.size(); ++i ) - { - if( this->IsFixedImage( inputNames[ i ] ) ) - { - fixedImageContainer->push_back( this->GetInput( inputNames[ i ] ) ); - } - - if( this->IsMovingImage( inputNames[ i ] ) ) - { - movingImageContainer->push_back( this->GetInput( inputNames[ i ] ) ); - } - } - - // Fixed mask (optional) - if( this->HasInput( "FixedMask" ) ) - { - fixedMaskContainer = DataObjectContainerType::New(); - fixedMaskContainer->CreateElementAt( 0 ) = this->GetInput( "FixedMask" ); - } - - // Moving mask (optional) - if( this->HasInput( "MovingMask" ) ) - { - movingMaskContainer = DataObjectContainerType::New(); - movingMaskContainer->CreateElementAt( 0 ) = this->GetInput( "MovingMask" ); - } - - ArgumentMapType argumentMap; - if( this->GetOutputDirectory().empty() ) { - // There must be an "-out", this is checked later in the code - argumentMap.insert( ArgumentMapEntryType( "-out", "output_path_not_set" ) ); - } - else - { - argumentMap.insert( ArgumentMapEntryType( "-out", this->GetOutputDirectory() ) ); - } - - // Fixed mesh (optional) - if( !this->m_FixedMeshFileName.empty() ) - { - argumentMap.insert( ArgumentMapEntryType( "-fp", std::string( this->m_FixedMeshFileName ) ) ); - } - - // Moving mesh (optional) - if( !this->m_MovingMeshFileName.empty() ) - { - argumentMap.insert( ArgumentMapEntryType( "-mp", std::string( this->m_MovingMeshFileName ) ) ); - } - - // Setup xout - std::string logFileName; - if( this->GetLogToFile() ) - { - if( this->GetOutputDirectory().empty() ) - { - itkExceptionMacro( "LogToFileOn() requires an output directory to be specified. Use SetOutputDirectory().") - } - - if( !itksys::SystemTools::FileExists( this->GetOutputDirectory() ) ) - { - itkExceptionMacro( "Output directory \"" << this->GetOutputDirectory() << "\" does not exist." ) - } - - if( this->GetOutputDirectory().back() != '/' || this->GetOutputDirectory().back() != '\\' ) - { - this->SetOutputDirectory( this->GetOutputDirectory() + "/" ); - } - - if( this->GetLogFileName().empty() ) - { - logFileName = this->GetOutputDirectory() + "transformix.log"; - } - else - { - logFileName = this->GetOutputDirectory() + this->GetLogFileName(); - } - } - - if( elx::xoutSetup( logFileName.c_str(), this->GetLogToFile(), this->GetLogToConsole() ) ) - { - itkExceptionMacro( "ERROR while setting up xout" ); - } - - // Get ParameterMap - ParameterObjectConstPointer parameterObject = static_cast< const ParameterObject* >( this->GetInput( "ParameterObject" ) ); - ParameterMapListType parameterMapList = parameterObject->GetParameterMapList(); - - // Run the (possibly multiple) registration(s) - for( unsigned int i = 0; i < parameterMapList.size(); ++i ) - { - // Create another instance of ElastixMain - ElastixMainPointer elastix = ElastixMainType::New(); - - // Set the current elastix-level - elastix->SetElastixLevel( i ); - elastix->SetTotalNumberOfElastixLevels( parameterMapList.size() ); - - // Set stuff we get from a previous registration - elastix->SetInitialTransform( transform ); - elastix->SetFixedImageContainer( fixedImageContainer ); - elastix->SetMovingImageContainer( movingImageContainer ); - elastix->SetFixedMaskContainer( fixedMaskContainer ); - elastix->SetMovingMaskContainer( movingMaskContainer ); - elastix->SetResultImageContainer( resultImageContainer ); - elastix->SetOriginalFixedImageDirectionFlat( fixedImageOriginalDirection ); - - // Start registration - unsigned int isError = 0; - try - { - unsigned int isError = elastix->Run( argumentMap, parameterMapList[ i ] ); - } - catch( itk::ExceptionObject &e ) - { - itkExceptionMacro( << "Errors occurred during registration: " << e.what() ); - } - - if( isError == -2 ) - { - itkExceptionMacro( << "Errors occurred during registration: Output directory does not exist." ); - } - - if( isError != 0 ) - { - itkExceptionMacro( << "Uncought errors occurred during registration." ); - } - - // Get the transform, the fixedImage and the movingImage - // in order to put it in the next registration - transform = elastix->GetFinalTransform(); - fixedImageContainer = elastix->GetFixedImageContainer(); - movingImageContainer = elastix->GetMovingImageContainer(); - fixedMaskContainer = elastix->GetFixedMaskContainer(); - movingMaskContainer = elastix->GetMovingMaskContainer(); - resultImageContainer = elastix->GetResultImageContainer(); - fixedImageOriginalDirection = elastix->GetOriginalFixedImageDirectionFlat(); - - TransformParameterMapList.push_back( elastix->GetTransformParametersMap() ); - - // Set initial transform to an index number instead of a parameter filename - if( i > 0 ) - { - std::stringstream index; - index << ( i - 1 ); - TransformParameterMapList[ i ][ "InitialTransformParametersFileName" ][ 0 ] = index.str(); - } - } // End loop over registrations - - // Save result image - if( resultImageContainer.IsNotNull() && resultImageContainer->Size() > 0 ) - { - this->GraftOutput( "ResultImage", resultImageContainer->ElementAt( 0 ) ); - } - - // Save parameter map - ParameterObject::Pointer TransformParameters = ParameterObject::New(); - TransformParameters->SetParameterMapList( TransformParameterMapList ); - this->SetOutput( "TransformParameterObject", static_cast< itk::DataObject* >( TransformParameters ) ); - - // Close the modules - ElastixMainType::UnloadComponents(); -} - -template< typename TFixedImage, typename TMovingImage > -void -ElastixFilter< TFixedImage, TMovingImage > -::SetParameterObject( ParameterObjectPointer parameterObject ) -{ - this->SetInput( "ParameterObject", static_cast< itk::DataObject* >( parameterObject ) ); -} - -template< typename TFixedImage, typename TMovingImage > -typename selx::ElastixFilter< TFixedImage, TMovingImage >::ParameterObjectPointer -ElastixFilter< TFixedImage, TMovingImage > -::GetTransformParameters( void ) -{ - // Make sure the transform parameters are up to date - this->Update(); - - return static_cast< ParameterObject* >( itk::ProcessObject::GetOutput( "TransformParameterObject" ) ); -} - -template< typename TFixedImage, typename TMovingImage > -void -ElastixFilter< TFixedImage, TMovingImage > -::SetFixedImage( FixedImagePointer fixedImage ) -{ - // Free references to fixed images that has already been set - this->RemoveFixedImages(); - - this->SetInput( "FixedImage", static_cast< itk::DataObject* >( fixedImage ) ); -} - -template< typename TFixedImage, typename TMovingImage > -void -ElastixFilter< TFixedImage, TMovingImage > -::SetFixedImage( DataObjectContainerPointer fixedImages ) -{ - if( fixedImages->Size() == 0 ) - { - itkExceptionMacro( "Cannot set fixed images from empty container.") - } - - // Free references to fixed images that has already been set - this->RemoveFixedImages(); - - // The first image will be used as the "FixedImage" required input. - // The rest of the images will be appended to the input container - // suffixed with _1, _2, etc. This allows us to read out only the - // fixed images for elastix fixed image container at a later stage - DataObjectContainerIterator fixedImageIterator = fixedImages->Begin(); - this->SetInput( "FixedImage", fixedImageIterator->Value() ); - ++fixedImageIterator; - - while( fixedImageIterator != fixedImages->End() ) - { - this->AddInputAutoIncrementName( "FixedImage", fixedImageIterator->Value() ); - ++fixedImageIterator; - } -} - -template< typename TFixedImage, typename TMovingImage > -void -ElastixFilter< TFixedImage, TMovingImage > -::AddFixedImage( FixedImagePointer fixedImage ) -{ - if( !this->HasInput( "FixedImage") ) - { - this->SetFixedImage( fixedImage ); - } - else - { - this->AddInputAutoIncrementName( "FixedImage", static_cast< itk::DataObject* >( fixedImage ) ); - } -} - -template< typename TFixedImage, typename TMovingImage > -void -ElastixFilter< TFixedImage, TMovingImage > -::SetMovingImage( MovingImagePointer movingImage ) -{ - // Free references to moving images that has already been set - this->RemoveMovingImages(); - - this->SetInput( "MovingImage", static_cast< itk::DataObject* >( movingImage ) ); -} - -template< typename TFixedImage, typename TMovingImage > -void -ElastixFilter< TFixedImage, TMovingImage > -::SetMovingImage( DataObjectContainerPointer movingImages ) -{ - if( movingImages->Size() == 0 ) - { - itkExceptionMacro( "Cannot set moving images from empty container.") - } - - // Free references to fixed images that has already been set - this->RemoveMovingImages(); - - // The first image will be used as the "MovingImage" required input. - // The rest of the images will be appended to the input container - // suffixed with _1, _2, etc. This allows us to read out only the - // moving images for elastix moving image container at a later stage - DataObjectContainerIterator movingImageIterator = movingImages->Begin(); - this->SetInput( "MovingImage", movingImageIterator->Value() ); - ++movingImageIterator; - - while( movingImageIterator != movingImages->End() ) - { - this->AddInputAutoIncrementName( "MovingImage", static_cast< itk::DataObject* >( movingImageIterator->Value() ) ); - ++movingImageIterator; - } -} - -template< typename TFixedImage, typename TMovingImage > -void -ElastixFilter< TFixedImage, TMovingImage > -::AddMovingImage( MovingImagePointer movingImage ) -{ - if( !this->HasInput( "MovingImage") ) - { - this->SetMovingImage( movingImage ); - } - else - { - this->AddInputAutoIncrementName( "MovingImage", static_cast< itk::DataObject* >( movingImage ) ); - } -} - - -template< typename TFixedImage, typename TMovingImage > -void -ElastixFilter< TFixedImage, TMovingImage > -::SetFixedMask( FixedImagePointer fixedMask ) -{ - this->SetInput( "FixedMask", static_cast< itk::DataObject* >( fixedMask ) ); -} - -template< typename TFixedImage, typename TMovingImage > -void -ElastixFilter< TFixedImage, TMovingImage > -::SetMovingMask( MovingImagePointer movingMask ) -{ - this->SetInput( "MovingMask", static_cast< itk::DataObject* >( movingMask ) ); -} - -/* - * Adds a named input to the first null position in the input list - * Expands the list memory if necessary - */ -template< typename TFixedImage, typename TMovingImage > -void -ElastixFilter< TFixedImage, TMovingImage > -::AddInputAutoIncrementName( DataObjectIdentifierType key, itk::DataObject* input ) -{ - for ( unsigned idx = 0; idx < this->GetNumberOfIndexedInputs(); ++idx ) - { - if ( !this->GetInput( idx ) ) - { - key += this->MakeNameFromInputIndex( idx ); - this->SetInput( key, input ); - return; - } - } - - key += this->MakeNameFromInputIndex( this->GetNumberOfIndexedInputs() ); - this->SetInput( key, input ); - return; -} - -template< typename TFixedImage, typename TMovingImage > -bool -ElastixFilter< TFixedImage, TMovingImage > -::IsFixedImage( DataObjectIdentifierType key ) -{ - return std::strncmp( "FixedImage", key.c_str(), 10 ) == 0; -} - -template< typename TFixedImage, typename TMovingImage > -bool -ElastixFilter< TFixedImage, TMovingImage > -::IsMovingImage( DataObjectIdentifierType key ) -{ - return std::strncmp( "MovingImage", key.c_str(), 11 ) == 0; -} - -template< typename TFixedImage, typename TMovingImage > -void -ElastixFilter< TFixedImage, TMovingImage > -::RemoveFixedImages( void ) -{ - // Free references to fixed images that has already been set - InputNameArrayType inputNames = this->GetInputNames(); - for( unsigned int i = 0; i < inputNames.size(); ++i ) - { - if ( this->IsFixedImage( inputNames[ i ] ) ) - { - this->RemoveInput( inputNames[ i ] ); - } - } -} - -template< typename TFixedImage, typename TMovingImage > -void -ElastixFilter< TFixedImage, TMovingImage > -::RemoveMovingImages( void ) -{ - // Free references to fixed images that has already been set - InputNameArrayType inputNames = this->GetInputNames(); - for( unsigned int i = 0; i < inputNames.size(); ++i ) - { - if ( this->IsMovingImage( inputNames[ i ] ) ) - { - this->RemoveInput( inputNames[ i ] ); - } - } -} - -} // namespace selx - -#endif // ElastixFilter_hxx \ No newline at end of file diff --git a/Modules/Components/Elastix/include/elxTransformixFilter.h b/Modules/Components/Elastix/include/elxTransformixFilter.h deleted file mode 100644 index 563cd62bb7ea8ebef973cdcf9e6c1dd049ec058f..0000000000000000000000000000000000000000 --- a/Modules/Components/Elastix/include/elxTransformixFilter.h +++ /dev/null @@ -1,115 +0,0 @@ -#ifndef TransformixFilter_h -#define TransformixFilter_h - -// ITK -#include "itkImageSource.h" - -// Transformix -#include "elxTransformixMain.h" - -// SuperElastix -#include "elxMacro.h" -#include "elxParameterObject.h" - -namespace selx { - -template< typename TInputImage > -class TransformixFilter : public itk::ImageSource< TInputImage > -{ -public: - - elxNewMacro( TransformixFilter, itk::ImageSource ); - - typedef elastix::TransformixMain TransformixMainType; - typedef TransformixMainType::Pointer TransformixMainPointer; - typedef TransformixMainType::ArgumentMapType ArgumentMapType; - typedef ArgumentMapType::value_type ArgumentMapEntryType; - - typedef itk::ProcessObject::DataObjectIdentifierType DataObjectIdentifierType; - typedef TransformixMainType::DataObjectContainerType DataObjectContainerType; - typedef TransformixMainType::DataObjectContainerPointer DataObjectContainerPointer; - - typedef ParameterObject::ParameterMapListType ParameterMapListType; - typedef ParameterObject::ParameterMapType ParameterMapType; - typedef ParameterObject::ParameterVectorType ParameterVectorType; - typedef typename ParameterObject::Pointer ParameterObjectPointer; - typedef typename ParameterObject::ConstPointer ParameterObjectConstPointer; - - typedef typename TInputImage::Pointer InputImagePointer; - - void SetInputImage( InputImagePointer inputImage ); - - void SetTransformParameterObject( ParameterObjectPointer parameterObject ); - ParameterObjectPointer GetTransformParameters( void ); - - itkSetMacro( ComputeSpatialJacobian, bool ); - itkGetConstMacro( ComputeSpatialJacobian, bool ); - itkBooleanMacro( ComputeSpatialJacobian ); - - itkSetMacro( ComputeDeterminantOfSpatialJacobian, bool ); - itkGetConstMacro( ComputeDeterminantOfSpatialJacobian, bool ); - itkBooleanMacro( ComputeDeterminantOfSpatialJacobian ); - - itkSetMacro( ComputeDeformationField, bool ); - itkGetConstMacro( ComputeDeformationField, bool ); - itkBooleanMacro( ComputeDeformationField ); - - itkSetMacro( PointSetFileName, std::string ); - itkGetConstMacro( PointSetFileName, std::string ); - void RemovePointSetFileName() { this->m_PointSetFileName = std::string(); }; - - itkSetMacro( OutputDirectory, std::string ); - itkGetConstMacro( OutputDirectory, std::string ); - void RemoveOutputDirectory() { this->m_OutputDirectory = std::string(); }; - - void SetLogFileName( std::string logFileName ) - { - this->m_LogFileName = logFileName; - this->LogToFileOn(); - this->Modified(); - } - - itkGetConstMacro( LogFileName, std::string ); - - void RemoveLogFileName( void ) { - this->m_LogFileName = std::string(); - this->LogToFileOff(); - }; - - itkSetMacro( LogToConsole, bool ); - itkGetConstMacro( LogToConsole, bool ); - itkBooleanMacro( LogToConsole ); - - itkSetMacro( LogToFile, bool ); - itkGetConstMacro( LogToFile, bool ); - itkBooleanMacro( LogToFile ); - -protected: - - void GenerateData( void ) ITK_OVERRIDE; - -private: - - TransformixFilter(); - - bool m_ComputeSpatialJacobian; - bool m_ComputeDeterminantOfSpatialJacobian; - bool m_ComputeDeformationField; - std::string m_PointSetFileName; - - std::string m_OutputDirectory; - std::string m_LogFileName; - - bool m_LogToConsole; - bool m_LogToFile; - - -}; - -} // namespace selx - -#ifndef ITK_MANUAL_INSTANTIATION -#include "elxTransformixFilter.hxx" -#endif - -#endif // TransformixFilter_h \ No newline at end of file diff --git a/Modules/Components/Elastix/include/elxTransformixFilter.hxx b/Modules/Components/Elastix/include/elxTransformixFilter.hxx deleted file mode 100644 index eb47dd85600340b822723d7930e0b15f657bd2e6..0000000000000000000000000000000000000000 --- a/Modules/Components/Elastix/include/elxTransformixFilter.hxx +++ /dev/null @@ -1,206 +0,0 @@ -#ifndef TransformixFilter_hxx -#define TransformixFilter_hxx - -namespace selx { - -template< typename TInputImage > -TransformixFilter< TInputImage > -::TransformixFilter( void ) -{ - this->AddRequiredInputName( "TransformParameterObject"); - - this->SetPrimaryInputName( "InputImage" ); - this->SetPrimaryOutputName( "ResultImage" ); - - this->ComputeSpatialJacobianOff(); - this->ComputeDeterminantOfSpatialJacobianOff(); - this->ComputeDeformationFieldOff(); - this->m_PointSetFileName = std::string(); - - this->m_OutputDirectory = std::string(); - this->m_LogFileName = std::string(); - - this->LogToConsoleOff(); - this->LogToFileOff(); -} - -template< typename TInputImage > -void -TransformixFilter< TInputImage > -::GenerateData( void ) -{ - // Assert that at least one output has been requested - if( !this->HasInput( "InputImage" ) && - !this->GetComputeSpatialJacobian() && - !this->GetComputeDeterminantOfSpatialJacobian() && - !this->GetComputeDeformationField() && - this->GetPointSetFileName().empty() ) - { - itkExceptionMacro( << "Expected at least one of SetInputImage(), ComputeSpatialJacobianOn(), " - << "ComputeDeterminantOfSpatialJacobianOn(), SetPointSetFileName() or " ); - } - - // Check if an output directory is needed - // TODO: Change behaviour upstream to have transformix save all output to its resultImageContainer - if( ( this->GetComputeSpatialJacobian() || - this->GetComputeDeterminantOfSpatialJacobian() || - this->GetComputeDeformationField() || - !this->GetPointSetFileName().empty() || - this->GetLogToFile() ) && - ( this->GetOutputDirectory().empty() ) ) - { - itkExceptionMacro( << "The requested outputs require an output directory to be specified." - << "Use SetOutputDirectory()." ) - } - - if( ( this->GetComputeSpatialJacobian() || - this->GetComputeDeterminantOfSpatialJacobian() || - this->GetComputeDeformationField() || - !this->GetPointSetFileName().empty() || - this->GetLogToFile() ) && - !itksys::SystemTools::FileExists( this->GetOutputDirectory() ) ) - { - itkExceptionMacro( "Output directory \"" << this->GetOutputDirectory() << "\" does not exist." ) - } - - // Transformix uses "-def" for path to point sets AND as flag for writing deformatin field - // TODO: Change behaviour upstream: Split into seperate arguments - if( this->GetComputeDeformationField() && !this->GetPointSetFileName().empty() ) - { - itkExceptionMacro( << "For backwards compatibility, only one of ComputeDeformationFieldOn() or SetPointSetFileName() can be " - << "active at any one time." ) - } - - // Setup argument map which transformix uses internally ito figure out what needs to be done - ArgumentMapType argumentMap; - if( this->GetOutputDirectory().empty() ) { - // There must be an "-out", this is checked later in the code - argumentMap.insert( ArgumentMapEntryType( "-out", "output_path_not_set" ) ); - } - else - { - argumentMap.insert( ArgumentMapEntryType( "-out", this->GetOutputDirectory() ) ); - } - - if( this->GetComputeSpatialJacobian() ) - { - argumentMap.insert( ArgumentMapEntryType( "-jacmat", "all" ) ); - } - - if( this->GetComputeDeterminantOfSpatialJacobian() ) - { - argumentMap.insert( ArgumentMapEntryType( "-jac", "all" ) ); - } - - if( this->GetComputeDeformationField() ) - { - argumentMap.insert( ArgumentMapEntryType( "-def" , "all" ) ); - } - - if( !this->GetPointSetFileName().empty() ) - { - argumentMap.insert( ArgumentMapEntryType( "-def", this->GetPointSetFileName() ) ); - } - - // Setup xout - std::string logFileName; - if( this->GetLogToFile() ) - { - if( this->GetOutputDirectory().empty() ) - { - itkExceptionMacro( "LogToFileOn() requires an output directory to be specified. Use SetOutputDirectory().") - } - - if( this->GetOutputDirectory().back() != '/' || this->GetOutputDirectory().back() != '\\' ) - { - this->SetOutputDirectory( this->GetOutputDirectory() + "/" ); - } - - if( this->GetLogFileName().empty() ) - { - logFileName = this->GetOutputDirectory() + "transformix.log"; - } - else - { - logFileName = this->GetOutputDirectory() + this->GetLogFileName(); - } - } - - if( elx::xoutSetup( logFileName.c_str(), this->GetLogToFile(), this->GetLogToConsole() ) ) - { - itkExceptionMacro( "ERROR while setting up xout" ); - } - - // Instantiate transformix - TransformixMainPointer transformix = TransformixMainType::New(); - - // Setup image containers - DataObjectContainerPointer inputImageContainer = 0; - DataObjectContainerPointer resultImageContainer = 0; - - if( this->HasInput( "InputImage" ) ) { - DataObjectContainerPointer inputImageContainer = DataObjectContainerType::New(); - inputImageContainer->CreateElementAt( 0 ) = this->GetInput("InputImage"); - transformix->SetInputImageContainer( inputImageContainer ); - transformix->SetResultImageContainer( resultImageContainer ); - } - - // Get ParameterMap - ParameterObjectConstPointer transformParameterObject = static_cast< const ParameterObject* >( this->GetInput( "TransformParameterObject" ) ); - ParameterMapListType transformParameterMapList = transformParameterObject->GetParameterMapList(); - - // Run transformix - unsigned int isError = 0; - try - { - isError = transformix->Run( argumentMap, transformParameterMapList ); - } - catch( itk::ExceptionObject &e ) - { - itkExceptionMacro( << "Errors occured during registration: " << e.what() ); - } - - if( isError != 0 ) - { - itkExceptionMacro( << "Uncought errors occured during registration." ); - } - - // Save result image - resultImageContainer = transformix->GetResultImageContainer(); - if( resultImageContainer.IsNotNull() && resultImageContainer->Size() > 0 ) - { - std::cout << "Setting result image: " << resultImageContainer->ElementAt( 0 ) << std::endl; - this->GraftOutput( "ResultImage", resultImageContainer->ElementAt( 0 ) ); - } - - // Clean up - TransformixMainType::UnloadComponents(); -} - -template< typename TInputImage > -void -TransformixFilter< TInputImage > -::SetInputImage( InputImagePointer inputImage ) -{ - this->SetInput( "InputImage", static_cast< itk::DataObject* >( inputImage ) ); -} - -template< typename TInputImage > -void -TransformixFilter< TInputImage > -::SetTransformParameterObject( ParameterObjectPointer parameterObject ) -{ - this->SetInput( "TransformParameterObject", static_cast< itk::DataObject* >( parameterObject ) ); -} - -template< typename TInputImage > -typename selx::TransformixFilter< TInputImage >::ParameterObjectPointer -TransformixFilter< TInputImage > -::GetTransformParameters( void ) -{ - return static_cast< ParameterObject* >( this->GetInput( "TransformParameterObject" ) ); -} - -} // namespace selx - -#endif // TransformixFilter_hxx \ No newline at end of file diff --git a/Modules/Core/ModuleCore.cmake b/Modules/Core/ModuleCore.cmake index e2d6c9d582c0696e561d67440480705e20e673f9..f88315ebceaab6c18f8a919098e7e95d5b7b2952 100644 --- a/Modules/Core/ModuleCore.cmake +++ b/Modules/Core/ModuleCore.cmake @@ -12,13 +12,19 @@ file(GLOB ${MODULE}_HEADER_FILES "${${MODULE}_SOURCE_DIR}/*/include/*.*") #@Kasper: file GLOB is generally disencouraged for source files (missing files are not detected and CMake doesn't know if the project has to be updated when due to a checkout extra source files are in the tree), but since this I think is not really an issue for header files... #I read: CMake will figure out that they're headers; it won't try to build them. http://stackoverflow.com/questions/8316104/specify-how-cmake-creates-visual-studio-project - - # Export libraries set( ${MODULE}_LIBRARIES ${MODULE} ) +# Export tests +set( ${MODULE}_TESTS + elxBlueprintTest.cxx + elxComponentFactoryTest.cxx + elxComponentInterfaceTest.cxx + elxOverlordTest.cxx +) + # Module source files set( ${MODULE}_SOURCE_FILES ${${MODULE}_SOURCE_DIR}/Blueprints/src/elxBlueprint.cxx @@ -28,7 +34,5 @@ set( ${MODULE}_SOURCE_FILES ) # Compile library - add_library( ${MODULE} STATIC "${${MODULE}_SOURCE_FILES}" ${${MODULE}_HEADER_FILES} ) - target_link_libraries( ${MODULE} ${ELASTIX_LIBRARIES} ) diff --git a/Modules/Core/ParameterObject/include/elxParameterObject.h b/Modules/Core/ParameterObject/include/elxParameterObject.h deleted file mode 100644 index 9cb838f17127694bfdf312f8f9412578e57c40a8..0000000000000000000000000000000000000000 --- a/Modules/Core/ParameterObject/include/elxParameterObject.h +++ /dev/null @@ -1,54 +0,0 @@ -#ifndef ParameterObject_h -#define ParameterObject_h - -#include "itkObjectFactory.h" -#include "itkDataObject.h" - -#include "elxMacro.h" - -namespace selx { - -class ParameterObject : public itk::DataObject -{ -public: - - elxNewMacro( ParameterObject, itk::DataObject ); - - typedef std::string ParameterKeyType; - typedef std::string ParameterValueType; - typedef std::vector< ParameterKeyType > ParameterVectorType; - typedef std::map< ParameterKeyType, ParameterVectorType > ParameterMapType; - typedef std::vector< ParameterMapType > ParameterMapListType; - - void SetParameterMap( ParameterMapType parameterMap ) - { - ParameterMapListType parameterMapList; - parameterMapList.push_back( parameterMap ); - this->SetParameterMapList( parameterMapList ); - } - - void SetParameterMapList( ParameterMapListType parameterMapList ) - { - this->m_ParameterMapList = parameterMapList; - }; - - ParameterMapListType& GetParameterMapList( void ) - { - this->Modified(); - return this->m_ParameterMapList; - }; - - const ParameterMapListType& GetParameterMapList( void ) const - { - return this->m_ParameterMapList; - }; - -private: - - ParameterMapListType m_ParameterMapList; - -}; - -} // namespace elx - -#endif // #define ParameterMap_h \ No newline at end of file diff --git a/SuperBuild/CMakeLists.txt b/SuperBuild/CMakeLists.txt index 097964a8c4670be97270b4a53c00ffb1ed30f7b9..ce4016f2f4d46fd5a84eb46ec016fe54e159da0e 100644 --- a/SuperBuild/CMakeLists.txt +++ b/SuperBuild/CMakeLists.txt @@ -59,10 +59,6 @@ endif() # --------------------------------------------------------------------- # Build Old Elastix -set( ELASTIX_VERSION_MAJOR "4" ) -set( ELASTIX_VERSION_MINOR "8" ) -set( ELASTIX_VERSION_STRING "${ELASTIX_VERSION_MAJOR}.${ELASTIX_VERSION_MINOR}" ) - mark_as_advanced( SUPERELASTIX_BUILD_ELASTIX ) option( SUPERELASTIX_BUILD_ELASTIX "Build support for Elastix ${ELASTIX_VERSION_STRING}." ON ) if( SUPERELASTIX_BUILD_ELASTIX ) @@ -70,10 +66,8 @@ if( SUPERELASTIX_BUILD_ELASTIX ) option( USE_SYSTEM_ELASTIX "Use an installed version of Elastix." OFF ) if( USE_SYSTEM_ELASTIX ) if( NOT EXISTS ${ELASTIX_USE_FILE} ) - # Expose CMake variable to user - set( ELASTIX_USE_FILE ) - # Stop the build - message( FATAL_ERROR "Please point ELASTIX_USE_FILE to your systems UseElastix.cmake file." ) + set( ELASTIX_USE_FILE "NOT_FOUND" CACHE PATH "Absolute path to UseElastix.cmake in the root of the elastix build tree." ) + message( FATAL_ERROR "Could not find the ELASTIX_USE_FILE (${ELASTIX_USE_FILE}). Use the SuperBuild or manually point the ELASTIX_USE_FILE CMake variable to the UseElastix.cmake file in the root of your elastix build tree." ) endif() else() include( ExternalElastix ) diff --git a/SuperBuild/ExternalElastix.cmake b/SuperBuild/ExternalElastix.cmake index 8a922598183686109bb27a7e9b283e18fb369d56..a9cbc55d080e780de9e17cfdee164d9b98587ba9 100644 --- a/SuperBuild/ExternalElastix.cmake +++ b/SuperBuild/ExternalElastix.cmake @@ -1,11 +1,11 @@ set( proj Elastix ) -set( ELASTIX_REPOSITORY https://github.com/mstaring/elastix.git ) -set( ELASTIX_TAG c35842cd0152d8fd2894e7c6706d2dd8396f0fed ) +set( ELASTIX_REPOSITORY https://svn.bigr.nl/elastix/trunkpublic/ ) +set( ELASTIX_REVISION 5186 ) ExternalProject_Add( ${proj} - GIT_REPOSITORY ${ELASTIX_REPOSITORY} - GIT_TAG ${ELASTIX_TAG} + SVN_REPOSITORY ${ELASTIX_REPOSITORY} + SVN_REVISION -r ${ELASTIX_REVISION} UPDATE_COMMAND "" SOURCE_DIR ${proj} BINARY_DIR ${proj}-build diff --git a/Testing/Unit/CMakeLists.txt b/Testing/Unit/CMakeLists.txt index 93f35c58d08c650d6f90eb5f873d6cd501f35d8b..274f50751c3ee268fbd9b8e3cdc17afd160b043d 100644 --- a/Testing/Unit/CMakeLists.txt +++ b/Testing/Unit/CMakeLists.txt @@ -1,18 +1,9 @@ # --------------------------------------------------------------------- -# To add a test to the build system, append it to the list below. +# To add a test to the build system, append it to the module's list of +# tests in the module's CMake file (e.g. "Modules/Core/ModuleCore.cmake"). # Any GoogleTests in these files are automatically added to CTest and # the elastix dashboard. -set( ElastixUnitTestFilenames - elxBlueprintTest.cxx - elxElastixFilterTest.cxx - elxTransformixFilterTest.cxx - elxComponentFactoryTest.cxx - elxComponentInterfaceTest.cxx - elxOverlordTest.cxx - elxitkImageFilterTest.cxx -) - # --------------------------------------------------------------------- # Options if( SUPERELASTIX_BUILD_LONG_TESTS ) @@ -37,6 +28,7 @@ endif() # --------------------------------------------------------------------- # Build test data manager + configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/elxDataDirectories.h.in ${CMAKE_CURRENT_BINARY_DIR}/elxDataDirectories.h @@ -52,13 +44,13 @@ list( APPEND TEST_LIBRARIES # --------------------------------------------------------------------- # Build tests -message( STATUS "ITK_LIBRARIES: ${ITK_LIBRARIES}" ) -foreach( ElastixUnitTestFilename ${ElastixUnitTestFilenames} ) + +foreach( SuperElastixUnitTestFilename ${SUPERELASTIX_TESTS} ) # Build tests executables - string( REPLACE ".cxx" "" ElastixUnitTest ${ElastixUnitTestFilename} ) - add_executable( ${ElastixUnitTest} ${ElastixUnitTestFilename} ) - target_link_libraries( "${ElastixUnitTest}" ${SUPERELASTIX_LIBRARIES} ${ITK_LIBRARIES} ${TEST_LIBRARIES} ) + string( REPLACE ".cxx" "" SuperElastixUnitTest ${SuperElastixUnitTestFilename} ) + add_executable( ${SuperElastixUnitTest} ${SuperElastixUnitTestFilename} ) + target_link_libraries( "${SuperElastixUnitTest}" ${SUPERELASTIX_LIBRARIES} ${ITK_LIBRARIES} ${TEST_LIBRARIES} ) # Add GoogleTest to CTest - GTEST_ADD_TESTS( ${ElastixUnitTest} "--gtest_output=xml:${CMAKE_BINARY_DIR}/Testing/Unit/${ElastixUnitTest}.xml" ${ElastixUnitTestFilename} ) + GTEST_ADD_TESTS( ${SuperElastixUnitTest} "--gtest_output=xml:${CMAKE_BINARY_DIR}/Testing/Unit/${SuperElastixUnitTest}.xml" ${SuperElastixUnitTestFilename} ) endforeach() diff --git a/Testing/Unit/elxElastixFilterTest.cxx b/Testing/Unit/elxElastixFilterTest.cxx index 50ab660e6cb6b9c8066f48950460032ba6a331d2..9c510eaa966b5516ea7bc470ce63d5eb08f1c44e 100644 --- a/Testing/Unit/elxElastixFilterTest.cxx +++ b/Testing/Unit/elxElastixFilterTest.cxx @@ -7,77 +7,17 @@ #include "elxDataManager.h" #include "gtest/gtest.h" -// TODO: -// - In the following examples, why do we need to call update on both reader and elastixFilter -// before using the writer? Should the call to update on the writer not be propagated upstream? -// (See http://itk.org/Wiki/ITK/Examples/Segmentation/OtsuThresholdImageFilter which defeats the whole -// purpose of having a pipeline, no?) -// - Compare result images against baseline -// - SetUp() runs before every test. Does GoogleTest have a function that is called once before tests are run? +// TODO: Check that desired results are actually obtained, e.g. by comparing result +// images against a baseline. Right now we only check that no errors are thrown. - -using namespace selx; +using namespace elastix; class ElastixFilterTest : public ::testing::Test { protected: typedef DataManager DataManagerType; - - // Parameter typedefs - typedef ParameterObject::ParameterVectorType ParameterVectorType; - typedef ParameterObject::ParameterMapType ParameterMapType; - - ParameterMapType parameterMap; - ParameterObject::Pointer nonRigidParameterObject; - ParameterObject::Pointer nonRigidParameterObject3D; - ParameterObject::Pointer groupwiseParameterObject; - ParameterObject::ConstPointer transformParameterObject; - - virtual void SetUp() - { - // Nonrigid ParameterMap - parameterMap = ParameterMapType(); - - // Images - parameterMap[ "FixedInternalImagePixelType" ] = ParameterVectorType( 1, "float" ); - parameterMap[ "FixedImageDimension" ] = ParameterVectorType( 1, "2" ); - parameterMap[ "MovingInternalImagePixelType" ] = ParameterVectorType( 1, "float" ); - parameterMap[ "MovingImageDimension" ] = ParameterVectorType( 1, "2" ); - parameterMap[ "ResultImagePixelType" ] = ParameterVectorType( 1, "float" ); - - // Common components - parameterMap[ "FixedImagePyramid" ] = ParameterVectorType( 1, "FixedSmoothingImagePyramid" ); - parameterMap[ "MovingImagePyramid" ] = ParameterVectorType( 1, "MovingSmoothingImagePyramid" ); - parameterMap[ "Interpolator"] = ParameterVectorType( 1, "LinearInterpolator"); - parameterMap[ "Optimizer" ] = ParameterVectorType( 1, "AdaptiveStochasticGradientDescent" ); - parameterMap[ "Resampler"] = ParameterVectorType( 1, "DefaultResampler" ); - parameterMap[ "ResampleInterpolator"] = ParameterVectorType( 1, "FinalLinearInterpolator" ); - parameterMap[ "FinalBSplineInterpolationOrder" ] = ParameterVectorType( 1, "2" ); - parameterMap[ "NumberOfResolutions" ] = ParameterVectorType( 1, "2" ); - - // Image Sampler - parameterMap[ "ImageSampler" ] = ParameterVectorType( 1, "RandomCoordinate" ); - parameterMap[ "NumberOfSpatialSamples"] = ParameterVectorType( 1, "2048" ); - parameterMap[ "CheckNumberOfSamples" ] = ParameterVectorType( 1, "true" ); - parameterMap[ "MaximumNumberOfSamplingAttempts" ] = ParameterVectorType( 1, "8" ); - parameterMap[ "NewSamplesEveryIteration" ] = ParameterVectorType( 1, "true"); - - // Optimizer - parameterMap[ "NumberOfSamplesForExactGradient" ] = ParameterVectorType( 1, "4096" ); - parameterMap[ "DefaultPixelValue" ] = ParameterVectorType( 1, "0" ); - parameterMap[ "AutomaticParameterEstimation" ] = ParameterVectorType( 1, "true" ); - - // Output - parameterMap[ "WriteResultImage" ] = ParameterVectorType( 1, "true" ); - parameterMap[ "ResultImageFormat" ] = ParameterVectorType( 1, "nii" ); - - // Registration - parameterMap[ "Registration" ] = ParameterVectorType( 1, "MultiResolutionRegistration" ); - parameterMap[ "Transform" ] = ParameterVectorType( 1, "EulerTransform" ); - parameterMap[ "Metric" ] = ParameterVectorType( 1, "AdvancedMattesMutualInformation" ); - parameterMap[ "MaximumNumberOfIterations" ] = ParameterVectorType( 1, "128" ); - } + typedef ParameterObject::ParameterValueVectorType ParameterValueVectorType; }; TEST_F( ElastixFilterTest, Instantiation ) @@ -87,7 +27,8 @@ TEST_F( ElastixFilterTest, Instantiation ) EXPECT_NO_THROW( ElastixFilterType::Pointer elastixFilter = ElastixFilterType::New() ); } -TEST_F( ElastixFilterTest, UpdateOnGetOutputEuler2D ) + +TEST_F( ElastixFilterTest, DefaultParameterObject2D ) { typedef itk::Image< float, 2 > ImageType; typedef itk::ImageFileReader< ImageType > ImageFileReaderType; @@ -98,22 +39,44 @@ TEST_F( ElastixFilterTest, UpdateOnGetOutputEuler2D ) ImageFileReaderType::Pointer fixedImageReader = ImageFileReaderType::New(); fixedImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20.png" ) ); - fixedImageReader->Update(); ImageFileReaderType::Pointer movingImageReader = ImageFileReaderType::New(); movingImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceR10X13Y17.png" ) ); - movingImageReader->Update(); - ParameterObject::Pointer eulerTransformParameterObject; - EXPECT_NO_THROW( eulerTransformParameterObject = ParameterObject::New() ); - EXPECT_NO_THROW( eulerTransformParameterObject->SetParameterMap( parameterMap ) ); + ElastixFilterType::Pointer elastixFilter; + + EXPECT_NO_THROW( elastixFilter = ElastixFilterType::New() ); + EXPECT_NO_THROW( elastixFilter->LogToConsoleOn() ); + EXPECT_NO_THROW( elastixFilter->SetFixedImage( fixedImageReader->GetOutput() ) ); + EXPECT_NO_THROW( elastixFilter->SetMovingImage( movingImageReader->GetOutput() ) ); + EXPECT_NO_THROW( elastixFilter->Update() ); +} + +TEST_F( ElastixFilterTest, UpdateOnGetOutputEuler2D ) +{ + ParameterObject::Pointer parameterObject; + EXPECT_NO_THROW( parameterObject = ParameterObject::New() ); + EXPECT_NO_THROW( parameterObject->SetParameterMap( "rigid" ) ); + + typedef itk::Image< float, 2 > ImageType; + typedef itk::ImageFileReader< ImageType > ImageFileReaderType; + typedef itk::ImageFileWriter< ImageType > ImageFileWriterType; + typedef ElastixFilter< ImageType, ImageType > ElastixFilterType; + + DataManagerType::Pointer dataManager = DataManagerType::New(); + + ImageFileReaderType::Pointer fixedImageReader = ImageFileReaderType::New(); + fixedImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20.png" ) ); + + ImageFileReaderType::Pointer movingImageReader = ImageFileReaderType::New(); + movingImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceR10X13Y17.png" ) ); ElastixFilterType::Pointer elastixFilter; EXPECT_NO_THROW( elastixFilter = ElastixFilterType::New() ); EXPECT_NO_THROW( elastixFilter->LogToConsoleOn() ); EXPECT_NO_THROW( elastixFilter->SetFixedImage( fixedImageReader->GetOutput() ) ); EXPECT_NO_THROW( elastixFilter->SetMovingImage( movingImageReader->GetOutput() ) ); - EXPECT_NO_THROW( elastixFilter->SetParameterObject( eulerTransformParameterObject ) ); + EXPECT_NO_THROW( elastixFilter->SetParameterObject( parameterObject ) ); // We try to write the image because simply calling GetOutput() will not result in an // error (a pointer is still passed even if elastix has not run, although the pointee is empty) @@ -125,6 +88,10 @@ TEST_F( ElastixFilterTest, UpdateOnGetOutputEuler2D ) TEST_F( ElastixFilterTest, UpdateOnGetTransformParametersEuler2D ) { + ParameterObject::Pointer parameterObject; + EXPECT_NO_THROW( parameterObject = ParameterObject::New() ); + EXPECT_NO_THROW( parameterObject->SetParameterMap( "rigid" ) ); + typedef itk::Image< float, 2 > ImageType; typedef itk::ImageFileReader< ImageType > ImageFileReaderType; typedef itk::ImageFileWriter< ImageType > ImageFileWriterType; @@ -134,15 +101,9 @@ TEST_F( ElastixFilterTest, UpdateOnGetTransformParametersEuler2D ) ImageFileReaderType::Pointer fixedImageReader = ImageFileReaderType::New(); fixedImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20.png" ) ); - fixedImageReader->Update(); ImageFileReaderType::Pointer movingImageReader = ImageFileReaderType::New(); movingImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceR10X13Y17.png" ) ); - movingImageReader->Update(); - - ParameterObject::Pointer eulerTransformParameterObject; - EXPECT_NO_THROW( eulerTransformParameterObject = ParameterObject::New() ); - EXPECT_NO_THROW( eulerTransformParameterObject->SetParameterMap( parameterMap ) ); ElastixFilterType::Pointer elastixFilter; ParameterObject::Pointer transformParameters; @@ -151,13 +112,26 @@ TEST_F( ElastixFilterTest, UpdateOnGetTransformParametersEuler2D ) EXPECT_NO_THROW( elastixFilter->LogToConsoleOn() ); EXPECT_NO_THROW( elastixFilter->SetFixedImage( fixedImageReader->GetOutput() ) ); EXPECT_NO_THROW( elastixFilter->SetMovingImage( movingImageReader->GetOutput() ) ); - EXPECT_NO_THROW( elastixFilter->SetParameterObject( eulerTransformParameterObject ) ); - EXPECT_NO_THROW( transformParameters = elastixFilter->GetTransformParameters() ); - EXPECT_TRUE( transformParameters->GetParameterMapList()[ 0 ].size() > 0 ); + EXPECT_NO_THROW( elastixFilter->SetParameterObject( parameterObject ) ); + EXPECT_NO_THROW( transformParameters = elastixFilter->GetTransformParameterObject() ); + EXPECT_TRUE( transformParameters->GetParameterMap()[ 0 ].size() > 0 ); } -TEST_F( ElastixFilterTest, AffineWithMultipleFixedAndMovingImages2D ) +TEST_F( ElastixFilterTest, AffineWithDataObjectContainerInterface2D ) { + // TODO: Internal logic to automatically broadcast metric, sampler, + // interpolator and pyramids to match the number of metrics. Can do + // it in such a way that we are guaranteed to not mess up user settings? + ParameterObject::Pointer parameterObject; + EXPECT_NO_THROW( parameterObject = ParameterObject::New() ); + EXPECT_NO_THROW( parameterObject->SetParameterMap( "affine" ) ); + EXPECT_NO_THROW( parameterObject->GetParameterMap( 0 )[ "Registration" ] = ParameterValueVectorType( 1, "MultiMetricMultiResolutionRegistration" ) ); + EXPECT_NO_THROW( parameterObject->GetParameterMap( 0 )[ "Metric" ] = ParameterValueVectorType( 2, parameterObject->GetParameterMap( 0 )[ "Metric" ][ 0 ] ) ); + EXPECT_NO_THROW( parameterObject->GetParameterMap( 0 )[ "ImageSampler" ] = ParameterValueVectorType( 2, parameterObject->GetParameterMap( 0 )[ "ImageSampler" ][ 0 ] ) ); + EXPECT_NO_THROW( parameterObject->GetParameterMap( 0 )[ "Interpolator" ] = ParameterValueVectorType( 2, parameterObject->GetParameterMap( 0 )[ "Interpolator" ][ 0 ] ) ); + EXPECT_NO_THROW( parameterObject->GetParameterMap( 0 )[ "FixedImagePyramid" ] = ParameterValueVectorType( 2, parameterObject->GetParameterMap( 0 )[ "FixedImagePyramid" ][ 0 ] ) ); + EXPECT_NO_THROW( parameterObject->GetParameterMap( 0 )[ "MovingImagePyramid" ] = ParameterValueVectorType( 2, parameterObject->GetParameterMap( 0 )[ "MovingImagePyramid" ][ 0 ] ) ); + typedef itk::Image< float, 2 > ImageType; typedef itk::ImageFileReader< ImageType > ImageFileReaderType; typedef itk::ImageFileWriter< ImageType > ImageFileWriterType; @@ -169,35 +143,35 @@ TEST_F( ElastixFilterTest, AffineWithMultipleFixedAndMovingImages2D ) ImageFileReaderType::Pointer fixedImageReader0 = ImageFileReaderType::New(); fixedImageReader0->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20.png" ) ); - fixedImageReader0->Update(); ImageFileReaderType::Pointer fixedImageReader1 = ImageFileReaderType::New(); fixedImageReader1->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20.png" ) ); - fixedImageReader1->Update(); ImageFileReaderType::Pointer movingImageReader0 = ImageFileReaderType::New(); movingImageReader0->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceR10X13Y17S12.png" ) ); - movingImageReader0->Update(); ImageFileReaderType::Pointer movingImageReader1 = ImageFileReaderType::New(); movingImageReader1->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceR10X13Y17S12.png" ) ); - movingImageReader1->Update(); - - ParameterMapType affineTransformParameterMap = parameterMap; - affineTransformParameterMap[ "Transform" ] = ParameterVectorType( 1, "AffineTransform" ); - ParameterObject::Pointer affineTransformParameterObject; - EXPECT_NO_THROW( affineTransformParameterObject = ParameterObject::New() ); - EXPECT_NO_THROW( affineTransformParameterObject->SetParameterMap( affineTransformParameterMap ) ); + // We fill the first pair of fixed and moving images with zeros to be able + // to inspect if the subsequent pair is able to drive the registration + ImageType::Pointer fixedImage0 = fixedImageReader0->GetOutput(); + fixedImage0->Update(); + fixedImage0->DisconnectPipeline(); + fixedImage0->FillBuffer( 0.0 ); + ImageType::Pointer movingImage0 = movingImageReader0->GetOutput(); + movingImage0->Update(); + movingImage0->DisconnectPipeline(); + movingImage0->FillBuffer( 0.0 ); DataObjectContainerPointer fixedImages; EXPECT_NO_THROW( fixedImages = DataObjectContainerType::New() ); - EXPECT_NO_THROW( fixedImages->CreateElementAt( 0 ) = static_cast< itk::DataObject* >( fixedImageReader0->GetOutput() ) ); + EXPECT_NO_THROW( fixedImages->CreateElementAt( 0 ) = static_cast< itk::DataObject* >( fixedImage0 ) ); EXPECT_NO_THROW( fixedImages->CreateElementAt( 1 ) = static_cast< itk::DataObject* >( fixedImageReader1->GetOutput() ) ); DataObjectContainerPointer movingImages; EXPECT_NO_THROW( movingImages = DataObjectContainerType::New() ); - EXPECT_NO_THROW( movingImages->CreateElementAt( 0 ) = static_cast< itk::DataObject* >( movingImageReader0->GetOutput() ) ); + EXPECT_NO_THROW( movingImages->CreateElementAt( 0 ) = static_cast< itk::DataObject* >( movingImage0 ) ); EXPECT_NO_THROW( movingImages->CreateElementAt( 1 ) = static_cast< itk::DataObject* >( movingImageReader1->GetOutput() ) ); ElastixFilterType::Pointer elastixFilter; @@ -205,21 +179,92 @@ TEST_F( ElastixFilterTest, AffineWithMultipleFixedAndMovingImages2D ) EXPECT_NO_THROW( elastixFilter->LogToConsoleOn() ); EXPECT_NO_THROW( elastixFilter->SetFixedImage( fixedImages ) ); EXPECT_NO_THROW( elastixFilter->SetMovingImage( movingImages ) ); - EXPECT_NO_THROW( elastixFilter->SetParameterObject( affineTransformParameterObject ) ); + EXPECT_NO_THROW( elastixFilter->SetParameterObject( parameterObject ) ); - // TODO: This update should not be needed (see description above) - EXPECT_NO_THROW( elastixFilter->Update() ); + ImageFileWriterType::Pointer writer = ImageFileWriterType::New(); + EXPECT_NO_THROW( writer->SetFileName( dataManager->GetOutputFile( "AffineWithDataObjectContainerInterface2D.nii" ) ) ); + EXPECT_NO_THROW( writer->SetInput( elastixFilter->GetOutput() ) ); + EXPECT_NO_THROW( writer->Update() ); + + ParameterObject::Pointer transformParameterObject; + EXPECT_NO_THROW( transformParameterObject = elastixFilter->GetTransformParameterObject() ); +} + +TEST_F( ElastixFilterTest, AffineWithAddImagesInterface2D ) +{ + // TODO: Internal logic to automatically broadcast metric, sampler, + // interpolator and pyramids to match the number of metrics. Can do + // it in such a way that we are guaranteed to not mess up user settings? + ParameterObject::Pointer parameterObject; + EXPECT_NO_THROW( parameterObject = ParameterObject::New() ); + EXPECT_NO_THROW( parameterObject->SetParameterMap( "affine" ) ); + EXPECT_NO_THROW( parameterObject->GetParameterMap( 0 )[ "Registration" ] = ParameterValueVectorType( 1, "MultiMetricMultiResolutionRegistration" ) ); + EXPECT_NO_THROW( parameterObject->GetParameterMap( 0 )[ "Metric" ] = ParameterValueVectorType( 2, parameterObject->GetParameterMap( 0 )[ "Metric" ][ 0 ] ) ); + EXPECT_NO_THROW( parameterObject->GetParameterMap( 0 )[ "ImageSampler" ] = ParameterValueVectorType( 2, parameterObject->GetParameterMap( 0 )[ "ImageSampler" ][ 0 ] ) ); + EXPECT_NO_THROW( parameterObject->GetParameterMap( 0 )[ "Interpolator" ] = ParameterValueVectorType( 2, parameterObject->GetParameterMap( 0 )[ "Interpolator" ][ 0 ] ) ); + EXPECT_NO_THROW( parameterObject->GetParameterMap( 0 )[ "FixedImagePyramid" ] = ParameterValueVectorType( 2, parameterObject->GetParameterMap( 0 )[ "FixedImagePyramid" ][ 0 ] ) ); + EXPECT_NO_THROW( parameterObject->GetParameterMap( 0 )[ "MovingImagePyramid" ] = ParameterValueVectorType( 2, parameterObject->GetParameterMap( 0 )[ "MovingImagePyramid" ][ 0 ] ) ); + + typedef itk::Image< float, 2 > ImageType; + typedef itk::ImageFileReader< ImageType > ImageFileReaderType; + typedef itk::ImageFileWriter< ImageType > ImageFileWriterType; + typedef ElastixFilter< ImageType, ImageType > ElastixFilterType; + typedef ElastixFilterType::DataObjectContainerType DataObjectContainerType; + typedef ElastixFilterType::DataObjectContainerPointer DataObjectContainerPointer; + + DataManagerType::Pointer dataManager = DataManagerType::New(); + + ImageFileReaderType::Pointer fixedImageReader0 = ImageFileReaderType::New(); + fixedImageReader0->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20.png" ) ); + + ImageFileReaderType::Pointer fixedImageReader1 = ImageFileReaderType::New(); + fixedImageReader1->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20.png" ) ); + + ImageFileReaderType::Pointer movingImageReader0 = ImageFileReaderType::New(); + movingImageReader0->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceR10X13Y17S12.png" ) ); + + ImageFileReaderType::Pointer movingImageReader1 = ImageFileReaderType::New(); + movingImageReader1->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceR10X13Y17S12.png" ) ); + + // We fill the first pair of fixed and moving images with zeros to be able + // to inspect that the subsequent pair is really driving the registration + ImageType::Pointer fixedImage0 = fixedImageReader0->GetOutput(); + fixedImage0->Update(); + fixedImage0->DisconnectPipeline(); + fixedImage0->FillBuffer( 0.0 ); + ImageType::Pointer movingImage0 = movingImageReader0->GetOutput(); + movingImage0->Update(); + movingImage0->DisconnectPipeline(); + movingImage0->FillBuffer( 0.0 ); + + ElastixFilterType::Pointer elastixFilter; + EXPECT_NO_THROW( elastixFilter = ElastixFilterType::New() ); + EXPECT_NO_THROW( elastixFilter->LogToConsoleOn() ); + EXPECT_NO_THROW( elastixFilter->AddFixedImage( fixedImage0 ) ); + EXPECT_NO_THROW( elastixFilter->AddFixedImage( fixedImageReader1->GetOutput() ) ); + EXPECT_NO_THROW( elastixFilter->AddMovingImage( movingImage0 ) ); + EXPECT_NO_THROW( elastixFilter->AddMovingImage( movingImageReader1->GetOutput() ) ); + EXPECT_NO_THROW( elastixFilter->SetParameterObject( parameterObject ) ); ImageFileWriterType::Pointer writer = ImageFileWriterType::New(); - EXPECT_NO_THROW( writer->SetFileName( dataManager->GetOutputFile( "AffineWithMultipleFixedAndMovingImages2DResultImage.nii" ) ) ); + EXPECT_NO_THROW( writer->SetFileName( dataManager->GetOutputFile( "AffineWithAddImagesInterface2D.nii" ) ) ); EXPECT_NO_THROW( writer->SetInput( elastixFilter->GetOutput() ) ); EXPECT_NO_THROW( writer->Update() ); - EXPECT_NO_THROW( transformParameterObject = elastixFilter->GetTransformParameters() ); + ParameterObject::Pointer transformParameterObject; + EXPECT_NO_THROW( transformParameterObject = elastixFilter->GetTransformParameterObject() ); } TEST_F( ElastixFilterTest, TranslationWithPointSets2D ) { + ParameterObject::Pointer parameterObject; + EXPECT_NO_THROW( parameterObject = ParameterObject::New() ); + EXPECT_NO_THROW( parameterObject->SetParameterMap( "translation" ) ); + EXPECT_NO_THROW( parameterObject->GetParameterMap( 0 )[ "Registration" ] = ParameterValueVectorType( 1, "MultiMetricMultiResolutionRegistration" ) ); + EXPECT_NO_THROW( parameterObject->GetParameterMap( 0 )[ "Transform" ] = ParameterValueVectorType( 1, "TranslationTransform" ) ); + EXPECT_NO_THROW( parameterObject->GetParameterMap( 0 )[ "Metric" ].push_back( "CorrespondingPointsEuclideanDistanceMetric" ) ); + EXPECT_NO_THROW( parameterObject->GetParameterMap( 0 )[ "Metric0Weight"] = ParameterValueVectorType( 1, "0.0" ) ); + typedef itk::Image< float, 2 > ImageType; typedef itk::ImageFileReader< ImageType > ImageFileReaderType; typedef itk::ImageFileWriter< ImageType > ImageFileWriterType; @@ -228,56 +273,42 @@ TEST_F( ElastixFilterTest, TranslationWithPointSets2D ) DataManagerType::Pointer dataManager = DataManagerType::New(); // We generate the point sets manually - std::ofstream fixedMeshFile; - fixedMeshFile.open( dataManager->GetInputFile( "FixedMesh.pts" )); - fixedMeshFile << "point\n"; - fixedMeshFile << "1\n"; - fixedMeshFile << "128.0 128.0\n"; - fixedMeshFile.close(); - - std::ofstream movingMeshFile; - movingMeshFile.open( dataManager->GetInputFile( "MovingMesh.pts" )); - movingMeshFile << "point\n"; - movingMeshFile << "1\n"; - movingMeshFile << "115.0 111.0\n"; - movingMeshFile.close(); + std::ofstream fixedPointSetFile; + fixedPointSetFile.open( dataManager->GetInputFile( "FixedPointSet.pts" ) ); + fixedPointSetFile << "point\n"; + fixedPointSetFile << "1\n"; + fixedPointSetFile << "128.0 128.0\n"; + fixedPointSetFile.close(); + + std::ofstream movingPointSetFile; + movingPointSetFile.open( dataManager->GetInputFile( "MovingPointSet.pts" ) ); + movingPointSetFile << "point\n"; + movingPointSetFile << "1\n"; + movingPointSetFile << "115.0 111.0\n"; + movingPointSetFile.close(); ImageFileReaderType::Pointer fixedImageReader = ImageFileReaderType::New(); fixedImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20.png" ) ); - fixedImageReader->Update(); ImageFileReaderType::Pointer movingImageReader = ImageFileReaderType::New(); movingImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceShifted13x17y.png" ) ); - movingImageReader->Update(); - - ParameterMapType correspondingPointsParameterMap = parameterMap; - correspondingPointsParameterMap[ "Registration" ] = ParameterVectorType( 1, "MultiMetricMultiResolutionRegistration" ); - correspondingPointsParameterMap[ "Transform" ] = ParameterVectorType( 1, "TranslationTransform" ); - correspondingPointsParameterMap[ "Metric" ].push_back( "CorrespondingPointsEuclideanDistanceMetric" ); - correspondingPointsParameterMap[ "Metric0Weight"] = ParameterVectorType( 1, "0.0" ); - - ParameterObject::Pointer correspondingPointsParameterObject; - EXPECT_NO_THROW( correspondingPointsParameterObject = ParameterObject::New() ); - EXPECT_NO_THROW( correspondingPointsParameterObject->SetParameterMap( correspondingPointsParameterMap ) ); ElastixFilterType::Pointer elastixFilter; EXPECT_NO_THROW( elastixFilter = ElastixFilterType::New() ); EXPECT_NO_THROW( elastixFilter->LogToConsoleOn() ); EXPECT_NO_THROW( elastixFilter->SetFixedImage( fixedImageReader->GetOutput() ) ); - EXPECT_NO_THROW( elastixFilter->SetFixedMeshFileName( dataManager->GetInputFile( "FixedMesh.pts" ) ) ); + EXPECT_NO_THROW( elastixFilter->SetFixedPointSetFileName( dataManager->GetInputFile( "FixedPointSet.pts" ) ) ); EXPECT_NO_THROW( elastixFilter->SetMovingImage( movingImageReader->GetOutput() ) ); - EXPECT_NO_THROW( elastixFilter->SetMovingMeshFileName( dataManager->GetInputFile( "MovingMesh.pts" ) ) ); - EXPECT_NO_THROW( elastixFilter->SetParameterObject( correspondingPointsParameterObject ) ); - - // TODO: This update should not be needed (see description above) - EXPECT_NO_THROW( elastixFilter->Update() ); + EXPECT_NO_THROW( elastixFilter->SetMovingPointSetFileName( dataManager->GetInputFile( "MovingPointSet.pts" ) ) ); + EXPECT_NO_THROW( elastixFilter->SetParameterObject( parameterObject ) ); ImageFileWriterType::Pointer writer = ImageFileWriterType::New(); EXPECT_NO_THROW( writer->SetFileName( "TranslationWithPointSets2DResultImage.nii" ) ); EXPECT_NO_THROW( writer->SetInput( elastixFilter->GetOutput() ) ); EXPECT_NO_THROW( writer->Update() ); - EXPECT_NO_THROW( transformParameterObject = elastixFilter->GetTransformParameters() ); + ParameterObject::Pointer transformParameterObject; + EXPECT_NO_THROW( transformParameterObject = elastixFilter->GetTransformParameterObject() ); } TEST_F( ElastixFilterTest, BSplineWithFixedMask2D ) @@ -291,20 +322,12 @@ TEST_F( ElastixFilterTest, BSplineWithFixedMask2D ) ImageFileReaderType::Pointer fixedImageReader = ImageFileReaderType::New(); fixedImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20.png" ) ); - fixedImageReader->Update(); ImageFileReaderType::Pointer fixedMaskReader = ImageFileReaderType::New(); fixedMaskReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20Mask.png" ) ); - fixedMaskReader->Update(); ImageFileReaderType::Pointer movingImageReader = ImageFileReaderType::New(); movingImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceR10X13Y17.png" ) ); - movingImageReader->Update(); - - ParameterMapType nonRigidParameterMap = parameterMap; - nonRigidParameterMap[ "Transform" ] = ParameterVectorType( 1, "BSplineTransform" ); - ParameterObject::Pointer nonRigidParameterObject = ParameterObject::New(); - nonRigidParameterObject->SetParameterMap( nonRigidParameterMap ); ElastixFilterType::Pointer elastixFilter; EXPECT_NO_THROW( elastixFilter = ElastixFilterType::New() ); @@ -312,23 +335,25 @@ TEST_F( ElastixFilterTest, BSplineWithFixedMask2D ) EXPECT_NO_THROW( elastixFilter->SetFixedImage( fixedImageReader->GetOutput() ) ); EXPECT_NO_THROW( elastixFilter->SetFixedMask( fixedMaskReader->GetOutput() ) ); EXPECT_NO_THROW( elastixFilter->SetMovingImage( movingImageReader->GetOutput() ) ); - EXPECT_NO_THROW( elastixFilter->SetParameterObject( nonRigidParameterObject ) ); - - // TODO: This update should not be needed (see description above) - EXPECT_NO_THROW( elastixFilter->Update() ); ImageFileWriterType::Pointer writer = ImageFileWriterType::New(); EXPECT_NO_THROW( writer->SetFileName( dataManager->GetOutputFile( "BSplineWithFixedMask2DResultImage.nii" ) ) ); EXPECT_NO_THROW( writer->SetInput( elastixFilter->GetOutput() ) ); EXPECT_NO_THROW( writer->Update() ); - EXPECT_NO_THROW( transformParameterObject = elastixFilter->GetTransformParameters() ); + ParameterObject::Pointer transformParameterObject; + EXPECT_NO_THROW( transformParameterObject = elastixFilter->GetTransformParameterObject() ); } #ifdef SUPERELASTIX_BUILD_LONG_TESTS TEST_F( ElastixFilterTest, BSpline3D ) { + ParameterObject::Pointer parameterObject; + EXPECT_NO_THROW( parameterObject = ParameterObject::New() ); + EXPECT_NO_THROW( parameterObject->SetParameterMap( "nonrigid" ) ); + EXPECT_NO_THROW( parameterObject->GetParameterMap( 0 )[ "MaximumNumberOfIterations" ] = ParameterValueVectorType( 1, "8" ) ); + typedef itk::Image< float, 3 > ImageType; typedef itk::ImageFileReader< ImageType > ImageFileReaderType; typedef itk::ImageFileWriter< ImageType > ImageFileWriterType; @@ -338,92 +363,64 @@ TEST_F( ElastixFilterTest, BSpline3D ) ImageFileReaderType::Pointer fixedImageReader = ImageFileReaderType::New(); fixedImageReader->SetFileName( dataManager->GetInputFile( "OAS1_0001_MR1_mpr-1_anon.nrrd" ) ); - fixedImageReader->Update(); ImageFileReaderType::Pointer movingImageReader = ImageFileReaderType::New(); movingImageReader->SetFileName( dataManager->GetInputFile( "OAS1_0002_MR1_mpr-1_anon.nrrd" ) ); - movingImageReader->Update(); - - ParameterMapType nonRigidParameterMap3D = parameterMap; - nonRigidParameterMap3D[ "FixedInternalImagePixelType" ] = ParameterVectorType( 1, "float" ); - nonRigidParameterMap3D[ "FixedImageDimension" ] = ParameterVectorType( 1, "3" ); - nonRigidParameterMap3D[ "MovingInternalImagePixelType" ] = ParameterVectorType( 1, "float" ); - nonRigidParameterMap3D[ "MovingImageDimension" ] = ParameterVectorType( 1, "3" ); - nonRigidParameterMap3D[ "ResultImagePixelType" ] = ParameterVectorType( 1, "float" ); - nonRigidParameterMap3D[ "Transform" ] = ParameterVectorType( 1, "BSplineTransform" ); - nonRigidParameterMap3D[ "MaximumNumberOfIterations" ] = ParameterVectorType( 1, "8" ); - - ParameterObject::Pointer nonRigidParameterObject3D; - EXPECT_NO_THROW( nonRigidParameterObject3D = ParameterObject::New() ); - EXPECT_NO_THROW( nonRigidParameterObject3D->SetParameterMap( nonRigidParameterMap3D ) ); ElastixFilterType::Pointer elastixFilter; EXPECT_NO_THROW( elastixFilter = ElastixFilterType::New() ); EXPECT_NO_THROW( elastixFilter->LogToConsoleOn() ); EXPECT_NO_THROW( elastixFilter->SetFixedImage( fixedImageReader->GetOutput() ) ); EXPECT_NO_THROW( elastixFilter->SetMovingImage( movingImageReader->GetOutput() ) ); - EXPECT_NO_THROW( elastixFilter->SetParameterObject( nonRigidParameterObject3D ) ); - - // TODO: This update should not be needed (see description above) - EXPECT_NO_THROW( elastixFilter->Update() ); + EXPECT_NO_THROW( elastixFilter->SetParameterObject( parameterObject ) ); ImageFileWriterType::Pointer writer = ImageFileWriterType::New(); EXPECT_NO_THROW( writer->SetFileName( dataManager->GetOutputFile( "BSpline3DResultImage.nii" ) ) ); EXPECT_NO_THROW( writer->SetInput( elastixFilter->GetOutput() ) ); EXPECT_NO_THROW( writer->Update() ); - EXPECT_NO_THROW( transformParameterObject = elastixFilter->GetTransformParameters() ); + ParameterObject::Pointer transformParameterObject; + EXPECT_NO_THROW( transformParameterObject = elastixFilter->GetTransformParameterObject() ); } -// TODO: Find out why this segfaults -//TEST_F( ElastixFilterTest, BSpline4D ) -//{ -// typedef itk::Image< float, 4 > ImageType; -// typedef itk::ImageFileReader< ImageType > ImageFileReaderType; -// typedef itk::ImageFileWriter< ImageType > ImageFileWriterType; -// typedef ElastixFilter< ImageType, ImageType > ElastixFilterType; -// -// DataManagerType::Pointer dataManager = DataManagerType::New(); -// -// ImageFileReaderType::Pointer fixedImageReader = ImageFileReaderType::New(); -// fixedImageReader->SetFileName( dataManager->GetInputFile( "4D.nii.gz" ) ); -// fixedImageReader->Update(); -// -// ImageFileReaderType::Pointer movingImageReader = ImageFileReaderType::New(); -// movingImageReader->SetFileName( dataManager->GetInputFile( "4D.nii.gz" ) ); -// movingImageReader->Update(); -// -// ParameterMapType groupwiseParameterMap = parameterMap; -// groupwiseParameterMap[ "FixedInternalImagePixelType" ] = ParameterVectorType( 1, "float" ); -// groupwiseParameterMap[ "FixedImageDimension" ] = ParameterVectorType( 1, "4" ); -// groupwiseParameterMap[ "MovingInternalImagePixelType" ] = ParameterVectorType( 1, "float" ); -// groupwiseParameterMap[ "MovingImageDimension" ] = ParameterVectorType( 1, "4" ); -// groupwiseParameterMap[ "ResultImagePixelType" ] = ParameterVectorType( 1, "float" ); -// groupwiseParameterMap[ "Transform" ] = ParameterVectorType( 1, "BSplineStackTransform" ); -// groupwiseParameterMap[ "Metric" ] = ParameterVectorType( 1, "VarianceOverLastDimensionMetric" ); -// groupwiseParameterMap[ "MaximumNumberOfIterations" ] = ParameterVectorType( 1, "512" ); -// groupwiseParameterMap[ "Interpolator"] = ParameterVectorType( 1, "ReducedDimensionBSplineInterpolator" ); -// groupwiseParameterMap[ "ResampleInterpolator" ] = ParameterVectorType( 1, "FinalReducedDimensionBSplineInterpolator" ); -// groupwiseParameterMap[ "MaximumNumberOfIterations" ] = ParameterVectorType( 1, "8" ); -// ParameterObject::Pointer groupwiseParameterObject = ParameterObject::New(); -// groupwiseParameterObject->SetParameterMap( nonRigidParameterMap ); -// -// ElastixFilterType::Pointer elastixFilter; -// EXPECT_NO_THROW( elastixFilter = ElastixFilterType::New() ); -// EXPECT_NO_THROW( elastixFilter->LogToConsoleOn() ); -// EXPECT_NO_THROW( elastixFilter->SetFixedImage( fixedImageReader->GetOutput() ) ); -// EXPECT_NO_THROW( elastixFilter->SetMovingImage( movingImageReader->GetOutput() ) ); -// EXPECT_NO_THROW( elastixFilter->SetParameterObject( groupwiseParameterObject ) ); -// -// // TODO: This update should not be needed (see description above) -// EXPECT_NO_THROW( elastixFilter->Update() ); -// -// ImageFileWriterType::Pointer writer = ImageFileWriterType::New(); -// writer->SetFileName( dataManager->GetOutputFile( "BSpline4DResultImage.nii" ) ); -// writer->SetInput( elastixFilter->GetOutput() ); -// EXPECT_NO_THROW( writer->Update() ); -// -// EXPECT_NO_THROW( transformParameterObject = elastixFilter->GetTransformParameters() ); -//} +#include "itkCastImageFilter.h" +TEST_F( ElastixFilterTest, BSpline4D ) +{ + ParameterObject::Pointer parameterObject = ParameterObject::New(); + parameterObject->SetParameterMap( "groupwise" ); + parameterObject->GetParameterMap( 0 )[ "MaximumNumberOfIterations" ] = ParameterValueVectorType( 1, "4" ); + + typedef itk::Image< float, 4 > FloatImageType; + typedef itk::ImageFileReader< FloatImageType > ImageFileReaderType; + + DataManagerType::Pointer dataManager = DataManagerType::New(); + + ImageFileReaderType::Pointer imageReader = ImageFileReaderType::New(); + imageReader->SetFileName( dataManager->GetInputFile( "4D.nii.gz" ) ); + + // Elastix is not compiled with the combination of float and dim = 4 by default + typedef itk::Image< short, 4 > ShortImageType; + typedef itk::CastImageFilter< FloatImageType, ShortImageType > CastImageFilterType; + typedef itk::ImageFileWriter< ShortImageType > ImageFileWriterType; + typedef ElastixFilter< ShortImageType, ShortImageType > ElastixFilterType; + + CastImageFilterType::Pointer castImageFilter = CastImageFilterType::New(); + castImageFilter->SetInput( imageReader->GetOutput() ); + + ElastixFilterType::Pointer elastixFilter; + EXPECT_NO_THROW( elastixFilter = ElastixFilterType::New() ); + EXPECT_NO_THROW( elastixFilter->LogToConsoleOn() ); + EXPECT_NO_THROW( elastixFilter->SetFixedImage( castImageFilter->GetOutput() ) ); + EXPECT_NO_THROW( elastixFilter->SetMovingImage( castImageFilter->GetOutput() ) ); + EXPECT_NO_THROW( elastixFilter->SetParameterObject( parameterObject ) ); + + ImageFileWriterType::Pointer writer = ImageFileWriterType::New(); + EXPECT_NO_THROW( writer->SetFileName( dataManager->GetOutputFile( "BSpline4DResultImage.nii" ) ) ); + EXPECT_NO_THROW( writer->SetInput( elastixFilter->GetOutput() ) ); + EXPECT_NO_THROW( writer->Update() ); + + ParameterObject::Pointer transformParameterObject; + EXPECT_NO_THROW( transformParameterObject = elastixFilter->GetTransformParameterObject() ); +} #endif // SUPERELASTIX_BUILD_LONG_TESTS diff --git a/Testing/Unit/elxTransformixFilterTest.cxx b/Testing/Unit/elxTransformixFilterTest.cxx index 3579796124c25d050a47ad7e6e385cbfe744d2e8..bb08242d778dd473c36bb7dd1039f9dbd40f0a92 100644 --- a/Testing/Unit/elxTransformixFilterTest.cxx +++ b/Testing/Unit/elxTransformixFilterTest.cxx @@ -8,7 +8,7 @@ #include "elxDataManager.h" #include "gtest/gtest.h" -using namespace selx; +using namespace elastix; class TransformixFilterTest : public ::testing::Test { @@ -16,8 +16,8 @@ protected: typedef DataManager DataManagerType; - typedef ParameterObject::ParameterVectorType ParameterVectorType; - typedef ParameterObject::ParameterMapType ParameterMapType; + typedef ParameterObject::ParameterValueVectorType ParameterValueVectorType; + typedef ParameterObject::ParameterMapType ParameterMapType; typedef itk::Image< float, 2 > ImageType; typedef itk::ImageFileReader< ImageType > ImageFileReaderType; @@ -26,64 +26,6 @@ protected: typedef TransformixFilter< ImageType > TransformixFilterType; ElastixFilterType::Pointer elastixFilter; - ParameterObject::Pointer eulerTransformParameterObject; - - virtual void SetUp() - { - // Nonrigid ParameterMap - ParameterMapType parameterMap = ParameterMapType(); - - // Images - parameterMap[ "FixedInternalImagePixelType" ] = ParameterVectorType( 1, "float" ); - parameterMap[ "FixedImageDimension" ] = ParameterVectorType( 1, "2" ); - parameterMap[ "MovingInternalImagePixelType" ] = ParameterVectorType( 1, "float" ); - parameterMap[ "MovingImageDimension" ] = ParameterVectorType( 1, "2" ); - parameterMap[ "ResultImagePixelType" ] = ParameterVectorType( 1, "float" ); - - // Common components - parameterMap[ "FixedImagePyramid" ] = ParameterVectorType( 1, "FixedSmoothingImagePyramid" ); - parameterMap[ "MovingImagePyramid" ] = ParameterVectorType( 1, "MovingSmoothingImagePyramid" ); - parameterMap[ "Interpolator"] = ParameterVectorType( 1, "LinearInterpolator"); - parameterMap[ "Optimizer" ] = ParameterVectorType( 1, "AdaptiveStochasticGradientDescent" ); - parameterMap[ "Resampler"] = ParameterVectorType( 1, "DefaultResampler" ); - parameterMap[ "ResampleInterpolator"] = ParameterVectorType( 1, "FinalLinearInterpolator" ); - parameterMap[ "FinalBSplineInterpolationOrder" ] = ParameterVectorType( 1, "2" ); - parameterMap[ "NumberOfResolutions" ] = ParameterVectorType( 1, "2" ); - - // Image Sampler - parameterMap[ "ImageSampler" ] = ParameterVectorType( 1, "RandomCoordinate" ); - parameterMap[ "NumberOfSpatialSamples"] = ParameterVectorType( 1, "2048" ); - parameterMap[ "CheckNumberOfSamples" ] = ParameterVectorType( 1, "true" ); - parameterMap[ "MaximumNumberOfSamplingAttempts" ] = ParameterVectorType( 1, "8" ); - parameterMap[ "NewSamplesEveryIteration" ] = ParameterVectorType( 1, "true"); - - // Optimizer - parameterMap[ "NumberOfSamplesForExactGradient" ] = ParameterVectorType( 1, "4096" ); - parameterMap[ "DefaultPixelValue" ] = ParameterVectorType( 1, "0" ); - parameterMap[ "AutomaticParameterEstimation" ] = ParameterVectorType( 1, "true" ); - - // Output - parameterMap[ "WriteResultImage" ] = ParameterVectorType( 1, "true" ); - parameterMap[ "ResultImageFormat" ] = ParameterVectorType( 1, "nii" ); - - // Registration - parameterMap[ "Registration" ] = ParameterVectorType( 1, "MultiResolutionRegistration" ); - parameterMap[ "Transform" ] = ParameterVectorType( 1, "EulerTransform" ); - parameterMap[ "Metric" ] = ParameterVectorType( 1, "AdvancedMattesMutualInformation" ); - parameterMap[ "MaximumNumberOfIterations" ] = ParameterVectorType( 1, "128" ); - - eulerTransformParameterObject = ParameterObject::New(); - eulerTransformParameterObject->SetParameterMap( parameterMap ); - - // We generate the point sets manually - DataManagerType::Pointer dataManager = DataManagerType::New(); - std::ofstream inputMeshFile; - inputMeshFile.open( dataManager->GetInputFile( "InputMesh.pts" )); - inputMeshFile << "point\n"; - inputMeshFile << "1\n"; - inputMeshFile << "115.0 111.0\n"; - inputMeshFile.close(); - } }; TEST_F( TransformixFilterTest, Instantiation ) @@ -99,31 +41,29 @@ TEST_F( TransformixFilterTest, Euler2D ) ImageFileReaderType::Pointer fixedImageReader = ImageFileReaderType::New(); fixedImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20.png" ) ); - fixedImageReader->Update(); ImageFileReaderType::Pointer movingImageReader = ImageFileReaderType::New(); movingImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceR10X13Y17.png" ) ); - movingImageReader->Update(); ElastixFilterType::Pointer elastixFilter; EXPECT_NO_THROW( elastixFilter = ElastixFilterType::New() ); EXPECT_NO_THROW( elastixFilter->SetFixedImage( fixedImageReader->GetOutput() ) ); EXPECT_NO_THROW( elastixFilter->SetMovingImage( movingImageReader->GetOutput() ) ); - EXPECT_NO_THROW( elastixFilter->SetParameterObject( eulerTransformParameterObject ) ); + elastixFilter->LogToConsoleOn(); TransformixFilterType::Pointer transformixFilter; EXPECT_NO_THROW( transformixFilter = TransformixFilterType::New() ); EXPECT_NO_THROW( transformixFilter->SetInputImage( movingImageReader->GetOutput() ) ); EXPECT_NO_THROW( transformixFilter->SetOutputDirectory( dataManager->GetOutputDirectory() ) ); - EXPECT_NO_THROW( transformixFilter->SetTransformParameterObject( elastixFilter->GetTransformParameters() ) ); + EXPECT_NO_THROW( transformixFilter->SetTransformParameterObject( elastixFilter->GetTransformParameterObject() ) ); EXPECT_NO_THROW( transformixFilter->LogToConsoleOn() ); EXPECT_NO_THROW( transformixFilter->LogToFileOn() ); EXPECT_NO_THROW( transformixFilter->Update() ); ImageFileWriterType::Pointer writer = ImageFileWriterType::New(); - writer->SetFileName( dataManager->GetOutputFile( "Euler2DTransformixResultImage.nii" ) ); - writer->SetInput( transformixFilter->GetOutput() ); - writer->Update(); + EXPECT_NO_THROW( writer->SetFileName( dataManager->GetOutputFile( "Euler2DTransformixResultImage.nii" ) ) ); + EXPECT_NO_THROW( writer->SetInput( transformixFilter->GetOutput() ) ); + EXPECT_NO_THROW( writer->Update() ); } @@ -133,67 +73,163 @@ TEST_F( TransformixFilterTest, UpdateOnGetOutput ) ImageFileReaderType::Pointer fixedImageReader = ImageFileReaderType::New(); fixedImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20.png" ) ); - fixedImageReader->Update(); ImageFileReaderType::Pointer movingImageReader = ImageFileReaderType::New(); movingImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceR10X13Y17.png" ) ); - movingImageReader->Update(); ElastixFilterType::Pointer elastixFilter; EXPECT_NO_THROW( elastixFilter = ElastixFilterType::New() ); EXPECT_NO_THROW( elastixFilter->SetFixedImage( fixedImageReader->GetOutput() ) ); EXPECT_NO_THROW( elastixFilter->SetMovingImage( movingImageReader->GetOutput() ) ); - EXPECT_NO_THROW( elastixFilter->SetParameterObject( eulerTransformParameterObject ) ); TransformixFilterType::Pointer transformixFilter; EXPECT_NO_THROW( transformixFilter = TransformixFilterType::New() ); EXPECT_NO_THROW( transformixFilter->SetInputImage( movingImageReader->GetOutput() ) ); EXPECT_NO_THROW( transformixFilter->SetOutputDirectory( dataManager->GetOutputDirectory() ) ); - EXPECT_NO_THROW( transformixFilter->SetTransformParameterObject( elastixFilter->GetTransformParameters() ) ); + EXPECT_NO_THROW( transformixFilter->SetTransformParameterObject( elastixFilter->GetTransformParameterObject() ) ); EXPECT_NO_THROW( transformixFilter->LogToConsoleOn() ); EXPECT_NO_THROW( transformixFilter->LogToFileOn() ); ImageFileWriterType::Pointer writer = ImageFileWriterType::New(); - writer->SetFileName( dataManager->GetOutputFile( "Euler2DTransformixResultImage.nii" ) ); - writer->SetInput( transformixFilter->GetOutput() ); - writer->Update(); + EXPECT_NO_THROW( writer->SetFileName( dataManager->GetOutputFile( "Euler2DTransformixResultImage.nii" ) ) ); + EXPECT_NO_THROW( writer->SetInput( transformixFilter->GetOutput() ) ); + EXPECT_NO_THROW( writer->Update() ); } -TEST_F( TransformixFilterTest, UpdateOnGetTransformParameters ) +TEST_F( TransformixFilterTest, UpdateOnGetTransformParameterObject ) { DataManagerType::Pointer dataManager = DataManagerType::New(); ImageFileReaderType::Pointer fixedImageReader = ImageFileReaderType::New(); fixedImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20.png" ) ); - fixedImageReader->Update(); ImageFileReaderType::Pointer movingImageReader = ImageFileReaderType::New(); movingImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceR10X13Y17.png" ) ); - movingImageReader->Update(); ElastixFilterType::Pointer elastixFilter; EXPECT_NO_THROW( elastixFilter = ElastixFilterType::New() ); EXPECT_NO_THROW( elastixFilter->SetFixedImage( fixedImageReader->GetOutput() ) ); EXPECT_NO_THROW( elastixFilter->SetMovingImage( movingImageReader->GetOutput() ) ); - EXPECT_NO_THROW( elastixFilter->SetParameterObject( eulerTransformParameterObject ) ); TransformixFilterType::Pointer transformixFilter; EXPECT_NO_THROW( transformixFilter = TransformixFilterType::New() ); EXPECT_NO_THROW( transformixFilter->SetInputImage( movingImageReader->GetOutput() ) ); EXPECT_NO_THROW( transformixFilter->SetOutputDirectory( dataManager->GetOutputDirectory() ) ); - EXPECT_NO_THROW( transformixFilter->SetTransformParameterObject( elastixFilter->GetTransformParameters() ) ); + EXPECT_NO_THROW( transformixFilter->SetTransformParameterObject( elastixFilter->GetTransformParameterObject() ) ); EXPECT_NO_THROW( transformixFilter->LogToConsoleOn() ); EXPECT_NO_THROW( transformixFilter->LogToFileOn() ); - EXPECT_NO_THROW( ParameterObject::Pointer transformParameters = transformixFilter->GetTransformParameters() ); + EXPECT_NO_THROW( ParameterObject::Pointer transformParameters = transformixFilter->GetTransformParameterObject() ); ImageFileWriterType::Pointer writer = ImageFileWriterType::New(); - writer->SetFileName( dataManager->GetOutputFile( "Euler2DTransformixResultImage.nii" ) ); - writer->SetInput( transformixFilter->GetOutput() ); - writer->Update(); + EXPECT_NO_THROW( writer->SetFileName( dataManager->GetOutputFile( "Euler2DTransformixResultImage.nii" ) ) ); + EXPECT_NO_THROW( writer->SetInput( transformixFilter->GetOutput() ) ); + EXPECT_NO_THROW( writer->Update() ); } -// TODO: Write tests for -// EXPECT_NO_THROW( transformixFilter->ComputeSpatialJacobianOn() ); -// EXPECT_NO_THROW( transformixFilter->ComputeDeterminantOfSpatialJacobianOn() ); -// EXPECT_NO_THROW( transformixFilter->ComputeDeformationFieldOn() ); -// EXPECT_NO_THROW( transformixFilter->SetPointSetFileName( dataManager->GetInputFile( "InputMesh.pts" ) ) ); +TEST_F( TransformixFilterTest, ComputeSpatialJacobian ) +{ + DataManagerType::Pointer dataManager = DataManagerType::New(); + + ImageFileReaderType::Pointer fixedImageReader = ImageFileReaderType::New(); + fixedImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20.png" ) ); + + ImageFileReaderType::Pointer movingImageReader = ImageFileReaderType::New(); + movingImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceR10X13Y17.png" ) ); + + ElastixFilterType::Pointer elastixFilter; + EXPECT_NO_THROW( elastixFilter = ElastixFilterType::New() ); + EXPECT_NO_THROW( elastixFilter->SetFixedImage( fixedImageReader->GetOutput() ) ); + EXPECT_NO_THROW( elastixFilter->SetMovingImage( movingImageReader->GetOutput() ) ); + + TransformixFilterType::Pointer transformixFilter; + EXPECT_NO_THROW( transformixFilter = TransformixFilterType::New() ); + EXPECT_NO_THROW( transformixFilter->SetOutputDirectory( dataManager->GetOutputDirectory() ) ); + EXPECT_NO_THROW( transformixFilter->SetTransformParameterObject( elastixFilter->GetTransformParameterObject() ) ); + EXPECT_NO_THROW( transformixFilter->LogToConsoleOn() ); + EXPECT_NO_THROW( transformixFilter->LogToFileOn() ); + EXPECT_NO_THROW( transformixFilter->ComputeSpatialJacobianOn() ); + transformixFilter->Update(); +} + +TEST_F( TransformixFilterTest, ComputeDeterminantOfSpatialJacobian ) +{ + DataManagerType::Pointer dataManager = DataManagerType::New(); + + ImageFileReaderType::Pointer fixedImageReader = ImageFileReaderType::New(); + fixedImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20.png" ) ); + + ImageFileReaderType::Pointer movingImageReader = ImageFileReaderType::New(); + movingImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceR10X13Y17.png" ) ); + + ElastixFilterType::Pointer elastixFilter; + EXPECT_NO_THROW( elastixFilter = ElastixFilterType::New() ); + EXPECT_NO_THROW( elastixFilter->SetFixedImage( fixedImageReader->GetOutput() ) ); + EXPECT_NO_THROW( elastixFilter->SetMovingImage( movingImageReader->GetOutput() ) ); + + TransformixFilterType::Pointer transformixFilter; + EXPECT_NO_THROW( transformixFilter = TransformixFilterType::New() ); + EXPECT_NO_THROW( transformixFilter->SetOutputDirectory( dataManager->GetOutputDirectory() ) ); + EXPECT_NO_THROW( transformixFilter->SetTransformParameterObject( elastixFilter->GetTransformParameterObject() ) ); + EXPECT_NO_THROW( transformixFilter->LogToConsoleOn() ); + EXPECT_NO_THROW( transformixFilter->LogToFileOn() ); + EXPECT_NO_THROW( transformixFilter->ComputeDeterminantOfSpatialJacobianOn() ); + EXPECT_NO_THROW( transformixFilter->Update() ); +} + +TEST_F( TransformixFilterTest, ComputeDeformationField ) +{ + DataManagerType::Pointer dataManager = DataManagerType::New(); + + ImageFileReaderType::Pointer fixedImageReader = ImageFileReaderType::New(); + fixedImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20.png" ) ); + + ImageFileReaderType::Pointer movingImageReader = ImageFileReaderType::New(); + movingImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceR10X13Y17.png" ) ); + + ElastixFilterType::Pointer elastixFilter; + EXPECT_NO_THROW( elastixFilter = ElastixFilterType::New() ); + EXPECT_NO_THROW( elastixFilter->SetFixedImage( fixedImageReader->GetOutput() ) ); + EXPECT_NO_THROW( elastixFilter->SetMovingImage( movingImageReader->GetOutput() ) ); + + TransformixFilterType::Pointer transformixFilter; + EXPECT_NO_THROW( transformixFilter = TransformixFilterType::New() ); + EXPECT_NO_THROW( transformixFilter->SetOutputDirectory( dataManager->GetOutputDirectory() ) ); + EXPECT_NO_THROW( transformixFilter->SetTransformParameterObject( elastixFilter->GetTransformParameterObject() ) ); + EXPECT_NO_THROW( transformixFilter->LogToConsoleOn() ); + EXPECT_NO_THROW( transformixFilter->LogToFileOn() ); + EXPECT_NO_THROW( transformixFilter->ComputeDeformationFieldOn() ); + EXPECT_NO_THROW( transformixFilter->Update() ); +} + +TEST_F( TransformixFilterTest, TransformPointSet ) +{ + DataManagerType::Pointer dataManager = DataManagerType::New(); + + ImageFileReaderType::Pointer fixedImageReader = ImageFileReaderType::New(); + fixedImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceBorder20.png" ) ); + + ImageFileReaderType::Pointer movingImageReader = ImageFileReaderType::New(); + movingImageReader->SetFileName( dataManager->GetInputFile( "BrainProtonDensitySliceR10X13Y17.png" ) ); + + // We generate point set manually + std::ofstream fixedMeshFile; + fixedMeshFile.open( dataManager->GetInputFile( "InputPoints.pts" )); + fixedMeshFile << "point\n"; + fixedMeshFile << "1\n"; + fixedMeshFile << "128.0 128.0\n"; + fixedMeshFile.close(); + + ElastixFilterType::Pointer elastixFilter; + EXPECT_NO_THROW( elastixFilter = ElastixFilterType::New() ); + EXPECT_NO_THROW( elastixFilter->SetFixedImage( fixedImageReader->GetOutput() ) ); + EXPECT_NO_THROW( elastixFilter->SetMovingImage( movingImageReader->GetOutput() ) ); + + TransformixFilterType::Pointer transformixFilter; + EXPECT_NO_THROW( transformixFilter = TransformixFilterType::New() ); + EXPECT_NO_THROW( transformixFilter->SetOutputDirectory( dataManager->GetOutputDirectory() ) ); + EXPECT_NO_THROW( transformixFilter->SetTransformParameterObject( elastixFilter->GetTransformParameterObject() ) ); + EXPECT_NO_THROW( transformixFilter->LogToConsoleOn() ); + EXPECT_NO_THROW( transformixFilter->LogToFileOn() ); + EXPECT_NO_THROW( transformixFilter->SetInputPointSetFileName( dataManager->GetInputFile( "InputPoints.pts" ) ) ); + EXPECT_NO_THROW( transformixFilter->Update() ); +} \ No newline at end of file