diff --git a/CMake/ElastixConfig.cmake.in b/CMake/ElastixConfig.cmake.in deleted file mode 100644 index bfd7bb1..0000000 --- a/CMake/ElastixConfig.cmake.in +++ /dev/null @@ -1,13 +0,0 @@ -SET(MatchPoint_Elastix_IS_ENABLED ON) - -# The Elastix source tree used by MatchPoint. -SET(MatchPoint_Elastix_SOURCE_DIR @Elastix_SOURCE_DIR@) - -# The Elastix source tree used by MatchPoint. -SET(MatchPoint_Elastix_BINARY_DIR @Elastix_DIR@) - -# The Elastix libraries used by MatchPoint. -SET(MatchPoint_Elastix_LIBRARIES @Elastix_LIBRARIES@) - -# The Elastix include directories used by MatchPoint. -SET(MatchPoint_Elastix_INCLUDE_DIRS @ELASTIX_INCLUDE_DIRECTORIES@) diff --git a/CMake/PackageDepends/MAP_Elastix_Config.cmake b/CMake/PackageDepends/MAP_Elastix_Config.cmake deleted file mode 100644 index 0e9b0b0..0000000 --- a/CMake/PackageDepends/MAP_Elastix_Config.cmake +++ /dev/null @@ -1,126 +0,0 @@ -#----------------------------------------------------------------------------- -# Find Elastix. -#----------------------------------------------------------------------------- - -if(NOT Elastix_FOUND AND NOT Elastix_DIR) - SET( Elastix_DIR "" CACHE PATH "Path to Elastix binary folder" ) -endif() - -IF(NOT Elastix_FOUND) - set(Elastix_FOUND True) - -IF(DEFINED Elastix_DIR) - IF(NOT IS_ABSOLUTE ${Elastix_DIR}) - SET(Elastix_DIR "${MatchPoint_BINARY_DIR}/${Elastix_DIR}") - ENDIF(NOT IS_ABSOLUTE ${Elastix_DIR}) -ENDIF(DEFINED Elastix_DIR) - -SET( Elastix_USE_FILE ${Elastix_DIR}/UseElastix.cmake ) - -IF( EXISTS ${Elastix_USE_FILE} ) - MESSAGE( STATUS "Including Elastix settings." ) - INCLUDE( ${Elastix_USE_FILE} ) -ELSE( EXISTS ${Elastix_USE_FILE} ) - MESSAGE( FATAL_ERROR "Cannot find Elastix settings (Use Elastix.cmake). Check Elastix_DIR." ) -ENDIF( EXISTS ${Elastix_USE_FILE} ) - -IF(${ELASTIX_VERSION_MAJOR} LESS 4 OR (${ELASTIX_VERSION_MAJOR} EQUAL 4 AND ${ELASTIX_VERSION_MINOR} LESS 6)) - MESSAGE(FATAL_ERROR - "Outdated Elastix version. Cannot build MatchPoint without sufficient Elastix version. Elastix 4.6 or above is needed.") -ENDIF(${ELASTIX_VERSION_MAJOR} LESS 4 OR (${ELASTIX_VERSION_MAJOR} EQUAL 4 AND ${ELASTIX_VERSION_MINOR} LESS 6)) - -#----------------------------------------------------------- -# Dynamic search for Elastix libs to include them with path -#----------------------------------------------------------- - -foreach(lib -FixedGenericPyramid -FixedRecursivePyramid -FixedSmoothingPyramid -FullSampler -GridSampler -MultiInputRandomCoordinateSampler -RandomSampler -RandomCoordinateSampler -RandomSamplerSparseMask -BSplineInterpolator -ReducedDimensionBSplineInterpolator -AdvancedMattesMutualInformationMetric -AdvancedMeanSquaresMetric -AdvancedNormalizedCorrelationMetric -TransformBendingEnergyPenalty -CorrespondingPointsEuclideanDistanceMetric -KNNGraphAlphaMutualInformationMetric -NormalizedMutualInformationMetric -TransformRigidityPenalty -VarianceOverLastDimensionMetric -MovingRecursivePyramid -MovingSmoothingPyramid -AdaptiveStochasticGradientDescent -ConjugateGradient -FiniteDifferenceGradientDescent -FullSearch -Powell -QuasiNewtonLBFGS -RegularStepGradientDescent -StandardGradientDescent -MultiMetricMultiResolutionRegistration -MultiResolutionRegistration -MultiResolutionRegistrationWithFeatures -BSplineResampleInterpolator -ReducedDimensionBSplineResampleInterpolator -MyStandardResampler -AdvancedAffineTransformElastix -AdvancedBSplineTransform -DeformationFieldTransform -EulerTransformElastix -SplineKernelTransform -BSplineStackTransform -TranslationTransformElastix -elxCommon -elxCore -param -) - - find_library(Elastix_${lib}_DEBUG_LIBRARY - ${lib} - PATHS - ${Elastix_DIR}/bin - ${Elastix_DIR}/bin/Debug) - - find_library(Elastix_${lib}_LIBRARY - ${lib} - PATHS - ${Elastix_DIR}/bin/Release - ${Elastix_DIR}/bin) - - mark_as_advanced(Elastix_${lib}_LIBRARY) - mark_as_advanced(Elastix_${lib}_DEBUG_LIBRARY) - - add_library(${lib} STATIC IMPORTED) - set_target_properties(${lib} PROPERTIES IMPORTED_LOCATION ${Elastix_${lib}_LIBRARY} IMPORTED_LOCATION_DEBUG ${Elastix_${lib}_DEBUG_LIBRARY}) - - if(Elastix_${lib}_LIBRARY OR Elastix_${lib}_DEBUG_LIBRARY) - list(APPEND Elastix_LIBRARIES ${lib}) - endif() - - if(${Elastix_${lib}_LIBRARY} STREQUAL Elastix_${lib}_LIBRARY-NOTFOUND) - message(WARNING "Cannot find release version of library Elastix_${lib}_LIBRARY") - endif() - - if(${Elastix_${lib}_DEBUG_LIBRARY} STREQUAL Elastix_${lib}_DEBUG_LIBRARY-NOTFOUND) - message(WARNING "Cannot find debug version of library Elastix_${lib}_DEBUG_LIBRARY") - endif() - - endforeach() - -ENDIF(NOT Elastix_FOUND) - -IF(NOT Elastix_FOUND) - MESSAGE(SEND_ERROR "Elastix development files not found.\n Please check variables (e.g. Elastix_DIR)") -ENDIF(NOT Elastix_FOUND) - -LIST(APPEND ALL_INCLUDE_DIRECTORIES ${ELASTIX_INCLUDE_DIRECTORIES}) -LIST(APPEND ALL_LIBRARIES ${Elastix_LIBRARIES}) - -CONFIGURE_FILE(${MatchPoint_SOURCE_DIR}/CMake/ElastixConfig.cmake.in ${MAP_MODULES_CONF_DIR}/ElastixConfig.cmake @ONLY) diff --git a/Code/Algorithms/Elastix/CMakeLists.txt b/Code/Algorithms/Elastix/CMakeLists.txt index ea454ac..57cbba8 100644 --- a/Code/Algorithms/Elastix/CMakeLists.txt +++ b/Code/Algorithms/Elastix/CMakeLists.txt @@ -1,17 +1,17 @@ -MAP_CREATE_MODULE(MAPAlgorithmsElastix DEPENDS MAPAlgorithms MAPUtilities MAPIO PACKAGE_DEPENDS Elastix) +MAP_CREATE_MODULE(MAPAlgorithmsElastix DEPENDS MAPAlgorithms MAPUtilities MAPIO) MAP_CREATE_MODULE_TESTS(MAPAlgorithmsElastix PACKAGE_DEPENDS Litmus HEADER_TESTS) IF (BUILD_TESTING) ADD_EXECUTABLE(mapDummyElastix "test/mapDummyElastix.cpp") SET_TARGET_PROPERTIES(mapDummyElastix PROPERTIES OUTPUT_NAME "elastix") TARGET_LINK_LIBRARIES(mapDummyElastix MAPCore) ADD_EXECUTABLE(mapDummyTransformix "test/mapDummyTransformix.cpp") SET_TARGET_PROPERTIES(mapDummyTransformix PROPERTIES OUTPUT_NAME "transformix") TARGET_LINK_LIBRARIES(mapDummyTransformix MAPCore) ENDIF (BUILD_TESTING) MAP_DEFINE_DEPLOYED_ALGORITHM(ElxParameterFileCLI2DRegistration PROFILE "deployed/ElxParameterFileCLI2DRegistration.profile" FILES "deployed/mapElxParameterFileCLI2DRegistration.cpp" MODULE_DEPENDS MAPAlgorithmsElastix MAPDeployment) MAP_DEFINE_DEPLOYED_ALGORITHM(ElxParameterFileCLI3DRegistration PROFILE "deployed/ElxParameterFileCLI3DRegistration.profile" FILES "deployed/mapElxParameterFileCLI3DRegistration.cpp" MODULE_DEPENDS MAPAlgorithmsElastix MAPDeployment) MAP_DEFINE_DEPLOYED_ALGORITHM(ElxBSplineCLI2DRegistration PROFILE "deployed/ElxBSplineCLI2DRegistration.profile" FILES "deployed/mapElxBSplineCLI2DRegistration.cpp" MODULE_DEPENDS MAPAlgorithmsElastix MAPDeployment) MAP_DEFINE_DEPLOYED_ALGORITHM(ElxBSplineCLI3DRegistration PROFILE "deployed/ElxBSplineCLI3DRegistration.profile" FILES "deployed/mapElxBSplineCLI3DRegistration.cpp" MODULE_DEPENDS MAPAlgorithmsElastix MAPDeployment) diff --git a/Code/Algorithms/Elastix/files.cmake b/Code/Algorithms/Elastix/files.cmake index dec425c..9fe1ece 100644 --- a/Code/Algorithms/Elastix/files.cmake +++ b/Code/Algorithms/Elastix/files.cmake @@ -1,21 +1,23 @@ SET(CPP_FILES source/mapElxAlgorithmHelper.cpp + source/ParameterFileParser/itkParameterFileParser.cxx ) SET(H_FILES include/mapElxCLIRegistrationAlgorithmBase.h include/mapElxParameterFileRegistrationAlgorithm.h include/mapElxAlgorithmHelper.h boxed/mapElxBSplineCLIRegistrationAlgorithm.h +source/ParameterFileParser/itkParameterFileParser.h ) SET(TPP_FILES include/mapElxCLIRegistrationAlgorithmBase.tpp include/mapElxParameterFileRegistrationAlgorithm.tpp boxed/mapElxBSplineCLIRegistrationAlgorithm.tpp ) SET(TEST_CPP_FILES test/mapAlgorithmsElastixTests.cpp test/mapElxParameterFileRegistrationAlgorithmTest.cpp ) \ No newline at end of file diff --git a/Code/Algorithms/Elastix/include/mapElxAlgorithmHelper.h b/Code/Algorithms/Elastix/include/mapElxAlgorithmHelper.h index f5dc1ac..d8b74ce 100644 --- a/Code/Algorithms/Elastix/include/mapElxAlgorithmHelper.h +++ b/Code/Algorithms/Elastix/include/mapElxAlgorithmHelper.h @@ -1,78 +1,77 @@ // ----------------------------------------------------------------------- // MatchPoint - DKFZ translational registration framework // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See mapCopyright.txt or // http://www.dkfz.de/en/sidt/projects/MatchPoint/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) // Subversion HeadURL: $HeadURL$ */ #ifndef __MAP_ELX_ALGORITHM_HELPER_H #define __MAP_ELX_ALGORITHM_HELPER_H -//Elastix -#include "itkParameterFileParser.h" - //MatchPoint #include "mapContinuous.h" #include "mapString.h" #include "mapConvert.h" #include "mapMAPAlgorithmsElastixExports.h" namespace map { namespace algorithm { namespace elastix { - - typedef ::itk::ParameterFileParser::ParameterMapType ParameterMapType; - typedef ::itk::ParameterFileParser::ParameterValuesType ParameterValuesType; + using ParameterValuesType = std::vector< std::string >; + using ParameterMapType = std::map< std::string, ParameterValuesType >; /**! Helper function that stores the passed parameter map to the given file path. If the file already exists it is overwritten. The parameter map is stored in the elastix format: ( [ [...]]).*/ MAPAlgorithmsElastix_EXPORT void saveParameterMapToFile(const ParameterMapType& parameterMap, const map::core::String& fileName); + /**! Helper function that loads a given parameter file and returns a parameter map.*/ + MAPAlgorithmsElastix_EXPORT ParameterMapType readParameterMapFromFile(const map::core::String& fileName); + class MAPAlgorithmsElastix_EXPORT ParamGenerator { public: ParamGenerator(); ~ParamGenerator(); ParamGenerator& addStr(const core::String& value); template ParamGenerator& add(const TElement& value) { this->_values.push_back(core::convert::toStrGeneric(value)); return *this; }; operator ParameterValuesType(); protected: ParameterValuesType _values; }; } } } #endif diff --git a/Code/Algorithms/Elastix/include/mapElxCLIRegistrationAlgorithmBase.h b/Code/Algorithms/Elastix/include/mapElxCLIRegistrationAlgorithmBase.h index af2c09c..3825ab4 100644 --- a/Code/Algorithms/Elastix/include/mapElxCLIRegistrationAlgorithmBase.h +++ b/Code/Algorithms/Elastix/include/mapElxCLIRegistrationAlgorithmBase.h @@ -1,363 +1,364 @@ // ----------------------------------------------------------------------- // MatchPoint - DKFZ translational registration framework // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See mapCopyright.txt or // http://www.dkfz.de/en/sidt/projects/MatchPoint/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) // Subversion HeadURL: $HeadURL$ */ #ifndef __MAP_ELX_CLI_REGISTRATION_ALGORITHM_BASE_H #define __MAP_ELX_CLI_REGISTRATION_ALGORITHM_BASE_H -//Elastix -#include "itkParameterFileParser.h" - //MatchPoint #include "mapContinuous.h" #include "mapIterativeRegistrationAlgorithm.h" #include "mapImageRegistrationAlgorithmBase.h" #include "mapClassMacros.h" #include "mapElxAlgorithmHelper.h" #include "mapMetaPropertyAlgorithmBase.h" #include "mapMaskedRegistrationAlgorithmBase.h" +#include "mapGenericVectorFieldTransform.h" + namespace map { namespace algorithm { namespace elastix { /*! @class CLIRegistrationAlgorithmBase @brief This is the base class for algorithms that serve as a wrapper for the registration tool "elastix". The algorithm is a very simple wrapper using a command line interface to facilitate elastix. For a registration task a temporary working directory is generated, where the algorithm stores the given moving and target image. Then the algorithms calls 'elastix' with appropriated command line arguments to trigger the registration as an external process. After elastix transformix will be used to generate a deformation field as result. This field will be loaded and converted into a MatchPoint registration object and returned. After the registration job is done, the temporary directory will be deleted by the algorithm. @remark @ingroup Algorithms @ingroup Elastix */ template class CLIRegistrationAlgorithmBase : public IterativeRegistrationAlgorithm, public ImageRegistrationAlgorithmBase, public MetaPropertyAlgorithmBase, public MaskedRegistrationAlgorithmBase, public TIdentificationPolicy { public: typedef CLIRegistrationAlgorithmBase Self; typedef IterativeRegistrationAlgorithm Superclass; typedef ::itk::SmartPointer Pointer; typedef ::itk::SmartPointer ConstPointer; itkTypeMacro(CLIRegistrationAlgorithmBase, IterativeRegistrationAlgorithm); typedef typename Superclass::UIDType UIDType; typedef typename Superclass::UIDPointer UIDPointer; typedef typename IterativeRegistrationAlgorithm::OptimizerMeasureType OptimizerMeasureType; typedef ImageRegistrationAlgorithmBase ImageRegistrationAlgorithmBaseType; typedef typename ImageRegistrationAlgorithmBaseType::TargetImageType TargetImageType; typedef typename ImageRegistrationAlgorithmBaseType::MovingImageType MovingImageType; typedef typename Superclass::MovingRepresentationDescriptorType MovingRepresentationDescriptorType; typedef typename Superclass::TargetRepresentationDescriptorType TargetRepresentationDescriptorType; typedef typename Superclass::RegistrationPointer RegistrationPointer; typedef typename Superclass::RegistrationType RegistrationType; typedef typename Superclass::FieldRepRequirement FieldRepRequirement; typedef typename MetaPropertyAlgorithmBase::MetaPropertyType MetaPropertyType; typedef typename MetaPropertyAlgorithmBase::MetaPropertyPointer MetaPropertyPointer; typedef typename MetaPropertyAlgorithmBase::MetaPropertyNameType MetaPropertyNameType; mapDefineAlgorithmIdentificationByPolicyMacro; // IterativeRegistrationAlgorithm /*! @eguarantee strong*/ virtual bool isStoppable() const; /*! has the algorithm an iteration count? @eguarantee no fail @return Indicates if the algorithm can determin its current iteration count */ virtual bool hasIterationCount() const; /*! has the algorithm an maximum iteration count? @eguarantee no fail @return Indicates if the algorithm can determin its maximum iteration count */ virtual bool hasMaxIterationCount() const; /*! This function indicates if the optimizer of the iterative registration algorithm is * able to return its current metric/optimizer value(s)? @eguarantee no fail @return Indicates if the algorithm can determin its curent value. */ virtual bool hasCurrentOptimizerValue() const; virtual typename FieldRepRequirement::Type isMovingRepresentationRequired() const; virtual typename FieldRepRequirement::Type isTargetRepresentationRequired() const; /*! @reimplemented */ virtual bool isReusable() const; mapGetMetaMacro(WorkingDirectory, core::String); mapSetMetaMacro(WorkingDirectory, core::String); mapGetMetaMacro(ElastixDirectory, core::String); mapSetMetaMacro(ElastixDirectory, core::String); mapGetMetaMacro(DeleteTempDirectory, bool); mapSetMetaMacro(DeleteTempDirectory, bool); protected: CLIRegistrationAlgorithmBase(); virtual ~CLIRegistrationAlgorithmBase(); typedef typename Superclass::InterimRegistrationType InterimRegistrationType; typedef typename Superclass::InterimRegistrationPointer InterimRegistrationPointer; typedef typename Superclass::IterationCountType IterationCountType; typedef typename ImageRegistrationAlgorithmBaseType::MovingImageConstPointer MovingImageConstPointer; typedef typename ImageRegistrationAlgorithmBaseType::TargetImageConstPointer TargetImageConstPointer; + typedef ::itk::GenericVectorFieldTransform< ::map::core::continuous::ScalarType, TTargetImage::ImageDimension, TTargetImage::ImageDimension> FieldTransformType; + typedef typename map::core::RegistrationTopology::InverseFieldType FinalFieldType; typedef typename FinalFieldType::Pointer FinalFieldPointer; typedef std::vector ParameterMapVectorType; /* @reimplemented*/ virtual void configureAlgorithm(); // MetaPropertyAlgorithmBase /*! @reimplemented*/ virtual void compileInfos(MetaPropertyVectorType& infos) const; /*! @reimplemented*/ virtual MetaPropertyPointer doGetProperty(const MetaPropertyNameType& name) const; /*! @reimplemented*/ virtual void doSetProperty(const MetaPropertyNameType& name, const MetaPropertyType* pProperty); // IterativeRegistrationAlgorithmInterface /*! @brief gets the registration result that has been computed in the last iteration. This result is limited by the passed region descriptors (pMovingRepresentation, pTargetRepresentation). @pre pMovingRepresentation and pTargetRepresentation must not be null. @param [in] pMovingRepresentation Pointer to @eguarantee strong @return the interim registration result as smart pointer @retval a Registration object @sa Registration */ virtual InterimRegistrationPointer determineInterimRegistration(const MovingRepresentationDescriptorType* pMovingRepresentation, const TargetRepresentationDescriptorType* pTargetRepresentation) const; /*! * Returns the final registration @eguarantee strong */ virtual RegistrationPointer doGetRegistration() const; /*! Returns if the registration should be computed. The registration is outdated if doGetRegistration returns null * or the modification time of at least one sub component is newer then the modification time of the registration. @eguarantee strong @return true if the registration should be (re)computed. False if the registration is uptodate. */ virtual bool registrationIsOutdated() const; virtual bool doStopAlgorithm(); /*! This method should do all preparation tasks right before the algorithm is executed. At the end of this method the algorithm should be set up and ready to use.\n The method delegates the main work of initialization to several sub methods. These sub methods serve as slots that can be rewritten by an algorithm developer to alter certain aspects and keep the rest untouched.\n The sequence of slot calls is: \n - prepCheckValidity - prepPerpareInternalInputData - prepSaveElastixInputData - prepParameterMaps - prepFinalizePreparation @remark If you want to change the execution style, then overwrite runAlgorithm(). @eguarantee strong*/ virtual void prepareAlgorithm(); /*! This method is the slot to check if all internal components and input data are properly set. @remark The default implementation checks the moving and target image. Overload this method to alter the validity check. @remark It is assumed that the implementation of this method throws an exception if the algorithm is not configured correctly.*/ virtual void prepCheckValidity(); /*! This method is the slot for internal preprocessing of input data. This method should be reimplemented if you want to prepare the input data before they go into the internal registration method. E.g. blurring or normalizing the moving and target image before registration. @remark The default implementation does nothing. Thus the public input data will be the data used by the internal algorithm. @remark Implementations of this method should work on _spInternalMoving and _spInternalTargetImage. In the default implementation of prepSetInternalInputData() these member will be passed to the internal algorithm. @eguarantee strong*/ virtual void prepPerpareInternalInputData(); /*! This method is the slot for storing the relevant input data to the working directory of elastix. * @remark The default implementation stores _spInternalMoving and _spInternalTargetImage and the masks if set. @eguarantee strong */ virtual void prepSaveElastixInputData(); /*! This method is the slot for the generation of the parameter maps that should be passed to elastix. The base class assumes that after calling this methods the member _parameterMaps contains all parameters for all stages. @eguarantee strong */ virtual void prepParameterMaps() = 0; /*! This method should just execute the iteration loop. * @remark If you want to change the initialization or the finalization, then overwrite prepareIteration() or finalizeAlgorithm(). * @return Indicates if the registration was successfully determined (e.g. could be * false if an iterative algorithm was stopped prematurely by the user). * @eguarantee strong */ virtual bool runAlgorithm(); /*! This method should do all the finalization work (e.g. generating the registration based on the iteration results). * @remark If you want to change the initialization or the iteration, then overwrite prepareIteration() or iterateAlgorithm(). @eguarantee strong */ virtual void finalizeAlgorithm(); /*! return the optimizer value(s) of the current iteration step. Will be called by getCurrentOptimizerValue() if hasCurrentValue() returns true. @eguarantee strong @return current measure */ virtual OptimizerMeasureType doGetCurrentOptimizerValue() const; /*! Methods invoked by derivated classes. */ virtual void PrintSelf(std::ostream& os, ::itk::Indent indent) const; /*! Feature is not supported by this wrapper. Therefore the methods returns only a dummy value (0). * @eguarantee strong*/ virtual IterationCountType doGetCurrentIteration() const; /*! Feature is not supported by this wrapper. Therefore the methods returns only a dummy value (0). @eguarantee strong */ virtual IterationCountType doGetMaxIterations() const; /*! This method generates a unique and random subdirectory contained by _workingDir. * The path to this directory is stored in _currentTempDir. * @eguarantee strong */ void initializeCurrentTempDir(); /*! Helper function that uses transformix to generate a deformation file. The generated file is loaded and returned by the function.*/ FinalFieldPointer generateField() const; /*! Helper function that generates the file path to the parameter file for a certain stage (passed by parameter) regarding the current settings of the instance. @remark This function does not check if the passed stage NR is out of bound.*/ core::String getParameterFilePath(unsigned int stageNr) const; /*! Helper function that generates the file path to the result parameters for the final(last stage) transform. @pre Algorithm must have at least one stage.*/ core::String getFinalTransformFilePath() const; /*!Pointer to the moving image used by the algorithm internally. This is used to allow the algorithm * or its derived classes to modify the moving image without changing the public moving image pointer. * The variable is set by prepareIteration() to _spMovingImage before calling prepareInternalInputData(). * (e.g.: An algorithm always normalizes an image before registration. Then the algorithm can use the prepareInternalInputData() * function to manipulate _spInternalMovingImage before it is used by prepareIteration() to set the internal algorithm)*/ MovingImageConstPointer _spInternalMovingImage; /*!Pointer to the target image used by the algorithm internally. This is used to allow the algorithm * or its derived classes to modify the target image with out changing the public target image pointer. * The variable is set by prepareIteration() to _spTargetImage before calling prepareInternalInputData(). * (e.g.: An algorithm always normalizes an image before registration. Then the algorithm can use the prepareInternalInputData() * function to manipulate _spInternalTargetImage before it is used by prepareIteration() to set the internal algorithm)*/ TargetImageConstPointer _spInternalTargetImage; /*!Directory that can be used to store temporary data. Process must have write access to this directory*/ core::String _workingDir; /*!Directory where the elastix tools 'elastix' and 'transformix' are located.*/ core::String _elastixDir; /*!Directory that is used to store temporary data on the current run*/ core::String _currentTempDir; /*!Vector with elastix parameter maps, each element of the vector is the parameter map for one registration stage of elastix*/ ParameterMapVectorType _parameterMaps; core::String _movingImageTempPath; core::String _targetImageTempPath; core::String _finalFieldTempPath; core::String _movingMaskTempPath; core::String _targetMaskTempPath; bool _deleteTempDirectory; /*! This member function is called by the process executer, whenever Elastix generates an output on stdout.*/ void onElxOutputEvent(::itk::Object* caller, const ::itk::EventObject& eventObject); /*! Helper method that removes the current temp dir (if it exists and _deleteTempDirectory is true). * @eguarantee no throw*/ void cleanTempDir() const; private: /*! The parameters of the registration field generated by transformix by using the results of elastix.*/ typename FinalFieldPointer _spFinalizedField; /*! Smartpointer to the finalized registration. Will be set by finalizeAlgorithm()*/ typename RegistrationType::Pointer _spFinalizedRegistration; /*! The lock is used to manage the access to the member variable _currentIterationCount.*/ mutable ::itk::SimpleFastMutexLock _currentIterationLock; CLIRegistrationAlgorithmBase(const Self& source); void operator=(const Self&); //purposely not implemented }; } } } #ifndef MatchPoint_MANUAL_TPP #include "mapElxCLIRegistrationAlgorithmBase.tpp" #endif #endif diff --git a/Code/Algorithms/Elastix/include/mapElxCLIRegistrationAlgorithmBase.tpp b/Code/Algorithms/Elastix/include/mapElxCLIRegistrationAlgorithmBase.tpp index 05282f4..37234d0 100644 --- a/Code/Algorithms/Elastix/include/mapElxCLIRegistrationAlgorithmBase.tpp +++ b/Code/Algorithms/Elastix/include/mapElxCLIRegistrationAlgorithmBase.tpp @@ -1,737 +1,742 @@ // ----------------------------------------------------------------------- // MatchPoint - DKFZ translational registration framework // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See mapCopyright.txt or // http://www.dkfz.de/en/sidt/projects/MatchPoint/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) // Subversion HeadURL: $HeadURL$ */ #ifndef __MAP_ELX_CLI_REGISTRATION_ALGORITHM_BASE_TPP #define __MAP_ELX_CLI_REGISTRATION_ALGORITHM_BASE_TPP #include "itkSpatialObjectToImageFilter.h" #include "itkImage.h" #include "mapAlgorithmException.h" -#include "mapFieldBasedRegistrationKernels.h" +#include "mapPreCachedRegistrationKernel.h" #include "mapInverseRegistrationKernelGenerator.h" #include "mapRegistrationManipulator.h" #include "mapAlgorithmWrapperEvent.h" #include "mapImageWriter.h" #include "mapProcessExecutor.h" #include "mapConvert.h" #include "mapMetaProperty.h" #include "mapString.h" #include "mapFieldByFileLoadFunctor.h" +#include "mapFieldDecomposer.h" namespace map { namespace algorithm { namespace elastix { template typename CLIRegistrationAlgorithmBase::FieldRepRequirement::Type CLIRegistrationAlgorithmBase:: isMovingRepresentationRequired() const { return FieldRepRequirement::No; }; template typename CLIRegistrationAlgorithmBase::FieldRepRequirement::Type CLIRegistrationAlgorithmBase:: isTargetRepresentationRequired() const { return FieldRepRequirement::No; }; template bool CLIRegistrationAlgorithmBase:: isStoppable() const { return false; }; template typename CLIRegistrationAlgorithmBase::IterationCountType CLIRegistrationAlgorithmBase:: doGetCurrentIteration() const { return 0; }; template typename CLIRegistrationAlgorithmBase::IterationCountType CLIRegistrationAlgorithmBase:: doGetMaxIterations() const { return 0; }; template bool CLIRegistrationAlgorithmBase:: hasIterationCount() const { return false; }; template bool CLIRegistrationAlgorithmBase:: hasMaxIterationCount() const { return false; }; template bool CLIRegistrationAlgorithmBase:: hasCurrentOptimizerValue() const { return false; }; template CLIRegistrationAlgorithmBase:: CLIRegistrationAlgorithmBase() : _deleteTempDirectory(true) { _spInternalMovingImage = NULL; _spInternalTargetImage = NULL; }; template CLIRegistrationAlgorithmBase:: ~CLIRegistrationAlgorithmBase() { }; template bool CLIRegistrationAlgorithmBase:: isReusable() const { return true; }; template void CLIRegistrationAlgorithmBase:: configureAlgorithm() { if (this->isFirstConfiguration()) { _elastixDir = ""; core::String envDir = ""; if (itksys::SystemTools::GetEnv("MAP_ELASTIX_PATH", envDir)) { _elastixDir = envDir; } _workingDir = itksys::SystemTools::GetCurrentWorkingDirectory(); _deleteTempDirectory = true; } }; template void CLIRegistrationAlgorithmBase:: compileInfos(MetaPropertyVectorType& infos) const { #ifndef MAP_SEAL_ALGORITHMS infos.push_back(map::algorithm::MetaPropertyInfo::New("WorkingDirectory", typeid(map::core::String), true, true)); infos.push_back(map::algorithm::MetaPropertyInfo::New("ElastixDirectory", typeid(map::core::String), true, true)); infos.push_back(map::algorithm::MetaPropertyInfo::New("DeleteTempDirectory", typeid(bool), true, true)); #endif }; template typename CLIRegistrationAlgorithmBase::MetaPropertyPointer CLIRegistrationAlgorithmBase:: doGetProperty(const MetaPropertyNameType& name) const { MetaPropertyPointer spResult; if (name == "WorkingDirectory") { spResult = map::core::MetaProperty::New(this->_workingDir); } else if (name == "ElastixDirectory") { spResult = map::core::MetaProperty::New(this->_elastixDir); } else if (name == "DeleteTempDirectory") { spResult = map::core::MetaProperty::New(this->_deleteTempDirectory); } else { assert(false); //any other property name should have been excluded by the calling function. } return spResult; }; template void CLIRegistrationAlgorithmBase:: doSetProperty(const MetaPropertyNameType& name, const MetaPropertyType* pProperty) { if (name == "WorkingDirectory") { core::String dir; map::core::unwrapMetaProperty(pProperty, dir); this->_workingDir = dir; } else if (name == "ElastixDirectory") { core::String dir; map::core::unwrapMetaProperty(pProperty, dir); this->_elastixDir = dir; } else if (name == "DeleteTempDirectory") { bool del; map::core::unwrapMetaProperty(pProperty, del); this->_deleteTempDirectory = del; } else { assert(false); //any other property name should have been excluded by the calling function. } }; template typename CLIRegistrationAlgorithmBase::InterimRegistrationPointer CLIRegistrationAlgorithmBase:: determineInterimRegistration(const MovingRepresentationDescriptorType* pMovingRepresentation, const TargetRepresentationDescriptorType* pTargetRepresentation) const { InterimRegistrationPointer spResult = NULL; return spResult; }; template bool CLIRegistrationAlgorithmBase:: doStopAlgorithm() { assert(false); mapExceptionMacro(AlgorithmException, << "Cannot stop Elastix algorithm. Interim stop feature is not supported. Wrong usage of iterative algorithm interface"); }; template void CLIRegistrationAlgorithmBase:: initializeCurrentTempDir() { srand(time(NULL)); core::OStringStream stream; - stream << itksys::SystemTools::GetCurrentDateTime("%Y-%m-%d_%H-%M-%S") << "_#" << rand(); + stream << itksys::SystemTools::GetCurrentDateTime("%Y-%m-%d_%H-%M-%S") << "_" << rand(); core::String currentTempDir = core::FileDispatch::createFullPath(_workingDir, stream.str()); if (!itksys::SystemTools::MakeDirectory(currentTempDir.c_str())) { mapExceptionMacro(AlgorithmException, << "Cannot create temporary working sub dir. Please check validity of given working dir and ensure right privileges for the application. Failed temporary sub dir: " << _currentTempDir); } _currentTempDir = currentTempDir; }; template void CLIRegistrationAlgorithmBase:: prepareAlgorithm() { try { this->prepCheckValidity(); this->_spFinalizedRegistration = NULL; //initialize registration components this->InvokeEvent(events::AlgorithmEvent(this, "Transfer cached MetaProperties.")); this->configureAlgorithmByMetaProperties(); this->InvokeEvent(events::AlgorithmEvent(this, "Initializing registration.")); this->initializeCurrentTempDir(); //preparing data this->InvokeEvent(events::AlgorithmEvent(this, "Initializing/Preparing input data.")); _spInternalMovingImage = this->getMovingImage(); _spInternalTargetImage = this->getTargetImage(); this->prepPerpareInternalInputData(); //storing temporary images this->InvokeEvent(events::AlgorithmEvent(this, "Passing input data to elastix working directory.")); this->prepSaveElastixInputData(); this->InvokeEvent(events::AlgorithmEvent(this, "Generating parameter maps for elastix.")); this->prepParameterMaps(); if (this->_parameterMaps.empty()) { mapExceptionMacro(AlgorithmException, << "Cannot start algorithm; no parameter maps are defined."); } unsigned int stageNR = 0; for (ParameterMapVectorType::const_iterator pos = this->_parameterMaps.begin(); pos != this->_parameterMaps.end(); ++pos, ++stageNR) { this->InvokeEvent(events::AlgorithmEvent(this, "Store parameter map for stage #" + map::core::convert::toStr(stageNR) + ".")); saveParameterMapToFile(*pos, this->getParameterFilePath(stageNR)); } } catch (...) { cleanTempDir(); throw; } }; template void CLIRegistrationAlgorithmBase:: cleanTempDir() const { try { if (itksys::SystemTools::FileExists(_currentTempDir.c_str()) && this->_deleteTempDirectory) { itksys::SystemTools::RemoveADirectory(_currentTempDir.c_str()); } } catch (...) { mapLogWarningObjMacro( << "Cannot clean up. Exception while removing the directory. Directory" << this->_currentTempDir); } }; template void CLIRegistrationAlgorithmBase:: prepCheckValidity() { if (!this->getMovingImage()) { mapExceptionMacro(AlgorithmException, << "Cannot start algorithm; no moving image."); } if (!this->getTargetImage()) { mapExceptionMacro(AlgorithmException, << "Cannot start algorithm; no target image."); } } template void CLIRegistrationAlgorithmBase:: prepPerpareInternalInputData() { //default implementation does nothing } template void saveTempImage(const TImage* image, const core::String& filePath) { typedef typename io::ImageWriter WriterType; typename WriterType::Pointer spWriter = WriterType::New(); spWriter->setInput(image); spWriter->setFilePath(filePath); spWriter->update(); }; template typename ::itk::Image::Pointer generateMaskImage(const ::itk::SpatialObject* so, const core::FieldRepresentationDescriptor* descriptor) { assert(so); assert(descriptor); typedef ::itk::Image MaskImageType; typedef ::itk::SpatialObject ObjectType; typedef ::itk::SpatialObjectToImageFilter FilterType; typename FilterType::Pointer spFilter = FilterType::New(); spFilter->SetInput(so); typename MaskImageType::SizeType size; for (unsigned long i = 0; i < VDimension; ++i) { size[i] = static_cast (descriptor->getSize()[i] / descriptor->getSpacing()[i]); } spFilter->SetSize(size); spFilter->SetSpacing(descriptor->getSpacing()); spFilter->SetOrigin(descriptor->getOrigin()); spFilter->SetDirection(descriptor->getDirection()); spFilter->Update(); spFilter->SetInsideValue(1); spFilter->SetOutsideValue(0); return spFilter->GetOutput(); }; template void CLIRegistrationAlgorithmBase:: prepSaveElastixInputData() { //save the images _movingImageTempPath = core::FileDispatch::createFullPath(_currentTempDir, "moving.mhd"); _targetImageTempPath = core::FileDispatch::createFullPath(_currentTempDir, "target.mhd"); _finalFieldTempPath = core::FileDispatch::createFullPath(_currentTempDir, "deformationField.mhd"); _movingMaskTempPath = ""; _targetMaskTempPath = ""; this->InvokeEvent(events::AlgorithmEvent(this, "Write temporary moving image. Path: " + _movingImageTempPath)); saveTempImage(_spInternalMovingImage.GetPointer(), _movingImageTempPath); this->InvokeEvent(events::AlgorithmEvent(this, "Write temporary target image. Path: " + _targetImageTempPath)); saveTempImage(_spInternalTargetImage.GetPointer(), _targetImageTempPath); //save the masks if (this->getMovingMask().IsNotNull()) { //add moving mask typedef itk::Image MaskImageType; MaskImageType::Pointer spMovingMaskImage = generateMaskImage (this->getMovingMask(), core::createFieldRepresentation(*(_spInternalMovingImage)).GetPointer()); _movingMaskTempPath = core::FileDispatch::createFullPath(_currentTempDir, "movingMask.mhd"); this->InvokeEvent(events::AlgorithmEvent(this, "Write temporary moving mask image. Path: " + _movingMaskTempPath)); saveTempImage(spMovingMaskImage.GetPointer(), _movingMaskTempPath); } if (this->getTargetMask().IsNotNull()) { //add target mask typedef itk::Image MaskImageType; MaskImageType::Pointer spTargetMaskImage = generateMaskImage (this->getTargetMask(), core::createFieldRepresentation(*(_spInternalTargetImage)).GetPointer()); _targetMaskTempPath = core::FileDispatch::createFullPath(_currentTempDir, "targetMask.mhd"); this->InvokeEvent(events::AlgorithmEvent(this, "Write temporary target mask image. Path: " + _targetMaskTempPath)); saveTempImage(spTargetMaskImage.GetPointer(), _targetMaskTempPath); } } template bool CLIRegistrationAlgorithmBase:: runAlgorithm() { map::utilities::ProcessExecutor::Pointer spExec = map::utilities::ProcessExecutor::New(); typename ::itk::MemberCommand::Pointer spCommand = ::itk::MemberCommand::New(); spCommand->SetCallbackFunction(this, &Self::onElxOutputEvent); spExec->AddObserver(map::events::ExternalProcessStdOutEvent(), spCommand); map::utilities::ProcessExecutor::ArgumentListType args; args.push_back("-m"); args.push_back(_movingImageTempPath); args.push_back("-f"); args.push_back(_targetImageTempPath); args.push_back("-out"); args.push_back(_currentTempDir); if (this->getMovingMask().IsNotNull()) { //add moving mask args.push_back("-mMask"); args.push_back(_movingMaskTempPath); } if (this->getTargetMask().IsNotNull()) { //add target mask args.push_back("-tMask"); args.push_back(_targetMaskTempPath); } unsigned int stageNR = 0; for (ParameterMapVectorType::const_iterator pos = this->_parameterMaps.begin(); pos != this->_parameterMaps.end(); ++pos, ++stageNR) { args.push_back("-p"); args.push_back(this->getParameterFilePath(stageNR)); } core::OStringStream ostr; ostr << "Calling elastix (" << _elastixDir << ") with arguments:"; for (map::utilities::ProcessExecutor::ArgumentListType::const_iterator pos = args.begin(); pos != args.end(); ++pos) { ostr << " " << *pos; } this->InvokeEvent(events::AlgorithmEvent(this, ostr.str())); if (!spExec->execute(_elastixDir, core::FileDispatch::createFullPath(_elastixDir, "elastix"), args)) { mapExceptionMacro(AlgorithmException, << "Error when executing elastix to determine the registration."); } return spExec->getExitValue() == 0; }; template typename CLIRegistrationAlgorithmBase::FinalFieldPointer CLIRegistrationAlgorithmBase:: generateField() const { map::utilities::ProcessExecutor::Pointer spExec = map::utilities::ProcessExecutor::New(); map::utilities::ProcessExecutor::ArgumentListType args; args.push_back("-def"); args.push_back("all"); args.push_back("-out"); args.push_back(_currentTempDir); args.push_back("-tp"); args.push_back(this->getFinalTransformFilePath()); core::OStringStream ostr; ostr << "Calling transformix (" << _elastixDir << ") with arguments:"; for (map::utilities::ProcessExecutor::ArgumentListType::const_iterator pos = args.begin(); pos != args.end(); ++pos) { ostr << " " << *pos; } this->InvokeEvent(events::AlgorithmEvent(NULL, ostr.str())); if (!spExec->execute(_elastixDir, core::FileDispatch::createFullPath(_elastixDir, "transformix"), args)) { mapExceptionMacro(AlgorithmException, << "Error when executing transformix to generate the deformation field."); } typedef map::core::functors::FieldByFileLoadFunctor FunctorType; FunctorType::Pointer spFunctor = FunctorType::New(_finalFieldTempPath); - FinalFieldPointer spField = spFunctor->generateField(); - + FinalFieldPointer spField; + ::map::core::FieldDecomposer::decomposeTransform(spFunctor->generateTransform(), spField); + if (spField.IsNull()) { mapExceptionMacro(AlgorithmException, << "Error when loading transformix deformation field. File name: " << _finalFieldTempPath); } return spField; }; template core::String map::algorithm::elastix::CLIRegistrationAlgorithmBase:: getParameterFilePath(unsigned int stageNr) const { core::OStringStream ostr; ostr << "parameters_stage_#" << stageNr << ".txt"; core::String result = core::FileDispatch::createFullPath(_currentTempDir, ostr.str()); return result; }; template core::String map::algorithm::elastix::CLIRegistrationAlgorithmBase:: getFinalTransformFilePath() const { if (this->_parameterMaps.empty()) { mapExceptionMacro(AlgorithmException, << "Cannot determine final transform file path; no parameter maps are defined."); } core::OStringStream ostr; ostr << "TransformParameters." << this->_parameterMaps.size() - 1 << ".txt"; core::String result = core::FileDispatch::createFullPath(_currentTempDir, ostr.str()); return result; }; template void CLIRegistrationAlgorithmBase:: finalizeAlgorithm() { RegistrationPointer spResult = NULL; try { _spFinalizedField = this->generateField(); - typedef map::core::FieldKernels::PreCachedFieldBasedRegistrationKernel - InverseKernelType; - typename InverseKernelType::Pointer spIKernel = InverseKernelType::New(); + typedef typename + map::core::PreCachedRegistrationKernel InverseKernelType; - spIKernel->setField(*(_spFinalizedField.GetPointer())); + typename FieldTransformType::Pointer transform = FieldTransformType::New(); + transform->SetDisplacementField(_spFinalizedField.GetPointer()); - //now build the direct kernel via inversion of the inverse kernel - typedef core::InverseRegistrationKernelGenerator - GeneratorType; - typename GeneratorType::Pointer spGenerator = GeneratorType::New(); - typedef typename GeneratorType::InverseKernelBaseType DirectKernelType; - typename Superclass::MovingRepresentationDescriptorType::ConstPointer spMovingRep = - core::createFieldRepresentation(*(this->getMovingImage())); + typename InverseKernelType::Pointer spIKernel = InverseKernelType::New(); + spIKernel->setTransformModel(transform); - if (this->getMovingRepresentation()) - { - //user has defined a representation descriptor -> use this one - spMovingRep = this->getMovingRepresentation(); - } + //now build the direct kernel via inversion of the inverse kernel + typedef core::InverseRegistrationKernelGenerator < RegistrationType::TargetDimensions, RegistrationType::MovingDimensions > + GeneratorType; + typename GeneratorType::Pointer spGenerator = GeneratorType::New(); + typedef typename GeneratorType::InverseKernelBaseType DirectKernelType; + typename Superclass::MovingRepresentationDescriptorType::ConstPointer spMovingRep = + ::map::core::createFieldRepresentation(*(this->getMovingImage())).GetPointer(); - typename DirectKernelType::Pointer spDKernel = spGenerator->generateInverse(* - (spIKernel.GetPointer()), spMovingRep); + if (this->getMovingRepresentation()) + { + //user has defined a representation descriptor -> use this one + spMovingRep = this->getMovingRepresentation(); + } - if (spDKernel.IsNull()) - { - mapExceptionMacro(AlgorithmException, - << "Error. Cannot determine direct mapping kernel of final registration. Current inverse kernel: " - << spIKernel); - } + typename DirectKernelType::Pointer spDKernel = spGenerator->generateInverse(* + (spIKernel.GetPointer()), spMovingRep); + + if (spDKernel.IsNull()) + { + mapExceptionMacro(AlgorithmException, + << "Error. Cannot determine direct mapping kernel of final registration. Current inverse kernel: " + << spIKernel); + } - //now create the registration and set the kernels - spResult = RegistrationType::New(); - core::RegistrationManipulator manipulator(spResult); + //now create the registration and set the kernels + spResult = RegistrationType::New(); + ::map::core::RegistrationManipulator manipulator(spResult); - manipulator.setDirectMapping(spDKernel); - manipulator.setInverseMapping(spIKernel); - manipulator.getTagValues()[tags::AlgorithmUID] = this->getUID()->toStr(); + manipulator.setDirectMapping(spDKernel); + manipulator.setInverseMapping(spIKernel); + manipulator.getTagValues()[tags::AlgorithmUID] = this->getUID()->toStr(); - _spFinalizedRegistration = spResult; + _spFinalizedRegistration = spResult; } catch (...) { //delete temp dir even in case of an exception cleanTempDir(); throw; } //delete temp dir cleanTempDir(); _currentTempDir = ""; }; template typename CLIRegistrationAlgorithmBase::RegistrationPointer CLIRegistrationAlgorithmBase:: doGetRegistration() const { return _spFinalizedRegistration; }; template bool CLIRegistrationAlgorithmBase:: registrationIsOutdated() const { bool outdated = _spFinalizedRegistration.IsNull(); if (_spFinalizedRegistration.IsNotNull()) { if (!outdated) { //check if the inputs have been changed outdated = this->_spInternalMovingImage != this->getMovingImage(); } if (!outdated) { //check if the inputs have been changed outdated = this->_spInternalTargetImage != this->getTargetImage(); } } return outdated; }; template typename CLIRegistrationAlgorithmBase::OptimizerMeasureType CLIRegistrationAlgorithmBase:: doGetCurrentOptimizerValue() const { OptimizerMeasureType result; return result; }; template void CLIRegistrationAlgorithmBase:: PrintSelf(std::ostream& os, ::itk::Indent indent) const { Superclass::PrintSelf(os, indent); ImageRegistrationAlgorithmBase::PrintSelf(os, indent); os << indent << "Finalized registration: " << _spFinalizedRegistration << std::endl; }; template void CLIRegistrationAlgorithmBase:: onElxOutputEvent(::itk::Object* caller, const ::itk::EventObject& eventObject) { const events::ExternalProcessStdOutEvent* pStdEvent = dynamic_cast(&eventObject); if (pStdEvent) { this->InvokeEvent(events::AlgorithmIterationEvent(this, pStdEvent->getComment())); } } } // end namespace elastix } // end namespace algorithm } // end namespace map #endif diff --git a/Code/Algorithms/Elastix/include/mapElxParameterFileRegistrationAlgorithm.tpp b/Code/Algorithms/Elastix/include/mapElxParameterFileRegistrationAlgorithm.tpp index b05bdd2..b539f05 100644 --- a/Code/Algorithms/Elastix/include/mapElxParameterFileRegistrationAlgorithm.tpp +++ b/Code/Algorithms/Elastix/include/mapElxParameterFileRegistrationAlgorithm.tpp @@ -1,126 +1,122 @@ // ----------------------------------------------------------------------- // MatchPoint - DKFZ translational registration framework // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See mapCopyright.txt or // http://www.dkfz.de/en/sidt/projects/MatchPoint/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) // Subversion HeadURL: $HeadURL$ */ #ifndef __MAP_ELX_PARAMETERFILE_REGISTRATION_ALGORITHM_TPP #define __MAP_ELX_PARAMETERFILE_REGISTRATION_ALGORITHM_TPP //Elastix -#include "itkParameterFileParser.h" namespace map { namespace algorithm { namespace elastix { template ParameterFileRegistrationAlgorithm:: ParameterFileRegistrationAlgorithm() { }; template ParameterFileRegistrationAlgorithm:: ~ParameterFileRegistrationAlgorithm() { }; template void ParameterFileRegistrationAlgorithm:: configureAlgorithm() { if (this->isFirstConfiguration()) { Superclass::configureAlgorithm(); _parameterFilePath = ""; } }; template void ParameterFileRegistrationAlgorithm:: compileInfos(MetaPropertyVectorType& infos) const { Superclass::compileInfos(infos); #ifndef MAP_SEAL_ALGORITHMS infos.push_back(map::algorithm::MetaPropertyInfo::New("ParameterFilePath", typeid(map::core::String), true, true)); #endif }; template typename ParameterFileRegistrationAlgorithm::MetaPropertyPointer ParameterFileRegistrationAlgorithm:: doGetProperty(const MetaPropertyNameType& name) const { MetaPropertyPointer spResult; if (name == "ParameterFilePath") { spResult = map::core::MetaProperty::New(this->_parameterFilePath); } else { spResult = Superclass::doGetProperty(name); } return spResult; }; template void ParameterFileRegistrationAlgorithm:: doSetProperty(const MetaPropertyNameType& name, const MetaPropertyType* pProperty) { if (name == "ParameterFilePath") { core::String path; map::core::unwrapMetaProperty(pProperty, path); this->_parameterFilePath = path; } else { Superclass::doSetProperty(name, pProperty); } }; template void ParameterFileRegistrationAlgorithm:: prepParameterMaps() { - itk::ParameterFileParser::Pointer spParser = itk::ParameterFileParser::New(); - spParser->SetParameterFileName(this->_parameterFilePath); - spParser->ReadParameterFile(); - ParameterMapType map = spParser->GetParameterMap(); + ParameterMapType map = readParameterMapFromFile(this->_parameterFilePath); this->_parameterMaps.clear(); this->_parameterMaps.push_back(map); } } // end namespace elastix } // end namespace algorithm } // end namespace map #endif diff --git a/Code/Algorithms/Elastix/source/ParameterFileParser/LICENSE b/Code/Algorithms/Elastix/source/ParameterFileParser/LICENSE new file mode 100644 index 0000000..d645695 --- /dev/null +++ b/Code/Algorithms/Elastix/source/ParameterFileParser/LICENSE @@ -0,0 +1,202 @@ + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/Code/Algorithms/Elastix/source/ParameterFileParser/README.md b/Code/Algorithms/Elastix/source/ParameterFileParser/README.md new file mode 100644 index 0000000..7f8d294 --- /dev/null +++ b/Code/Algorithms/Elastix/source/ParameterFileParser/README.md @@ -0,0 +1,8 @@ +The files in this directory are from "elastix" + +The have been directly extracted form "elastix/Common/ParameterFileParser/" in order to allow the build of MatchPoint CLI based elastix wrappers without the need of have a development version of elastix for linkage. +The content of this directory is lincensed under Apache License 2.0 (see LICENSE for more information). + +For more information regarding elastix please visit: +https://github.com/SuperElastix/elastix +http://elastix.isi.uu.nl/index.php diff --git a/Code/Algorithms/Elastix/source/ParameterFileParser/itkParameterFileParser.cxx b/Code/Algorithms/Elastix/source/ParameterFileParser/itkParameterFileParser.cxx new file mode 100644 index 0000000..e427fef --- /dev/null +++ b/Code/Algorithms/Elastix/source/ParameterFileParser/itkParameterFileParser.cxx @@ -0,0 +1,477 @@ +/*========================================================================= + * + * Copyright UMC Utrecht and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ + +#ifndef __itkParameterFileParser_cxx +#define __itkParameterFileParser_cxx + +#include "itkParameterFileParser.h" + +#include +#include + +namespace itk +{ + +/** + * **************** Constructor *************** + */ + +ParameterFileParser +::ParameterFileParser() +{ + this->m_ParameterFileName = ""; + this->m_ParameterMap.clear(); + +} // end Constructor() + + +/** + * **************** Destructor *************** + */ + +ParameterFileParser +::~ParameterFileParser() +{ + if( this->m_ParameterFile.is_open() ) + { + this->m_ParameterFile.close(); + } + +} // end Destructor() + + +/** + * **************** GetParameterMap *************** + */ + +const ParameterFileParser::ParameterMapType & +ParameterFileParser +::GetParameterMap( void ) const +{ + return this->m_ParameterMap; + +} // end GetParameterMap() + + +/** + * **************** ReadParameterFile *************** + */ + +void +ParameterFileParser +::ReadParameterFile( void ) +{ + /** Perform some basic checks. */ + this->BasicFileChecking(); + + /** Open the parameter file for reading. */ + if( this->m_ParameterFile.is_open() ) + { + this->m_ParameterFile.clear(); + this->m_ParameterFile.close(); + } + this->m_ParameterFile.open( this->m_ParameterFileName.c_str(), std::fstream::in ); + + /** Check if it opened. */ + if( !this->m_ParameterFile.is_open() ) + { + itkExceptionMacro( << "ERROR: could not open " + << this->m_ParameterFileName + << " for reading." ); + } + + /** Clear the map. */ + this->m_ParameterMap.clear(); + + /** Loop over the parameter file, line by line. */ + std::string lineIn = ""; + std::string lineOut = ""; + while( this->m_ParameterFile.good() ) + { + /** Extract a line. */ + itksys::SystemTools::GetLineFromStream( this->m_ParameterFile, lineIn ); + + /** Check this line. */ + bool validLine = this->CheckLine( lineIn, lineOut ); + + if( validLine ) + { + /** Get the parameter name from this line and store it. */ + this->GetParameterFromLine( lineIn, lineOut ); + } + // Otherwise, we simply ignore this line + + } + + /** Close the parameter file. */ + this->m_ParameterFile.clear(); + this->m_ParameterFile.close(); + +} // end ReadParameterFile() + + +/** + * **************** BasicFileChecking *************** + */ + +void +ParameterFileParser +::BasicFileChecking( void ) const +{ + /** Check if the file name is given. */ + if( this->m_ParameterFileName == "" ) + { + itkExceptionMacro( << "ERROR: FileName has not been set." ); + } + + /** Basic error checking: existence. */ + bool exists = itksys::SystemTools::FileExists( + this->m_ParameterFileName.c_str() ); + if( !exists ) + { + itkExceptionMacro( << "ERROR: the file " + << this->m_ParameterFileName + << " does not exist." ); + } + + /** Basic error checking: file or directory. */ + bool isDir = itksys::SystemTools::FileIsDirectory( + this->m_ParameterFileName.c_str() ); + if( isDir ) + { + itkExceptionMacro( << "ERROR: the file " + << this->m_ParameterFileName + << " is a directory." ); + } + + /** Check the extension. */ + std::string ext = itksys::SystemTools::GetFilenameLastExtension( + this->m_ParameterFileName ); + if( ext != ".txt" ) + { + itkExceptionMacro( << "ERROR: the file " + << this->m_ParameterFileName + << " should be a text file (*.txt)." ); + } + +} // end BasicFileChecking() + + +/** + * **************** CheckLine *************** + */ + +bool +ParameterFileParser +::CheckLine( const std::string & lineIn, std::string & lineOut ) const +{ + /** Preprocessing of lineIn: + * 1) Replace tabs with spaces + * 2) Remove everything after comment sign // + * 3) Remove leading spaces + * 4) Remove trailing spaces + */ + lineOut = lineIn; + itksys::SystemTools::ReplaceString( lineOut, "\t", " " ); + + itksys::RegularExpression commentPart( "//" ); + if( commentPart.find( lineOut ) ) + { + lineOut = lineOut.substr( 0, commentPart.start() ); + } + + itksys::RegularExpression leadingSpaces( "^[ ]*(.*)" ); + leadingSpaces.find( lineOut ); + lineOut = leadingSpaces.match( 1 ); + + itksys::RegularExpression trailingSpaces( "[ \t]+$" ); + if( trailingSpaces.find( lineOut ) ) + { + lineOut = lineOut.substr( 0, trailingSpaces.start() ); + } + + /** + * Checks: + * 1. Empty line -> false + * 2. Comment (line starts with "//") -> false + * 3. Line is not between brackets (...) -> exception + * 4. Line contains less than two words -> exception + * + * Otherwise return true. + */ + + /** 1. Check for non-empty lines. */ + itksys::RegularExpression reNonEmptyLine( "[^ ]+" ); + bool match1 = reNonEmptyLine.find( lineOut ); + if( !match1 ) + { + return false; + } + + /** 2. Check for comments. */ + itksys::RegularExpression reComment( "^//" ); + bool match2 = reComment.find( lineOut ); + if( match2 ) + { + return false; + } + + /** 3. Check if line is between brackets. */ + if( !itksys::SystemTools::StringStartsWith( lineOut.c_str(), "(" ) + || !itksys::SystemTools::StringEndsWith( lineOut.c_str(), ")" ) ) + { + std::string hint = "Line is not between brackets: \"(...)\"."; + this->ThrowException( lineIn, hint ); + } + + /** Remove brackets. */ + lineOut = lineOut.substr( 1, lineOut.size() - 2 ); + + /** 4. Check: the line should contain at least two words. */ + itksys::RegularExpression reTwoWords( "([ ]+)([^ ]+)" ); + bool match4 = reTwoWords.find( lineOut ); + if( !match4 ) + { + std::string hint = "Line does not contain a parameter name and value."; + this->ThrowException( lineIn, hint ); + } + + /** At this point we know its at least a line containing a parameter. + * However, this line can still be invalid, for example: + * (string &^%^*) + * This will be checked later. + */ + + return true; + +} // end CheckLine() + + +/** + * **************** GetParameterFromLine *************** + */ + +void +ParameterFileParser +::GetParameterFromLine( const std::string & fullLine, + const std::string & line ) +{ + /** A line has a parameter name followed by one or more parameters. + * They are all separated by one or more spaces (all tabs have been + * removed previously) or by quotes in case of strings. So, + * 1) we split the line at the spaces or quotes + * 2) the first one is the parameter name + * 3) the other strings that are not a series of spaces, are parameter values + */ + + /** 1) Split the line. */ + std::vector< std::string > splittedLine; + this->SplitLine( fullLine, line, splittedLine ); + + /** 2) Get the parameter name. */ + std::string parameterName = splittedLine[ 0 ]; + itksys::SystemTools::ReplaceString( parameterName, " ", "" ); + splittedLine.erase( splittedLine.begin() ); + + /** 3) Get the parameter values. */ + std::vector< std::string > parameterValues; + for( unsigned int i = 0; i < splittedLine.size(); ++i ) + { + if( splittedLine[ i ] != "" ) + { + parameterValues.push_back( splittedLine[ i ] ); + } + } + + /** 4) Perform some checks on the parameter name. */ + itksys::RegularExpression reInvalidCharacters1( "[.,:;!@#$%^&-+|<>?]" ); + bool match = reInvalidCharacters1.find( parameterName ); + if( match ) + { + std::string hint = "The parameter \"" + + parameterName + + "\" contains invalid characters (.,:;!@#$%^&-+|<>?)."; + this->ThrowException( fullLine, hint ); + } + + /** 5) Perform checks on the parameter values. */ + itksys::RegularExpression reInvalidCharacters2( "[,;!@#$%&|<>?]" ); + for( unsigned int i = 0; i < parameterValues.size(); ++i ) + { + /** For all entries some characters are not allowed. */ + if( reInvalidCharacters2.find( parameterValues[ i ] ) ) + { + std::string hint = "The parameter value \"" + + parameterValues[ i ] + + "\" contains invalid characters (,;!@#$%&|<>?)."; + this->ThrowException( fullLine, hint ); + } + } + + /** 6) Insert this combination in the parameter map. */ + if( this->m_ParameterMap.count( parameterName ) ) + { + std::string hint = "The parameter \"" + + parameterName + + "\" is specified more than once."; + this->ThrowException( fullLine, hint ); + } + else + { + this->m_ParameterMap.insert( make_pair( parameterName, parameterValues ) ); + } + +} // end GetParameterFromLine() + + +/** + * **************** SplitLine *************** + */ + +void +ParameterFileParser +::SplitLine( const std::string & fullLine, const std::string & line, + std::vector< std::string > & splittedLine ) const +{ + splittedLine.clear(); + splittedLine.resize( 1 ); + std::vector< itksys::String > splittedLine1; + + /** Count the number of quotes in the line. If it is an odd value, the + * line contains an error; strings should start and end with a quote, so + * the total number of quotes is even. + */ + std::size_t numQuotes = itksys::SystemTools::CountChar( line.c_str(), '"' ); + if( numQuotes % 2 == 1 ) + { + /** An invalid parameter line. */ + std::string hint = "This line has an odd number of quotes (\")."; + this->ThrowException( fullLine, hint ); + } + + /** Loop over the line. */ + std::string::const_iterator it; + unsigned int index = 0; + numQuotes = 0; + for( it = line.begin(); it < line.end(); ++it ) + { + if( *it == '"' ) + { + /** Start a new element. */ + splittedLine.push_back( "" ); + index++; + numQuotes++; + } + else if( *it == ' ' ) + { + /** Only start a new element if it is not a quote, otherwise just add + * the space to the string. + */ + if( numQuotes % 2 == 0 ) + { + splittedLine.push_back( "" ); + index++; + } + else + { + splittedLine[ index ].push_back( *it ); + } + } + else + { + /** Add this character to the element. */ + splittedLine[ index ].push_back( *it ); + } + } + +} // end SplitLine() + + +/** + * **************** ThrowException *************** + */ + +void +ParameterFileParser +::ThrowException( const std::string & line, const std::string & hint ) const +{ + /** Construct an error message. */ + std::string errorMessage + = "ERROR: the following line in your parameter file is invalid: \n\"" + + line + + "\"\n" + + hint + + "\nPlease correct you parameter file!"; + + /** Throw exception. */ + itkExceptionMacro( << errorMessage.c_str() ); + +} // end ThrowException() + + +/** + * **************** ReturnParameterFileAsString *************** + */ + +std::string +ParameterFileParser +::ReturnParameterFileAsString( void ) +{ + /** Perform some basic checks. */ + this->BasicFileChecking(); + + /** Open the parameter file for reading. */ + if( this->m_ParameterFile.is_open() ) + { + this->m_ParameterFile.clear(); + this->m_ParameterFile.close(); + } + this->m_ParameterFile.open( this->m_ParameterFileName.c_str(), std::fstream::in ); + + /** Check if it opened. */ + if( !this->m_ParameterFile.is_open() ) + { + itkExceptionMacro( << "ERROR: could not open " + << this->m_ParameterFileName + << " for reading." ); + } + + /** Loop over the parameter file, line by line. */ + std::string line = ""; + std::string output; + while( this->m_ParameterFile.good() ) + { + /** Extract a line. */ + itksys::SystemTools::GetLineFromStream( this->m_ParameterFile, line ); // \todo: returns bool + + output += line + "\n"; + } + + /** Close the parameter file. */ + this->m_ParameterFile.clear(); + this->m_ParameterFile.close(); + + /** Return the string. */ + return output; + +} // end ReturnParameterFileAsString() + + +} // end namespace itk + +#endif // end __itkParameterFileParser_cxx diff --git a/Code/Algorithms/Elastix/source/ParameterFileParser/itkParameterFileParser.h b/Code/Algorithms/Elastix/source/ParameterFileParser/itkParameterFileParser.h new file mode 100644 index 0000000..e2e19d5 --- /dev/null +++ b/Code/Algorithms/Elastix/source/ParameterFileParser/itkParameterFileParser.h @@ -0,0 +1,163 @@ +/*========================================================================= + * + * Copyright UMC Utrecht and contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0.txt + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + *=========================================================================*/ +#ifndef __itkParameterFileParser_h +#define __itkParameterFileParser_h + +#include "itkObject.h" +#include "itkObjectFactory.h" +#include "itkMacro.h" + +#include +#include +#include +#include + +namespace itk +{ + +/** \class ParameterFileParser + * + * \brief Implements functionality to read a parameter file. + * + * A parameter file is a text file that contains parameters and their values. + * Parameters should be specified obeying certain rules.\n + * 1) A single parameter should be on a single line\n + * 2) A parameter should be specified between brackets: (...)\n + * 3) Parameters are specified by a single name, followed by one or more + * values, all separated by spaces\n + * 4) Values that are strings should be quoted using "\n + * 5) Values that are numbers should be unquoted\n + * + * For example: \n + * (ParameterName1 "string1" "string2")\n + * (ParameterName2 3 5.8)\n + * (ParameterName3 "true" "false" "true")\n + * + * The parameter file is read, and parameter name-value combinations are + * stored in an std::map< std::string, std::vector >, where the + * string is the parameter name, and the vector of strings are the values. + * Exceptions are raised in case:\n + * - the parameter text file cannot be opened,\n + * - rule 2 or 3 is not satisfied,\n + * - the parameter name or value contains invalid characters.\n + * + * Here is an example on how to use this class:\n + * + * itk::ParameterFileParser::Pointer parser = itk::ParameterFileParser::New(); + * parser->SetParameterFileName( parameterFileName ); + * try + * { + * parser->Initialize(); + * } + * catch ( itk::ExceptionObject & e ) + * { + * ... + * } + * + * The resulting map can be accessed via:\n + * + * parser->GetParameterMap(); + * + * \sa itk::ParameterMapInterface + */ + +class ParameterFileParser : public Object +{ +public: + + /** Standard ITK typedefs. */ + typedef ParameterFileParser Self; + typedef Object Superclass; + typedef SmartPointer< Self > Pointer; + typedef SmartPointer< const Self > ConstPointer; + + /** Method for creation through the object factory. */ + itkNewMacro( Self ); + + /** Run-time type information (and related methods). */ + itkTypeMacro( ParameterFileParser, Object ); + + /** Typedefs. */ + typedef std::vector< std::string > ParameterValuesType; + typedef std::map< + std::string, + ParameterValuesType > ParameterMapType; + + /** Set the name of the file containing the parameters. */ + itkSetStringMacro( ParameterFileName ); + itkGetStringMacro( ParameterFileName ); + + /** Return the parameter map. */ + virtual const ParameterMapType & GetParameterMap( void ) const; + + /** Read the parameters in the parameter map. */ + void ReadParameterFile( void ); + + /** Read the parameter file and return the content as a string. + * Useful for printing the content. + */ + std::string ReturnParameterFileAsString( void ); + +protected: + + ParameterFileParser(); + virtual ~ParameterFileParser(); + +private: + + ParameterFileParser( const Self & ); // purposely not implemented + void operator=( const Self & ); // purposely not implemented + + /** Performs the following checks: + * - Is a filename is given + * - Does the file exist + * - Is a text file, i.e. does it end with .txt + * If one of these conditions fail, an exception is thrown. + */ + void BasicFileChecking( void ) const; + + /** Checks a line. + * - Returns true if it is a valid line: containing a parameter. + * - Returns false if it is a valid line: empty or comment. + * - Throws an exception if it is not a valid line. + */ + bool CheckLine( const std::string & line, std::string & lineOut ) const; + + /** Fills m_ParameterMap with valid entries. */ + void GetParameterFromLine( const std::string & fullLine, + const std::string & line ); + + /** Splits a line in parameter name and values. */ + void SplitLine( const std::string & fullLine, const std::string & line, + std::vector< std::string > & splittedLine ) const; + + /** Uniform way to throw exceptions when the parameter file appears to be + * invalid. + */ + void ThrowException( const std::string & line, const std::string & hint ) const; + + /** Member variables. */ + std::string m_ParameterFileName; + std::ifstream m_ParameterFile; + ParameterMapType m_ParameterMap; + +}; + +} // end of namespace itk + +#endif // end __itkParameterFileParser_h diff --git a/Code/Algorithms/Elastix/source/mapElxAlgorithmHelper.cpp b/Code/Algorithms/Elastix/source/mapElxAlgorithmHelper.cpp index ab07f84..f0cda40 100644 --- a/Code/Algorithms/Elastix/source/mapElxAlgorithmHelper.cpp +++ b/Code/Algorithms/Elastix/source/mapElxAlgorithmHelper.cpp @@ -1,90 +1,101 @@ // ----------------------------------------------------------------------- // MatchPoint - DKFZ translational registration framework // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See mapCopyright.txt or // http://www.dkfz.de/en/sidt/projects/MatchPoint/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) // Subversion HeadURL: $HeadURL$ */ +//Elastix +#include "ParameterFileParser\itkParameterFileParser.h" //MatchPoint #include "mapElxAlgorithmHelper.h" #include "mapString.h" #include "mapExceptionObjectMacros.h" namespace map { namespace algorithm { namespace elastix { void saveParameterMapToFile(const ParameterMapType& parameterMap, const map::core::String& filePath) { std::ofstream file; std::ios_base::openmode iOpenFlag = std::ios_base::out | std::ios_base::trunc; file.open(filePath.c_str(), iOpenFlag); if (!file.is_open()) { mapDefaultExceptionStaticMacro( << "Cannot open or create parameter map file to save. File path: " << filePath); } for (ParameterMapType::const_iterator pos = parameterMap.begin(); pos != parameterMap.end(); ++pos) { file << "(" << pos->first; for (ParameterValuesType::const_iterator valPos = pos->second.begin(); valPos != pos->second.end(); ++valPos) { file << " " << *valPos; } file << ")\n"; } file.close(); }; + + ParameterMapType readParameterMapFromFile(const map::core::String& fileName) + { + itk::ParameterFileParser::Pointer spParser = itk::ParameterFileParser::New(); + spParser->SetParameterFileName(fileName); + spParser->ReadParameterFile(); + return spParser->GetParameterMap(); + }; + ParamGenerator::ParamGenerator() { } ParamGenerator::~ParamGenerator() { } ParamGenerator& ParamGenerator:: addStr(const core::String& value) { this->_values.push_back("\"" + value + "\""); return *this; } ParamGenerator:: operator ParameterValuesType() { return this->_values; } } } } diff --git a/Code/Algorithms/Elastix/test/mapDummyTransformix.cpp b/Code/Algorithms/Elastix/test/mapDummyTransformix.cpp index 4f96d15..a31a5c1 100644 --- a/Code/Algorithms/Elastix/test/mapDummyTransformix.cpp +++ b/Code/Algorithms/Elastix/test/mapDummyTransformix.cpp @@ -1,88 +1,91 @@ // ----------------------------------------------------------------------- // MatchPoint - DKFZ translational registration framework // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See mapCopyright.txt or // http://www.dkfz.de/en/sidt/projects/MatchPoint/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) // Subversion HeadURL: $HeadURL$ */ #include #include #include #include "itkImageFileWriter.h" #include "mapString.h" #include "test/mapTestFieldGenerationFunctor.h" #include "mapFileDispatch.h" +#include "mapFieldByModelFunctor.h" int main(int argc, char* argv[]) { std::cout << "MatchPoint Transformix testing dummy." << std::endl << "This is a mock up exe, used by MatchPoint to test its Transformix integration." << std::endl << std::endl; std::cout << "Passed command line arguments:" << std::endl; std::ofstream file; std::ios_base::openmode iOpenFlag = std::ios_base::out | std::ios_base::trunc; file.open("transformixDummyCall.log", iOpenFlag); map::core::String outputPath; bool nextIsOutput = false; for (int i = 0; i < argc; ++i) { std::cout << argv[i] << std::endl; file << argv[i] << std::endl; if (nextIsOutput) { outputPath = argv[i]; } nextIsOutput = argv[i] == map::core::String("-out"); } file.close(); //generate result a field - typedef map::testing::TestFieldGenerationFunctor<2, 2> FieldFunctorType; + typedef map::testing::TestFieldGenerationFunctor<3, 3> FieldFunctorType; FieldFunctorType::InFieldRepresentationType::SpacingType spacing(0.5); FieldFunctorType::InFieldRepresentationType::PointType origin; origin.Fill(0); FieldFunctorType::InFieldRepresentationType::SizeType size; size.fill(10); FieldFunctorType::InFieldRepresentationType::Pointer spInRep = FieldFunctorType::InFieldRepresentationType::New(); spInRep->setSize(size); spInRep->setSpacing(spacing); spInRep->setOrigin(origin); FieldFunctorType::Pointer spFunctor = FieldFunctorType::New(spInRep); - FieldFunctorType::FieldPointer spField = spFunctor->generateField(); + auto spTransform = spFunctor->generateTransform(); - typedef ::itk::ImageFileWriter< FieldFunctorType::FieldType > FieldWriterType; - FieldWriterType::Pointer spFieldWriter = FieldWriterType::New(); + ::map::core::RegistrationTopology<3, 3>::DirectFieldPointer spField = ::map::core::generateFieldFromTransform<3, 3>(spTransform, spInRep); + + typedef ::itk::ImageFileWriter< ::map::core::RegistrationTopology<3, 3>::DirectFieldType > FieldWriterType; + FieldWriterType::Pointer spFieldWriter = FieldWriterType::New(); spFieldWriter->SetFileName(map::core::FileDispatch::createFullPath(outputPath, "deformationField.mhd").c_str()); spFieldWriter->SetInput(spField); spFieldWriter->Update(); return EXIT_SUCCESS; } diff --git a/Code/Algorithms/Plastimatch/include/mapPlmCLIRegistrationAlgorithmBase.h b/Code/Algorithms/Plastimatch/include/mapPlmCLIRegistrationAlgorithmBase.h index af1c85f..a60c628 100644 --- a/Code/Algorithms/Plastimatch/include/mapPlmCLIRegistrationAlgorithmBase.h +++ b/Code/Algorithms/Plastimatch/include/mapPlmCLIRegistrationAlgorithmBase.h @@ -1,425 +1,425 @@ // ----------------------------------------------------------------------- // MatchPoint - DKFZ translational registration framework // // Copyright (c) German Cancer Research Center (DKFZ), // Software development for Integrated Diagnostics and Therapy (SIDT). // ALL RIGHTS RESERVED. // See mapCopyright.txt or // http://www.dkfz.de/en/sidt/projects/MatchPoint/copyright.html // // This software is distributed WITHOUT ANY WARRANTY; without even // the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // PURPOSE. See the above copyright notices for more information. // //------------------------------------------------------------------------ /*! // @file // @version $Revision$ (last changed revision) // @date $Date$ (last change date) // @author $Author$ (last changed by) // Subversion HeadURL: $HeadURL$ */ #ifndef __MAP_PLM_CLI_REGISTRATION_ALGORITHM_BASE_H #define __MAP_PLM_CLI_REGISTRATION_ALGORITHM_BASE_H //MatchPoint #include "mapContinuous.h" #include "mapIterativeRegistrationAlgorithm.h" #include "mapImageRegistrationAlgorithmBase.h" #include "mapClassMacros.h" #include "mapPlmAlgorithmHelper.h" #include "mapMetaPropertyAlgorithmBase.h" #include "mapMaskedRegistrationAlgorithmBase.h" #include "mapPointSetRegistrationAlgorithmInterfaceV2.h" #include "mapGenericVectorFieldTransform.h" namespace map { namespace algorithm { namespace plastimatch { /*! @class CLIRegistrationAlgorithmBase @brief This is the base class for algorithms that serve as a wrapper for the registration tool "plastimatch". The algorithm is a very simple wrapper using a command line interface to facilitate plastimatch. For a registration task a temporary working directory is generated, where the algorithm stores the given moving and target image. Then the algorithms calls 'plastimatch' with appropriated command line arguments to trigger the registration as an external process and to produce a deformation field as output. This field will be loaded, converted into a MatchPoint registration object and returned. After the registration job is done, the temporary directory will be deleted by the algorithm. @remark @ingroup Algorithms @ingroup Plastimatch */ template class CLIRegistrationAlgorithmBase : public IterativeRegistrationAlgorithm, public ImageRegistrationAlgorithmBase, public MetaPropertyAlgorithmBase, public MaskedRegistrationAlgorithmBase, public facet::PointSetRegistrationAlgorithmInterfaceV2, public TIdentificationPolicy { public: typedef CLIRegistrationAlgorithmBase Self; typedef IterativeRegistrationAlgorithm Superclass; typedef ::itk::SmartPointer Pointer; typedef ::itk::SmartPointer ConstPointer; itkTypeMacro(CLIRegistrationAlgorithmBase, IterativeRegistrationAlgorithm); typedef typename Superclass::UIDType UIDType; typedef typename Superclass::UIDPointer UIDPointer; typedef typename IterativeRegistrationAlgorithm::OptimizerMeasureType OptimizerMeasureType; typedef ImageRegistrationAlgorithmBase ImageRegistrationAlgorithmBaseType; typedef typename ImageRegistrationAlgorithmBaseType::TargetImageType TargetImageType; typedef typename ImageRegistrationAlgorithmBaseType::MovingImageType MovingImageType; typedef typename Superclass::MovingRepresentationDescriptorType MovingRepresentationDescriptorType; typedef typename Superclass::TargetRepresentationDescriptorType TargetRepresentationDescriptorType; typedef typename Superclass::RegistrationPointer RegistrationPointer; typedef typename Superclass::RegistrationType RegistrationType; typedef typename Superclass::FieldRepRequirement FieldRepRequirement; typedef facet::PointSetRegistrationAlgorithmInterfaceV2 PointSetInterfaceType; typedef typename PointSetInterfaceType::MovingPointSetConstPointer MovingPointSetConstPointer; typedef typename PointSetInterfaceType::TargetPointSetConstPointer TargetPointSetConstPointer; typedef typename PointSetInterfaceType::SlotIndexType SlotIndexType; typedef typename PointSetInterfaceType::MovingPointSetType MovingPointSetType; typedef typename PointSetInterfaceType::TargetPointSetType TargetPointSetType; typedef typename MetaPropertyAlgorithmBase::MetaPropertyType MetaPropertyType; typedef typename MetaPropertyAlgorithmBase::MetaPropertyPointer MetaPropertyPointer; typedef typename MetaPropertyAlgorithmBase::MetaPropertyNameType MetaPropertyNameType; mapDefineAlgorithmIdentificationByPolicyMacro; // IterativeRegistrationAlgorithm /*! @eguarantee strong*/ virtual bool isStoppable() const; /*! has the algorithm an iteration count? @eguarantee no fail @return Indicates if the algorithm can determin its current iteration count */ virtual bool hasIterationCount() const; /*! has the algorithm an maximum iteration count? @eguarantee no fail @return Indicates if the algorithm can determin its maximum iteration count */ virtual bool hasMaxIterationCount() const; /*! This function indicates if the optimizer of the iterative registration algorithm is * able to return its current metric/optimizer value(s)? @eguarantee no fail @return Indicates if the algorithm can determin its curent value. */ virtual bool hasCurrentOptimizerValue() const; virtual typename FieldRepRequirement::Type isMovingRepresentationRequired() const; virtual typename FieldRepRequirement::Type isTargetRepresentationRequired() const; /*! @reimplemented */ virtual bool isReusable() const; mapGetMetaMacro(WorkingDirectory, core::String); mapSetMetaMacro(WorkingDirectory, core::String); mapGetMetaMacro(PlastimatchDirectory, core::String); mapSetMetaMacro(PlastimatchDirectory, core::String); mapGetMetaMacro(DeleteTempDirectory, bool); mapSetMetaMacro(DeleteTempDirectory, bool); virtual bool hasCoupledPointSetInputs() const override { return true; }; virtual bool isOptionalTargetPointSet(SlotIndexType index) const override { return true; }; virtual bool isOptionalMovingPointSet(SlotIndexType index) const override { return true; }; virtual SlotIndexType getTargetPointSetCount(bool onlyMandatory = false) const override { if (onlyMandatory) return 0; return 1; }; virtual SlotIndexType getMovingPointSetCount(bool onlyMandatory = false) const override { if (onlyMandatory) return 0; return 1; }; virtual unsigned long getNthTargetPointSetMTime(SlotIndexType index) const override; virtual unsigned long getNthMovingPointSetMTime(SlotIndexType index) const override; protected: CLIRegistrationAlgorithmBase(); virtual ~CLIRegistrationAlgorithmBase(); typedef typename Superclass::InterimRegistrationType InterimRegistrationType; typedef typename Superclass::InterimRegistrationPointer InterimRegistrationPointer; typedef typename Superclass::IterationCountType IterationCountType; typedef typename ImageRegistrationAlgorithmBaseType::MovingImageConstPointer MovingImageConstPointer; typedef typename ImageRegistrationAlgorithmBaseType::TargetImageConstPointer TargetImageConstPointer; - typedef ::itk::GenericVectorFieldTransform< ::map::core::continuous::ScalarType, TTargetImage::ImageDimension, TTargetImage::ImageDimension> FieldTransformType; + typedef ::itk::GenericVectorFieldTransform< ::map::core::continuous::ScalarType, TTargetImage::ImageDimension, TTargetImage::ImageDimension> FieldTransformType; typedef typename map::core::RegistrationTopology::InverseFieldType FinalFieldType; typedef typename FinalFieldType::Pointer FinalFieldPointer; /* @reimplemented*/ virtual void configureAlgorithm(); // MetaPropertyAlgorithmBase /*! @reimplemented*/ virtual void compileInfos(MetaPropertyVectorType& infos) const; /*! @reimplemented*/ virtual MetaPropertyPointer doGetProperty(const MetaPropertyNameType& name) const; /*! @reimplemented*/ virtual void doSetProperty(const MetaPropertyNameType& name, const MetaPropertyType* pProperty); // IterativeRegistrationAlgorithmInterface /*! @brief gets the registration result that has been computed in the last iteration. This result is limited by the passed region descriptors (pMovingRepresentation, pTargetRepresentation). @pre pMovingRepresentation and pTargetRepresentation must not be null. @param [in] pMovingRepresentation Pointer to @eguarantee strong @return the interim registration result as smart pointer @retval a Registration object @sa Registration */ virtual InterimRegistrationPointer determineInterimRegistration(const MovingRepresentationDescriptorType* pMovingRepresentation, const TargetRepresentationDescriptorType* pTargetRepresentation) const; /*! * Returns the final registration @eguarantee strong */ virtual RegistrationPointer doGetRegistration() const; /*! Returns if the registration should be computed. The registration is outdated if doGetRegistration returns null * or the modification time of at least one sub component is newer then the modification time of the registration. @eguarantee strong @return true if the registration should be (re)computed. False if the registration is uptodate. */ virtual bool registrationIsOutdated() const; virtual bool doStopAlgorithm(); /*! This method should do all preparation tasks right before the algorithm is executed. At the end of this method the algorithm should be set up and ready to use.\n The method delegates the main work of initialization to several sub methods. These sub methods serve as slots that can be rewritten by an algorithm developer to alter certain aspects and keep the rest untouched.\n The sequence of slot calls is: \n - prepCheckValidity - prepPerpareInternalInputData - prepSavePlastimatchInputData - prepParameterMaps - prepFinalizePreparation @remark If you want to change the execution style, then overwrite runAlgorithm(). @eguarantee strong*/ virtual void prepareAlgorithm(); /*! This method is the slot to check if all internal components and input data are properly set. @remark The default implementation checks the moving and target image. Overload this method to alter the validity check. @remark It is assumed that the implementation of this method throws an exception if the algorithm is not configured correctly.*/ virtual void prepCheckValidity(); /*! This method is the slot for internal preprocessing of input data. This method should be reimplemented if you want to prepare the input data before they go into the internal registration method. E.g. blurring or normalizing the moving and target image before registration. @remark The default implementation does nothing. Thus the public input data will be the data used by the internal algorithm. @remark Implementations of this method should work on _spInternalMoving and _spInternalTargetImage. In the default implementation of prepSetInternalInputData() these member will be passed to the internal algorithm. @eguarantee strong*/ virtual void prepPerpareInternalInputData(); /*! This method is the slot for storing the relevant input data to the working directory of plastimatch. * @remark The default implementation stores _spInternalMoving and _spInternalTargetImage and the masks if set. @eguarantee strong */ virtual void prepSavePlastimatchInputData(); /*! This method is the slot for the generation of the configuration that should be passed to plastimatch. The base class assumes that after calling this methods the member _configurationPLM contains all parameters for all stages. @eguarantee strong */ virtual void prepConfigurationPLM() = 0; /*! This method is used after preConfifurationPLM() to ensure that parameters for input images, masks and resulting vector field are correctly set. If the parameters are already set, they will be overwritten. In addition the function removes all settings for the output of result images or xform (they are deactivated). @eguarantee strong */ void ensureCorrectGlobalConfigSettings(); /*! This method should just execute the iteration loop. * @remark If you want to change the initialization or the finalization, then overwrite prepareIteration() or finalizeAlgorithm(). * @return Indicates if the registration was successfully determined (e.g. could be * false if an iterative algorithm was stopped prematurely by the user). * @eguarantee strong */ virtual bool runAlgorithm(); /*! This method should do all the finalization work (e.g. generating the registration based on the iteration results). * @remark If you want to change the initialization or the iteration, then overwrite prepareIteration() or iterateAlgorithm(). @eguarantee strong */ virtual void finalizeAlgorithm(); /*! return the optimizer value(s) of the current iteration step. Will be called by getCurrentOptimizerValue() if hasCurrentValue() returns true. @eguarantee strong @return current measure */ virtual OptimizerMeasureType doGetCurrentOptimizerValue() const; /*! Methods invoked by derivated classes. */ virtual void PrintSelf(std::ostream& os, ::itk::Indent indent) const; /*! Feature is not supported by this wrapper. Therefore the methods returns only a dummy value (0). * @eguarantee strong*/ virtual IterationCountType doGetCurrentIteration() const; /*! Feature is not supported by this wrapper. Therefore the methods returns only a dummy value (0). @eguarantee strong */ virtual IterationCountType doGetMaxIterations() const; /*! This method generates a unique and random subdirectory contained by _workingDir. * The path to this directory is stored in _currentTempDir. * @eguarantee strong */ void initializeCurrentTempDir(); /*! Helper function that loads the deformation file generated by plastimatch. The generated file is loaded and returned by the function.*/ FinalFieldPointer generateField() const; /*! Helper function that generates the file path to the parameter file.*/ ::map::core::String getParameterFilePath() const; /*! Helper function that generates the file path to the result parameters for the final(last stage) transform. @pre Algorithm must have at least one stage.*/ ::map::core::String getFinalTransformFilePath() const; /*!Pointer to the moving image used by the algorithm internally. This is used to allow the algorithm * or its derived classes to modify the moving image without changing the public moving image pointer. * The variable is set by prepareIteration() to _spMovingImage before calling prepareInternalInputData(). * (e.g.: An algorithm always normalizes an image before registration. Then the algorithm can use the prepareInternalInputData() * function to manipulate _spInternalMovingImage before it is used by prepareIteration() to set the internal algorithm)*/ MovingImageConstPointer _spInternalMovingImage; /*!Pointer to the target image used by the algorithm internally. This is used to allow the algorithm * or its derived classes to modify the target image with out changing the public target image pointer. * The variable is set by prepareIteration() to _spTargetImage before calling prepareInternalInputData(). * (e.g.: An algorithm always normalizes an image before registration. Then the algorithm can use the prepareInternalInputData() * function to manipulate _spInternalTargetImage before it is used by prepareIteration() to set the internal algorithm)*/ TargetImageConstPointer _spInternalTargetImage; /*!Directory that can be used to store temporary data. Process must have write access to this directory*/ ::map::core::String _workingDir; /*!Directory where the plastimatch tool 'plastimatch' is located.*/ ::map::core::String _plastimatchDir; /*!Directory that is used to store temporary data on the current run*/ ::map::core::String _currentTempDir; /*!Vector with plastimatch parameter maps, each element of the vector is the parameter map for one registration stage of plastimatch*/ ConfigurationType _configurationPLM; ::map::core::String _movingImageTempPath; ::map::core::String _targetImageTempPath; ::map::core::String _finalFieldTempPath; ::map::core::String _movingMaskTempPath; ::map::core::String _targetMaskTempPath; ::map::core::String _movingPointSetTempPath; ::map::core::String _targetPointSetTempPath; bool _deleteTempDirectory; /*! This member function is called by the process executer, whenever Plastimatch generates an output on stdout.*/ void onPlmOutputEvent(::itk::Object* caller, const ::itk::EventObject& eventObject); /*! Helper method that removes the current temp dir (if it exists and _deleteTempDirectory is true). * @eguarantee no throw*/ void cleanTempDir() const; ::map::core::String _parameterFilePath; virtual MovingPointSetConstPointer doGetNthMovingPointSet(SlotIndexType index) const override; virtual TargetPointSetConstPointer doGetNthTargetPointSet(SlotIndexType index) const override;; virtual void doSetNthMovingPointSet(SlotIndexType index, const MovingPointSetType* pMovingPointSet) override;; virtual void doSetNthTargetPointSet(SlotIndexType index, const TargetPointSetType* pTargetPointSet) override;; ::map::core::ModificationTimeValidator _targetPSMTime; ::map::core::ModificationTimeValidator _movingPSMTime; MovingPointSetConstPointer _spMovingPointSet; TargetPointSetConstPointer _spTargetPointSet; private: /*! The parameters of the registration field generated by plastimatch.*/ FinalFieldPointer _spFinalizedField; /*! Smartpointer to the finalized registration. Will be set by finalizeAlgorithm()*/ typename RegistrationType::Pointer _spFinalizedRegistration; /*! The lock is used to manage the access to the member variable _currentIterationCount.*/ mutable ::itk::SimpleFastMutexLock _currentIterationLock; CLIRegistrationAlgorithmBase(const Self& source); void operator=(const Self&); //purposely not implemented }; } } } #ifndef MatchPoint_MANUAL_TPP #include "mapPlmCLIRegistrationAlgorithmBase.tpp" #endif #endif