diff --git a/CMakeLists.txt b/CMakeLists.txt index 14ff4f586e..b08bc3bfd6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,1401 +1,1401 @@ set(MITK_CMAKE_MINIMUM_REQUIRED_VERSION 3.2) cmake_minimum_required(VERSION ${MITK_CMAKE_MINIMUM_REQUIRED_VERSION}) #----------------------------------------------------------------------------- # See http://www.cmake.org/cmake/help/v3.2/manual/cmake-policies.7.html for details #----------------------------------------------------------------------------- set(project_policies ) foreach(policy ${project_policies}) if(POLICY ${policy}) cmake_policy(SET ${policy} NEW) endif() endforeach() #----------------------------------------------------------------------------- # Superbuild Option - Enabled by default #----------------------------------------------------------------------------- option(MITK_USE_SUPERBUILD "Build MITK and the projects it depends on via SuperBuild.cmake." ON) if(MITK_USE_SUPERBUILD) project(MITK-superbuild) set(MITK_SOURCE_DIR ${PROJECT_SOURCE_DIR}) set(MITK_BINARY_DIR ${PROJECT_BINARY_DIR}) else() project(MITK VERSION 2016.03.99) endif() #----------------------------------------------------------------------------- # Update CMake module path #------------------------------------------------------------------------------ set(MITK_CMAKE_DIR ${MITK_SOURCE_DIR}/CMake) set(CMAKE_MODULE_PATH ${MITK_CMAKE_DIR} ${CMAKE_MODULE_PATH} ) #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- # Standard CMake macros include(FeatureSummary) include(CTestUseLaunchers) include(CMakeParseArguments) include(FindPackageHandleStandardArgs) # MITK macros include(mitkFunctionGetGccVersion) include(mitkFunctionCheckCompilerFlags) include(mitkFunctionSuppressWarnings) # includes several functions include(mitkMacroEmptyExternalProject) include(mitkFunctionGenerateProjectXml) include(mitkFunctionEnableBuildConfiguration) include(mitkFunctionWhitelists) include(mitkFunctionAddExternalProject) SUPPRESS_VC_DEPRECATED_WARNINGS() #----------------------------------------------------------------------------- # Set a default build type if none was specified #----------------------------------------------------------------------------- if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Debug' as none was specified.") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() #----------------------------------------------------------------------------- # Check miminum Mac OS X version #----------------------------------------------------------------------------- # The minimum supported Mac OS X version is 10.9. If you use a version less than 10.9, there is no guarantee that the build still works. if(APPLE) exec_program(sw_vers ARGS -productVersion OUTPUT_VARIABLE osx_version) if (osx_version VERSION_LESS "10.9") message(WARNING "Detected OS X version \"${osx_version}\" is not supported anymore. Minimum required OS X version is 10.9 or greater.") endif() if (CMAKE_OSX_DEPLOYMENT_TARGET AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS 10.9) message(WARNING "Detected OS X deployment target \"${CMAKE_OSX_DEPLOYMENT_TARGET}\" is not supported anymore. Minimum required OS X version is 10.9 or greater.") endif() endif() #----------------------------------------------------------------------------- # Check miminum compiler versions #----------------------------------------------------------------------------- if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") # require at least gcc 4.7.3 as provided by ppa:ubuntu-toolchain-r/test for Ubuntu 12.04 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.7.3) message(FATAL_ERROR "GCC version must be at least 4.7.3 If you are using Ubuntu 12.04, you can easily install gcc and g++ 4.7.3 (or any later version available) in addition to your version ${CMAKE_CXX_COMPILER_VERSION}: sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update sudo apt-get install gcc-4.7 g++-4.7 Make sure to explicitly specify these compilers when configuring MITK: CMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc-4.7 CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/g++-4.7 For more information on the proposed PPA see the Toolchain Updates section of https://wiki.ubuntu.com/ToolChain.") endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # require at least clang 3.4 as provided by Ubuntu 12.04 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4) message(FATAL_ERROR "Clang version must be at least 3.4") endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") # require at least clang 5.0 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) message(FATAL_ERROR "Apple Clang version must be at least 5.0") endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # require at least Visual Studio 2012 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 17.0.61030.0) message(FATAL_ERROR "Microsoft Visual Studio 2012 Update 4 or newer required (MSVC 17.0.61030.0)") endif() else() message(WARNING "You are using an unsupported compiler! Compilation has only been tested with Clang (Linux or Apple), GCC and MSVC.") endif() if(CMAKE_COMPILER_IS_GNUCXX) mitkFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) else() set(GCC_VERSION 0) endif() set(MITK_CXX_STANDARD 11) set(CMAKE_CXX_EXTENSIONS 0) set(CMAKE_CXX_STANDARD ${MITK_CXX_STANDARD}) set(CMAKE_CXX_STANDARD_REQUIRED 1) # This is necessary to avoid problems with compile feature checks. # CMAKE_CXX_STANDARD seems to only set the -std=c++11 flag for targets. # However, compile flag checks also need to be done with -std=c++11. # The MITK_CXX11_FLAG variable is also used for external projects # build during the MITK super-build. mitkFunctionCheckCompilerFlags("-std=c++11" MITK_CXX11_FLAG) if(NOT MITK_CXX11_FLAG) # Older gcc compilers use -std=c++0x mitkFunctionCheckCompilerFlags("-std=c++0x" MITK_CXX11_FLAG) endif() #----------------------------------------------------------------------------- # Warn if source or build path is too long #----------------------------------------------------------------------------- if(WIN32) set(_src_dir_length_max 50) set(_bin_dir_length_max 50) if(MITK_USE_SUPERBUILD) set(_src_dir_length_max 34) # _src_dir_length_max - strlen(ep/src/ITK-build) set(_bin_dir_length_max 40) # _bin_dir_length_max - strlen(MITK-build) endif() string(LENGTH "${MITK_SOURCE_DIR}" _src_n) string(LENGTH "${MITK_BINARY_DIR}" _bin_n) # The warnings should be converted to errors if(_src_n GREATER _src_dir_length_max) message(WARNING "MITK source code directory path length is too long (${_src_n} > ${_src_dir_length_max})." "Please move the MITK source code directory to a directory with a shorter path." ) endif() if(_bin_n GREATER _bin_dir_length_max) message(WARNING "MITK build directory path length is too long (${_bin_n} > ${_bin_dir_length_max})." "Please move the MITK build directory to a directory with a shorter path." ) endif() endif() #----------------------------------------------------------------------------- # Additional MITK Options (also shown during superbuild) #----------------------------------------------------------------------------- macro(env_option name doc value) set(_value $ENV{${name}}) if("${_value}" STREQUAL "") set(_value ${value}) endif() option(${name} "${doc}" ${_value}) endmacro() # ----------------------------------------- # General build options option(BUILD_SHARED_LIBS "Build MITK with shared libraries" ON) option(WITH_COVERAGE "Enable/Disable coverage" OFF) option(BUILD_TESTING "Test the project" ON) env_option(MITK_BUILD_ALL_APPS "Build all MITK applications" OFF) env_option(MITK_BUILD_EXAMPLES "Build the MITK Examples" OFF) option(MITK_ENABLE_PIC_READER "Enable support for reading the DKFZ pic file format." ON) mark_as_advanced(MITK_BUILD_ALL_APPS MITK_ENABLE_PIC_READER ) # ----------------------------------------- # Qt version related variables env_option(MITK_USE_QT "Use Qt library" ON) if(MITK_USE_QT) set(MITK_QT5_MINIMUM_VERSION 5.6.0) set(MITK_QT5_COMPONENTS Concurrent OpenGL PrintSupport Script Sql Svg Widgets WebEngineWidgets Xml XmlPatterns UiTools Help LinguistTools) if(APPLE) set(MITK_QT5_COMPONENTS ${MITK_QT5_COMPONENTS} DBus) endif() find_package(Qt5 ${MITK_QT5_MINIMUM_VERSION} COMPONENTS ${MITK_QT5_COMPONENTS} REQUIRED) if(Qt5_DIR) get_filename_component(_Qt5_DIR "${Qt5_DIR}/../../../" ABSOLUTE) list(FIND CMAKE_PREFIX_PATH "${_Qt5_DIR}" _result) if(_result LESS 0) set(CMAKE_PREFIX_PATH "${_Qt5_DIR};${CMAKE_PREFIX_PATH}" CACHE PATH "" FORCE) endif() endif() endif() # ------------------------------------------------------------------------ # Register external projects which can be build with the MITK superbuild # system. Each mitkFunctionAddExternalProject() call registers an external # project for which a CMakeExternals/.cmake file must exist. The # call also creates a MITK_USE_ variable (appearing in the CMake # UI if the NO_CACHE option is *not* given). # ----------------------------------------- # Optional external projects with no # inter-dependencies set_property(GLOBAL PROPERTY MITK_EXTERNAL_PROJECTS "") mitkFunctionAddExternalProject(NAME Poco ON COMPONENTS Foundation Net Util XML Zip) mitkFunctionAddExternalProject(NAME DCMTK ON DOC "EXPERIMENTAL, superbuild only: Use DCMTK in MITK") mitkFunctionAddExternalProject(NAME OpenIGTLink OFF) mitkFunctionAddExternalProject(NAME tinyxml ON ADVANCED) mitkFunctionAddExternalProject(NAME GDCM ON ADVANCED) mitkFunctionAddExternalProject(NAME GLUT OFF ADVANCED) mitkFunctionAddExternalProject(NAME Raptor2 OFF ADVANCED) mitkFunctionAddExternalProject(NAME Eigen ON ADVANCED DOC "Use the Eigen library") mitkFunctionAddExternalProject(NAME GLEW ON ADVANCED DOC "Use the GLEW library") mitkFunctionAddExternalProject(NAME ANN ON ADVANCED DOC "Use Approximate Nearest Neighbor Library") mitkFunctionAddExternalProject(NAME CppUnit ON ADVANCED DOC "Use CppUnit for unit tests") mitkFunctionAddExternalProject(NAME PCRE OFF ADVANCED NO_PACKAGE) mitkFunctionAddExternalProject(NAME ZLIB OFF ADVANCED NO_PACKAGE NO_CACHE) mitkFunctionAddExternalProject(NAME HDF5 OFF ADVANCED) # ----------------------------------------- # The following external projects must be # ordered according to their # inter-dependencies mitkFunctionAddExternalProject(NAME SWIG OFF ADVANCED NO_PACKAGE DEPENDS PCRE) mitkFunctionAddExternalProject(NAME Python OFF NO_PACKAGE DEPENDS SWIG DOC "Use Python wrapping in MITK") mitkFunctionAddExternalProject(NAME Numpy OFF ADVANCED NO_PACKAGE) mitkFunctionAddExternalProject(NAME OpenCV OFF) mitkFunctionAddExternalProject(NAME Vigra OFF DEPENDS HDF5) # These are "hard" dependencies and always set to ON mitkFunctionAddExternalProject(NAME ITK ON NO_CACHE) mitkFunctionAddExternalProject(NAME VTK ON NO_CACHE) mitkFunctionAddExternalProject(NAME Boost ON NO_CACHE) mitkFunctionAddExternalProject(NAME SimpleITK OFF DEPENDS ITK GDCM SWIG) mitkFunctionAddExternalProject(NAME ACVD OFF DOC "Use Approximated Centroidal Voronoi Diagrams") mitkFunctionAddExternalProject(NAME CTK ON DEPENDS QT DCMTK DOC "Use CTK in MITK") mitkFunctionAddExternalProject(NAME Rasqal OFF DEPENDS Raptor2 PCRE ADVANCED) mitkFunctionAddExternalProject(NAME Redland OFF DEPENDS Rasqal DOC "Use the Redland RDF library") mitkFunctionAddExternalProject(NAME SOFA OFF DEPENDS GLUT Boost DOC "Use Simulation Open Framework Architecture") mitkFunctionAddExternalProject(NAME VMTK OFF DEPENDS ITK VTK) if(MITK_USE_QT) mitkFunctionAddExternalProject(NAME Qwt ON ADVANCED DEPENDS QT) endif() # ----------------------------------------- # Other MITK_USE_* options not related to # external projects build via the # MITK superbuild env_option(MITK_USE_BLUEBERRY "Build the BlueBerry platform" ON) env_option(MITK_USE_OpenCL "Use OpenCL GPU-Computing library" OFF) #----------------------------------------------------------------------------- # Build configurations #----------------------------------------------------------------------------- set(_buildConfigs "Custom") file(GLOB _buildConfigFiles CMake/BuildConfigurations/*.cmake) foreach(_buildConfigFile ${_buildConfigFiles}) get_filename_component(_buildConfigFile ${_buildConfigFile} NAME_WE) list(APPEND _buildConfigs ${_buildConfigFile}) endforeach() set(MITK_BUILD_CONFIGURATION "Custom" CACHE STRING "Use pre-defined MITK configurations") set_property(CACHE MITK_BUILD_CONFIGURATION PROPERTY STRINGS ${_buildConfigs}) mitkFunctionEnableBuildConfiguration() mitkFunctionCreateWhitelistPaths(MITK) mitkFunctionFindWhitelists(MITK) # ----------------------------------------- # Custom dependency logic option(MITK_USE_SYSTEM_Boost "Use the system Boost" OFF) set(MITK_USE_Boost_LIBRARIES "" CACHE STRING "A semi-colon separated list of required Boost libraries") if(MITK_USE_SOFA) # SOFA requires boost system library list(FIND MITK_USE_Boost_LIBRARIES system _result) if(_result LESS 0) message("> Adding 'system' to MITK_USE_Boost_LIBRARIES.") list(APPEND MITK_USE_Boost_LIBRARIES system) endif() # SOFA requires boost thread library list(FIND MITK_USE_Boost_LIBRARIES thread _result) if(_result LESS 0) message("> Adding 'thread' to MITK_USE_Boost_LIBRARIES.") list(APPEND MITK_USE_Boost_LIBRARIES thread) endif() # Simulation plugin requires boost chrono library list(FIND MITK_USE_Boost_LIBRARIES chrono _result) if(_result LESS 0) message("> Adding 'chrono' to MITK_USE_Boost_LIBRARIES.") list(APPEND MITK_USE_Boost_LIBRARIES chrono) endif() set(MITK_USE_Boost_LIBRARIES ${MITK_USE_Boost_LIBRARIES} CACHE STRING "" FORCE) # Allow setting external SOFA plugins directory and SOFA plugins set(MITK_USE_SOFA_PLUGINS_DIR ${MITK_USE_SOFA_PLUGINS_DIR} CACHE PATH "External SOFA plugins directory" FORCE) set(MITK_USE_SOFA_PLUGINS ${MITK_USE_SOFA_PLUGINS} CACHE PATH "List of semicolon-separated plugin names" FORCE) endif() # sanity check for supported Qt version. Only >= 5.3 is supported by CTK/PythonQt if(MITK_USE_QT AND MITK_USE_Python) set(minimum_required_python_qt5_version "5.3.0") find_package(Qt5 COMPONENTS Core REQUIRED) if(${Qt5Core_VERSION_STRING} VERSION_LESS ${minimum_required_python_qt5_version}) message(WARNING "Can't build MITK Python with Qt version < ${minimum_required_python_qt5_version}. Disabling Python support") set(MITK_USE_Python OFF CACHE BOOL "Use python wrapping in MITK" FORCE) endif() endif() # only windows can't build python in debug mode if(MITK_USE_Python AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug" AND WIN32) message(WARNING "Disabling Python support. Building MITK Python in debug mode on Windowsis not supported!") set(MITK_USE_Python OFF CACHE BOOL "Use python wrapping in MITK" FORCE) set(MITK_USE_Numpy OFF CACHE BOOL "Use Numpy" FORCE) set(MITK_USE_SimpleITK OFF CACHE BOOL "Use SimpleITK" FORCE) elseif(MITK_USE_Python) set(MITK_USE_ZLIB ON) if(NOT MITK_USE_Numpy) message("> Forcing MITK_USE_Numpy to ON because of MITK_USE_Python") set(MITK_USE_Numpy ON CACHE BOOL "Use Numpy" FORCE) endif() - if(NOT MITK_USE_SimpleITK) - message("> Forcing MITK_USE_SimpleITK to ON because of MITK_USE_Python") - set(MITK_USE_SimpleITK ON CACHE BOOL "Use SimpleITK" FORCE) - endif() + #if(NOT MITK_USE_SimpleITK) + # message("> Forcing MITK_USE_SimpleITK to ON because of MITK_USE_Python") + # set(MITK_USE_SimpleITK ON CACHE BOOL "Use SimpleITK" FORCE) + #endif() option(MITK_USE_SYSTEM_PYTHON "Use the system python runtime" OFF) if(MITK_USE_SYSTEM_PYTHON) find_package(PythonLibs REQUIRED) find_package(PythonInterp REQUIRED) endif() elseif(MITK_USE_Python AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug" AND WIN32) message(WARNING "Disabling Python support. Building MITK Python in debug mode on Windowsis not supported!") set(MITK_USE_Python OFF CACHE BOOL "Use python wrapping in MITK" FORCE) endif() if(BUILD_TESTING AND NOT MITK_USE_CppUnit) message("> Forcing MITK_USE_CppUnit to ON because BUILD_TESTING=ON") set(MITK_USE_CppUnit ON CACHE BOOL "Use CppUnit for unit tests" FORCE) endif() if(MITK_USE_BLUEBERRY) option(MITK_BUILD_ALL_PLUGINS "Build all MITK plugins" OFF) mark_as_advanced(MITK_BUILD_ALL_PLUGINS) if(NOT MITK_USE_CTK) message("> Forcing MITK_USE_CTK to ON because of MITK_USE_BLUEBERRY") set(MITK_USE_CTK ON CACHE BOOL "Use CTK in MITK" FORCE) endif() endif() #----------------------------------------------------------------------------- # Pixel type multiplexing #----------------------------------------------------------------------------- # Customize the default pixel types for multiplex macros set(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES "int, unsigned int, short, unsigned short, char, unsigned char" CACHE STRING "List of integral pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES "double, float" CACHE STRING "List of floating pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES "itk::RGBPixel, itk::RGBAPixel" CACHE STRING "List of composite pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_DIMENSIONS "2,3" CACHE STRING "List of dimensions used in AccessByItk and InstantiateAccessFunction macros") mark_as_advanced(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES MITK_ACCESSBYITK_DIMENSIONS ) # consistency checks if(NOT MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES) set(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES "int, unsigned int, short, unsigned short, char, unsigned char" CACHE STRING "List of integral pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES) set(MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES "double, float" CACHE STRING "List of floating pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES) set(MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES "itk::RGBPixel, itk::RGBAPixel" CACHE STRING "List of composite pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES) string(REPLACE "," ";" _integral_types ${MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES}) string(REPLACE "," ";" _floating_types ${MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES}) foreach(_scalar_type ${_integral_types} ${_floating_types}) set(MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES "${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}itk::VariableLengthVector<${_scalar_type}>,") endforeach() string(LENGTH "${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}" _length) math(EXPR _length "${_length} - 1") string(SUBSTRING "${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}" 0 ${_length} MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES) set(MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES ${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES} CACHE STRING "List of vector pixel types used in AccessByItk and InstantiateAccessFunction macros for itk::VectorImage types" FORCE) endif() if(NOT MITK_ACCESSBYITK_DIMENSIONS) set(MITK_ACCESSBYITK_DIMENSIONS "2,3" CACHE STRING "List of dimensions used in AccessByItk and InstantiateAccessFunction macros") endif() #----------------------------------------------------------------------------- # Project.xml #----------------------------------------------------------------------------- # A list of topologically ordered targets set(CTEST_PROJECT_SUBPROJECTS) list(APPEND CTEST_PROJECT_SUBPROJECTS MITK-Core MITK-CoreUI MITK-IGT MITK-ToF MITK-DTI MITK-Registration MITK-Modules # all modules not contained in a specific subproject MITK-Plugins # all plugins not contained in a specific subproject MITK-Examples Unlabeled # special "subproject" catching all unlabeled targets and tests ) # Configure CTestConfigSubProject.cmake that could be used by CTest scripts configure_file(${MITK_SOURCE_DIR}/CTestConfigSubProject.cmake.in ${MITK_BINARY_DIR}/CTestConfigSubProject.cmake) if(CTEST_PROJECT_ADDITIONAL_TARGETS) # those targets will be executed at the end of the ctest driver script # and they also get their own subproject label set(subproject_list "${CTEST_PROJECT_SUBPROJECTS};${CTEST_PROJECT_ADDITIONAL_TARGETS}") else() set(subproject_list "${CTEST_PROJECT_SUBPROJECTS}") endif() # Generate Project.xml file expected by the CTest driver script mitkFunctionGenerateProjectXml(${MITK_BINARY_DIR} MITK "${subproject_list}" ${MITK_USE_SUPERBUILD}) #----------------------------------------------------------------------------- # Superbuild script #----------------------------------------------------------------------------- if(MITK_USE_SUPERBUILD) include("${CMAKE_CURRENT_SOURCE_DIR}/SuperBuild.cmake") # Print configuration summary message("\n\n") feature_summary( DESCRIPTION "------- FEATURE SUMMARY FOR ${PROJECT_NAME} -------" WHAT ALL) return() endif() #***************************************************************************** #**************************** END OF SUPERBUILD **************************** #***************************************************************************** #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(WriteBasicConfigVersionFile) include(CheckCXXSourceCompiles) include(GenerateExportHeader) include(mitkFunctionAddCustomModuleTest) include(mitkFunctionCheckModuleDependencies) include(mitkFunctionCompileSnippets) include(mitkFunctionConfigureVisualStudioUserProjectFile) include(mitkFunctionConvertXPSchema) include(mitkFunctionCreateBlueBerryApplication) include(mitkFunctionCreateCommandLineApp) include(mitkFunctionCreateModule) include(mitkFunctionCreatePlugin) include(mitkFunctionCreateProvisioningFile) include(mitkFunctionCreateWindowsBatchScript) include(mitkFunctionGetLibrarySearchPaths) include(mitkFunctionGetVersion) include(mitkFunctionGetVersionDescription) include(mitkFunctionInstallAutoLoadModules) include(mitkFunctionInstallCTKPlugin) include(mitkFunctionInstallProvisioningFiles) include(mitkFunctionInstallThirdPartyCTKPlugins) include(mitkFunctionOrganizeSources) include(mitkFunctionTestPlugin) include(mitkFunctionUseModules) include(mitkMacroConfigureItkPixelTypes) include(mitkMacroCreateExecutable) include(mitkMacroCreateModuleTests) include(mitkMacroGenerateToolsLibrary) include(mitkMacroGetLinuxDistribution) include(mitkMacroGetPMDPlatformString) include(mitkMacroInstall) include(mitkMacroInstallHelperApp) include(mitkMacroInstallTargets) include(mitkMacroMultiplexPicType) # Deprecated include(mitkMacroCreateCTKPlugin) #----------------------------------------------------------------------------- # Global CMake variables #----------------------------------------------------------------------------- # Required and enabled C++11 features for all MITK code. # These are added as PUBLIC compile features to all MITK modules. set(MITK_CXX_FEATURES cxx_auto_type cxx_decltype cxx_enum_forward_declarations cxx_extended_friend_declarations cxx_extern_templates cxx_final cxx_lambdas cxx_local_type_template_args cxx_long_long_type cxx_nullptr cxx_override cxx_range_for cxx_right_angle_brackets cxx_rvalue_references cxx_static_assert cxx_strong_enums cxx_template_template_parameters cxx_trailing_return_types cxx_variadic_macros ) if(NOT DEFINED CMAKE_DEBUG_POSTFIX) # We can't do this yet because the CTK Plugin Framework # cannot cope with a postfix yet. #set(CMAKE_DEBUG_POSTFIX d) endif() #----------------------------------------------------------------------------- # Output directories. #----------------------------------------------------------------------------- set(_default_LIBRARY_output_dir lib) set(_default_RUNTIME_output_dir bin) set(_default_ARCHIVE_output_dir lib) foreach(type LIBRARY RUNTIME ARCHIVE) # Make sure the directory exists if(MITK_CMAKE_${type}_OUTPUT_DIRECTORY AND NOT EXISTS ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}) message("Creating directory MITK_CMAKE_${type}_OUTPUT_DIRECTORY: ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}") file(MAKE_DIRECTORY "${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}") endif() if(MITK_CMAKE_${type}_OUTPUT_DIRECTORY) set(CMAKE_${type}_OUTPUT_DIRECTORY ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}) else() set(CMAKE_${type}_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/${_default_${type}_output_dir}) set(MITK_CMAKE_${type}_OUTPUT_DIRECTORY ${CMAKE_${type}_OUTPUT_DIRECTORY}) endif() set(CMAKE_${type}_OUTPUT_DIRECTORY ${CMAKE_${type}_OUTPUT_DIRECTORY} CACHE INTERNAL "Output directory for ${type} files.") mark_as_advanced(CMAKE_${type}_OUTPUT_DIRECTORY) endforeach() #----------------------------------------------------------------------------- # Set MITK specific options and variables (NOT available during superbuild) #----------------------------------------------------------------------------- # Look for optional Doxygen package find_package(Doxygen) option(BLUEBERRY_DEBUG_SMARTPOINTER "Enable code for debugging smart pointers" OFF) mark_as_advanced(BLUEBERRY_DEBUG_SMARTPOINTER) # ASK THE USER TO SHOW THE CONSOLE WINDOW FOR CoreApp and mitkWorkbench option(MITK_SHOW_CONSOLE_WINDOW "Use this to enable or disable the console window when starting MITK GUI Applications" ON) mark_as_advanced(MITK_SHOW_CONSOLE_WINDOW) # TODO: check if necessary option(USE_ITKZLIB "Use the ITK zlib for pic compression." ON) mark_as_advanced(USE_ITKZLIB) if(NOT MITK_FAST_TESTING) if(DEFINED MITK_CTEST_SCRIPT_MODE AND (MITK_CTEST_SCRIPT_MODE STREQUAL "continuous" OR MITK_CTEST_SCRIPT_MODE STREQUAL "experimental") ) set(MITK_FAST_TESTING 1) endif() endif() if(NOT UNIX AND NOT MINGW) set(MITK_WIN32_FORCE_STATIC "STATIC" CACHE INTERNAL "Use this variable to always build static libraries on non-unix platforms") endif() if(MITK_BUILD_ALL_PLUGINS) set(MITK_BUILD_ALL_PLUGINS_OPTION "FORCE_BUILD_ALL") endif() # Configure pixel types used for ITK image access multiplexing mitkMacroConfigureItkPixelTypes() # Configure module naming conventions set(MITK_MODULE_NAME_REGEX_MATCH "^[A-Z].*$") set(MITK_MODULE_NAME_REGEX_NOT_MATCH "^[Mm][Ii][Tt][Kk].*$") set(MITK_MODULE_NAME_PREFIX "Mitk") set(MITK_MODULE_NAME_DEFAULTS_TO_DIRECTORY_NAME 1) #----------------------------------------------------------------------------- # Get MITK version info #----------------------------------------------------------------------------- mitkFunctionGetVersion(${MITK_SOURCE_DIR} MITK) mitkFunctionGetVersionDescription(${MITK_SOURCE_DIR} MITK) # MITK_VERSION set(MITK_VERSION_STRING "${MITK_VERSION_MAJOR}.${MITK_VERSION_MINOR}.${MITK_VERSION_PATCH}") if(MITK_VERSION_PATCH STREQUAL "99") set(MITK_VERSION_STRING "${MITK_VERSION_STRING}-${MITK_REVISION_SHORTID}") endif() #----------------------------------------------------------------------------- # Installation preparation # # These should be set before any MITK install macros are used #----------------------------------------------------------------------------- # on Mac OSX all BlueBerry plugins get copied into every # application bundle (.app directory) specified here if(MITK_USE_BLUEBERRY AND APPLE) include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/AppList.cmake") foreach(mitk_app ${MITK_APPS}) # extract option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 1 option_name) list(GET target_info_list 0 app_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) set(MACOSX_BUNDLE_NAMES ${MACOSX_BUNDLE_NAMES} Mitk${app_name}) endif() endforeach() endif() #----------------------------------------------------------------------------- # Set coverage Flags #----------------------------------------------------------------------------- if(WITH_COVERAGE) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(coverage_flags "-g -fprofile-arcs -ftest-coverage -O0 -DNDEBUG") set(COVERAGE_CXX_FLAGS ${coverage_flags}) set(COVERAGE_C_FLAGS ${coverage_flags}) endif() endif() #----------------------------------------------------------------------------- # MITK C/CXX Flags #----------------------------------------------------------------------------- set(MITK_C_FLAGS "${COVERAGE_C_FLAGS}") set(MITK_C_FLAGS_DEBUG ) set(MITK_C_FLAGS_RELEASE ) set(MITK_CXX_FLAGS "${COVERAGE_CXX_FLAGS} ${MITK_CXX11_FLAG}") set(MITK_CXX_FLAGS_DEBUG ) set(MITK_CXX_FLAGS_RELEASE ) set(MITK_EXE_LINKER_FLAGS ) set(MITK_SHARED_LINKER_FLAGS ) find_package(OpenMP) if (OPENMP_FOUND) set(MITK_C_FLAGS "${MITK_C_FLAGS} ${OpenMP_C_FLAGS}") set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") endif() if(WIN32) set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} -D_WIN32_WINNT=0x0501 -DPOCO_NO_UNWINDOWS -DWIN32_LEAN_AND_MEAN -DNOMINMAX") mitkFunctionCheckCompilerFlags("/wd4005" MITK_CXX_FLAGS) # warning C4005: macro redefinition mitkFunctionCheckCompilerFlags("/wd4231" MITK_CXX_FLAGS) # warning C4231: nonstandard extension used : 'extern' before template explicit instantiation # the following line should be removed after fixing bug 17637 mitkFunctionCheckCompilerFlags("/wd4316" MITK_CXX_FLAGS) # warning C4316: object alignment on heap mitkFunctionCheckCompilerFlags("/wd4180" MITK_CXX_FLAGS) # warning C4180: qualifier applied to function type has no meaning endif() if(NOT MSVC_VERSION) foreach(_flag -Wall -Wextra -Wpointer-arith -Winvalid-pch -Wcast-align -Wwrite-strings -Wno-error=gnu -Wno-error=unknown-pragmas # The strict-overflow warning is generated by ITK template code -Wno-error=strict-overflow -Woverloaded-virtual -Wstrict-null-sentinel #-Wold-style-cast #-Wsign-promo -Wno-array-bounds -fdiagnostics-show-option ) mitkFunctionCheckCAndCXXCompilerFlags(${_flag} MITK_C_FLAGS MITK_CXX_FLAGS) endforeach() endif() if(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) mitkFunctionCheckCompilerFlags("-Wl,--no-undefined" MITK_SHARED_LINKER_FLAGS) mitkFunctionCheckCompilerFlags("-Wl,--as-needed" MITK_SHARED_LINKER_FLAGS) endif() if(CMAKE_COMPILER_IS_GNUCXX) mitkFunctionCheckCAndCXXCompilerFlags("-fstack-protector-all" MITK_C_FLAGS MITK_CXX_FLAGS) if(MINGW) # suppress warnings about auto imported symbols set(MITK_SHARED_LINKER_FLAGS "-Wl,--enable-auto-import ${MITK_SHARED_LINKER_FLAGS}") endif() set(MITK_CXX_FLAGS_RELEASE "-U_FORTIFY_SOURCES -D_FORTIFY_SOURCE=2 ${MITK_CXX_FLAGS_RELEASE}") endif() set(MITK_MODULE_LINKER_FLAGS ${MITK_SHARED_LINKER_FLAGS}) set(MITK_EXE_LINKER_FLAGS ${MITK_SHARED_LINKER_FLAGS}) #----------------------------------------------------------------------------- # MITK Packages #----------------------------------------------------------------------------- set(MITK_MODULES_PACKAGE_DEPENDS_DIR ${MITK_SOURCE_DIR}/CMake/PackageDepends) set(MODULES_PACKAGE_DEPENDS_DIRS ${MITK_MODULES_PACKAGE_DEPENDS_DIR}) if(NOT MITK_USE_SYSTEM_Boost) set(Boost_NO_SYSTEM_PATHS 1) endif() set(Boost_USE_MULTITHREADED 1) set(Boost_USE_STATIC_LIBS 0) set(Boost_USE_STATIC_RUNTIME 0) set(Boost_ADDITIONAL_VERSIONS "1.60" "1.60.0") # We need this later for a DCMTK workaround set(_dcmtk_dir_orig ${DCMTK_DIR}) # This property is populated at the top half of this file get_property(MITK_EXTERNAL_PROJECTS GLOBAL PROPERTY MITK_EXTERNAL_PROJECTS) foreach(ep ${MITK_EXTERNAL_PROJECTS}) get_property(_package GLOBAL PROPERTY MITK_${ep}_PACKAGE) get_property(_components GLOBAL PROPERTY MITK_${ep}_COMPONENTS) if(MITK_USE_${ep} AND _package) if(_components) find_package(${_package} COMPONENTS ${_components} REQUIRED CONFIG) else() # Prefer config mode first because it finds external # Config.cmake files pointed at by _DIR variables. # Otherwise, existing Find.cmake files could fail. # (e.g. in the case of GLEW and the FindGLEW.cmake file shipped # with CMake). find_package(${_package} QUIET CONFIG) string(TOUPPER "${_package}" _package_uc) if(NOT (${_package}_FOUND OR ${_package_uc}_FOUND)) find_package(${_package} REQUIRED) endif() endif() endif() endforeach() # Ensure that the MITK CMake module path comes first set(CMAKE_MODULE_PATH ${MITK_CMAKE_DIR} ${CMAKE_MODULE_PATH} ) if(MITK_USE_DCMTK) # Due to the preferred CONFIG mode in find_package calls above, # the DCMTKConfig.cmake file is read, which does not provide useful # package information. We explictly need MODULE mode to find DCMTK. if(${_dcmtk_dir_orig} MATCHES "${MITK_EXTERNAL_PROJECT_PREFIX}.*") # Help our FindDCMTK.cmake script find our super-build DCMTK set(DCMTK_DIR ${MITK_EXTERNAL_PROJECT_PREFIX}) else() # Use the original value set(DCMTK_DIR ${_dcmtk_dir_orig}) endif() find_package(DCMTK REQUIRED MODULE) endif() if(MITK_USE_Python) find_package(PythonLibs REQUIRED) find_package(PythonInterp REQUIRED) if(MITK_USE_Numpy) find_package(Numpy REQUIRED) endif() endif() if(MITK_USE_SOFA) # The SOFAConfig.cmake file does not provide exported targets or # libraries with absolute paths, hence we need to make the link # directories globally available until the SOFAConfig.cmake file # supports a proper mechanism for handling targets. # The same code is needed in MITKConfig.cmake. link_directories(${SOFA_LIBRARY_DIRS}) endif() # Same as SOFA above link_directories(${Boost_LIBRARY_DIRS}) if(MITK_USE_OpenIGTLink) # Same as SOFA above link_directories(${OpenIGTLink_LIBRARY_DIRS}) endif() if(MITK_USE_SimpleITK) link_directories(${SimpleITK_LIBRARY_DIRS}) endif() if(MITK_USE_OpenCL) find_package(OpenCL REQUIRED) endif() # Qt support if(MITK_USE_QT) find_package(Qt5Core ${MITK_QT5_MINIMUM_VERSION} REQUIRED) # at least Core required get_target_property(_qmake_exec Qt5::qmake LOCATION) execute_process(COMMAND ${_qmake_exec} -query QT_INSTALL_BINS RESULT_VARIABLE _result OUTPUT_VARIABLE QT_BINARY_DIR ERROR_VARIABLE _error ) string(STRIP "${QT_BINARY_DIR}" QT_BINARY_DIR) if(_result OR NOT EXISTS "${QT_BINARY_DIR}") message(FATAL_ERROR "Could not determine Qt binary directory: ${_result} ${QT_BINARY_DIR} ${_error}") endif() find_program(QT_HELPGENERATOR_EXECUTABLE NAMES qhelpgenerator qhelpgenerator-qt5 qhelpgenerator5 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_COLLECTIONGENERATOR_EXECUTABLE NAMES qcollectiongenerator qcollectiongenerator-qt5 qcollectiongenerator5 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_ASSISTANT_EXECUTABLE NAMES assistant assistant-qt5 assistant5 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_XMLPATTERNS_EXECUTABLE NAMES xmlpatterns PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) mark_as_advanced(QT_HELPGENERATOR_EXECUTABLE QT_COLLECTIONGENERATOR_EXECUTABLE QT_ASSISTANT_EXECUTABLE QT_XMLPATTERNS_EXECUTABLE ) if(MITK_USE_BLUEBERRY) option(BLUEBERRY_USE_QT_HELP "Enable support for integrating plugin documentation into Qt Help" ${DOXYGEN_FOUND}) mark_as_advanced(BLUEBERRY_USE_QT_HELP) # Sanity checks for in-application BlueBerry plug-in help generation if(BLUEBERRY_USE_QT_HELP) set(_force_blueberry_use_qt_help_to_off 0) if(NOT DOXYGEN_FOUND) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because Doxygen was not found.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(DOXYGEN_FOUND AND DOXYGEN_VERSION VERSION_LESS 1.8.7) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because Doxygen version 1.8.7 or newer not found.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(NOT QT_HELPGENERATOR_EXECUTABLE) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because QT_HELPGENERATOR_EXECUTABLE is empty.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(NOT QT_XMLPATTERNS_EXECUTABLE) message("You have enabled Qt Help support, but QT_XMLPATTERNS_EXECUTABLE is empty") set(_force_blueberry_use_qt_help_to_off 1) endif() if(_force_blueberry_use_qt_help_to_off) set(BLUEBERRY_USE_QT_HELP OFF CACHE BOOL "Enable support for integrating plugin documentation into Qt Help" FORCE) endif() endif() if(BLUEBERRY_QT_HELP_REQUIRED AND NOT BLUEBERRY_USE_QT_HELP) message(FATAL_ERROR "BLUEBERRY_USE_QT_HELP is required to be set to ON") endif() endif() endif() #----------------------------------------------------------------------------- # Testing #----------------------------------------------------------------------------- if(BUILD_TESTING) enable_testing() include(CTest) mark_as_advanced(TCL_TCLSH DART_ROOT) option(MITK_ENABLE_RENDERING_TESTING OFF "Enable the MITK rendering tests. Requires x-server in Linux.") #Rendering testing does not work for Linux nightlies, thus it is disabled per default #and activated for Mac and Windows. if(WIN32 OR APPLE) set(MITK_ENABLE_RENDERING_TESTING ON) endif() mark_as_advanced( MITK_ENABLE_RENDERING_TESTING ) # Setup file for setting custom ctest vars configure_file( CMake/CTestCustom.cmake.in ${MITK_BINARY_DIR}/CTestCustom.cmake @ONLY ) # Initial cache for ProjectTemplate and PluginGenerator tests configure_file( CMake/mitkTestInitialCache.txt.in ${MITK_BINARY_DIR}/mitkTestInitialCache.txt @ONLY ) # Configuration for the CMake-generated test driver set(CMAKE_TESTDRIVER_EXTRA_INCLUDES "#include ") set(CMAKE_TESTDRIVER_BEFORE_TESTMAIN " try {") set(CMAKE_TESTDRIVER_AFTER_TESTMAIN " } catch( std::exception & excp ) { fprintf(stderr,\"%s\\n\",excp.what()); return EXIT_FAILURE; } catch( ... ) { printf(\"Exception caught in the test driver\\n\"); return EXIT_FAILURE; } ") set(MITK_TEST_OUTPUT_DIR "${MITK_BINARY_DIR}/test_output") if(NOT EXISTS ${MITK_TEST_OUTPUT_DIR}) file(MAKE_DIRECTORY ${MITK_TEST_OUTPUT_DIR}) endif() # Test the external project template if(MITK_USE_BLUEBERRY) include(mitkTestProjectTemplate) endif() # Test the package target include(mitkPackageTest) endif() configure_file(mitkTestingConfig.h.in ${MITK_BINARY_DIR}/mitkTestingConfig.h) #----------------------------------------------------------------------------- # MITK_SUPERBUILD_BINARY_DIR #----------------------------------------------------------------------------- # If MITK_SUPERBUILD_BINARY_DIR isn't defined, it means MITK is *NOT* build using Superbuild. # In that specific case, MITK_SUPERBUILD_BINARY_DIR should default to MITK_BINARY_DIR if(NOT DEFINED MITK_SUPERBUILD_BINARY_DIR) set(MITK_SUPERBUILD_BINARY_DIR ${MITK_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # Set C/CXX and linker flags for MITK code #----------------------------------------------------------------------------- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MITK_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${MITK_CXX_FLAGS_DEBUG}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${MITK_CXX_FLAGS_RELEASE}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MITK_C_FLAGS}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${MITK_C_FLAGS_DEBUG}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${MITK_C_FLAGS_RELEASE}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MITK_EXE_LINKER_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${MITK_SHARED_LINKER_FLAGS}") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${MITK_MODULE_LINKER_FLAGS}") #----------------------------------------------------------------------------- # Add custom targets representing CDash subprojects #----------------------------------------------------------------------------- foreach(subproject ${CTEST_PROJECT_SUBPROJECTS}) if(NOT TARGET ${subproject} AND NOT subproject MATCHES "Unlabeled") add_custom_target(${subproject}) endif() endforeach() #----------------------------------------------------------------------------- # Add subdirectories #----------------------------------------------------------------------------- add_subdirectory(Utilities) add_subdirectory(Modules) if(MITK_USE_BLUEBERRY) set(BLUEBERRY_XPDOC_OUTPUT_DIR ${MITK_DOXYGEN_OUTPUT_DIR}/html/extension-points/html/) set(MITK_DEFAULT_SUBPROJECTS MITK-Plugins) # Plug-in testing (needs some work to be enabled again) if(BUILD_TESTING) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CoreApp") if(TARGET CoreApp) get_target_property(_is_macosx_bundle CoreApp MACOSX_BUNDLE) if(APPLE AND _is_macosx_bundle) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CoreApp.app/Contents/MacOS/CoreApp") endif() endif() set(BLUEBERRY_TEST_APP_ID "org.mitk.qt.coreapplication") endif() include("${CMAKE_CURRENT_SOURCE_DIR}/Plugins/PluginList.cmake") mitkFunctionWhitelistPlugins(MITK MITK_PLUGINS) set(mitk_plugins_fullpath "") foreach(mitk_plugin ${MITK_PLUGINS}) list(APPEND mitk_plugins_fullpath Plugins/${mitk_plugin}) endforeach() if(EXISTS ${MITK_PRIVATE_MODULES}/PluginList.cmake) include(${MITK_PRIVATE_MODULES}/PluginList.cmake) foreach(mitk_plugin ${MITK_PRIVATE_PLUGINS}) list(APPEND mitk_plugins_fullpath ${MITK_PRIVATE_MODULES}/${mitk_plugin}) endforeach() endif() if(MITK_BUILD_EXAMPLES) include("${CMAKE_CURRENT_SOURCE_DIR}/Examples/Plugins/PluginList.cmake") set(mitk_example_plugins_fullpath ) foreach(mitk_example_plugin ${MITK_EXAMPLE_PLUGINS}) list(APPEND mitk_example_plugins_fullpath Examples/Plugins/${mitk_example_plugin}) list(APPEND mitk_plugins_fullpath Examples/Plugins/${mitk_example_plugin}) endforeach() endif() # Specify which plug-ins belong to this project macro(GetMyTargetLibraries all_target_libraries varname) set(re_ctkplugin_mitk "^org_mitk_[a-zA-Z0-9_]+$") set(re_ctkplugin_bb "^org_blueberry_[a-zA-Z0-9_]+$") set(_tmp_list) list(APPEND _tmp_list ${all_target_libraries}) ctkMacroListFilter(_tmp_list re_ctkplugin_mitk re_ctkplugin_bb OUTPUT_VARIABLE ${varname}) endmacro() # Get infos about application directories and build options include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/AppList.cmake") set(mitk_apps_fullpath ) foreach(mitk_app ${MITK_APPS}) # extract option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 0 directory_name) list(GET target_info_list 1 option_name) if(${option_name}) list(APPEND mitk_apps_fullpath "${CMAKE_CURRENT_SOURCE_DIR}/Applications/${directory_name}^^${option_name}") endif() endforeach() if (mitk_plugins_fullpath) ctkMacroSetupPlugins(${mitk_plugins_fullpath} BUILD_OPTION_PREFIX MITK_BUILD_ APPS ${mitk_apps_fullpath} BUILD_ALL ${MITK_BUILD_ALL_PLUGINS} COMPACT_OPTIONS) endif() set(MITK_PLUGIN_USE_FILE "${MITK_BINARY_DIR}/MitkPluginUseFile.cmake") if(${PROJECT_NAME}_PLUGIN_LIBRARIES) ctkFunctionGeneratePluginUseFile(${MITK_PLUGIN_USE_FILE}) else() file(REMOVE ${MITK_PLUGIN_USE_FILE}) set(MITK_PLUGIN_USE_FILE ) endif() endif() #----------------------------------------------------------------------------- # Documentation #----------------------------------------------------------------------------- if(DOXYGEN_FOUND) add_subdirectory(Documentation) endif() #----------------------------------------------------------------------------- # Installation #----------------------------------------------------------------------------- # set MITK cpack variables # These are the default variables, which can be overwritten ( see below ) include(mitkSetupCPack) set(use_default_config ON) # MITK_APPS is set in Applications/AppList.cmake (included somewhere above # if MITK_USE_BLUEBERRY is set to ON). if(MITK_APPS) set(activated_apps_no 0) list(LENGTH MITK_APPS app_count) # Check how many apps have been enabled # If more than one app has been activated, the we use the # default CPack configuration. Otherwise that apps configuration # will be used, if present. foreach(mitk_app ${MITK_APPS}) # extract option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 1 option_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) MATH(EXPR activated_apps_no "${activated_apps_no} + 1") endif() endforeach() if(app_count EQUAL 1 AND (activated_apps_no EQUAL 1 OR MITK_BUILD_ALL_APPS)) # Corner case if there is only one app in total set(use_project_cpack ON) elseif(activated_apps_no EQUAL 1 AND NOT MITK_BUILD_ALL_APPS) # Only one app is enabled (no "build all" flag set) set(use_project_cpack ON) else() # Less or more then one app is enabled set(use_project_cpack OFF) endif() foreach(mitk_app ${MITK_APPS}) # extract target_dir and option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 0 target_dir) list(GET target_info_list 1 option_name) list(GET target_info_list 2 executable_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) # check whether application specific configuration files will be used if(use_project_cpack) # use files if they exist if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/Applications/${target_dir}/CPackOptions.cmake") include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/${target_dir}/CPackOptions.cmake") endif() if(EXISTS "${PROJECT_SOURCE_DIR}/Applications/${target_dir}/CPackConfig.cmake.in") set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_BINARY_DIR}/Applications/${target_dir}/CPackConfig.cmake") configure_file(${PROJECT_SOURCE_DIR}/Applications/${target_dir}/CPackConfig.cmake.in ${CPACK_PROJECT_CONFIG_FILE} @ONLY) set(use_default_config OFF) endif() endif() # add link to the list list(APPEND CPACK_CREATE_DESKTOP_LINKS "${executable_name}") endif() endforeach() endif() # if no application specific configuration file was used, use default if(use_default_config) configure_file(${MITK_SOURCE_DIR}/MITKCPackOptions.cmake.in ${MITK_BINARY_DIR}/MITKCPackOptions.cmake @ONLY) set(CPACK_PROJECT_CONFIG_FILE "${MITK_BINARY_DIR}/MITKCPackOptions.cmake") endif() # include CPack model once all variables are set include(CPack) # Additional installation rules include(mitkInstallRules) #----------------------------------------------------------------------------- # Last configuration steps #----------------------------------------------------------------------------- # ---------------- Export targets ----------------- set(MITK_EXPORTS_FILE "${MITK_BINARY_DIR}/MitkExports.cmake") file(REMOVE ${MITK_EXPORTS_FILE}) set(targets_to_export) get_property(module_targets GLOBAL PROPERTY MITK_MODULE_TARGETS) if(module_targets) list(APPEND targets_to_export ${module_targets}) endif() if(MITK_USE_BLUEBERRY) if(MITK_PLUGIN_LIBRARIES) list(APPEND targets_to_export ${MITK_PLUGIN_LIBRARIES}) endif() endif() export(TARGETS ${targets_to_export} APPEND FILE ${MITK_EXPORTS_FILE}) set(MITK_EXPORTED_TARGET_PROPERTIES ) foreach(target_to_export ${targets_to_export}) get_target_property(autoload_targets ${target_to_export} MITK_AUTOLOAD_TARGETS) if(autoload_targets) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_AUTOLOAD_TARGETS \"${autoload_targets}\")") endif() get_target_property(autoload_dir ${target_to_export} MITK_AUTOLOAD_DIRECTORY) if(autoload_dir) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_AUTOLOAD_DIRECTORY \"${autoload_dir}\")") endif() get_target_property(deprecated_module ${target_to_export} MITK_MODULE_DEPRECATED_SINCE) if(deprecated_module) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_MODULE_DEPRECATED_SINCE \"${deprecated_module}\")") endif() endforeach() # ---------------- External projects ----------------- get_property(MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS_CONFIG GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS) set(MITK_CONFIG_EXTERNAL_PROJECTS ) #string(REPLACE "^^" ";" _mitk_external_projects ${MITK_EXTERNAL_PROJECTS}) foreach(ep ${MITK_EXTERNAL_PROJECTS}) get_property(_components GLOBAL PROPERTY MITK_${ep}_COMPONENTS) set(MITK_CONFIG_EXTERNAL_PROJECTS "${MITK_CONFIG_EXTERNAL_PROJECTS} set(MITK_USE_${ep} ${MITK_USE_${ep}}) set(MITK_${ep}_DIR \"${${ep}_DIR}\") set(MITK_${ep}_COMPONENTS ${_components}) ") endforeach() foreach(ep ${MITK_EXTERNAL_PROJECTS}) get_property(_package GLOBAL PROPERTY MITK_${ep}_PACKAGE) get_property(_components GLOBAL PROPERTY MITK_${ep}_COMPONENTS) if(_components) set(_components_arg COMPONENTS \${_components}) else() set(_components_arg) endif() if(_package) set(MITK_CONFIG_EXTERNAL_PROJECTS "${MITK_CONFIG_EXTERNAL_PROJECTS} if(MITK_USE_${ep}) set(${ep}_DIR \${MITK_${ep}_DIR}) if(MITK_${ep}_COMPONENTS) mitkMacroFindDependency(${_package} COMPONENTS \${MITK_${ep}_COMPONENTS}) else() mitkMacroFindDependency(${_package}) endif() endif()") endif() endforeach() # ---------------- Tools ----------------- configure_file(${MITK_SOURCE_DIR}/CMake/ToolExtensionITKFactory.cpp.in ${MITK_BINARY_DIR}/ToolExtensionITKFactory.cpp.in COPYONLY) configure_file(${MITK_SOURCE_DIR}/CMake/ToolExtensionITKFactoryLoader.cpp.in ${MITK_BINARY_DIR}/ToolExtensionITKFactoryLoader.cpp.in COPYONLY) configure_file(${MITK_SOURCE_DIR}/CMake/ToolGUIExtensionITKFactory.cpp.in ${MITK_BINARY_DIR}/ToolGUIExtensionITKFactory.cpp.in COPYONLY) # ---------------- Configure files ----------------- configure_file(mitkVersion.h.in ${MITK_BINARY_DIR}/mitkVersion.h) configure_file(mitkConfig.h.in ${MITK_BINARY_DIR}/mitkConfig.h) set(IPFUNC_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ipFunc) set(UTILITIES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities) configure_file(mitkConfig.h.in ${MITK_BINARY_DIR}/mitkConfig.h) configure_file(MITKConfig.cmake.in ${MITK_BINARY_DIR}/MITKConfig.cmake @ONLY) write_basic_config_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake VERSION ${MITK_VERSION_STRING} COMPATIBILITY AnyNewerVersion) # If we are under Windows, create two batch files which correctly # set up the environment for the application and for Visual Studio if(WIN32) include(mitkFunctionCreateWindowsBatchScript) set(VS_SOLUTION_FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME}.sln") if(MITK_USE_HDF5) list(APPEND MITK_LIBRARY_DIRS ${HDF5_DIR}/install/bin) message(STATUS "MITK-Runtime " ${MITK_RUNTIME_PATH}) endif(MITK_USE_HDF5) foreach(VS_BUILD_TYPE debug release) mitkFunctionCreateWindowsBatchScript("${MITK_SOURCE_DIR}/CMake/StartVS.bat.in" ${PROJECT_BINARY_DIR}/StartVS_${VS_BUILD_TYPE}.bat ${VS_BUILD_TYPE}) endforeach() endif(WIN32) #----------------------------------------------------------------------------- # MITK Applications #----------------------------------------------------------------------------- # This must come after MITKConfig.h was generated, since applications # might do a find_package(MITK REQUIRED). add_subdirectory(Applications) #----------------------------------------------------------------------------- # MITK Examples #----------------------------------------------------------------------------- if(MITK_BUILD_EXAMPLES) # This must come after MITKConfig.h was generated, since applications # might do a find_package(MITK REQUIRED). add_subdirectory(Examples) endif() #----------------------------------------------------------------------------- # Print configuration summary #----------------------------------------------------------------------------- message("\n\n") feature_summary( DESCRIPTION "------- FEATURE SUMMARY FOR ${PROJECT_NAME} -------" WHAT ALL ) diff --git a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter.hxx b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter.hxx index bf3eb4a6d6..3891b37206 100644 --- a/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter.hxx +++ b/Modules/Classification/CLUtilities/include/itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter.hxx @@ -1,401 +1,401 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ /*========================================================================= * * Copyright Insight Software Consortium * * 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 __itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter_hxx #define __itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter_hxx #include "itkEnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter.h" #include "itkConstNeighborhoodIterator.h" #include "itkNeighborhood.h" #include "vnl/vnl_math.h" #include "itkMacro.h" #include "itkRescaleIntensityImageFilter.h" #include "itkMaskImageFilter.h" #include "itkLabelStatisticsImageFilter.h" #include "itkScalarConnectedComponentImageFilter.h" #include "itkRelabelComponentImageFilter.h" #include "itkCastImageFilter.h" #include namespace itk { namespace Statistics { template EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter() : m_NumberOfBinsPerAxis( itkGetStaticConstMacro( DefaultBinsPerAxis ) ), m_Min( NumericTraits::NonpositiveMin() ), m_Max( NumericTraits::max() ), m_MinDistance( NumericTraits::ZeroValue() ), m_MaxDistance( NumericTraits::max() ), m_InsidePixelValue( NumericTraits::OneValue() ) { this->SetNumberOfRequiredInputs( 1 ); this->SetNumberOfRequiredOutputs( 1 ); const unsigned int measurementVectorSize = 1; this->ProcessObject::SetNthOutput( 0, this->MakeOutput( 0 ) ); this->ProcessObject::SetNthOutput( 1, this->MakeOutput( 1 ) ); HistogramType *output = const_cast( this->GetOutput() ); output->SetMeasurementVectorSize( measurementVectorSize ); m_siMatrix = new double[m_NumberOfBinsPerAxis]; for(int i = 0; i < m_NumberOfBinsPerAxis; i++) { m_siMatrix[i] = 0; } this->m_LowerBound.SetSize( measurementVectorSize ); this->m_UpperBound.SetSize( measurementVectorSize ); this->m_LowerBound[0] = this->m_Min; this->m_LowerBound[1] = this->m_MinDistance; this->m_UpperBound[0] = this->m_Max; this->m_UpperBound[1] = this->m_MaxDistance; } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::SetOffset( const OffsetType offset ) { OffsetVectorPointer offsetVector = OffsetVector::New(); offsetVector->push_back( offset ); this->SetOffsets( offsetVector ); MITK_WARN << "We now have " << this->GetOffsets()->size() << " offsets in matrixgenerator"; } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::AddOffsets( const std::vector _offsets ) { OffsetVectorPointer offsetVector = OffsetVector::New(); typename OffsetVector::ConstIterator offsets; //MITK_WARN << "We have " << this->GetOffsets()->size() << " offsets!"; for( int i = 0; i < _offsets.size(); i++) { offsetVector->push_back(_offsets[i]); auto k = _offsets[i]; this->NormalizeOffsetDirection(k); offsetVector->push_back(k); } this->SetOffsets( offsetVector ); MITK_WARN << "We now have " << this->GetOffsets()->size() << " offsets in matrixgenerator"; } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::SetInput( const ImageType *image ) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput( 0, const_cast( image ) ); } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::SetMaskImage( const ImageType *image ) { // Process object is not const-correct so the const_cast is required here this->ProcessObject::SetNthInput( 1, const_cast( image ) ); } template const TImageType * EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::GetInput() const { if( this->GetNumberOfInputs() < 1 ) { return ITK_NULLPTR; } return static_cast( this->ProcessObject::GetInput( 0 ) ); } template const TImageType * EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::GetMaskImage() const { if( this->GetNumberOfInputs() < 2 ) { return ITK_NULLPTR; } return static_cast( this->ProcessObject::GetInput( 1 ) ); } template const typename EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter::HistogramType * EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::GetOutput() const { const HistogramType *output = static_cast( this->ProcessObject::GetOutput( 0 ) ); return output; } template double* EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::GetSiMatrix() const { return m_siMatrix; } template typename EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter::DataObjectPointer EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::MakeOutput( DataObjectPointerArraySizeType itkNotUsed( idx ) ) { return HistogramType::New().GetPointer(); } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::GenerateData() { HistogramType *output = static_cast( this->ProcessObject::GetOutput( 0 ) ); const ImageType * inputImage = this->GetInput(); const ImageType * maskImage = this->GetMaskImage(); // First, create an appropriate histogram with the right number of bins // and mins and maxes correct for the image type. typename HistogramType::SizeType size( output->GetMeasurementVectorSize() ); size.Fill( this->m_NumberOfBinsPerAxis ); this->m_LowerBound[0] = this->m_Min; this->m_LowerBound[1] = this->m_MinDistance; this->m_UpperBound[0] = this->m_Max; this->m_UpperBound[1] = this->m_MaxDistance; output->Initialize( size, this->m_LowerBound, this->m_UpperBound ); MeasurementVectorType run( output->GetMeasurementVectorSize() ); typename HistogramType::IndexType hIndex; //Cast the image to a float image - with no respect to the incoming image //to prevent some non-templated itk issues typedef itk::Image FloatImageType; typedef itk::CastImageFilter CastFilterType; typename CastFilterType::Pointer caster = CastFilterType::New(); caster->SetInput(inputImage); caster->Update(); typename FloatImageType::Pointer floatImage = caster->GetOutput(); //Cast the mask to an unsigned short image - with no respect to the incomimg maskimage //to prevent some non-templated itk issues typedef unsigned short LabelPixelType; typedef itk::Image LabelImageType; typedef itk::CastImageFilter MaskCastFilterType; typename MaskCastFilterType::Pointer maskCaster = MaskCastFilterType::New(); maskCaster->SetInput(maskImage); maskCaster->Update(); //Set all values out of the mask to nans. typedef itk::MaskImageFilter< FloatImageType, LabelImageType, FloatImageType > MaskFilterType; typename MaskFilterType::Pointer maskFilter = MaskFilterType::New(); maskFilter->SetInput(floatImage); maskFilter->SetMaskImage(maskCaster->GetOutput()); maskFilter->SetOutsideValue( std::numeric_limits::quiet_NaN()); maskFilter->Update(); FloatImageType::Pointer floatImageMasked = maskFilter->GetOutput(); typedef ConstNeighborhoodIterator NeighborhoodIteratorType; typename NeighborhoodIteratorType::RadiusType radius; radius.Fill( 1 ); NeighborhoodIteratorType neighborIt( radius, inputImage, inputImage->GetRequestedRegion() ); for( neighborIt.GoToBegin(); !neighborIt.IsAtEnd(); ++neighborIt ) { const PixelType centerPixelIntensity = neighborIt.GetCenterPixel(); IndexType centerIndex = neighborIt.GetIndex(); FloatImageType::IndexType cIndex; cIndex[0] = centerIndex[0]; cIndex[1] = centerIndex[1]; cIndex[2] = centerIndex[2]; float centerFloatPixel = floatImageMasked->GetPixel(cIndex); int px = 0; PixelType sum = 0.0; bool canCalculate = true; typename OffsetVector::ConstIterator offsets; for( offsets = this->GetOffsets()->Begin(); offsets != this->GetOffsets()->End(); offsets++ ) { OffsetType offset = offsets.Value(); IndexType index; index = centerIndex + offset; if(!inputImage->GetRequestedRegion().IsInside(index)) { canCalculate = false; break; } PixelType offsetPixel = inputImage->GetPixel(index); FloatImageType::IndexType fIndex; fIndex[0] = index[0]; fIndex[1] = index[1]; fIndex[2] = index[2]; float floatPixel = floatImageMasked->GetPixel(fIndex); //We have a nan here if(floatPixel != floatPixel || centerFloatPixel!= centerFloatPixel) { canCalculate = false; break; } sum += offsetPixel; px++; } //If we have a nan in the neighbourhood, continue if(!canCalculate) continue; PixelType mean = sum / px; - double si = std::abs(mean-centerPixelIntensity); + double si = std::abs((float)mean-(float)centerPixelIntensity); run[0] = centerPixelIntensity; //Check for NaN and inf if(run[0] == run[0] && !std::isinf(std::abs(run[0]))) { output->GetIndex( run, hIndex ); output->IncreaseFrequencyOfIndex( hIndex, 1 ); m_siMatrix[hIndex[0]] += si; } //MITK_WARN << " -> In this round we added: " << centerIndex << " with value " << centerPixelIntensity << " and si = " << si; //MITK_WARN << " -> Values are now siMatrix["< Values are now niMatrix: " << output->GetFrequency(hIndex) << "/" << run; } } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::SetPixelValueMinMax( PixelType min, PixelType max ) { if( this->m_Min != min || this->m_Max != max ) { itkDebugMacro( "setting Min to " << min << "and Max to " << max ); this->m_Min = min; this->m_Max = max; this->Modified(); } } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::SetDistanceValueMinMax( RealType min, RealType max ) { if( this->m_MinDistance != min || this->m_MaxDistance != max ) { itkDebugMacro( "setting MinDistance to " << min << "and MaxDistance to " << max ); this->m_MinDistance = min; this->m_MaxDistance = max; this->Modified(); } } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::PrintSelf( std::ostream& os, Indent indent ) const { Superclass::PrintSelf( os,indent ); os << indent << "Offsets: " << this->GetOffsets() << std::endl; os << indent << "Min: " << this->m_Min << std::endl; os << indent << "Max: " << this->m_Max << std::endl; os << indent << "Min distance: " << this->m_MinDistance << std::endl; os << indent << "Max distance: " << this->m_MaxDistance << std::endl; os << indent << "NumberOfBinsPerAxis: " << this->m_NumberOfBinsPerAxis << std::endl; os << indent << "InsidePixelValue: " << this->m_InsidePixelValue << std::endl; } template void EnhancedScalarImageToNeighbourhoodGreyLevelDifferenceMatrixFilter ::NormalizeOffsetDirection(OffsetType &offset) { //MITK_WARN <<" -> NGTDM old offset = " << offset; itkDebugMacro("old offset = " << offset << std::endl); int sign = 1; bool metLastNonZero = false; for (int i = offset.GetOffsetDimension()-1; i>=0; i--) { if (metLastNonZero) { offset[i] *= sign; } else if (offset[i] != 0) { sign = (offset[i] > 0 ) ? 1 : -1; metLastNonZero = true; offset[i] *= sign; } } //MITK_WARN << " ->NGTDM new offset = " << offset; itkDebugMacro("new offset = " << offset << std::endl); } } // end of namespace Statistics } // end of namespace itk #endif diff --git a/Modules/Radiomics/RadiomicsCore/include/mitkRadiomicsCollection.h b/Modules/Radiomics/RadiomicsCore/include/mitkRadiomicsCollection.h index 7ee4ad2539..ede7829aba 100644 --- a/Modules/Radiomics/RadiomicsCore/include/mitkRadiomicsCollection.h +++ b/Modules/Radiomics/RadiomicsCore/include/mitkRadiomicsCollection.h @@ -1,139 +1,144 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkRadiomicsCollection_h #define mitkRadiomicsCollection_h #include #include #include #include #include namespace mitk { class MITKRADIOMICSCORE_EXPORT RadiomicsCollection : public itk::Object { public: mitkClassMacroItkParent(RadiomicsCollection, itk::Object); itkFactorylessNewMacro(RadiomicsCollection) itkCloneMacro(Self) enum formatType { CsvType = 1, WideType = 2, XMLType = 3 }; void setImageNode(mitk::DataNode::Pointer imageNode); void setSegmentationNode(mitk::DataNode::Pointer segmentationNode); void setRegistrationNode(mitk::DataNode::Pointer registrationNode); void setImageNormalization(bool imageNormalization); void setName(std::string name); void setOutputFile(std::string outputFile); void setFormatType(formatType type); void setUse3d(bool use3d); void setCoocString(std::string coocstring); void setRunLengthString(std::string runlengthstring); void setUseFirstOrder(bool firstOrder); void setUseVolumetric(bool volumetric); void setUseTexture(bool texture); void setUseNorm(bool useNorm) { m_UseNorm = useNorm; } void setUseGeomCorrection(bool useGeomCorrection) { m_UseGeomCorrection = useGeomCorrection; } void setUseResampling(bool useResampling) { m_UseResampling = useResampling; } void setUseCoiflet(bool coiflet) { m_UseCoiflet = coiflet; } void setUseDaubechies(bool daubechies) { m_UseDaubechies = daubechies; } mitk::DataNode::Pointer getImageNode() { return m_ImageNode; } mitk::DataNode::Pointer getSegmentationNode() {return m_SegmentationNode; } mitk::DataNode::Pointer getRegistrationNode() { return m_RegistrationImageNode; } std::string getOutputFile() { return m_OutputFile; } std::string getName() { return m_Name; } std::string getCoocString() { return m_CoocString; } std::string getRunLengthString() { return m_RunLengthString; } formatType getFormatType() { return m_FormatType; } bool getImageNormalization() { return m_ImageNormalization; } bool getUse3d() { return m_Use3d; } bool getUseCoiflet() { return m_UseCoiflet; } bool getUseDaubechies() { return m_UseDaubechies; } bool getUseFirstOrder() { return m_UseFirstOrder; } bool getUseVolumetric() { return m_UseVolumetric; } bool getUseTexture() { return m_UseTexture; } bool getUseNorm() { return m_UseNorm; } bool getUseGeomCorrection() { return m_UseGeomCorrection; } bool getUseResampling() { return m_UseResampling; } itkGetConstMacro(Direction, unsigned int); itkSetMacro(Direction, unsigned int); itkGetConstMacro(WaveletLevels, unsigned int); itkSetMacro(WaveletLevels, unsigned int); itkGetConstMacro(ResX, float); itkSetMacro(ResX, float); itkGetConstMacro(ResY, float); itkSetMacro(ResY, float); itkGetConstMacro(ResZ, float); itkSetMacro(ResZ, float); + itkGetConstMacro(UseStationary, bool); + itkSetMacro(UseStationary, bool); + private: mitk::DataNode::Pointer m_ImageNode; mitk::DataNode::Pointer m_SegmentationNode; mitk::DataNode::Pointer m_RegistrationImageNode; bool m_ImageNormalization = false; bool m_Use3d = false; bool m_UseFirstOrder = true; bool m_UseVolumetric = true; bool m_UseTexture = true; bool m_UseNorm = true; bool m_UseGeomCorrection = true; bool m_UseResampling = true; bool m_UseCoiflet = true; bool m_UseDaubechies = true; std::string m_OutputFile; std::string m_Name; std::string m_CoocString; std::string m_RunLengthString; formatType m_FormatType; unsigned int m_Direction; unsigned int m_WaveletLevels; float m_ResX; float m_ResY; float m_ResZ; + + bool m_UseStationary; }; } #endif diff --git a/Modules/Radiomics/RadiomicsCore/include/mitkRadiomicsFeatures.h b/Modules/Radiomics/RadiomicsCore/include/mitkRadiomicsFeatures.h index f1b3081622..513719a1a2 100644 --- a/Modules/Radiomics/RadiomicsCore/include/mitkRadiomicsFeatures.h +++ b/Modules/Radiomics/RadiomicsCore/include/mitkRadiomicsFeatures.h @@ -1,50 +1,49 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkRadiomicsFeatures_h #define mitkRadiomicsFeatures_h #include #include #include #include #include #include namespace mitk { -class MITKRADIOMICSCORE_EXPORT RadiomicsFeatures : public BaseData +class MITKRADIOMICSCORE_EXPORT RadiomicsFeatures { - mitkClassMacro(RadiomicsFeatures,BaseData) public: static mitk::AbstractGlobalImageFeature::FeatureListType calculateFeatures(mitk::Image::Pointer inputImage, mitk::Image::Pointer segmentation, std::string coocString, std::string runlengthString, unsigned int direction, bool firstOrder, bool volumetric, bool texture); static void writeToCsvFile(mitk::AbstractGlobalImageFeature::FeatureListType stats, std::string fileName, std::string selectionName, std::string imageName, std::string maskName); }; } #endif diff --git a/Modules/Radiomics/RadiomicsCore/include/mitkRadiomicsResampling.h b/Modules/Radiomics/RadiomicsCore/include/mitkRadiomicsResampling.h index f6b62a467b..1e9af0c808 100644 --- a/Modules/Radiomics/RadiomicsCore/include/mitkRadiomicsResampling.h +++ b/Modules/Radiomics/RadiomicsCore/include/mitkRadiomicsResampling.h @@ -1,58 +1,71 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef mitkRadiomicsResampling_h #define mitkRadiomicsResampling_h #include #include #include #include #include +#include namespace mitk { class MITKRADIOMICSCORE_EXPORT RadiomicsResampling : public itk::Object { public: mitkClassMacroItkParent(RadiomicsResampling, itk::Object); itkFactorylessNewMacro(RadiomicsResampling) itkCloneMacro(Self) template mitk::Image::Pointer resampleImage(mitk::Image::Pointer inputImage, float x = 0.25, float y = 0.25, float z = 3.00) ; template mitk::Image::Pointer resampleMask( mitk::Image::Pointer inputMask, float x = 0.25, float y = 0.25, float z = 3.00); + static mitk::Image::Pointer resampleImageFloat(mitk::Image::Pointer inputImage, + float x = 0.25, + float y = 0.25, + float z = 3.00); + + static mitk::Image::Pointer resampleMaskUnsignedShort(mitk::Image::Pointer inputMask, + float x = 0.25, + float y = 0.25, + float z = 3.00); + + static mitk::Image::Pointer binarizeMaskUnsignedShort(mitk::Image::Pointer im); + template mitk::Image::Pointer returnSample(mitk::Image::Pointer im, float x, float y, float z); template mitk::Image::Pointer binarizeMask(mitk::Image::Pointer im); }; } #include #endif diff --git a/Modules/Radiomics/RadiomicsCore/include/mitkRadiomicsResampling.hxx b/Modules/Radiomics/RadiomicsCore/include/mitkRadiomicsResampling.hxx index 30dc46660e..7d56ae1e74 100644 --- a/Modules/Radiomics/RadiomicsCore/include/mitkRadiomicsResampling.hxx +++ b/Modules/Radiomics/RadiomicsCore/include/mitkRadiomicsResampling.hxx @@ -1,150 +1,257 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include //ITK includes #include #include #include #include #include #include #include #include #include template mitk::Image::Pointer mitk::RadiomicsResampling::returnSample(mitk::Image::Pointer image, float x, float y, float z) { return image; } template mitk::Image::Pointer mitk::RadiomicsResampling::resampleImage(mitk::Image::Pointer inputImage, float x, float y, float z) { const int ImageDimension = 3; typedef itk::Image ImageType; typename ImageType::Pointer itkImage = NULL; typename ImageType::Pointer resampledImage = NULL; mitk::Image::Pointer resultImage; mitk::CastToItkImage(inputImage, itkImage); double factor = itkImage->GetSpacing()[0] / x; // Resize typename ImageType::SizeType outputSize; outputSize[0] = itkImage->GetLargestPossibleRegion().GetSize()[0]*itkImage->GetSpacing()[0] / x; outputSize[1] = itkImage->GetLargestPossibleRegion().GetSize()[1]*itkImage->GetSpacing()[1] / y; outputSize[2] = itkImage->GetLargestPossibleRegion().GetSize()[2] * itkImage->GetSpacing()[2] / z; typename ImageType::SpacingType outputSpacing; outputSpacing[0] = x; outputSpacing[1] = y; outputSpacing[2] = z; typedef itk::IdentityTransform TransformType; typedef itk::BSplineInterpolateImageFunction InterpolatorType; typedef itk::ResampleImageFilter ResampleImageFilterType; typename InterpolatorType::Pointer interpolator = InterpolatorType::New(); interpolator->SetSplineOrder(3); MITK_WARN << "Spacing information " << outputSpacing; MITK_WARN << "Outsize information " << outputSize; typename ResampleImageFilterType::Pointer filter = ResampleImageFilterType::New(); filter->SetInput(itkImage); filter->SetSize(outputSize); filter->SetOutputSpacing(outputSpacing); filter->SetOutputOrigin(itkImage->GetOrigin()); filter->SetOutputDirection(itkImage->GetDirection()); //filter->SetTransform(TransformType::New()); filter->SetInterpolator(interpolator); filter->Update(); filter->UpdateLargestPossibleRegion(); itkImage = filter->GetOutput(); try { mitk::CastToMitkImage(itkImage, resultImage); } catch (itk::ExceptionObject & error) { return nullptr; } MITK_WARN << "returning image to pipeline."; return resultImage; } +mitk::Image::Pointer mitk::RadiomicsResampling::resampleImageFloat(mitk::Image::Pointer inputImage, + float x, + float y, + float z) +{ + const int ImageDimension = 3; + typedef itk::Image ImageType; + + ImageType::Pointer itkImage = NULL; + ImageType::Pointer resampledImage = NULL; + + mitk::Image::Pointer resultImage; + + mitk::CastToItkImage(inputImage, itkImage); + + double factor = itkImage->GetSpacing()[0] / x; + + // Resize + + ImageType::SizeType outputSize; + outputSize[0] = itkImage->GetLargestPossibleRegion().GetSize()[0] * itkImage->GetSpacing()[0] / x; + outputSize[1] = itkImage->GetLargestPossibleRegion().GetSize()[1] * itkImage->GetSpacing()[1] / y; + outputSize[2] = itkImage->GetLargestPossibleRegion().GetSize()[2] * itkImage->GetSpacing()[2] / z; + + ImageType::SpacingType outputSpacing; + outputSpacing[0] = x; + outputSpacing[1] = y; + outputSpacing[2] = z; + + typedef itk::IdentityTransform TransformType; + typedef itk::BSplineInterpolateImageFunction InterpolatorType; + typedef itk::ResampleImageFilter ResampleImageFilterType; + + InterpolatorType::Pointer interpolator = InterpolatorType::New(); + interpolator->SetSplineOrder(3); + + MITK_WARN << "Spacing information " << outputSpacing; + MITK_WARN << "Outsize information " << outputSize; + + ResampleImageFilterType::Pointer filter = ResampleImageFilterType::New(); + filter->SetInput(itkImage); + filter->SetSize(outputSize); + filter->SetOutputSpacing(outputSpacing); + filter->SetOutputOrigin(itkImage->GetOrigin()); + filter->SetOutputDirection(itkImage->GetDirection()); + //filter->SetTransform(TransformType::New()); + filter->SetInterpolator(interpolator); + + filter->Update(); + filter->UpdateLargestPossibleRegion(); + + itkImage = filter->GetOutput(); + + try + { + mitk::CastToMitkImage(itkImage, resultImage); + } + catch (itk::ExceptionObject & error) + { + return nullptr; + } + MITK_WARN << "returning image to pipeline."; + return resultImage; +} + template mitk::Image::Pointer mitk::RadiomicsResampling::resampleMask(mitk::Image::Pointer inputImage, float x, float y, float z) { return binarizeMask(resampleImage(inputImage, x, y, z)); } +mitk::Image::Pointer mitk::RadiomicsResampling::resampleMaskUnsignedShort(mitk::Image::Pointer inputImage, + float x, + float y, + float z) +{ + return binarizeMaskUnsignedShort(resampleImageFloat(inputImage, x, y, z)); +} + template mitk::Image::Pointer mitk::RadiomicsResampling::binarizeMask(mitk::Image::Pointer im) { const int ImageDimension = 3; typedef itk::Image ImageType; typedef itk::Image FloatingSegmentationType; typename FloatingSegmentationType::Pointer itkImage = NULL; mitk::Image::Pointer resultImage; mitk::CastToItkImage(im, itkImage); typedef itk::BinaryThresholdImageFilter < FloatingSegmentationType, ImageType> ThresholderType; typename ThresholderType::Pointer threshold = ThresholderType::New(); threshold->SetInput(itkImage); threshold->SetLowerThreshold(0.1); threshold->SetUpperThreshold(10000); threshold->SetInsideValue(1); threshold->SetOutsideValue(0); threshold->Update(); try { typename ImageType::Pointer binImage = threshold->GetOutput(); mitk::CastToMitkImage(binImage, resultImage); return resultImage; } catch (itk::ExceptionObject & error) { std::cerr << error.what(); mitk::CastToMitkImage(itkImage, resultImage); } return im; } + +mitk::Image::Pointer mitk::RadiomicsResampling::binarizeMaskUnsignedShort(mitk::Image::Pointer im) +{ + const int ImageDimension = 3; + typedef itk::Image ImageType; + typedef itk::Image FloatingSegmentationType; + + FloatingSegmentationType::Pointer itkImage = NULL; + mitk::Image::Pointer resultImage; + mitk::CastToItkImage(im, itkImage); + + typedef itk::BinaryThresholdImageFilter < FloatingSegmentationType, ImageType> ThresholderType; + ThresholderType::Pointer threshold = ThresholderType::New(); + + threshold->SetInput(itkImage); + threshold->SetLowerThreshold(0.1); + threshold->SetUpperThreshold(10000); + threshold->SetInsideValue(1); + threshold->SetOutsideValue(0); + threshold->Update(); + + try + { + ImageType::Pointer binImage = threshold->GetOutput(); + mitk::CastToMitkImage(binImage, resultImage); + return resultImage; + } + catch (itk::ExceptionObject & error) + { + std::cerr << error.what(); + mitk::CastToMitkImage(itkImage, resultImage); + } + return im; +} diff --git a/Modules/Radiomics/RadiomicsCore/src/mitkRadiomicsSegmentationTools.cpp b/Modules/Radiomics/RadiomicsCore/src/mitkRadiomicsSegmentationTools.cpp index 9693fa1e86..4311f2da97 100644 --- a/Modules/Radiomics/RadiomicsCore/src/mitkRadiomicsSegmentationTools.cpp +++ b/Modules/Radiomics/RadiomicsCore/src/mitkRadiomicsSegmentationTools.cpp @@ -1,308 +1,308 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include //ITK includes #include #include #include #include #include #include #include "mitkPixelTypeMultiplex.h" #include bool mitk::SegmentationTools::isCorrectionNeeded(mitk::Image::Pointer inputImage, mitk::Image::Pointer maskImage) { /// /// Check if we need to transform the mask /// auto imageGeom = inputImage->GetGeometry(); auto maskGeom = maskImage->GetGeometry(); if(inputImage->GetDimensions()[0] == maskImage->GetDimensions()[0] && inputImage->GetDimensions()[1] == maskImage->GetDimensions()[1] && inputImage->GetDimensions()[2] == maskImage->GetDimensions()[2] && imageGeom->GetSpacing() == maskGeom->GetSpacing() && imageGeom->GetOrigin() == imageGeom->GetOrigin() && imageGeom->GetIndexToWorldTransform()->GetTranslation() == maskGeom->GetIndexToWorldTransform()->GetTranslation() && imageGeom->GetIndexToWorldTransform()->GetOffset() == maskGeom->GetIndexToWorldTransform()->GetOffset() && imageGeom->GetIndexToWorldTransform()->GetMatrix() == maskGeom->GetIndexToWorldTransform()->GetMatrix()) { return false; } return true; } mitk::Image::Pointer mitk::SegmentationTools::makeRoiFitToImage(mitk::Image::Pointer inputImage, mitk::Image::Pointer maskImage) { /// /// Load segmentation and transform it to a surface /// We don't check if we really need a transformation here, /// this can be done by calling isCorrectionNeeded(*,*) /// bool smooth = false; double gaussianSD = 1.5; bool applyMedian = false; double medianKernelSize = 3; bool decimateMesh = false; double reductionRate = 0.5; mitk::ManualSegmentationToSurfaceFilter::Pointer surfaceFilter = mitk::ManualSegmentationToSurfaceFilter::New(); surfaceFilter->SetInput(maskImage); surfaceFilter->SetThreshold(0.5); //expects binary image with zeros and ones surfaceFilter->SetUseGaussianImageSmooth(smooth); // apply gaussian to thresholded image ? surfaceFilter->SetSmooth(smooth); if (smooth) { surfaceFilter->InterpolationOn(); surfaceFilter->SetGaussianStandardDeviation(gaussianSD); } surfaceFilter->SetMedianFilter3D(applyMedian); // apply median to segmentation before marching cubes ? if (applyMedian) { surfaceFilter->SetMedianKernelSize(medianKernelSize, medianKernelSize, medianKernelSize); // apply median to segmentation before marching cubes } //fix to avoid vtk warnings see bug #5390 if (maskImage->GetDimension() > 3) decimateMesh = false; if (decimateMesh) { surfaceFilter->SetDecimate(mitk::ImageToSurfaceFilter::QuadricDecimation); surfaceFilter->SetTargetReduction(reductionRate); } else { surfaceFilter->SetDecimate(mitk::ImageToSurfaceFilter::NoDecimation); } surfaceFilter->UpdateLargestPossibleRegion(); // calculate normals for nicer display mitk::Surface::Pointer mySurface = surfaceFilter->GetOutput(); mitk::Image::Pointer resultImage(nullptr); /// /// Transform surface back to image /// mitk::SurfaceToImageFilter::Pointer surfaceToImageFilter = mitk::SurfaceToImageFilter::New(); surfaceToImageFilter->MakeOutputBinaryOn(); surfaceToImageFilter->SetInput(mySurface); surfaceToImageFilter->SetImage(inputImage); MITK_WARN << "Size of inputImage: " << inputImage->GetDimensions(); try { surfaceToImageFilter->Update(); } catch (itk::ExceptionObject& excpt) { MITK_ERROR << excpt.GetDescription(); return maskImage; } resultImage = surfaceToImageFilter->GetOutput(); MITK_WARN << "Size of resultImage: " << resultImage->GetDimensions(); if (resultImage.IsNull()) { MITK_ERROR << "Convert Surface to binary image failed"; return maskImage; } return resultImage; } /// /// \brief mitk::SegmentationTools::shrinkImageToLevel /// \param inputImage - the image that should be shrinked in X and Y direction (Z direction will be kept) /// \param level - unsigned int level of shrinkage (usually 2,4,8,16,...) /// \return the shrinked image mitk::Image::Pointer mitk::SegmentationTools::shrinkImageToLevel(Image::Pointer inputImage, unsigned int level) { if (level > 1) { mitk::Image::Pointer ritw = mitk::Image::New(); ritw = mitk::GeometryTools::ResetIndexToWorld(inputImage); const unsigned int Dimension = 3; typedef unsigned short PixelType; typedef itk::Image< PixelType, Dimension > MaskImageType; typedef itk::Image< PixelType, Dimension > ImageType; MaskImageType::Pointer itkMaskImage = NULL; mitk::Image::Pointer resultImage; mitk::CastToItkImage(ritw, itkMaskImage); // Resize MITK_WARN << "current Size " << itkMaskImage->GetLargestPossibleRegion().GetSize()[0] << " " << itkMaskImage->GetLargestPossibleRegion().GetSize()[1] << " " << itkMaskImage->GetLargestPossibleRegion().GetSize()[2]; MITK_WARN << "Shrink Factor " << level; ImageType::SizeType outputSize; outputSize[0] = itkMaskImage->GetLargestPossibleRegion().GetSize()[0] / level; outputSize[1] = itkMaskImage->GetLargestPossibleRegion().GetSize()[1] / level; outputSize[2] = itkMaskImage->GetLargestPossibleRegion().GetSize()[2]; ImageType::SpacingType outputSpacing; outputSpacing[0] = itkMaskImage->GetSpacing()[0] * level; outputSpacing[1] = itkMaskImage->GetSpacing()[1] * level; outputSpacing[2] = itkMaskImage->GetSpacing()[2]; typedef itk::ScalableAffineTransform TransformType; typedef itk::ResampleImageFilter ResampleImageFilterType; ResampleImageFilterType::Pointer filter = ResampleImageFilterType::New(); filter->SetInput(itkMaskImage); filter->SetSize(outputSize); filter->SetOutputSpacing(outputSpacing); filter->SetTransform(TransformType::New()); filter->Update(); filter->UpdateLargestPossibleRegion(); typedef itk::ChangeInformationImageFilter< ImageType > FilterType; FilterType::Pointer changeSpacing = FilterType::New(); changeSpacing->SetInput(filter->GetOutput()); ImageType::SpacingType spacing; spacing[0] = itkMaskImage->GetSpacing()[0]; spacing[1] = itkMaskImage->GetSpacing()[1]; spacing[2] = itkMaskImage->GetSpacing()[2]; changeSpacing->SetOutputSpacing(spacing); changeSpacing->ChangeSpacingOn(); try { changeSpacing->UpdateOutputInformation(); } catch (itk::ExceptionObject & error) { std::cerr << "Error: " << error << std::endl; return ritw; } try { mitk::CastToMitkImage(filter->GetOutput(), resultImage); } catch (itk::ExceptionObject & error) { MITK_WARN << "There was an error while casting to MITK Image."; return ritw; } auto newGeom = resultImage->GetGeometry(); auto newI2W = newGeom->GetIndexToWorldTransform(); auto newI2WMatrix = newI2W->GetMatrix(); newI2WMatrix[0][0] =1; newI2WMatrix[1][1] =1; newI2WMatrix[2][2] =1; newI2W->SetMatrix(newI2WMatrix); newGeom->SetIndexToWorldTransform(newI2W); resultImage->SetGeometry(newGeom); return resultImage; } } mitk::Image::Pointer mitk::SegmentationTools::removeNaNsFromSegmentation(Image::Pointer inputImage, Image::Pointer maskImage) { const unsigned int Dimension = 3; typedef unsigned short PixelType; typedef itk::Image< PixelType, Dimension > ImageType; - typename ImageType::Pointer itkMask = ImageType::New(); + ImageType::Pointer itkMask = ImageType::New(); mitk::CastToItkImage(maskImage, itkMask); ImageType::Pointer resultImage; mitk::CastToItkImage(maskImage, resultImage); int xx = itkMask->GetLargestPossibleRegion().GetSize()[0]; int yy = itkMask->GetLargestPossibleRegion().GetSize()[1]; int zz = itkMask->GetLargestPossibleRegion().GetSize()[2]; //MITK_WARN << xx << " " << yy << " " << zz; for (int x = 0; x < xx; x++) { for (int y = 0; y < yy; y++) { for (int z = 0; z < zz; z++) { //MITK_WARN << "Checking Pos " << x << " " << y << " " << z; ImageType::IndexType index; index[0] = x; index[1] = y; index[2] = z; mitk::ScalarType pxImage; mitkPixelTypeMultiplex5( mitk::FastSinglePixelAccess, inputImage->GetChannelDescriptor().GetPixelType(), inputImage, inputImage->GetVolumeData(), index, pxImage, 0); unsigned short pxMask = itkMask->GetPixel(index); //MITK_WARN << " -> Image/Segmentation Value: " << pxImage << "/" << pxMask; //Check for NaNs if (pxImage != pxImage) //if pxImage is NaN, then f!=f! { resultImage->SetPixel(index, 0); } else { resultImage->SetPixel(index, pxMask); } } } } mitk::Image::Pointer resultImageMitk; mitk::CastToMitkImage(resultImage,resultImageMitk); return resultImageMitk; } diff --git a/Modules/Radiomics/RadiomicsMiniApps/CMakeLists.txt b/Modules/Radiomics/RadiomicsMiniApps/CMakeLists.txt index 6ced3c4c49..8dd6e360ac 100644 --- a/Modules/Radiomics/RadiomicsMiniApps/CMakeLists.txt +++ b/Modules/Radiomics/RadiomicsMiniApps/CMakeLists.txt @@ -1,114 +1,115 @@ option(BUILD_RadiomicsMiniApps "Build commandline tools for radiomics" OFF) if(BUILD_RadiomicsMiniApps OR MITK_BUILD_ALL_APPS) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of miniapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( radiomicsminiapps RadiomicFeatures^^MitkImageStatistics_MitkCLUtilities_MitkRigidRegistration_MitkRemeshing_MitkCLCore_MitkSegmentation_MitkDiffusionCore RadiomicsMakeROIFitToImage^^MitkSegmentation RadiomicsShrinkMask^^MitkSegmentation RadiomicsCropImagesWithMargin^^MitkSegmentation RadiomicsResample^^ RadiomicsImageCorrection^^MitkSegmentation_MitkDiffusionCore ConvertToType^^ RadiomicsCombineTwoMasks^^ + RadiomicsSumMasks^^MitkSegmentation #RadiomicsExtractSegmentationAndDilate^^ RadiomicsMRFRefineSegmentation^^ RadiomicsGeometryCorrection^^ AdjustGeometry^^ CompareGeometries^^ RadiomicsRegistration^^MitkSegmentation_MitkDiffusionCore RadiomicsDeformableRegistration^^ RadiomicsRemesh^^MitkRemeshing RadiomicsConvertMaskToNii^^ RadiomicsGetDice^^ RadiomicsStlToSeg^^ RadiomicsConvertDicomDir^^ RadiomicsPipeline^^MitkRadiomicsCore_MitkRadiomicsWavelets #RadiomicsRenderImageToPng^^MitkTestingHelper # RandomForestPrediction^^MitkCLVigraRandomForest ) mitk_create_executable(RadiomicsRenderImageToPng DEPENDS MitkTestingHelper MitkCore MitkCLCore CPP_FILES RadiomicsRenderImageToPng.cpp mitkCommandLineParser.cpp mitkRenderWindowToImageFilter.cpp ) foreach(radiomicsminiapps ${radiomicsminiapps}) # extract mini app name and dependencies string(REPLACE "^^" "\\;" miniapp_info ${radiomicsminiapps}) set(miniapp_info_list ${miniapp_info}) list(GET miniapp_info_list 0 appname) list(GET miniapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitk_create_executable(${appname} DEPENDS MitkCore MitkCLCore ${dependencies_list} PACKAGE_DEPENDS ITK Qt5|Core PUBLIC Boost CPP_FILES ${appname}.cpp mitkCommandLineParser.cpp ) if(EXECUTABLE_IS_ENABLED) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() get_target_property(_is_bundle ${EXECUTABLE_TARGET} MACOSX_BUNDLE) if(APPLE) if(_is_bundle) set(_target_locations ${EXECUTABLE_TARGET}.app) set(${_target_locations}_qt_plugins_install_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_bundle_dest_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_plugins_for_current_bundle ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_conf_install_dirs ${EXECUTABLE_TARGET}.app/Contents/Resources) install(TARGETS ${EXECUTABLE_TARGET} BUNDLE DESTINATION . ) else() if(NOT MACOSX_BUNDLE_NAMES) set(_qt_conf_install_dirs bin) set(_target_locations bin/${EXECUTABLE_TARGET}) set(${_target_locations}_qt_plugins_install_dir bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) set(_current_target_location ${bundle_name}.app/Contents/MacOS/${EXECUTABLE_TARGET}) list(APPEND _target_locations ${_current_target_location}) set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) endforeach() endif() endif() else() set(_target_locations bin/${EXECUTABLE_TARGET}${CMAKE_EXECUTABLE_SUFFIX}) set(${_target_locations}_qt_plugins_install_dir bin) set(_qt_conf_install_dirs bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) endif() endif() endforeach() # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() if(EXECUTABLE_IS_ENABLED) MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) endif() endif() diff --git a/Modules/Radiomics/RadiomicsMiniApps/RadiomicsPipeline.cpp b/Modules/Radiomics/RadiomicsMiniApps/RadiomicsPipeline.cpp index 892f22eb86..9e89dc7e4b 100644 --- a/Modules/Radiomics/RadiomicsMiniApps/RadiomicsPipeline.cpp +++ b/Modules/Radiomics/RadiomicsMiniApps/RadiomicsPipeline.cpp @@ -1,517 +1,542 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkCommandLineParser.h" #include "mitkImage.h" #include "mitkIOUtil.h" #include #include #include #include "mitkIOUtil.h" #include #include //MITK #include #include #include #include #include #include //Used to check if file exists before trying to open it. //However, this might get a wrong result if the file exists but the user is not allowed to open it. bool fileExists(const std::string& filename) { ifstream infile(filename.c_str()); return infile.good(); } void radiomicsPipeline(std::string inputPath, std::string maskPath, std::string outputPath, bool useNorm, bool useGeom, bool useRes, float resX, float resY, float resZ , bool useDaub, bool useCoif, int wLevels, + bool useStationary, bool firstOF, bool volumeF, bool textureF, bool calc2D, std::string coocString, std::string textureBins ) { if(!fileExists(inputPath) || !fileExists(maskPath)) { MITK_ERROR << "Not allimages available!"; return; } mitk::Image::Pointer image = mitk::IOUtil::LoadImage(inputPath); mitk::Image::Pointer segmentation = mitk::IOUtil::LoadImage(maskPath); std::string imageName = itksys::SystemTools::GetFilenameName(inputPath); std::string maskName = itksys::SystemTools::GetFilenameName(maskPath); std::string folderName = itksys::SystemTools::GetFilenamePath(inputPath); /// /// Image Correction /// if(useNorm) { MITK_WARN << "Perform Image Correction..."; image = mitk::RadiomicsNormalization::normalizeImage(image); } /// /// Resampling /// if(useRes) { MITK_WARN << "Perform Resampling..."; mitk::RadiomicsResampling::Pointer myRes = mitk::RadiomicsResampling::New(); - image = myRes->resampleImage(image, + image = mitk::RadiomicsResampling::resampleImageFloat(image, resX, resY, calc2D ? (float)image->GetGeometry()->GetSpacing()[2]: (float)resZ); //resample segmentation image - segmentation = myRes->resampleMask(segmentation, + segmentation = mitk::RadiomicsResampling::resampleMaskUnsignedShort(segmentation, resX, resY, calc2D ? (float)image->GetGeometry()->GetSpacing()[2]: (float)resZ); } /// /// Make the segmentation fit to the image (w.r.t geometry etc.) /// if(mitk::SegmentationTools::isCorrectionNeeded(image,segmentation)) { MITK_WARN << "Making ROI fit to image"; segmentation = mitk::SegmentationTools::makeRoiFitToImage(image,segmentation); } /// /// Geometry correction /// if(useGeom) { MITK_WARN << "checking Geometry!"; //adjust image MITK_WARN << "Initial New image dimensions: " << image->GetDimensions()[0]; image = mitk::GeometryTools::ResetIndexToWorld(image); //adjust segmentation segmentation = mitk::GeometryTools::ResetIndexToWorld(segmentation); } /// /// Remove NaNs from Segmentation image to prevent miscalculated features. /// /// bool removeNaNs = false; if(removeNaNs) { segmentation = mitk::SegmentationTools::removeNaNsFromSegmentation(image,segmentation->Clone()); } /// /// Calculate the features /// + if(firstOF == false && volumeF == false && textureF == false) + { + // + } + else { MITK_WARN << "Calculating features."; mitk::AbstractGlobalImageFeature::FeatureListType stats = mitk::RadiomicsFeatures::calculateFeatures(image, segmentation, coocString, textureBins, (calc2D ? 4 : 0), firstOF, volumeF, textureF); mitk::RadiomicsFeatures::writeToCsvFile(stats,outputPath,folderName, imageName, maskName); } /// /// Calculate Coiflet Wavelets /// if(useCoif) { mitk::RadiomicsWavelets::Pointer wavelets = mitk::RadiomicsWavelets::New(); wavelets->setup(); - std::vector wavs = wavelets->createCoifletWavelets(image, wLevels,true); + std::vector wavs = wavelets->createCoifletWavelets(image, wLevels,useStationary); std::vector finalSegs; //Contains the fitted and shrinked segs std::vector finalWavs; //Contains the wavelets in the same order as the finalSegs - mitk::Image::Pointer sitkSegmentation = wavelets->getSitkSegmentation(segmentation); - if(wavs.size() == 0) { MITK_ERROR << "Wavelet calculation failed. Aborting."; return; } else { for(int i = wLevels; i > 0; i--) { mitk::DataNode::Pointer tmpWavNode = mitk::DataNode::New(); mitk::Image::Pointer empty = mitk::Image::New(); empty->Initialize(image); tmpWavNode->SetData(empty); tmpWavNode->SetVisibility(false); tmpWavNode->SetName("Coiflet Level " + std::to_string(wLevels - i + 1 )); for(int j = 0; j < 4; j++) { int index = (i-1) * 4 + j; //Let's fit the segmentation to the wavelet image - mitk::Image::Pointer finalSeg = mitk::SegmentationTools::makeRoiFitToImage(wavs[index],segmentation); + mitk::Image::Pointer finalSeg = mitk::SegmentationTools::makeRoiFitToImage(wavs[index],segmentation->Clone()); finalSegs.push_back(finalSeg); finalWavs.push_back(wavs[index]); std::string waveletType = "Lowpass"; if(j == 3) waveletType = "H"; else if(j == 2) waveletType = "V"; else if(j == 1) waveletType = "D"; mitk::DataNode::Pointer tmpImageNode = mitk::DataNode::New(); tmpImageNode->SetData(wavs[index]); tmpImageNode->SetName("Image " + waveletType); tmpImageNode->SetVisibility(false); mitk::DataNode::Pointer tmpSegNode = mitk::DataNode::New(); tmpSegNode->SetData(finalSeg); //tmpSegNode->SetData(segs[index]); tmpSegNode->SetName("Segmentation " + waveletType); tmpSegNode->SetVisibility(false); } } } /// /// Calculate the Coiflet features /// - if(finalWavs.size() != 4*wLevels || - finalSegs.size() != 4*wLevels) + if(firstOF == false && volumeF == false && textureF == false) { - MITK_ERROR << "Size of list of segmentations or of the wavelet-files are not as expected. Aborting."; - return; + // } - - for(int i = wLevels; i > 0; i--) + else { - for(int j = 0; j < 4; j++) + if(finalWavs.size() != 4*wLevels || + finalSegs.size() != 4*wLevels) { - int index = (i-1) * 4 + j; - - std::string waveletType = "Lowpass"; - if(j == 3) - waveletType = "H"; - else if(j == 2) - waveletType = "V"; - else if(j == 1) - waveletType = "D"; - - - MITK_WARN << "Calculating Coiflet features (Level " << i << "/" << waveletType << ")."; - - MITK_WARN << "Calulating features for Coiflet " << i << "/" < 0; i--) + { + for(int j = 0; j < 4; j++) + { + int index = (i-1) * 4 + j; + + std::string waveletType = "Lowpass"; + if(j == 3) + waveletType = "H"; + else if(j == 2) + waveletType = "V"; + else if(j == 1) + waveletType = "D"; + + + MITK_WARN << "Calculating Coiflet features (Level " << i << "/" << waveletType << ")."; + + MITK_WARN << "Calulating features for Coiflet " << i << "/" <setup(); - std::vector wavs = wavelets->createCoifletWavelets(image, wLevels,true); + std::vector wavs = wavelets->createDaubechiesWavelets(image, wLevels,useStationary); std::vector finalSegs; //Contains the fitted and shrinked segs std::vector finalWavs; //Contains the wavelets in the same order as the finalSegs - mitk::Image::Pointer sitkSegmentation = wavelets->getSitkSegmentation(segmentation); - if(wavs.size() == 0) { MITK_ERROR << "Wavelet calculation failed. Aborting."; return; } else { for(int i = wLevels; i > 0; i--) { mitk::DataNode::Pointer tmpWavNode = mitk::DataNode::New(); mitk::Image::Pointer empty = mitk::Image::New(); empty->Initialize(image); tmpWavNode->SetData(empty); tmpWavNode->SetVisibility(false); tmpWavNode->SetName("Daubechies Level " + std::to_string(wLevels - i + 1 )); for(int j = 0; j < 4; j++) { int index = (i-1) * 4 + j; //Let's fit the segmentation to the wavelet image - mitk::Image::Pointer finalSeg = mitk::SegmentationTools::makeRoiFitToImage(wavs[index],segmentation); + mitk::Image::Pointer finalSeg = mitk::SegmentationTools::makeRoiFitToImage(wavs[index],segmentation->Clone()); finalSegs.push_back(finalSeg); finalWavs.push_back(wavs[index]); std::string waveletType = "Lowpass"; if(j == 3) waveletType = "H"; else if(j == 2) waveletType = "V"; else if(j == 1) waveletType = "D"; mitk::DataNode::Pointer tmpImageNode = mitk::DataNode::New(); tmpImageNode->SetData(wavs[index]); tmpImageNode->SetName("Image " + waveletType); tmpImageNode->SetVisibility(false); mitk::DataNode::Pointer tmpSegNode = mitk::DataNode::New(); tmpSegNode->SetData(finalSeg); //tmpSegNode->SetData(segs[index]); tmpSegNode->SetName("Segmentation " + waveletType); tmpSegNode->SetVisibility(false); } } } /// - /// Calculate the Coiflet features + /// Calculate the Daubechies features /// - if(finalWavs.size() != 4*wLevels || - finalSegs.size() != 4*wLevels) + if(firstOF == false && volumeF == false && textureF == false) { - MITK_ERROR << "Size of list of segmentations or of the wavelet-files are not as expected. Aborting."; - return; + // } - - for(int i = wLevels; i > 0; i--) + else { - for(int j = 0; j < 4; j++) + + if(finalWavs.size() != 4*wLevels || + finalSegs.size() != 4*wLevels) { - int index = (i-1) * 4 + j; - - std::string waveletType = "Lowpass"; - if(j == 3) - waveletType = "H"; - else if(j == 2) - waveletType = "V"; - else if(j == 1) - waveletType = "D"; - - - MITK_WARN << "Calculating Daubechies features (Level " << i << "/" << waveletType << ")."; - - MITK_WARN << "Calulating features for Daubechies " << i<< "/" < 0; i--) + { + for(int j = 0; j < 4; j++) + { + int index = (i-1) * 4 + j; + + std::string waveletType = "Lowpass"; + if(j == 3) + waveletType = "H"; + else if(j == 2) + waveletType = "V"; + else if(j == 1) + waveletType = "D"; + + + MITK_WARN << "Calculating Daubechies features (Level " << i << "/" << waveletType << ")."; + + MITK_WARN << "Calulating features for Daubechies " << i<< "/" < parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0 || parsedArgs.count("help") || parsedArgs.count("h")) { std::cout << "===" << parser.getTitle() << "===" << endl; std::cout << parser.versionText() << endl; std::cout << "MiniApp Description: \nPerforms a radiomics pipeline on the given input image and mask" << endl; std::cout << "\n\nParameters:" << endl; std::cout << parser.helpText(); return EXIT_SUCCESS; } std::string inputPath = us::any_cast(parsedArgs["input"]); std::string maskPath = us::any_cast(parsedArgs["mask"]); std::string outputPath = us::any_cast(parsedArgs["output"]); bool useNorm = false; bool useGeom = false; bool useRes = false; float resX = 0.25; float resY = 0.25; float resZ = 3.00; bool useDaub = false; bool useCoif = false; int wLevels = 2; + bool useStationary = false; + bool firstOF = true; bool volumeF = true; bool textureF= true; - bool calc2D = true; + bool calc2D = false; std::string coocString = "1;2;3"; std::string textureBins= "64;128;256"; //Parse the arguments if (parsedArgs.count("norm") || parsedArgs.count("n")) { useNorm = us::any_cast(parsedArgs["norm"]); } if (parsedArgs.count("adjustgeometry") || parsedArgs.count("g")) { useGeom = us::any_cast(parsedArgs["adjustgeometry"]); } if (parsedArgs.count("resample") || parsedArgs.count("r")) { useRes = us::any_cast(parsedArgs["resample"]); } if (parsedArgs.count("resX") || parsedArgs.count("x")) { resX = us::any_cast(parsedArgs["resX"]); } if (parsedArgs.count("resY") || parsedArgs.count("y")) { resY = us::any_cast(parsedArgs["resY"]); } if (parsedArgs.count("resZ") || parsedArgs.count("z")) { resZ = us::any_cast(parsedArgs["resZ"]); } if (parsedArgs.count("daubechies") || parsedArgs.count("d")) { useDaub = us::any_cast(parsedArgs["daubechies"]); } if (parsedArgs.count("coiflet") || parsedArgs.count("c")) { useCoif = us::any_cast(parsedArgs["coiflet"]); } if (parsedArgs.count("waveletlevel") || parsedArgs.count("w")) { wLevels = us::any_cast(parsedArgs["waveletlevel"]); } + if (parsedArgs.count("stationary") || parsedArgs.count("sw")) + { + useStationary = us::any_cast(parsedArgs["stationary"]); + } if (parsedArgs.count("firstorder") || parsedArgs.count("f")) { firstOF = us::any_cast(parsedArgs["firstorder"]); } if (parsedArgs.count("volumetric") || parsedArgs.count("v")) { volumeF = us::any_cast(parsedArgs["volumetric"]); } if (parsedArgs.count("texture") || parsedArgs.count("t")) { textureF = us::any_cast(parsedArgs["texture"]); } if (parsedArgs.count("calculate2D") || parsedArgs.count("xy")) { calc2D = us::any_cast(parsedArgs["calculate2D"]); } if (parsedArgs.count("coocsteps") || parsedArgs.count("s")) { coocString = us::any_cast(parsedArgs["coocsteps"]); } if (parsedArgs.count("texturebins") || parsedArgs.count("b")) { textureBins = us::any_cast(parsedArgs["texturebins"]); } radiomicsPipeline(inputPath, maskPath, outputPath, useNorm, useGeom, useRes, resX, resY, resZ , useDaub, useCoif, wLevels, + useStationary, firstOF, volumeF, textureF, calc2D, coocString, textureBins); return EXIT_SUCCESS; } diff --git a/Modules/Radiomics/RadiomicsMiniApps/RadiomicsSumMasks.cpp b/Modules/Radiomics/RadiomicsMiniApps/RadiomicsSumMasks.cpp new file mode 100644 index 0000000000..eb12006e07 --- /dev/null +++ b/Modules/Radiomics/RadiomicsMiniApps/RadiomicsSumMasks.cpp @@ -0,0 +1,242 @@ +/*=================================================================== + + The Medical Imaging Interaction Toolkit (MITK) + + Copyright (c) German Cancer Research Center, + Division of Medical and Biological Informatics. + All rights reserved. + + This software is distributed WITHOUT ANY WARRANTY; without + even the implied warranty of MERCHANTABILITY or FITNESS FOR + A PARTICULAR PURPOSE. + + See LICENSE.txt or http://www.mitk.org for details. + + ===================================================================*/ + +#include "mitkCommandLineParser.h" +#include "mitkImage.h" +#include "mitkIOUtil.h" +#include +#include +#include + +#include "itkFileTools.h" +#include + + +//additional includes +#include +#include +#include + + + +static vector splitDouble(string str, char delimiter) { + vector internal; + stringstream ss(str); // Turn the string into a stream. + string tok; + double val; + while (getline(ss, tok, delimiter)) { + stringstream s2(tok); + s2 >> val; + internal.push_back(val); + } + + return internal; +} + +static std::vector splitString(const std::string &s, char delim) +{ + std::vector < std::string > elems; + std::stringstream ss(s); + std::string item; + while (std::getline(ss, item, delim)) + { + elems.push_back(item); + } + return elems; +} + +std::string intToFixedLengthString(int value, int digits = 3) +{ + unsigned int uvalue = value; + if (value < 0) { + uvalue = -uvalue; + } + std::string result; + while (digits-- > 0) { + result += ('0' + uvalue % 10); + uvalue /= 10; + } + if (value < 0) { + result += '-'; + } + std::reverse(result.begin(), result.end()); + return result; +} + +//Used to check if file exists before trying to open it. +//However, this might get a wrong result if the file exists but the user is not allowed to open it. +bool fileExists(const std::string& filename) +{ + ifstream infile(filename.c_str()); + return infile.good(); +} + +bool replaceInString(std::string& str, const std::string& from, const std::string& to) { + size_t start_pos = str.find(from); + if (start_pos == std::string::npos) + return false; + str.replace(start_pos, from.length(), to); + return true; +} + +int combineMasks(std::string inputMaskPath1, std::string inputMaskPath2, bool subtract) +{ + if (!fileExists(inputMaskPath1) || !fileExists(inputMaskPath2)) + { + MITK_ERROR << "Not all required files found!"; + return EXIT_FAILURE; + } + + std::size_t fileSplitter = inputMaskPath1.find_last_of("/\\"); + std::string maskFile = inputMaskPath1.substr(fileSplitter + 1); + std::string path = inputMaskPath1.substr(0, fileSplitter); + std::string fileTypeIm = itksys::SystemTools::GetFilenameExtension(maskFile); + size_t pos = maskFile.find(fileTypeIm); + maskFile = maskFile.substr(0, pos); + + std::string fileTypeAp = itksys::SystemTools::GetFilenameExtension(inputMaskPath1); + + std::stringstream toSave; + + toSave << path << "/"; + toSave << "combined" << fileTypeAp; + std::string savePath = toSave.str(); + + MITK_WARN << savePath; + + if (fileExists(savePath)) + return EXIT_SUCCESS; + + + mitk::Image::Pointer maskImage1 = mitk::IOUtil::LoadImage(inputMaskPath1); + mitk::Image::Pointer maskImage2 = mitk::IOUtil::LoadImage(inputMaskPath2); + + if(maskImage1->GetPixelType().GetComponentTypeAsString() == "float") + { + auto geom1 = maskImage1->GetGeometry()->Clone(); + const int ImageDimension = 3; + typedef itk::Image ImageType; + typedef itk::Image FloatingSegmentationType; + + typename FloatingSegmentationType::Pointer itkImage = NULL; + mitk::Image::Pointer resultImage; + mitk::CastToItkImage(maskImage1, itkImage); + + typedef itk::BinaryThresholdImageFilter < FloatingSegmentationType, ImageType> ThresholderType; + typename ThresholderType::Pointer threshold = ThresholderType::New(); + + threshold->SetInput(itkImage); + threshold->SetLowerThreshold(0.1); + threshold->SetUpperThreshold(10000); + threshold->SetInsideValue(1); + threshold->SetOutsideValue(0); + threshold->Update(); + + mitk::CastToMitkImage(threshold->GetOutput(),resultImage); + resultImage->SetGeometry(geom1); + maskImage1 = resultImage; + } + + + if(maskImage2->GetPixelType().GetComponentTypeAsString() == "float") + { + auto geom1 = maskImage2->GetGeometry()->Clone(); + const int ImageDimension = 3; + typedef itk::Image ImageType; + typedef itk::Image FloatingSegmentationType; + + typename FloatingSegmentationType::Pointer itkImage = NULL; + mitk::Image::Pointer resultImage; + mitk::CastToItkImage(maskImage2, itkImage); + + typedef itk::BinaryThresholdImageFilter < FloatingSegmentationType, ImageType> ThresholderType; + typename ThresholderType::Pointer threshold = ThresholderType::New(); + + threshold->SetInput(itkImage); + threshold->SetLowerThreshold(0.1); + threshold->SetUpperThreshold(10000); + threshold->SetInsideValue(1); + threshold->SetOutsideValue(0); + threshold->Update(); + + mitk::CastToMitkImage(threshold->GetOutput(),resultImage); + resultImage->SetGeometry(geom1); + maskImage2 = resultImage; + } + + if(!subtract) + { + mitk::BooleanOperation* myBool = new mitk::BooleanOperation(mitk::BooleanOperation::Union, maskImage1, maskImage2); + mitk::LabelSetImage::Pointer result = myBool->GetResult(); + mitk::IOUtil::Save(result,savePath); + } + else + { + mitk::BooleanOperation* myBool = new mitk::BooleanOperation(mitk::BooleanOperation::Difference, maskImage1, maskImage2); + mitk::LabelSetImage::Pointer result = myBool->GetResult(); + mitk::IOUtil::Save(result,savePath); + } + +} + +int main(int argc, char* argv[]) +{ + mitkCommandLineParser parser; + + parser.setTitle("Make unsuitable ROI fit to Image"); + parser.setCategory("Preprocessing Tools"); + parser.setDescription(""); + parser.setContributor("MBI"); + + parser.setArgumentPrefix("--", "-"); + parser.addArgument("help", "h", mitkCommandLineParser::String, "Help:", "Show this help text"); + parser.addArgument("mask1", "m", mitkCommandLineParser::InputFile, "Mask1:", "mask image", us::Any(), false); + parser.addArgument("mask2", "n", mitkCommandLineParser::InputFile, "Mask2:", "mask image", us::Any(), false); + parser.addArgument("subtract", "s", mitkCommandLineParser::Bool, "Subtract:", "If set, the masks will be subtracted instead of unified", us::Any()); + + + map parsedArgs = parser.parseArguments(argc, argv); + + if (parsedArgs.size() == 0 || parsedArgs.count("help") || parsedArgs.count("h")) + { + std::cout << "\n\n MiniApp Description: \nMakes a unsuitable mask fit to another image." << endl; + std::cout << "\n\n Parameters:" << endl; + std::cout << parser.helpText(); + return EXIT_SUCCESS; + } + + std::string maskImageFile1 = us::any_cast(parsedArgs["mask1"]); + std::string maskImageFile2 = us::any_cast(parsedArgs["mask2"]); + + bool subtract = false; + if (parsedArgs.count("subtract") || parsedArgs.count("s")) + { + subtract = us::any_cast(parsedArgs["subtract"]); + } + + + if (fileExists(maskImageFile1) && fileExists(maskImageFile2)) + { + int fit = combineMasks(maskImageFile1, maskImageFile2, subtract); + return fit; + } + + + + return EXIT_SUCCESS; +} + + diff --git a/Modules/Radiomics/RadiomicsWavelets/src/mitkRadiomicsWavelets.cpp b/Modules/Radiomics/RadiomicsWavelets/src/mitkRadiomicsWavelets.cpp index 2e5536e0d2..42742a1a63 100644 --- a/Modules/Radiomics/RadiomicsWavelets/src/mitkRadiomicsWavelets.cpp +++ b/Modules/Radiomics/RadiomicsWavelets/src/mitkRadiomicsWavelets.cpp @@ -1,376 +1,382 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include void mitk::RadiomicsWavelets::setup() { us::Module* module = us::ModuleRegistry::GetModule("MitkPythonService"); if(module == nullptr || module->IsLoaded() == false) { MITK_WARN << "Python not loaded -> Force to load it!"; mitk::IPythonService::ForceLoadModule(); module = us::ModuleRegistry::GetModule("MitkPythonService"); } us::ModuleContext* context = module->GetModuleContext(); us::ServiceReference serviceRef = context->GetServiceReference(); m_PythonService = dynamic_cast(context->GetService(serviceRef)); m_PythonService->Execute("import SimpleITK as sitk"); m_PythonService->Execute("import _SimpleITK"); m_PythonService->Execute("import numpy"); m_PythonService->Execute("import pywt"); setupDaubechiesWaveletPipeline(); setupCoifletWaveletPipeline(); setupSegmentationPipeline(); MITK_INFO << "Wavelet Setup finished."; } void mitk::RadiomicsWavelets::simpleExample(mitk::DataNode *node, mitk::DataStorage *ds) { mitk::Image* m_Image = dynamic_cast( node->GetData() ); mitk::Image::Pointer ritw = mitk::Image::New(); ritw = mitk::GeometryTools::ResetIndexToWorld(m_Image); m_PythonService->CopyToPythonAsSimpleItkImage(ritw,"mitkImage"); m_PythonService->Execute("filter = sitk.MedianImageFilter()"); m_PythonService->Execute("filter.SetRadius(3)"); m_PythonService->Execute("mitkImage_new = filter.Execute(mitkImage)"); MITK_WARN << "execution done."; mitk::Image::Pointer img = m_PythonService->CopySimpleItkImageFromPython("mitkImage_new"); mitk::DataNode::Pointer tmp = mitk::DataNode::New(); tmp->SetData(img); tmp->SetName("SimpleITK Output"); ds->Add(tmp); } void mitk::RadiomicsWavelets::setupCoifletWaveletPipeline() { std::string def1 = "def getArrayFromItkImage(im):\n\treturn (im.GetSize(),sitk.GetArrayFromImage(im))"; m_PythonService->Execute(def1,mitk::IPythonService::MULTI_LINE_COMMAND); std::string def2 = "def createCoifletWavelets(array,useDwt=True):" "\n\tslices = array[0][2]" "\n\twvlt = pywt.Wavelet('coif1')" "\n\ttoReturn = list()" "\n\tfor i in range(slices):" "\n\t\ttmpSlice = array[1][i,:,:]" "\n\t\tif(useDwt == True):" "\n\t\t\twd = pywt.wavedec2(tmpSlice, wvlt, level=1)" "\n\t\telse:" "\n\t\t\t(w,h) = tmpSlice.shape" "\n\t\t\tif w % 2 != 0:" "\n\t\t\t\ttmpSlice = tmpSlice[:-1,:]" "\n\t\t\tif h % 2 != 0:" "\n\t\t\t\ttmpSlice = tmpSlice[:,:-1]" "\n\t\t\twd = pywt.swt2(tmpSlice, wvlt, level=1)" "\n\t\ttoReturn.append(wd)" "\n\treturn toReturn"; std::string def3 = "def waveletCoifletPipeline(array, useDwt, level):" "\n\tkk = createCoifletWavelets(array, useDwt)" "\n\tlevel1H = list()" "\n\tlevel1V = list()" "\n\tlevel1D = list()" "\n\tlevel2H = list()" "\n\tlevel2V = list()" "\n\tlevel2D = list()" "\n\tlevel3H = list()" "\n\tlevel3V = list()" "\n\tlevel3D = list()" "\n\tlevel4H = list()" "\n\tlevel4V = list()" "\n\tlevel4D = list()" "\n\tlowpass1 = list()" "\n\tlowpass2 = list()" "\n\tlowpass3 = list()" "\n\tlowpass4 = list()" "\n\tfor i in kk:" "\n\t\tif(useDwt == False):" "\n\t\t\ti = i[0]\t\t#The return format differs when using dwt and swt!!!" "\n\t\tlevel1H.append(i[1][1])" "\n\t\tlevel1V.append(i[1][0])" "\n\t\tlevel1D.append(i[1][2])" "\n\t\tlowpass1.append(i[0])" "\n\tfor i in createCoifletWavelets((k[0],numpy.array(lowpass1)), useDwt):" "\n\t\tif(useDwt == False):" "\n\t\t\ti = i[0]" "\n\t\tlevel2H.append(i[1][1])" "\n\t\tlevel2V.append(i[1][0])" "\n\t\tlevel2D.append(i[1][2])" "\n\t\tlowpass2.append(i[0])" "\n\tfor i in createCoifletWavelets((k[0],numpy.array(lowpass2)), useDwt):" "\n\t\tif(useDwt == False):" "\n\t\t\ti = i[0]" "\n\t\tlevel3H.append(i[1][1])" "\n\t\tlevel3V.append(i[1][0])" "\n\t\tlevel3D.append(i[1][2])" "\n\t\t" "\n\t\tlowpass3.append(i[0])" "\n\tfor i in createCoifletWavelets((k[0],numpy.array(lowpass3)), useDwt):" "\n\t\tif(useDwt == False):" "\n\t\t\ti = i[0]" "\n\t\tlevel4H.append(i[1][1])" "\n\t\tlevel4V.append(i[1][0])" "\n\t\tlevel4D.append(i[1][2])" "\n\t\tlowpass4.append(i[0])" "\n\ttoReturn=list()" "\n\ttoReturn.append(level1H)" "\n\ttoReturn.append(level1V)" "\n\ttoReturn.append(level1D)" "\n\ttoReturn.append(lowpass1)" "\n\ttoReturn.append(level2H)" "\n\ttoReturn.append(level2V)" "\n\ttoReturn.append(level2D)" "\n\ttoReturn.append(lowpass2)" "\n\ttoReturn.append(level3H)" "\n\ttoReturn.append(level3V)" "\n\ttoReturn.append(level3D)" "\n\ttoReturn.append(lowpass3)" "\n\ttoReturn.append(level4H)" "\n\ttoReturn.append(level4V)" "\n\ttoReturn.append(level4D)" "\n\ttoReturn.append(lowpass4)" "\n\treturn toReturn"; std::string def4 = "def saveItkImageFromArray(array):" "\n\treturn sitk.GetImageFromArray(array)"; m_PythonService->Execute(def1,mitk::IPythonService::MULTI_LINE_COMMAND); m_PythonService->Execute(def2,mitk::IPythonService::MULTI_LINE_COMMAND); m_PythonService->Execute(def3,mitk::IPythonService::MULTI_LINE_COMMAND); m_PythonService->Execute(def4,mitk::IPythonService::MULTI_LINE_COMMAND); } void mitk::RadiomicsWavelets::setupDaubechiesWaveletPipeline() { std::string def2 = "def createDaubechiesWavelets(array,useDwt=True):" "\n\tslices = array[0][2]" "\n\twvlt = pywt.Wavelet('db1')" "\n\ttoReturn = list()" "\n\tfor i in range(slices):" "\n\t\ttmpSlice = array[1][i,:,:]" "\n\t\tif(useDwt == True):" "\n\t\t\twd = pywt.wavedec2(tmpSlice, wvlt, level=1)" "\n\t\telse:" "\n\t\t\t(w,h) = tmpSlice.shape" "\n\t\t\tif w % 2 != 0:" "\n\t\t\t\ttmpSlice = tmpSlice[:-1,:]" "\n\t\t\tif h % 2 != 0:" "\n\t\t\t\ttmpSlice = tmpSlice[:,:-1]" "\n\t\t\twd = pywt.swt2(tmpSlice, wvlt, level=1)" "\n\t\ttoReturn.append(wd)" "\n\treturn toReturn"; std::string def3 = "def waveletDaubechiesPipeline(array, useDwt, level):" "\n\tkk = createDaubechiesWavelets(array, useDwt)" "\n\tlevel1H = list()" "\n\tlevel1V = list()" "\n\tlevel1D = list()" "\n\tlevel2H = list()" "\n\tlevel2V = list()" "\n\tlevel2D = list()" "\n\tlevel3H = list()" "\n\tlevel3V = list()" "\n\tlevel3D = list()" "\n\tlevel4H = list()" "\n\tlevel4V = list()" "\n\tlevel4D = list()" "\n\tlowpass1 = list()" "\n\tlowpass2 = list()" "\n\tlowpass3 = list()" "\n\tlowpass4 = list()" "\n\tfor i in kk:" "\n\t\tif(useDwt == False):" "\n\t\t\ti = i[0]\t\t#The return format differs when using dwt and swt!!!" "\n\t\tlevel1H.append(i[1][1])" "\n\t\tlevel1V.append(i[1][0])" "\n\t\tlevel1D.append(i[1][2])" "\n\t\tlowpass1.append(i[0])" "\n\tfor i in createDaubechiesWavelets((k[0],numpy.array(lowpass1)), useDwt):" "\n\t\tif(useDwt == False):" "\n\t\t\ti = i[0]" "\n\t\tlevel2H.append(i[1][1])" "\n\t\tlevel2V.append(i[1][0])" "\n\t\tlevel2D.append(i[1][2])" "\n\t\tlowpass2.append(i[0])" "\n\tfor i in createDaubechiesWavelets((k[0],numpy.array(lowpass2)), useDwt):" "\n\t\tif(useDwt == False):" "\n\t\t\ti = i[0]" "\n\t\tlevel3H.append(i[1][1])" "\n\t\tlevel3V.append(i[1][0])" "\n\t\tlevel3D.append(i[1][2])" "\n\t\t" "\n\t\tlowpass3.append(i[0])" "\n\tfor i in createDaubechiesWavelets((k[0],numpy.array(lowpass3)), useDwt):" "\n\t\tif(useDwt == False):" "\n\t\t\ti = i[0]" "\n\t\tlevel4H.append(i[1][1])" "\n\t\tlevel4V.append(i[1][0])" "\n\t\tlevel4D.append(i[1][2])" "\n\t\tlowpass4.append(i[0])" "\n\ttoReturn=list()" "\n\ttoReturn.append(level1H)" "\n\ttoReturn.append(level1V)" "\n\ttoReturn.append(level1D)" "\n\ttoReturn.append(lowpass1)" "\n\ttoReturn.append(level2H)" "\n\ttoReturn.append(level2V)" "\n\ttoReturn.append(level2D)" "\n\ttoReturn.append(lowpass2)" "\n\ttoReturn.append(level3H)" "\n\ttoReturn.append(level3V)" "\n\ttoReturn.append(level3D)" "\n\ttoReturn.append(lowpass3)" "\n\ttoReturn.append(level4H)" "\n\ttoReturn.append(level4V)" "\n\ttoReturn.append(level4D)" "\n\ttoReturn.append(lowpass4)" "\n\treturn toReturn"; m_PythonService->Execute(def2,mitk::IPythonService::MULTI_LINE_COMMAND); m_PythonService->Execute(def3,mitk::IPythonService::MULTI_LINE_COMMAND); } void mitk::RadiomicsWavelets::setupSegmentationPipeline() { std::string def1 = "def convertImages(fname):" "\n\tk=getArrayFromItkImage(fname)" "\n\ti=sitk.GetImageFromArray(k[1])" "\n\treturn i"; m_PythonService->Execute(def1,mitk::IPythonService::MULTI_LINE_COMMAND); } -std::vector mitk::RadiomicsWavelets::createDaubechiesWavelets(mitk::Image::Pointer inputImage, int levels, bool dwt) +std::vector mitk::RadiomicsWavelets::createDaubechiesWavelets(mitk::Image::Pointer inputImage, int levels, bool swt) { std::vector toReturn; + std::string cmd = "n = waveletDaubechiesPipeline(k,True," + std::to_string(levels) + ")"; + if(swt == true) //The wavelet pipeline will be called with waveletDaubechiesPipeline(array, useDwt, level) + cmd = "n = waveletDaubechiesPipeline(k,False," + std::to_string(levels) + ")"; mitk::Image::Pointer ritw = mitk::Image::New(); auto oldGeom1 = inputImage->GetGeometry(); auto oldGeom = oldGeom1->Clone(); float sizeX = oldGeom->GetSpacing()[0] * inputImage->GetDimensions()[0]; float sizeY = oldGeom->GetSpacing()[1] * inputImage->GetDimensions()[1]; float sizeZ = oldGeom->GetSpacing()[2] * inputImage->GetDimensions()[2]; ritw = mitk::GeometryTools::ResetIndexToWorld(inputImage->Clone()); m_PythonService->CopyToPythonAsSimpleItkImage(ritw,"mitkImage"); MITK_WARN << "Start to calculate the wavelets."; m_PythonService->Execute("k = getArrayFromItkImage(mitkImage)"); - m_PythonService->Execute("n = waveletDaubechiesPipeline(k,True,3)"); + m_PythonService->Execute(cmd); MITK_WARN << "Done. Starting extracting the images to mitk."; for(int i = levels -1; i >= 0;i--) { for(int j = 3; j >= 0; j--) { m_PythonService->Execute("tmpImage" + std::to_string(i*4+j) + " = saveItkImageFromArray(n[" + std::to_string(i*4+j) + "])"); mitk::Image::Pointer img = m_PythonService->CopySimpleItkImageFromPython("tmpImage" +std::to_string(i*4+j)); //Write old Geometry to new image auto newGeom = img->GetGeometry(); newGeom->SetIndexToWorldTransform(oldGeom->GetIndexToWorldTransform()); auto newSpacing = img->GetGeometry()->GetSpacing(); newSpacing[0] = sizeX / (double)img->GetDimensions()[0]; newSpacing[1] = sizeY / (double)img->GetDimensions()[1]; newSpacing[2] = sizeZ / (double)img->GetDimensions()[2]; newGeom->SetSpacing(newSpacing); img->SetGeometry(newGeom); toReturn.push_back(img); } } MITK_WARN << "Daubechies Wavelets done."; return toReturn; } -std::vector mitk::RadiomicsWavelets::createCoifletWavelets(mitk::Image::Pointer inputImage, int levels, bool dwt) +std::vector mitk::RadiomicsWavelets::createCoifletWavelets(mitk::Image::Pointer inputImage, int levels, bool swt) { std::vector toReturn; + std::string cmd = "n = waveletCoifletPipeline(k,True," + std::to_string(levels) + ")"; + if(swt == true) //The wavelet pipeline will be called with waveletDaubechiesPipeline(array, useDwt, level) + cmd = "n = waveletCoifletPipeline(k,False," + std::to_string(levels) + ")"; mitk::Image::Pointer ritw = mitk::Image::New(); auto oldGeom1 = inputImage->GetGeometry(); auto oldGeom = oldGeom1->Clone(); float sizeX = oldGeom->GetSpacing()[0] * inputImage->GetDimensions()[0]; float sizeY = oldGeom->GetSpacing()[1] * inputImage->GetDimensions()[1]; float sizeZ = oldGeom->GetSpacing()[2] * inputImage->GetDimensions()[2]; ritw = mitk::GeometryTools::ResetIndexToWorld(inputImage->Clone()); m_PythonService->CopyToPythonAsSimpleItkImage(ritw,"mitkImage"); MITK_WARN << "Start to calculate the wavelets."; m_PythonService->Execute("k = getArrayFromItkImage(mitkImage)"); - m_PythonService->Execute("n = waveletCoifletPipeline(k,True,3)"); + m_PythonService->Execute(cmd); MITK_WARN << "Done. Starting extracting the images to mitk."; for(int i = levels -1; i >= 0;i--) { for(int j = 3; j >= 0; j--) { m_PythonService->Execute("tmpImage" + std::to_string(i*4+j) + " = saveItkImageFromArray(n[" + std::to_string(i*4+j) + "])"); mitk::Image::Pointer img = m_PythonService->CopySimpleItkImageFromPython("tmpImage" +std::to_string(i*4+j)); //Write old Geometry to new image auto newGeom = img->GetGeometry(); newGeom->SetIndexToWorldTransform(oldGeom->GetIndexToWorldTransform()); auto newSpacing = img->GetGeometry()->GetSpacing(); newSpacing[0] = sizeX / (double)img->GetDimensions()[0]; newSpacing[1] = sizeY / (double)img->GetDimensions()[1]; newSpacing[2] = sizeZ / (double)img->GetDimensions()[2]; newGeom->SetSpacing(newSpacing); img->SetGeometry(newGeom); toReturn.push_back(img); } } MITK_WARN << "Coiflet Wavelets done."; return toReturn; } mitk::Image::Pointer mitk::RadiomicsWavelets::getSitkSegmentation(mitk::Image::Pointer seg) { mitk::Image::Pointer ritw = mitk::Image::New(); ritw = mitk::GeometryTools::ResetIndexToWorld(seg); m_PythonService->CopyToPythonAsSimpleItkImage(ritw,"mitkSeg"); MITK_WARN << "Start to calculate the wavelets."; m_PythonService->Execute("newSeg = convertImages(mitkSeg)"); mitk::Image::Pointer img = m_PythonService->CopySimpleItkImageFromPython("newSeg"); MITK_WARN << "Extract Segmentation."; return img; } diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomics.cpp b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomics.cpp index 91906e323c..934cfa7e0c 100644 --- a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomics.cpp +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomics.cpp @@ -1,1144 +1,1160 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkRadiomics.h" // Qt #include #include #include #include #include #include //mitk image #include #include #include //Radiomics include #include #include #include #include #include #include #include #include #include #include /// /// START OF TEST /// //#include /// /// END OF TEST /// const std::string QmitkRadiomics::VIEW_ID = "org.mitk.views.radiomics"; QmitkRadiomics::QmitkRadiomics() { } void QmitkRadiomics::SetFocus() { } void QmitkRadiomics::NodeAdded(const mitk::DataNode *node) { bool isBinary (false); bool isHelperObject (false); bool isImage (false); node->GetBoolProperty("binary", isBinary); mitk::LabelSetImage::Pointer labelSetImage = dynamic_cast(node->GetData()); isBinary = isBinary || labelSetImage.IsNotNull(); node->GetBoolProperty("helper object", isHelperObject); if( dynamic_cast(node->GetData()) ) { isImage = true; } /*if (m_AutoSelectionEnabled) { if (!isBinary && isImage) { FireNodeSelected(const_cast(node)); } } if(isImage && !isHelperObject) { MITK_WARN << "Is Image"; m_Controls.patImageSelector->AddNode(node); } else if(isBinary && !isHelperObject) { MITK_WARN << "Is Binary!"; m_Controls.segImageSelector->AddNode(node); } */ if (isImage && !isHelperObject) { itk::SimpleMemberCommand::Pointer command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkRadiomics::OnWorkingNodeVisibilityChanged); m_WorkingDataObserverTags.insert( std::pair( const_cast(node), node->GetProperty("visible")->AddObserver( itk::ModifiedEvent(), command ) ) ); itk::SimpleMemberCommand::Pointer command2 = itk::SimpleMemberCommand::New(); command2->SetCallbackFunction(this, &QmitkRadiomics::OnBinaryPropertyChanged); m_BinaryPropertyObserverTags.insert( std::pair( const_cast(node), node->GetProperty("binary")->AddObserver( itk::ModifiedEvent(), command2 ) ) ); //this->ApplyDisplayOptions( const_cast(node) ); m_Controls.segImageSelector->setCurrentIndex( m_Controls.segImageSelector->Find(node) ); } } void QmitkRadiomics::CreateQtPartControl( QWidget *parent ) { qRegisterMetaType("mitk::Image::Pointer"); qRegisterMetaType("mitk::DataNode::Pointer"); qRegisterMetaType("std::string"); // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi( parent ); m_Controls.tabSettings->setLayout(m_Controls.layoutSettings); m_Controls.tabImages->setLayout(m_Controls.imagesLayout); m_Controls.singleImageGroupBox->setLayout(m_Controls.layoutSingleImages); m_Controls.batchGroupBox->setLayout(m_Controls.batchLayout); m_Controls.batchGroupBox->setVisible(false); m_Controls.patImageSelector->SetDataStorage(this->GetDataStorage()); m_Controls.regImageSelector->SetDataStorage(this->GetDataStorage()); m_Controls.segImageSelector->SetDataStorage(this->GetDataStorage()); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateNot::Pointer isNotBinaryPredicate = mitk::NodePredicateNot::New( isBinaryPredicate ); mitk::NodePredicateAnd::Pointer isNotABinaryImagePredicate = mitk::NodePredicateAnd::New( mitk::TNodePredicateDataType::New(), isNotBinaryPredicate ); mitk::NodePredicateAnd::Pointer isABinaryImagePredicate = mitk::NodePredicateAnd::New( mitk::TNodePredicateDataType::New(), isBinaryPredicate); mitk::NodePredicateOr::Pointer isASegmentationImagePredicate = mitk::NodePredicateOr::New(isABinaryImagePredicate, mitk::TNodePredicateDataType::New()); mitk::NodePredicateAnd::Pointer isAPatientImagePredicate = mitk::NodePredicateAnd::New(isNotABinaryImagePredicate, mitk::NodePredicateNot::New(mitk::TNodePredicateDataType::New())); /* m_Controls.patImageSelector->SetPredicate(isAPatientImagePredicate); m_Controls.segImageSelector->SetPredicate(isASegmentationImagePredicate); */ m_Controls.patImageSelector->SetPredicate(mitk::NodePredicateAnd::New(mitk::TNodePredicateDataType::New(), mitk::NodePredicateNot::New(mitk::TNodePredicateDataType::New()))); m_Controls.regImageSelector->SetPredicate(mitk::NodePredicateAnd::New(mitk::TNodePredicateDataType::New(), mitk::NodePredicateNot::New(mitk::TNodePredicateDataType::New()))); m_Controls.segImageSelector->SetPredicate(mitk::TNodePredicateDataType::New()); connect( m_Controls.btnAddCoocEntry, SIGNAL(clicked()), this, SLOT(addCoocEntry()) ); connect( m_Controls.btnAddRunLength, SIGNAL(clicked()), this, SLOT(addRunLengthEntry()) ); connect( m_Controls.btnClearCooc, SIGNAL(clicked()), this, SLOT(clearCoocList() ) ); connect( m_Controls.btnClearRunLength, SIGNAL(clicked()), this, SLOT(clearRunLengthList()) ); connect( m_Controls.radiomicsRun, SIGNAL(clicked()), this, SLOT(performRadiomicsPipeline())); connect( m_Controls.checkRegistration, SIGNAL(toggled(bool)),this, SLOT(toggledRegistrationMode(bool))); connect( m_Controls.check3D, SIGNAL(toggled(bool)), this, SLOT(toggled3dCalculationMode(bool))); connect( m_Controls.btnAddImageSelection, SIGNAL(clicked()),this, SLOT(addImageSegmentationSelection())); connect( m_Controls.btnRemoveSelection, SIGNAL(clicked()),this, SLOT(removeImageSegmentationSelection())); connect( m_Controls.btnOutFileSelector, SIGNAL(clicked()), this, SLOT(selectOutputFile())); connect( m_Controls.selectionTreeWidget, SIGNAL(itemSelectionChanged()), this, SLOT(observeSelectedItems())); connect( this, SIGNAL(stepCompleted(mitk::Image::Pointer, std::string, bool)), this, SLOT(updateProgressBar())); connect( this, SIGNAL(stepCompleted(mitk::Image::Pointer, std::string, bool)), this, SLOT(updateDataNode(mitk::Image::Pointer, std::string,bool))); connect( this, SIGNAL(workItemCompleted()), this, SLOT(onWorkItemFinished())); connect( this, SIGNAL(readyToStartNewTask(int)), this, SLOT(onStartingSingleTask(int))); connect( this, SIGNAL(readyToStartNewTask(int)), this, SLOT(updateAfterCompletion(int))); connect( this, SIGNAL(allDone()), this, SLOT(onPipelineFinished())); connect (this, SIGNAL(addParentNode(mitk::Image::Pointer, std::string, mitk::Image::Pointer, std::string, std::string)), this, SLOT(addParentNodeSlot(mitk::Image::Pointer, std::string, mitk::Image::Pointer, std::string, std::string))); connect (this, SIGNAL(addSubNode(mitk::Image::Pointer, std::string)), this, SLOT(addSubNodeSlot(mitk::Image::Pointer, std::string))); connect (this, SIGNAL(updateStepIndicator(std::string, int)), this, SLOT(updateStepIndicatorSlot(std::string, int))); connect(m_Controls.radioSingleImages, SIGNAL(toggled(bool)), this, SLOT(singleImageBatchToggled(bool))); connect(m_Controls.patImageSelector, SIGNAL(currentIndexChanged(int)), this, SLOT(patImageChanged())); m_Controls.patImageSelector->setCurrentIndex(0); } void QmitkRadiomics::toggled3dCalculationMode(bool use3d) { m_Controls.resZBox->setEnabled(use3d); } void QmitkRadiomics::performRadiomicsPipeline() { if(m_Collections.size() == 0) { QMessageBox::warning(nullptr,"Warning","You need to specify at least an image and a segmentation!"); return; } int waveletMultiplier = 0; //Multiplier calculated by checking if Daubechies and/or coiflet is checked if(m_Controls.checkDaub->isChecked()) waveletMultiplier++; if(m_Controls.checkCoif->isChecked()) waveletMultiplier++; m_MaxValue = 0; m_MaxValue += (m_Controls.checkNorm->isChecked() ? 1 : 0); //Image Normalization m_MaxValue += (m_Controls.checkRes->isChecked() ? 2 : 0); //Resampling m_MaxValue += 1; //Fit ROI to image m_MaxValue += (m_Controls.checkGeom->isChecked() ? 2 : 0); //Geometry correction m_MaxValue += 2; //Image-Features m_MaxValue += waveletMultiplier*(2*4*m_Controls.waveletLevels->value()); //Wavelet extraction m_MaxValue += waveletMultiplier*(2*4*m_Controls.waveletLevels->value()); //Wavelet features MITK_WARN << "Number of steps per patient: " << m_MaxValue; m_Controls.currentProgress->setMaximum(m_MaxValue); m_Controls.overallProgress->setMaximum(m_Collections.size() * m_MaxValue); m_Controls.radiomicsRun->setEnabled(false); m_Controls.btnAddImageSelection->setEnabled(false); m_Controls.btnRemoveSelection->setEnabled(false); m_Controls.layoutSettings->setEnabled(false); m_Controls.imagesLayout->setEnabled(false); m_Controls.layoutSingleImages->setEnabled(false); m_Controls.batchLayout->setEnabled(false); emit readyToStartNewTask(0); //readyToStartNewTask will call onStartingSingleTask } void QmitkRadiomics::onStartingSingleTask(int j) { std::thread::id this_id = std::this_thread::get_id(); MITK_WARN << "Starting task " << j << " of " << m_Collections.size() << " from thread " << this_id; if(j < m_Collections.size()) { //std::thread pipelineThread(&QmitkRadiomics::radiomicsPipeline, this, imageNodeCopied,segmentationNodeCopied, // m_Collections[j]->getImageNode()->GetName(), m_Collections[j]->getSegmentationNode()->GetName(), // m_Collections[j]->getName(),j); m_Controls.currentProgress->setFormat(QString::fromStdString("Progress of " + m_Collections[j]->getName() + ": %p%")); std::thread pipelineThread(&QmitkRadiomics::radiomicsPipeline, this, m_Collections[j], j); pipelineThread.detach(); } else emit allDone(); } void QmitkRadiomics::radiomicsPipeline(mitk::RadiomicsCollection::Pointer collection, int noOfRun) { //Sleep for how long to prevent crashes int timeToSleep = 0; emit updateStepIndicator("Preparing Calculation...",0); mitk::Image::Pointer image = (dynamic_cast(collection->getImageNode()->GetData()))->Clone(); mitk::Image::Pointer segmentation = (dynamic_cast(collection->getSegmentationNode()->GetData()))->Clone(); unsigned int wLevels = collection->GetWaveletLevels(); emit addParentNode(image->Clone(), collection->getImageNode()->GetName(), segmentation->Clone(), collection->getSegmentationNode()->GetName(), collection->getName()); //Sleep to prevent crashes.... std::this_thread::sleep_for(std::chrono::seconds(timeToSleep)); /// /// Image Correction /// if(collection->getUseNorm() == true) { MITK_WARN << "Perform Image Correction..."; emit updateStepIndicator("Performing Image Correction...",0); image = mitk::RadiomicsNormalization::normalizeImage(image); emit stepCompleted(image->Clone(), "Image normalized"); //Workitem completed emit workItemCompleted(); } /// /// Resampling /// if(collection->getUseResampling() == true) { MITK_WARN << "Perform Resampling..."; - mitk::RadiomicsResampling::Pointer myRes = mitk::RadiomicsResampling::New(); - emit updateStepIndicator("Resampling...",0); //Resample original image - image = myRes->resampleImage(image, + image = mitk::RadiomicsResampling::resampleImageFloat(image, (float)collection->GetResX(), (float)collection->GetResY(), collection->getUse3d() ? (float)collection->GetResZ() : (float)image->GetGeometry()->GetSpacing()[2] ); emit stepCompleted(image->Clone(), "Image resampled"); //resample segmentation image - segmentation = myRes->resampleMask(segmentation, + segmentation = mitk::RadiomicsResampling::resampleMaskUnsignedShort(segmentation, (float)collection->GetResX(), (float)collection->GetResY(), collection->getUse3d() ? (float)collection->GetResZ() : (float)segmentation->GetGeometry()->GetSpacing()[2] ); emit stepCompleted(segmentation->Clone(), "Segmentation resampled"); //Workitem completed emit workItemCompleted(); } /// /// Make the segmentation fit to the image (w.r.t geometry etc.) /// if(mitk::SegmentationTools::isCorrectionNeeded(image,segmentation)) { MITK_WARN << "Making ROI fit to image"; emit updateStepIndicator("Fitting ROI to image...",0); segmentation = mitk::SegmentationTools::makeRoiFitToImage(image,segmentation); emit stepCompleted(segmentation->Clone(), "Transferred segmentation"); emit workItemCompleted(); } else emit stepCompleted(); /// /// Geometry correction /// if(collection->getUseGeomCorrection() == true) { MITK_WARN << "checking Geometry!"; emit updateStepIndicator("Adjusting Geometry...",0); //adjust image MITK_WARN << "Initial New image dimensions: " << image->GetDimensions()[0]; image = mitk::GeometryTools::ResetIndexToWorld(image); emit stepCompleted(image->Clone(), "Image Geometry corrected"); //adjust segmentation segmentation = mitk::GeometryTools::ResetIndexToWorld(segmentation); emit stepCompleted(segmentation->Clone(), "Segmentation Geometry corrected"); //Workitem completed emit workItemCompleted(); } /// /// Remove NaNs from Segmentation image to prevent miscalculated features. /// /// /* bool removeNaNs = false; if(removeNaNs) { segmentation = mitk::SegmentationTools::removeNaNsFromSegmentation(image,segmentation->Clone()); emit stepCompleted(segmentation, "Segmentation NaNs cleaned"); //Workitem completed emit workItemCompleted(); } */ /// /// Calculate the features /// + if(collection->getUseFirstOrder() == false && collection->getUseVolumetric() == false && collection->getUseTexture() == false) + { + // + } + else { MITK_WARN << "Calculating features."; emit updateStepIndicator("Calculating features...",0); mitk::AbstractGlobalImageFeature::FeatureListType stats = mitk::RadiomicsFeatures::calculateFeatures(image, segmentation, collection->getCoocString(), collection->getRunLengthString(), collection->GetDirection(), collection->getUseFirstOrder(), collection->getUseVolumetric(), collection->getUseTexture()); emit stepCompleted(); emit updateStepIndicator("Writing to file...",0); mitk::RadiomicsFeatures::writeToCsvFile(stats,collection->getOutputFile(),collection->getName(), collection->getImageNode()->GetName(), collection->getSegmentationNode()->GetName()); emit stepCompleted(); emit workItemCompleted(); } /// /// Calculate Coiflet Wavelets /// if(collection->getUseCoiflet() == true) { emit updateStepIndicator("Creating Coiflet Wavelets...",0); mitk::RadiomicsWavelets::Pointer wavelets = mitk::RadiomicsWavelets::New(); wavelets->setup(); - std::vector wavs = wavelets->createCoifletWavelets(image, wLevels,true); + std::vector wavs = wavelets->createCoifletWavelets(image, wLevels,collection->GetUseStationary()); std::vector finalSegs; //Contains the fitted and shrinked segs std::vector finalWavs; //Contains the wavelets in the same order as the finalSegs if(wavs.size() == 0) { MITK_ERROR << "Wavelet calculation failed. Aborting."; return; } else { for(int i = wLevels; i > 0; i--) { std::string name = "Coiflet Level " + std::to_string(wLevels - i + 1 ); emit addSubNode(image, name); std::this_thread::sleep_for(std::chrono::seconds(timeToSleep)); for(int j = 0; j < 4; j++) { int index = (i-1) * 4 + j; //Let's fit the segmentation to the wavelet image - mitk::Image::Pointer finalSeg = mitk::SegmentationTools::makeRoiFitToImage(wavs[index],segmentation); + mitk::Image::Pointer finalSeg = mitk::SegmentationTools::makeRoiFitToImage(wavs[index],segmentation->Clone()); finalSegs.push_back(finalSeg); finalWavs.push_back(wavs[index]); std::string waveletType = "Lowpass"; if(j == 3) waveletType = "H"; else if(j == 2) waveletType = "V"; else if(j == 1) waveletType = "D"; emit stepCompleted(wavs[index]->Clone(), "Image " + waveletType, true); emit stepCompleted(finalSeg->Clone(), "Segmentation " + waveletType, true); } } } //emit stepCompleted(); /// /// Calculate the Coiflet features /// - if(finalWavs.size() != 4*wLevels || - finalSegs.size() != 4*wLevels) + if(collection->getUseFirstOrder() == false && collection->getUseVolumetric() == false && collection->getUseTexture() == false) { - MITK_ERROR << "Size of list of segmentations or of the wavelet-files are not as expected. Aborting."; - return; + // } - - for(int i = wLevels; i > 0; i--) + else { - for(int j = 0; j < 4; j++) + if(finalWavs.size() != 4*wLevels || + finalSegs.size() != 4*wLevels) { - int index = (i-1) * 4 + j; - - std::string waveletType = "Lowpass"; - if(j == 3) - waveletType = "H"; - else if(j == 2) - waveletType = "V"; - else if(j == 1) - waveletType = "D"; - - - MITK_WARN << "Calculating Coiflet features (Level " << i << "/" << waveletType << ")."; - emit updateStepIndicator("Calculating Coiflet features (Level " + std::to_string(i) +"/" + waveletType + ")...",0); - - MITK_WARN << "Calulating features for Coiflet " << i << "/" <getCoocString(), collection->getRunLengthString(), collection->GetDirection(), - collection->getUseFirstOrder(), collection->getUseVolumetric(), collection->getUseTexture()); - emit stepCompleted(); - emit updateStepIndicator("Writing to file...",0); - - mitk::RadiomicsFeatures::writeToCsvFile(stats,collection->getOutputFile(),collection->getName(), - collection->getImageNode()->GetName() +"/Coiflet Level " + std::to_string(i) + "/" + waveletType, //Name of image - collection->getSegmentationNode()->GetName() + "/Coiflet Level " + std::to_string(i) + "/" + waveletType); //Name of segmentation - emit stepCompleted(); - emit workItemCompleted(); + MITK_ERROR << "Size of list of segmentations or of the wavelet-files are not as expected. Aborting."; + return; + } + + for(int i = wLevels; i > 0; i--) + { + for(int j = 0; j < 4; j++) + { + int index = (i-1) * 4 + j; + + std::string waveletType = "Lowpass"; + if(j == 3) + waveletType = "H"; + else if(j == 2) + waveletType = "V"; + else if(j == 1) + waveletType = "D"; + + + MITK_WARN << "Calculating Coiflet features (Level " << i << "/" << waveletType << ")."; + emit updateStepIndicator("Calculating Coiflet features (Level " + std::to_string(i) +"/" + waveletType + ")...",0); + + MITK_WARN << "Calulating features for Coiflet " << i << "/" <getCoocString(), collection->getRunLengthString(), collection->GetDirection(), + collection->getUseFirstOrder(), collection->getUseVolumetric(), collection->getUseTexture()); + emit stepCompleted(); + emit updateStepIndicator("Writing to file...",0); + + mitk::RadiomicsFeatures::writeToCsvFile(stats,collection->getOutputFile(),collection->getName(), + collection->getImageNode()->GetName() +"/Coiflet Level " + std::to_string(i) + "/" + waveletType, //Name of image + collection->getSegmentationNode()->GetName() + "/Coiflet Level " + std::to_string(i) + "/" + waveletType); //Name of segmentation + emit stepCompleted(); + emit workItemCompleted(); + } } } } /// /// Calculate Daubechies Wavelets /// if(collection->getUseDaubechies() == true) { emit updateStepIndicator("Creating Daubechies Wavelets",0); mitk::RadiomicsWavelets::Pointer wavelets = mitk::RadiomicsWavelets::New(); wavelets->setup(); - std::vector wavs = wavelets->createCoifletWavelets(image, wLevels,true); + std::vector wavs = wavelets->createDaubechiesWavelets(image, wLevels,collection->GetUseStationary()); std::vector finalSegs; //Contains the fitted and shrinked segs std::vector finalWavs; //Contains the wavelets in the same order as the finalSegs - mitk::Image::Pointer sitkSegmentation = wavelets->getSitkSegmentation(segmentation); - if(wavs.size() == 0) { MITK_ERROR << "Wavelet calculation failed. Aborting."; return; } else { for(int i = wLevels; i > 0; i--) { std::string name = "Daubechies Level " + std::to_string(wLevels - i + 1 ); emit addSubNode(image, name); for(int j = 0; j < 4; j++) { int index = (i-1) * 4 + j; //Let's fit the segmentation to the wavelet image - mitk::Image::Pointer finalSeg = mitk::SegmentationTools::makeRoiFitToImage(wavs[index],segmentation); + mitk::Image::Pointer finalSeg = mitk::SegmentationTools::makeRoiFitToImage(wavs[index],segmentation->Clone()); finalSegs.push_back(finalSeg); finalWavs.push_back(wavs[index]); std::string waveletType = "Lowpass"; if(j == 3) waveletType = "H"; else if(j == 2) waveletType = "V"; else if(j == 1) waveletType = "D"; emit stepCompleted(wavs[index]->Clone(), "Image " + waveletType, true); emit stepCompleted(finalSeg->Clone(), "Segmentation " + waveletType, true); } } } //emit stepCompleted(); /// - /// Calculate the Coiflet features + /// Calculate the Daubechies features /// - if(finalWavs.size() != 4*wLevels || - finalSegs.size() != 4*wLevels) + if(collection->getUseFirstOrder() == false && collection->getUseVolumetric() == false && collection->getUseTexture() == false) { - MITK_ERROR << "Size of list of segmentations or of the wavelet-files are not as expected. Aborting."; - return; + // } - - for(int i = wLevels; i > 0; i--) + else { - for(int j = 0; j < 4; j++) + if(finalWavs.size() != 4*wLevels || + finalSegs.size() != 4*wLevels) + { + MITK_ERROR << "Size of list of segmentations or of the wavelet-files are not as expected. Aborting."; + return; + } + + for(int i = wLevels; i > 0; i--) { - int index = (i-1) * 4 + j; - - std::string waveletType = "Lowpass"; - if(j == 3) - waveletType = "H"; - else if(j == 2) - waveletType = "V"; - else if(j == 1) - waveletType = "D"; - - - MITK_WARN << "Calculating Daubechies features (Level " << i << "/" << waveletType << ")."; - emit updateStepIndicator("Calculating Daubechies features (Level " + std::to_string(i) +"/" + waveletType + ")...",0); - - MITK_WARN << "Calulating features for Daubechies " << i<< "/" <getCoocString(), collection->getRunLengthString(), collection->GetDirection(), - collection->getUseFirstOrder(), collection->getUseVolumetric(), collection->getUseTexture()); - emit stepCompleted(); - - emit updateStepIndicator("Writing to file...",0); - mitk::RadiomicsFeatures::writeToCsvFile(stats,collection->getOutputFile(),collection->getName(), - collection->getImageNode()->GetName() + "/Daubechies Level " + std::to_string(i) + "/" + waveletType, //Name of image - collection->getSegmentationNode()->GetName() +"/Daubechies Level " + std::to_string(i) + "/" + waveletType); //Name of segmentation - emit stepCompleted(); - emit workItemCompleted(); + for(int j = 0; j < 4; j++) + { + int index = (i-1) * 4 + j; + + std::string waveletType = "Lowpass"; + if(j == 3) + waveletType = "H"; + else if(j == 2) + waveletType = "V"; + else if(j == 1) + waveletType = "D"; + + + MITK_WARN << "Calculating Daubechies features (Level " << i << "/" << waveletType << ")."; + emit updateStepIndicator("Calculating Daubechies features (Level " + std::to_string(i) +"/" + waveletType + ")...",0); + + MITK_WARN << "Calulating features for Daubechies " << i<< "/" <getCoocString(), collection->getRunLengthString(), collection->GetDirection(), + collection->getUseFirstOrder(), collection->getUseVolumetric(), collection->getUseTexture()); + emit stepCompleted(); + + emit updateStepIndicator("Writing to file...",0); + mitk::RadiomicsFeatures::writeToCsvFile(stats,collection->getOutputFile(),collection->getName(), + collection->getImageNode()->GetName() + "/Daubechies Level " + std::to_string(i) + "/" + waveletType, //Name of image + collection->getSegmentationNode()->GetName() +"/Daubechies Level " + std::to_string(i) + "/" + waveletType); //Name of segmentation + emit stepCompleted(); + emit workItemCompleted(); + } } } } MITK_WARN << "Ready to start new task!"; emit readyToStartNewTask(noOfRun+1); } void QmitkRadiomics::updateStepIndicatorSlot(std::string text, int maximum) { m_Controls.statusLabel->setText(QString::fromStdString(text)); m_Controls.progressIndicator->setMaximum(maximum); } void QmitkRadiomics::addSubNodeSlot(mitk::Image::Pointer image, std::string name) { mitk::DataNode::Pointer tmpWavNode = mitk::DataNode::New(); mitk::Image::Pointer empty = mitk::Image::New(); empty->Initialize(image); tmpWavNode->SetData(empty); tmpWavNode->SetVisibility(false); tmpWavNode->SetName(name); m_WaveletNode = tmpWavNode; this->GetDataStorage()->Add(tmpWavNode,m_ParentNode); } void QmitkRadiomics::addParentNodeSlot(mitk::Image::Pointer image, std::string imageName, mitk::Image::Pointer segmentation, std::string segmentationName, std::string name) { /// /// Add helper objects /// mitk::DataNode::Pointer modifiedNode = mitk::DataNode::New(); mitk::Image::Pointer empty = mitk::Image::New(); empty->Initialize(image); modifiedNode->SetData(empty); modifiedNode->SetVisibility(false); modifiedNode->SetName(name); m_ParentNode = modifiedNode; std::thread::id this_id = std::this_thread::get_id(); MITK_WARN << "Lets add the helper objects from thread " << this_id; try { this->GetDataStorage()->Add(modifiedNode); } catch(mitk::Exception &e) { MITK_ERROR << "ERROR!!!!"; MITK_WARN << e.what(); } //Sleep to prevent some random, non-reproducable crashes.... //std::this_thread::sleep_for(std::chrono::seconds(timeToSleep)); MITK_WARN << "Lets add the helper objects 1!"; //add image to the data storage mitk::DataNode::Pointer childImageNode = mitk::DataNode::New(); childImageNode->SetData(image); childImageNode->SetName(imageName+" Original"); childImageNode->SetVisibility(false); this->GetDataStorage()->Add(childImageNode,modifiedNode); this->GetDataStorage()->Modified(); //Sleep to prevent crashes.... //std::this_thread::sleep_for(std::chrono::seconds(timeToSleep)); MITK_WARN << "Lets add the helper objects 2!"; //add segmentation to the data storage mitk::DataNode::Pointer childSegmentationNode = mitk::DataNode::New(); childSegmentationNode->SetData(segmentation); childSegmentationNode->SetName(segmentationName+" Original"); childSegmentationNode->SetVisibility(false); this->GetDataStorage()->Add(childSegmentationNode,modifiedNode); this->GetDataStorage()->Modified(); } void QmitkRadiomics::updateDataNode(mitk::Image::Pointer image, std::string suffix, bool isWavelet) { if(image == nullptr) { return; } std::thread::id this_id = std::this_thread::get_id(); MITK_WARN << "Calling updateDataNode! " << image->GetGeometry()->GetSpacing() << " from thread " << this_id; mitk::DataNode::Pointer tmpNode = mitk::DataNode::New(); tmpNode->SetData(image); tmpNode->SetVisibility(false); tmpNode->SetName(suffix); if(isWavelet) { this->GetDataStorage()->Add(tmpNode,m_WaveletNode); MITK_WARN << " ---> Adding to wavelet node!"; } else { MITK_WARN << " ---> Adding to parent node!"; this->GetDataStorage()->Add(tmpNode,m_ParentNode); } this->GetDataStorage()->Modified(); } void QmitkRadiomics::onWorkItemFinished() { MITK_WARN << "Work item Completed!"; return; //Single workitem completed m_Controls.statusLabel->setText(""); m_Controls.progressIndicator->setMaximum(1); } void QmitkRadiomics::onPipelineFinished() { MITK_WARN << "Pipeline finished."; m_Controls.statusLabel->setText(""); m_Controls.progressIndicator->setMaximum(1); m_Controls.currentProgress->setValue(0); m_Controls.radiomicsRun->setEnabled(true); m_Controls.btnAddImageSelection->setEnabled(true); m_Controls.btnRemoveSelection->setEnabled(true); m_Controls.layoutSettings->setEnabled(true); m_Controls.imagesLayout->setEnabled(true); m_Controls.layoutSingleImages->setEnabled(true); m_Controls.batchLayout->setEnabled(true); m_Controls.currentProgress->setFormat(""); QMessageBox::information(nullptr,"Calculation completed","The calculation is completed. You can now further process the results."); } void QmitkRadiomics::updateProgressBar() { MITK_WARN << "Update progress bars!"; MITK_WARN << " -> patient progress: " << (m_Controls.currentProgress->value() + 1) << "/" << m_Controls.currentProgress->maximum(); m_Controls.currentProgress->setValue(m_Controls.currentProgress->value() + 1); m_Controls.overallProgress->setValue(m_Controls.overallProgress->value() + 1); } void QmitkRadiomics::updateAfterCompletion(int i) { if(i < m_Collections.size()) { //Everything ok, let's continue! } else { //No more data available. m_Controls.overallProgress->setValue(0); } m_Controls.currentProgress->setValue(0); } void QmitkRadiomics::toggledRegistrationMode(bool useRegistration) { m_Controls.regImageSelector->setEnabled(useRegistration); } void QmitkRadiomics::observeSelectedItems() { if(m_Controls.selectionTreeWidget->selectedItems().size() > 0) { QTreeWidgetItem *tmpItem = m_Controls.selectionTreeWidget->selectedItems()[0]; if(tmpItem->childCount() > 0) m_Controls.btnRemoveSelection->setEnabled(true); else m_Controls.btnRemoveSelection->setEnabled(false); } else m_Controls.btnRemoveSelection->setEnabled(false); } void QmitkRadiomics::doSimpleRadiomicsExample() { MITK_WARN << "Do simple example!"; mitk::DataNode* node = m_Controls.patImageSelector->GetNode(0); //MITK_WARN << "Run simple example"; //mitk::RadiomicsWavelets::simpleExample(node, this->GetDataStorage()); MITK_WARN << "Create Wavelets"; mitk::RadiomicsWavelets::Pointer m_Wavelets = mitk::RadiomicsWavelets::New(); m_Wavelets->setup(); //m_Wavelets->createCoifletWavelets(node,this->GetDataStorage(),m_Controls.waveletLevels->value(),true); } void QmitkRadiomics::addCoocEntry() { if(m_Controls.coOccLabel->text().isEmpty()) { m_Controls.coOccLabel->setText(QString::number(m_Controls.coOccBox->value())); } else { m_Controls.coOccLabel->setText(m_Controls.coOccLabel->text() + ";" + QString::number(m_Controls.coOccBox->value())); } } void QmitkRadiomics::clearCoocList() { m_Controls.coOccLabel->setText(""); } void QmitkRadiomics::addRunLengthEntry() { if(m_Controls.runLengthLabel->text().isEmpty()) { m_Controls.runLengthLabel->setText(QString::number(m_Controls.runLengthBox->value())); } else { m_Controls.runLengthLabel->setText(m_Controls.runLengthLabel->text() + ";" + QString::number(m_Controls.runLengthBox->value())); } } void QmitkRadiomics::clearRunLengthList() { m_Controls.runLengthLabel->setText(""); } void QmitkRadiomics::OnSelectionChanged( berry::IWorkbenchPart::Pointer /*source*/, const QList& nodes ) { // iterate all selected objects, adjust warning visibility foreach( mitk::DataNode::Pointer node, nodes ) { if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { return; } } } void QmitkRadiomics::addImageSegmentationSelection() { if(m_Controls.patImageSelector->count() > 0 && m_Controls.patImageSelector->GetSelectedNode().IsNotNull() && m_Controls.segImageSelector->count() > 0 && m_Controls.segImageSelector->GetSelectedNode().IsNotNull() && m_Controls.outputFileBox->text() != "") { if(m_Controls.checkFirstOrder->isChecked() == false && m_Controls.checkVolumetric->isChecked() == false && m_Controls.checkTexture->isChecked() == false) { QMessageBox msgBox; msgBox.setWindowTitle("Warning"); msgBox.setText("With your current settings no features will be calculated!\nContinue?"); msgBox.setStandardButtons(QMessageBox::Yes); msgBox.addButton(QMessageBox::No); msgBox.setDefaultButton(QMessageBox::No); msgBox.setIcon(QMessageBox::Warning); if(msgBox.exec() == QMessageBox::Yes) { //Nothing to do } else { return; } //QMessageBox::warning(nullptr,"Warning","With your current settings no features will be calculated!"); //return; } mitk::DataNode::Pointer imageNode = m_Controls.patImageSelector->GetSelectedNode(); mitk::DataNode::Pointer segmentationNode = m_Controls.segImageSelector->GetSelectedNode(); mitk::RadiomicsCollection::Pointer tmpCollection = mitk::RadiomicsCollection::New(); tmpCollection->setImageNode(imageNode); tmpCollection->setSegmentationNode(segmentationNode); tmpCollection->setImageNormalization(m_Controls.checkNorm->isChecked()); tmpCollection->setOutputFile(m_Controls.outputFileBox->text().toUtf8().constData()); tmpCollection->setFormatType((mitk::RadiomicsCollection::formatType)m_Controls.formatSelectionBox->currentIndex()); tmpCollection->setUse3d(m_Controls.check3D->isChecked()); tmpCollection->setUseFirstOrder(m_Controls.checkFirstOrder->isChecked()); tmpCollection->setUseVolumetric(m_Controls.checkVolumetric->isChecked()); tmpCollection->setUseTexture(m_Controls.checkTexture->isChecked()); tmpCollection->setCoocString(m_Controls.coOccLabel->text().toUtf8().constData()); tmpCollection->setRunLengthString(m_Controls.runLengthLabel->text().toUtf8().constData()); tmpCollection->setUseNorm(m_Controls.checkNorm->isChecked()); tmpCollection->setUseGeomCorrection(m_Controls.checkGeom->isChecked()); tmpCollection->setUseResampling(m_Controls.checkRes->isChecked()); tmpCollection->SetDirection(m_Controls.check3D->isChecked() ? 0 : 4); //4 Means without direction 2? To be checked!! tmpCollection->SetWaveletLevels(m_Controls.waveletLevels->value()); tmpCollection->setUseDaubechies(m_Controls.checkDaub->isChecked()); tmpCollection->setUseCoiflet(m_Controls.checkCoif->isChecked()); + tmpCollection->SetUseStationary(m_Controls.checkSwt->isChecked()); tmpCollection->SetResX(m_Controls.resXBox->value()); tmpCollection->SetResY(m_Controls.resYBox->value()); tmpCollection->SetResZ(m_Controls.resZBox->value()); QTreeWidgetItem *treeItem = new QTreeWidgetItem(m_Controls.selectionTreeWidget); if(m_Controls.patientName->text() == "") { - treeItem->setText(0, QString("Selection %1 ").arg(m_Counter)); + treeItem->setText(0, QString("Selection %1").arg(m_Counter)); } else { treeItem->setText(0, m_Controls.patientName->text()); } treeItem->setText(1, ""); tmpCollection->setName(treeItem->text(0).toUtf8().constData()); QTreeWidgetItem *imageItem = new QTreeWidgetItem(); imageItem->setText(0, "Image"); imageItem->setText(1, imageNode->GetName().c_str()); QTreeWidgetItem *segmentationItem = new QTreeWidgetItem(); segmentationItem->setText(0, "Segmentation"); segmentationItem->setText(1, segmentationNode->GetName().c_str()); QTreeWidgetItem *registrationItem = new QTreeWidgetItem(); registrationItem->setText(0, "Registration"); if(m_Controls.checkRegistration->isChecked() == true) { mitk::DataNode::Pointer registrationNode = m_Controls.regImageSelector->GetSelectedNode(); tmpCollection->setRegistrationNode(registrationNode); registrationItem->setText(1, registrationNode->GetName().c_str()); } else registrationItem->setText(1, "None"); QTreeWidgetItem *normalizationItem = new QTreeWidgetItem(); normalizationItem->setText(0, "Use Normalization"); normalizationItem->setText(1, m_Controls.checkNorm ? "True" : "False" ); QTreeWidgetItem *outputItem = new QTreeWidgetItem(); outputItem->setText(0, "Output File"); outputItem->setText(1, m_Controls.outputFileBox->text() ); QTreeWidgetItem *use3dItem = new QTreeWidgetItem(); use3dItem->setText(0, "3D Feature Calculation"); use3dItem->setText(1, m_Controls.check3D->isChecked() ? "True" : "False" ); treeItem->addChild(imageItem); treeItem->addChild(segmentationItem); treeItem->addChild(registrationItem); treeItem->addChild(normalizationItem); treeItem->addChild(outputItem); m_Collections.push_back(tmpCollection); m_Counter++; } else { QMessageBox::warning(nullptr,"Warning","You need to specify at least an image and a segmentation and a location for the feature file!"); return; } } void QmitkRadiomics::removeImageSegmentationSelection() { if(m_Controls.selectionTreeWidget->currentIndex().isValid()) { QTreeWidgetItem *tmp = m_Controls.selectionTreeWidget->selectedItems().first(); int index = 0; for(int i = 0; i < m_Collections.size(); i++) { if(m_Collections[i]->getName() == tmp->text(0).toUtf8().constData()) { MITK_WARN << "Removing " + m_Collections[i]->getName(); index = i; break; } } m_Collections.erase(m_Collections.begin() + index); if(tmp == nullptr) { MITK_WARN << "jo"; } delete tmp; } } void QmitkRadiomics::selectOutputFile() { QFileDialog saveDialog; saveDialog.setWindowModality(Qt::WindowModal); saveDialog.setFileMode(QFileDialog::AnyFile); saveDialog.setAcceptMode(QFileDialog::AcceptSave); saveDialog.selectFile("Radiomics.csv"); QString fileName = saveDialog.getSaveFileName(nullptr, tr("Select Output"), QDir::homePath(), tr("Data Files (*.csv *.dat, *.txt)")); if(!fileName.isEmpty() && !fileName.isNull()) { m_Controls.outputFileBox->setText(fileName); } } void QmitkRadiomics::OnWorkingNodeVisibilityChanged() { mitk::DataNode* selectedNode = m_Controls.segImageSelector->GetSelectedNode(); if ( !selectedNode ) { return; } bool selectedNodeIsVisible = selectedNode->IsVisible(mitk::BaseRenderer::GetInstance( mitk::BaseRenderer::GetRenderWindowByName("stdmulti.widget1"))); if (!selectedNodeIsVisible) { } else { } } void QmitkRadiomics::OnBinaryPropertyChanged() { mitk::DataStorage::SetOfObjects::ConstPointer patImages = m_Controls.patImageSelector->GetNodes(); bool isBinary(false); for (mitk::DataStorage::SetOfObjects::ConstIterator it = patImages->Begin(); it != patImages->End(); ++it) { const mitk::DataNode* node = it->Value(); node->GetBoolProperty("binary", isBinary); mitk::LabelSetImage::Pointer labelSetImage = dynamic_cast(node->GetData()); isBinary = isBinary || labelSetImage.IsNotNull(); if(isBinary) { m_Controls.patImageSelector->RemoveNode(node); m_Controls.segImageSelector->AddNode(node); return; } } mitk::DataStorage::SetOfObjects::ConstPointer segImages = m_Controls.segImageSelector->GetNodes(); isBinary = true; for (mitk::DataStorage::SetOfObjects::ConstIterator it = segImages->Begin(); it != segImages->End(); ++it) { const mitk::DataNode* node = it->Value(); node->GetBoolProperty("binary", isBinary); mitk::LabelSetImage::Pointer labelSetImage = dynamic_cast(node->GetData()); isBinary = isBinary || labelSetImage.IsNotNull(); if(!isBinary) { MITK_WARN << "Add to pat image"; m_Controls.segImageSelector->RemoveNode(node); m_Controls.patImageSelector->AddNode(node); if (mitk::ToolManagerProvider::GetInstance()->GetToolManager()->GetWorkingData(0) == node) mitk::ToolManagerProvider::GetInstance()->GetToolManager()->SetWorkingData(NULL); return; } } } void QmitkRadiomics::DoImageProcessing() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataNode* node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return QMessageBox::information( NULL, "Template", "Please load and select an image before starting image processing."); return; } // here we have a valid mitk::DataNode // a node itself is not very useful, we need its data item (the image) mitk::BaseData* data = node->GetData(); if (data) { // test if this data item is an image or not (could also be a surface or something totally different) mitk::Image* image = dynamic_cast( data ); if (image) { std::stringstream message; std::string name; message << "Performing image processing for image "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; } message << "."; MITK_INFO << message.str(); // actually do something here... } } } void QmitkRadiomics::singleImageBatchToggled(bool useSingleImages) { if(useSingleImages == true) { m_Controls.singleImageGroupBox->setVisible(true); m_Controls.batchGroupBox->setVisible(false); } else { m_Controls.singleImageGroupBox->setVisible(false); m_Controls.batchGroupBox->setVisible(true); } } void QmitkRadiomics::patImageChanged() { mitk::PropertyList::Pointer propertyList = m_Controls.patImageSelector->GetSelectedNode()->GetData()->GetPropertyList(); if (propertyList.IsNotNull() && !propertyList->IsEmpty()) { const mitk::PropertyList::PropertyMap* map = propertyList->GetMap(); for (mitk::PropertyList::PropertyMap::const_iterator iter = map->begin(); iter != map->end(); iter++) { if((*iter).first == "path") { QDir path(QString::fromStdString((*iter).second->GetValueAsString())); path.cdUp(); //m_Controls.outputFileBox->setText(path.path() + "/test.csv"); } } } } diff --git a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsControls.ui b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsControls.ui index 8a76f4dc08..5d2f2b02fd 100644 --- a/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsControls.ui +++ b/Plugins/org.mitk.gui.qt.radiomics/src/internal/QmitkRadiomicsControls.ui @@ -1,1307 +1,1307 @@ RadiomicsControls 0 0 370 1488 0 0 QmitkTemplate 0 Images 0 0 341 1000426 8 8 8 8 Use Single Images true false Use Batch Qt::Vertical QSizePolicy::Fixed 20 20 0 0 Single Images 0 20 334 1397 8 8 8 8 QLayout::SetMinimumSize 4 0 0 OutputFile - /media/gaehlert/Data/Gaehlert/experiments/oncorayRadiomics/test.csv + 0 0 20 0 20 16777215 ... 0 0 Segmentation false 0 0 0 0 0 0 0 0 Register To 0 0 Patient Image Patient Name Qt::Vertical QSizePolicy::Fixed 20 15 <html><head/><body><p><span style=" font-weight:600;">Preprocessing</span></p></body></html> Qt::RichText Use Image Normalization true false false Register Image false Qt::Vertical QSizePolicy::Fixed 20 15 <html><head/><body><p><span style=" font-weight:600;">Result-Format</span></p></body></html> Qt::RichText false CSV-Format Wide-Format XML-Format Qt::Vertical QSizePolicy::Fixed 20 20 0 0 Batch Images 0 20 321 301 8 8 8 8 0 0 80 0 80 16777215 Dicrectory /asd/ 0 0 20 0 20 16777215 ... 0 0 80 0 80 16777215 Image Name /asd/ 0 0 20 0 20 16777215 ... 0 0 80 0 80 16777215 Mask Name /asd/ 0 0 20 0 20 16777215 ... Qt::Vertical QSizePolicy::Fixed 20 10 0 0 80 0 80 16777215 Output File /asd/ 0 0 20 0 20 16777215 ... Add Batch Qt::Vertical 20 40 Qt::Vertical QSizePolicy::Expanding 20 20 Settings 0 0 358 658 8 8 8 8 <html><head/><body><p><span style=" font-weight:600;">Preprocessing</span></p></body></html> Qt::RichText Use Geometry Adjustment - false + true Use Resampling - false + true x [mm] Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 3.000000000000000 0.050000000000000 0.250000000000000 y [mm] Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 0 0 3.000000000000000 0.050000000000000 0.250000000000000 z [mm] Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter false 0 0 3.000000000000000 0.050000000000000 3.000000000000000 Qt::Vertical QSizePolicy::Fixed 20 15 <html><head/><body><p><span style=" font-weight:600;">Wavelets</span></p></body></html> Qt::RichText Use Daubechies Wavelets - false + true Use Coiflet Wavelets - false + true - + - false + true - Use Dwt + Stationary Wavelets - true + false 0 0 Wavelet-Levels 0 0 2 2 Qt::Vertical QSizePolicy::Fixed 20 15 <html><head/><body><p><span style=" font-weight:600;">Features</span></p></body></html> Qt::RichText true Calculate Features in 3D false Use First Order Features true Use Volumetric Features true Use Texture Features true Co-Occurrance Steps 1 20 0 0 Add 0 0 Clear 1;2;3 true Qt::Vertical QSizePolicy::Fixed 20 10 Run-Length Bin Sizes 1 1000 10 10 0 0 Add 0 0 Clear 64;128;256 true Qt::Vertical 20 40 Add 0 200 16777215 250 QAbstractItemView::SelectItems Property Value false Remove - Your ad could be placed here for just 0.99€*! + true 1 0 false 0 true 0 true Overall progress: %p% Run! QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h