diff --git a/CMake/elxWinConfig.cmake b/CMake/elxWinConfig.cmake index c9a8eb734b8260f259e95fa5be4f6dd3605ea79d..6e2408335a8f8040c6f40e532f4d2286dc8e7760 100644 --- a/CMake/elxWinConfig.cmake +++ b/CMake/elxWinConfig.cmake @@ -1,19 +1,23 @@ # Visual Studio complains if paths are too long -string( LENGTH "${CMAKE_CURRENT_SOURCE_DIR}" n ) -if( n GREATER 50 ) -message( - FATAL_ERROR - "ITK source code directory path length is too long (${n} > 50)." - "Please move the ITK source code directory to a directory with a shorter path." - ) -endif() +if( MSVC ) + string( LENGTH "${CMAKE_CURRENT_SOURCE_DIR}" n ) + if( n GREATER 50 ) + message( + FATAL_ERROR + "ITK source code directory path length is too long for MSVC (${n} > 50)." + ) + endif() + + string( LENGTH "${CMAKE_CURRENT_BINARY_DIR}" n ) + if( n GREATER 50 ) + message( + FATAL_ERROR + "ITK build directory path length is too long for MSVC (${n} > 50)." + ) + endif() -string( LENGTH "${CMAKE_CURRENT_BINARY_DIR}" n ) -if( n GREATER 50 ) -message( - FATAL_ERROR - "ITK build directory path length is too long (${n} > 50)." - "Please set the ITK build directory to a directory with a shorter path." - ) + set( CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /bigobj" ) + set( CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /bigobj" ) + set( CMAKE_CXX_FLAGS_RELWITHDEBINFO "${CMAKE_CXX_FLAGS_RELWITHDEBINFO} /bigobj" ) endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index c5a3e96f42343649c90a9bd5889ca4b03d978616..d9251974b8dd47987cf7101639f8be8d8093e561 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,46 +1,66 @@ cmake_minimum_required( VERSION 2.8 ) +# Explicitly add INCREMENTAL linking option to command lines. +# http://www.cmake.org/pipermail/cmake/2010-February/035174.html +set( MSVC_INCREMENTAL_DEFAULT ON ) + +# --------------------------------------------------------------------- +project( Elastix ) + # Include SuperElastix CMake scripts -list( APPEND CMAKE_MODULE_PATH - "${CMAKE_CURRENT_SOURCE_DIR}/CMake" +list( APPEND CMAKE_MODULE_PATH + "${CMAKE_CURRENT_SOURCE_DIR}/CMake" ) -if( CMAKE_HOST_WIN32 ) +if( ${CMAKE_CXX_COMPILER_ID} STREQUAL "MSVC" ) include( elxWinConfig.cmake ) endif() -#--------------------------------------------------------------------- -project( Elastix ) - -#--------------------------------------------------------------------- +# --------------------------------------------------------------------- # ITK find_package( ITK REQUIRED ) -set( ITK_NO_IO_FACTORY_REGISTER_MANAGER 1 ) include( ${ITK_USE_FILE} ) include( "${CMAKE_CURRENT_SOURCE_DIR}/CMake/elxITKRequiredModules.cmake" ) -#--------------------------------------------------------------------- +# --------------------------------------------------------------------- # Build Elastix -#--------------------------------------------------------------------- -# Testing +set( ELASTIX_COMMON_INCLUDE_DIRECTORIES + ${CMAKE_SOURCE_DIR}/Modules/Core/Common/include +) -# Build tests by default -option( ELASTIX_BUILD_TESTING "Enable building tests." ON ) +set( ELASTIX_CORE_INCLUDE_DIRECTORIES + ${CMAKE_SOURCE_DIR}/Modules/Core/Blueprints/include +) + +set( ELASTIX_INCLUDE_DIRECTORIES + ${ELASTIX_COMMON_INCLUDE_DIRECTORIES} + ${ELASTIX_CORE_INCLUDE_DIRECTORIES} +) + +include_directories( ${ELASTIX_INCLUDE_DIRECTORIES} ) +add_subdirectory( Modules ) -# ExternalData module requires newer CMake versions +# --------------------------------------------------------------------- +# Testing + +# Testing requires CMake version 2.8.11 to download test data if( CMAKE_VERSION VERSION_LESS 2.8.11 ) - set( ELASTIX_BUILD_TESTING OFF FORCE ) - message( STATUS "ELASTIX_BUILD_TESTING was set to OFF because CMake version is less than 2.8.11") + set( ELASTIX_BUILD_TESTING_DEFAULT OFF ) + message( STATUS "ELASTIX_BUILD_TESTING is set to OFF by default because CMake version is less than 2.8.11" ) +else() + set( ELASTIX BUILD_TESTING_DEFAULT ON ) endif() +option( ELASTIX_BUILD_TESTING "Enable building tests." ${ELASTIX_BUILD_TESTING_DEFAULT} ) + if( ELASTIX_BUILD_TESTING ) enable_testing() add_subdirectory( Testing ) endif() -#--------------------------------------------------------------------- +# --------------------------------------------------------------------- # Build Documentation mark_as_advanced( ELASTIX_BUILD_DOXYGEN ) diff --git a/Modules/CMakeLists.txt b/Modules/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..ed8ac28d118442a7668ad4b7d36363991a040500 --- /dev/null +++ b/Modules/CMakeLists.txt @@ -0,0 +1,3 @@ +add_subdirectory( + Core +) \ No newline at end of file diff --git a/Modules/Core/CMakeLists.txt b/Modules/Core/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..dac4f7215cdf262d7f6c95cbbf835032a65bd4ce --- /dev/null +++ b/Modules/Core/CMakeLists.txt @@ -0,0 +1,4 @@ +add_subdirectory( + Common + Blueprints +) \ No newline at end of file diff --git a/Modules/Core/Common/CMakeLists.txt b/Modules/Core/Common/CMakeLists.txt new file mode 100644 index 0000000000000000000000000000000000000000..fc2d9b4b5d0a3c36a784b891478afd95cc7c4302 --- /dev/null +++ b/Modules/Core/Common/CMakeLists.txt @@ -0,0 +1 @@ +include_directories( include ) \ No newline at end of file diff --git a/Modules/Core/Common/include/elxMacro.h b/Modules/Core/Common/include/elxMacro.h new file mode 100644 index 0000000000000000000000000000000000000000..d176d1a5dce073af5baa7421e4e35628bbfc9504 --- /dev/null +++ b/Modules/Core/Common/include/elxMacro.h @@ -0,0 +1,15 @@ +#ifndef __elxMacro_h +#define __elxMacro_h + +/** + * Register class with the object factory and provide + * associated RTTI (Run-Time Type Information) + */ +#define elxNewMacro( className, superClassName ) \ + typedef className Self; \ + typedef itk::SmartPointer< Self > Pointer; \ + typedef itk::SmartPointer< const Self > ConstPointer; \ + itkNewMacro( Self ); \ + itkTypeMacro( Self, superClassName ); \ + +#endif // __elxMacro_h \ No newline at end of file diff --git a/Testing/CMakeLists.txt b/Testing/CMakeLists.txt index ea6d3697c6ed80937d7202666712bfc5954c3ad1..9598ac8c17113e6a582022ec82d0d1b53eef530e 100644 --- a/Testing/CMakeLists.txt +++ b/Testing/CMakeLists.txt @@ -30,7 +30,7 @@ endforeach() ExternalData_Add_Target( ElastixData ) # --------------------------------------------------------------------- -# Setup GoogleTest +# Add GoogleTest find_package( Git ) if( NOT EXISTS "${CMAKE_SOURCE_DIR}/Testing/GoogleTest/.git" AND GIT_EXECUTABLE ) @@ -70,7 +70,6 @@ add_subdirectory( Unit ) # Benchmarks option( ELASTIX_BUILD_BENCHMARKING "Enable building benchmarks." OFF ) - if( ${ELASTIX_BUILD_BENCHMARKING} ) add_subdirectory( Benchmark ) endif() diff --git a/Testing/Dashboard/CMakeLists.txt b/Testing/Dashboard/CMakeLists.txt index 244b8d862e71723c82cb1539df163350ade6a0fe..202478325aeea62261d1c8dd11773e54eb1ba132 100644 --- a/Testing/Dashboard/CMakeLists.txt +++ b/Testing/Dashboard/CMakeLists.txt @@ -8,24 +8,23 @@ mark_as_advanced( ELASTIX_DASHBOARD_BINARY_DIR ) set( ELASTIX_DASHBOARD_BINARY_DIR "${CMAKE_BINARY_DIR}/Testing/Dashboard" ) mark_as_advanced( ELASTIX_DASHBOARD_LOGSTASH_CERTIFICATE ) -set( ELASTIX_DASHBOARD_LOGSTASH_CERTIFICATE "elxLogstashForwarder.crt" ) +set( ELASTIX_DASHBOARD_LOGSTASH_CERTIFICATE "elxLogstash.crt" ) mark_as_advanced( ELASTIX_DASHBOARD_LOGSTASH_RSA_PRIVATE_KEY ) -set( ELASTIX_DASHBOARD_LOGSTASH_RSA_PRIVATE_KEY "elxLogstashForwarder.key" ) +set( ELASTIX_DASHBOARD_LOGSTASH_RSA_PRIVATE_KEY "elxLogstash.key" ) mark_as_advanced( ELASTIX_DASHBOARD_VOLUME ) -set( ELASTIX_DASHBOARD_VOLUME "${ELASTIX_DASHBOARD_BINARY_DIR}/Data" ) - if( NOT EXISTS "${ELASTIX_DASHBOARD_VOLUME}" ) message( STATUS - "ELASTIX_DASHBOARD_VOLUME points to the default ${CMAKE_BINARY_DIR}/Testing/Dashboard/Data path in your build directory. In production you should point this variable to a safe directory outside the build tree." + "ELASTIX_DASHBOARD_VOLUME points to the folder ${CMAKE_BINARY_DIR}/Testing/Dashboard/Data in your build directory. In production you should point this variable to a safe directory outside the build tree." ) - + + set( ELASTIX_DASHBOARD_VOLUME "${ELASTIX_DASHBOARD_BINARY_DIR}/Data" ) file( MAKE_DIRECTORY "${ELASTIX_DASHBOARD_VOLUME}" ) endif() # Test/Benchmark results will be forwarded to this IP. You will probably -# have change this in order to match docker settings on your own machine. +# have change this in order to match docker settings on your own machine. mark_as_advanced( ELASTIX_DASHBOARD_IP ) set( ELASTIX_DASHBOARD_IP "192.168.59.103" ) diff --git a/Testing/Dashboard/elxLogstashForwarder.crt b/Testing/Dashboard/elxLogstash.crt similarity index 100% rename from Testing/Dashboard/elxLogstashForwarder.crt rename to Testing/Dashboard/elxLogstash.crt diff --git a/Testing/Dashboard/elxLogstashForwarder.key b/Testing/Dashboard/elxLogstash.key similarity index 100% rename from Testing/Dashboard/elxLogstashForwarder.key rename to Testing/Dashboard/elxLogstash.key diff --git a/Testing/Unit/CMakeLists.txt b/Testing/Unit/CMakeLists.txt index 17d66ca7225d3a1e017d817ac8d8e7c40d11be70..152463661b386eebef9985f5071fa38a1f427f9e 100644 --- a/Testing/Unit/CMakeLists.txt +++ b/Testing/Unit/CMakeLists.txt @@ -24,19 +24,24 @@ if( NOT EXISTS ${ELASTIX_UNITTEST_OUTPUT_DATA_DIR} ) ) endif() +# --------------------------------------------------------------------- +# Build test data manager configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/elxDataDirectories.h.in - ${CMAKE_CURRENT_SOURCE_DIR}/elxDataDirectories.h + ${CMAKE_CURRENT_BINARY_DIR}/elxDataDirectories.h ESCAPE_QUOTES ) -# Build tests +include_directories( ${CMAKE_CURRENT_BINARY_DIR} ) + add_library( DataManager elxDataManager.cxx ) list( APPEND TEST_LIBRARIES DataManager ) +# --------------------------------------------------------------------- +# Build tests foreach( ElastixUnitTestFilename ${ElastixUnitTestFilenames} ) # Build tests executables string( REPLACE ".cxx" "" ElastixUnitTest ${ElastixUnitTestFilename} ) diff --git a/Testing/Unit/elxDataDirectories.h b/Testing/Unit/elxDataDirectories.h deleted file mode 100644 index 9f2b7ef3eeaf6c66923099c297779d8476b96857..0000000000000000000000000000000000000000 --- a/Testing/Unit/elxDataDirectories.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef __elxTestDataDirectories_h -#define __elxTestDataDirectories_h - -#define ELASTIX_UNITTEST_INPUT_DATA_DIR "/Users/kasper/Development/build/SuperElastix/Elastix-build/Testing/Unit/Data/Input" -#define ELASTIX_UNITTEST_OUTPUT_DATA_DIR "/Users/kasper/Development/build/SuperElastix/Elastix-build/Testing/Unit/Data/Output" -#define ELASTIX_UNITTEST_BASELINE_DATA_DIR "/Users/kasper/Development/build/SuperElastix/Elastix-build/Testing/Unit/Data/Baseline" - -#endif // __elxTestDataDirectories_h diff --git a/Testing/Unit/elxDataDirectories.h.in b/Testing/Unit/elxDataDirectories.h.in index 835845d15b56febeb9f8d8ca19b81b8a344555b3..2081964057c33d7647da456782aff3e956135efd 100644 --- a/Testing/Unit/elxDataDirectories.h.in +++ b/Testing/Unit/elxDataDirectories.h.in @@ -1,5 +1,5 @@ -#ifndef __elxTestDataDirectories_h -#define __elxTestDataDirectories_h +#ifndef __elxDataDirectories_h +#define __elxDataDirectories_h #define ELASTIX_UNITTEST_INPUT_DATA_DIR "@ELASTIX_UNITTEST_INPUT_DATA_DIR@" #define ELASTIX_UNITTEST_OUTPUT_DATA_DIR "@ELASTIX_UNITTEST_OUTPUT_DATA_DIR@" diff --git a/Testing/Unit/elxDataManager.cxx b/Testing/Unit/elxDataManager.cxx index e9aa4e4afd6f58cc26420fdd947bfbc29817cae9..6b7da8aa318a592f9ff654404d5412f93d829dd5 100644 --- a/Testing/Unit/elxDataManager.cxx +++ b/Testing/Unit/elxDataManager.cxx @@ -1,29 +1,30 @@ #ifndef __DataManager_cxx #define __DataManager_cxx +#include <itkSimpleDataObjectDecorator.h> #include "elxDataManager.h" -std::string +const std::string DataManager -::GetInput( const std::string filename ) const +::GetInputFullPath( const std::string filename ) const { - const std::string path = this->GetInputDirectory() + this->GetPathSeparator() + filename; + const std::string path = this->GetInputDirectory() + this->GetFolderSeparator() + filename; return path; } -std::string +const std::string DataManager -::GetOutput( const std::string filename ) const +::GetOutputFullPath( const std::string filename ) const { - const std::string path = this->GetOutputDirectory() + this->GetPathSeparator() + filename; + const std::string path = this->GetOutputDirectory() + this->GetFolderSeparator() + filename; return path; } -std::string +const std::string DataManager -::GetBaseline( const std::string filename ) const +::GetBaselineFullPath( const std::string filename ) const { - const std::string path = this->GetBaselineDirectory() + this->GetPathSeparator() + filename; + const std::string path = this->GetBaselineDirectory() + this->GetFolderSeparator() + filename; return path; } diff --git a/Testing/Unit/elxDataManager.h b/Testing/Unit/elxDataManager.h index 61d4dcade79545c7c85210f663d9ca07390e3f5c..fc85a65c4a30c00d979a10aa6b7a464ba2481937 100644 --- a/Testing/Unit/elxDataManager.h +++ b/Testing/Unit/elxDataManager.h @@ -2,16 +2,19 @@ #define __DataManager_h #include <string> +#include <itkSimpleDataObjectDecorator.h> -#include "itkMacro.h" -#include "itkProcessObject.h" - +#include "elxMacro.h" +#include "itkObjectFactory.h" +#include "itkLightObject.h" #include "elxDataDirectories.h" -class DataManager +class DataManager : public itk::LightObject { public: + elxNewMacro( DataManager, itk::LightObject ); + DataManager() { this->m_InputDirectory = ELASTIX_UNITTEST_INPUT_DATA_DIR; @@ -20,16 +23,25 @@ public: } std::string GetInputDirectory( void ) const { return this->m_InputDirectory; }; - std::string GetOutputDirectory( void ) const { return this->m_InputDirectory; }; - std::string GetBaselineDirectory( void ) const { return this->m_InputDirectory; }; + std::string GetOutputDirectory( void ) const { return this->m_OutputDirectory; }; + std::string GetBaselineDirectory( void ) const { return this->m_BaselineDirectory; }; + + const std::string GetInputFullPath( const std::string filename ) const; + const std::string GetOutputFullPath( const std::string filename ) const; + const std::string GetBaselineFullPath( const std::string filename ) const; - std::string GetInput( const std::string filename ) const; - std::string GetOutput( const std::string filename ) const; - std::string GetBaseline( const std::string filename ) const; + std::string GetFolderSeparator() const + { +#ifdef _WIN32 + return "\\"; +#else + return "/"; +#endif + } std::string GetPathSeparator () const { -#ifdef WIN32 +#ifdef _WIN32 return ";"; #else return ":"; diff --git a/Testing/Unit/itkRegistration.cxx b/Testing/Unit/itkRegistration.cxx index 449ed7bd286373d1d15e2d5769b6ccf9b16d3715..3988f3089daaff475b4d1a4b359286d75eb6995d 100644 --- a/Testing/Unit/itkRegistration.cxx +++ b/Testing/Unit/itkRegistration.cxx @@ -3,27 +3,84 @@ #include "elxDataManager.h" #include "gtest/gtest.h" +#include "itkImageRegistrationMethod.h" +#include "itkTranslationTransform.h" +#include "itkMeanSquaresImageToImageMetric.h" +#include "itkLinearInterpolateImageFunction.h" +#include "itkRegularStepGradientDescentOptimizer.h" +#include "itkImage.h" +#include "itkImageFileReader.h" +#include "itkResampleImageFilter.h" +#include "itkCastImageFilter.h" + class itkRegistration : public ::testing::Test { public: virtual void SetUp() { - DataManager dataManager; - typedef itk::ImageFileReader< ImageType > ReaderType; + // TODO: Loading images here result in segfault + } - ReaderType::Pointer reader = ReaderType::New(); - reader->SetFileName( dataManager.GetInput( "BrainProtonDensitySliceR10X13Y17.png" ) ); - inputImage = reader->GetOutput(); + typedef itk::Image< unsigned short, 2 > ImageType; - reader->SetFileName( dataManager.GetBaseline( "BrainProtonDensitySlice.png" ) ); - baselineImage = reader->GetOutput(); - } + typedef itk::ImageFileReader< ImageType > FixedImageReaderType; + typedef itk::ImageFileReader< ImageType > MovingImageReaderType; + + FixedImageReaderType::Pointer fixedImageReader; + MovingImageReaderType::Pointer movingImageReader; - typedef itk::Image< unsigned int, 2 > ImageType; - ImageType::Pointer inputImage; - ImageType::Pointer baselineImage; }; -TEST_F( itkRegistration, Affine2D ) -{ - ASSERT_TRUE( true ); +TEST_F( itkRegistration, ImageRegistration3 ) +{ + + typedef itk::TranslationTransform< double, ImageType::ImageDimension > TransformType; + typedef itk::RegularStepGradientDescentOptimizer OptimizerType; + typedef itk::LinearInterpolateImageFunction< ImageType, double > InterpolatorType; + typedef itk::ImageRegistrationMethod< ImageType, ImageType > RegistrationType; + + + typedef itk::MeanSquaresImageToImageMetric< ImageType, ImageType > MetricType; + + TransformType::Pointer transform = TransformType::New(); + OptimizerType::Pointer optimizer = OptimizerType::New(); + InterpolatorType::Pointer interpolator = InterpolatorType::New(); + RegistrationType::Pointer registration = RegistrationType::New(); + + MetricType::Pointer metric = MetricType::New(); + registration->SetMetric( metric ); + registration->SetOptimizer( optimizer ); + registration->SetTransform( transform ); + registration->SetInterpolator( interpolator ); + + FixedImageReaderType::Pointer fixedImageReader = FixedImageReaderType::New(); + MovingImageReaderType::Pointer movingImageReader = MovingImageReaderType::New(); + + DataManager::Pointer dataManager = DataManager::New(); + + fixedImageReader->SetFileName( dataManager->GetInputFullPath( "BrainProtonDensitySlice.png" ) ); + movingImageReader->SetFileName( dataManager->GetInputFullPath( "BrainProtonDensitySliceR10X13Y17.png" ) ); + + registration->SetFixedImage( fixedImageReader->GetOutput() ); + registration->SetMovingImage( movingImageReader->GetOutput() ); + + fixedImageReader->Update(); // This is needed to make the BufferedRegion valid. + registration->SetFixedImageRegion( fixedImageReader->GetOutput()->GetBufferedRegion() ); + + typedef RegistrationType::ParametersType ParametersType; + ParametersType initialParameters( transform->GetNumberOfParameters() ); + + initialParameters[0] = 0.0; // Initial offset in mm along X + initialParameters[1] = 0.0; // Initial offset in mm along Y + + registration->SetInitialTransformParameters( initialParameters ); + + optimizer->SetMaximumStepLength( 4.00 ); + optimizer->SetMinimumStepLength( 0.01 ); + optimizer->SetNumberOfIterations( 200 ); + + optimizer->MaximizeOff(); + + EXPECT_NO_THROW( registration->Update() ); + RecordProperty( "MetricValue", optimizer->GetValue() ); } +