diff --git a/Applications/Diffusion/CMakeLists.txt b/Applications/Diffusion/CMakeLists.txt index f6af42f8ae..6844ea78d9 100644 --- a/Applications/Diffusion/CMakeLists.txt +++ b/Applications/Diffusion/CMakeLists.txt @@ -1,103 +1,103 @@ #if(MITK_USE_Python) project(MitkDiffusion) set(DIFFUSIONAPP_NAME MitkDiffusion) set(_app_options) if(MITK_SHOW_CONSOLE_WINDOW) list(APPEND _app_options SHOW_CONSOLE) endif() # Create a cache entry for the provisioning file which is used to export # the file name in the MITKConfig.cmake file. This will keep external projects # which rely on this file happy. set(DIFFUSIONIMAGINGAPP_PROVISIONING_FILE "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${DIFFUSIONAPP_NAME}.provisioning" CACHE INTERNAL "${DIFFUSIONAPP_NAME} provisioning file" FORCE) # should be identical to the list in /CMake/mitkBuildConfigurationmitkDiffusion.cmake # remember to set plugins which should be automatically toggled in target_libraries.cmake set(_plugins org.commontk.configadmin org.commontk.eventadmin org.blueberry.core.runtime org.blueberry.core.expressions org.blueberry.core.commands org.blueberry.ui.qt org.blueberry.ui.qt.log org.blueberry.ui.qt.help org.mitk.core.services org.mitk.gui.common org.mitk.planarfigure org.mitk.core.ext org.mitk.gui.qt.application org.mitk.gui.qt.ext org.mitk.gui.qt.diffusionimagingapp org.mitk.gui.qt.common org.mitk.gui.qt.stdmultiwidgeteditor org.mitk.gui.qt.datamanager org.mitk.gui.qt.measurementtoolbox org.mitk.gui.qt.segmentation - org.mitk.gui_qt.multilabelsegmentation +# org.mitk.gui_qt.multilabelsegmentation org.mitk.gui.qt.volumevisualization org.mitk.gui.qt.diffusionimaging org.mitk.gui.qt.diffusionimaging.connectomics org.mitk.gui.qt.diffusionimaging.fiberfox org.mitk.gui.qt.diffusionimaging.fiberprocessing org.mitk.gui.qt.diffusionimaging.ivim org.mitk.gui.qt.diffusionimaging.odfpeaks org.mitk.gui.qt.diffusionimaging.preprocessing org.mitk.gui.qt.diffusionimaging.reconstruction org.mitk.gui.qt.diffusionimaging.tractography org.mitk.gui.qt.diffusionimaging.registration # org.mitk.gui.qt.diffusionimaging.python org.mitk.gui.qt.diffusionimaging.denoising # org.mitk.gui.qt.matchpoint.algorithm.browser # org.mitk.gui.qt.matchpoint.algorithm.control # org.mitk.gui.qt.matchpoint.mapper org.mitk.gui.qt.imagenavigator org.mitk.gui.qt.moviemaker org.mitk.gui.qt.basicimageprocessing org.mitk.gui.qt.properties org.mitk.gui.qt.viewnavigator ) # Plug-ins listed below will not be # - added as a build-time dependency to the executable # - listed in the provisioning file for the executable # - installed if they are external plug-ins set(_exclude_plugins org.blueberry.test org.blueberry.uitest org.mitk.gui.qt.coreapplication org.mitk.gui.qt.extapplication ) set(_src_files MitkDiffusion.cpp ) qt5_add_resources(_src_files splashscreen.qrc) mitkFunctionCreateBlueBerryApplication( NAME ${DIFFUSIONAPP_NAME} DESCRIPTION "MITK Diffusion" PLUGINS ${_plugins} EXCLUDE_PLUGINS ${_exclude_plugins} SOURCES ${_src_files} ${_app_options} ) mitk_use_modules(TARGET ${DIFFUSIONAPP_NAME} MODULES MitkAppUtil) # Add meta dependencies (e.g. on auto-load modules from depending modules) if(TARGET ${CMAKE_PROJECT_NAME}-autoload) add_dependencies(${DIFFUSIONAPP_NAME} ${CMAKE_PROJECT_NAME}-autoload) endif() # Add a build time dependency to legacy BlueBerry bundles. if(MITK_MODULES_ENABLED_PLUGINS) add_dependencies(${DIFFUSIONAPP_NAME} ${MITK_MODULES_ENABLED_PLUGINS}) endif() # endif() # MITK_USE_PYTHON diff --git a/Applications/Diffusion/target_libraries.cmake b/Applications/Diffusion/target_libraries.cmake index f208e9035d..e2b4c14e92 100644 --- a/Applications/Diffusion/target_libraries.cmake +++ b/Applications/Diffusion/target_libraries.cmake @@ -1,35 +1,35 @@ # A list of plug-in targets which should be automatically enabled # (or be available in external projects) for this application set(target_libraries org_blueberry_ui_qt org_blueberry_ui_qt_help org_mitk_planarfigure org_mitk_gui_qt_diffusionimagingapp org_mitk_gui_qt_ext org_mitk_gui_qt_datamanager org_mitk_gui_qt_segmentation - org_mitk_gui_qt_multilabelsegmentation +# org_mitk_gui_qt_multilabelsegmentation org_mitk_gui_qt_volumevisualization org_mitk_gui_qt_diffusionimaging org_mitk_gui_qt_diffusionimaging_connectomics org_mitk_gui_qt_diffusionimaging_fiberfox org_mitk_gui_qt_diffusionimaging_fiberprocessing org_mitk_gui_qt_diffusionimaging_ivim org_mitk_gui_qt_diffusionimaging_odfpeaks org_mitk_gui_qt_diffusionimaging_preprocessing org_mitk_gui_qt_diffusionimaging_reconstruction org_mitk_gui_qt_diffusionimaging_tractography org_mitk_gui_qt_diffusionimaging_registration # org_mitk_gui_qt_diffusionimaging_python org_mitk_gui_qt_diffusionimaging_denoising # org_mitk_gui_qt_matchpoint_algorithm_browser # org_mitk_gui_qt_matchpoint_algorithm_control # org_mitk_gui_qt_matchpoint_mapper org_mitk_gui_qt_imagenavigator org_mitk_gui_qt_moviemaker org_mitk_gui_qt_measurementtoolbox org_mitk_gui_qt_basicimageprocessing org_mitk_gui_qt_viewnavigator ) diff --git a/CMake/BuildConfigurations/DiffusionAll.cmake b/CMake/BuildConfigurations/DiffusionAll.cmake index 96f0ce462e..3b560dac34 100644 --- a/CMake/BuildConfigurations/DiffusionAll.cmake +++ b/CMake/BuildConfigurations/DiffusionAll.cmake @@ -1,37 +1,37 @@ message(STATUS "Configuring MITK Diffusion with all Plugins") # Enable non-optional external dependencies set(MITK_USE_Vigra ON CACHE BOOL "MITK Use Vigra Library" FORCE) set(MITK_USE_HDF5 ON CACHE BOOL "MITK Use HDF5 Library" FORCE) set(MITK_USE_MatchPoint ON CACHE BOOL "" FORCE) set(MITK_USE_DCMTK ON CACHE BOOL "" FORCE) -set(MITK_USE_DCMQI ON CACHE BOOL "" FORCE) -set(MITK_USE_Python ON CACHE BOOL "" FORCE) -set(MITK_USE_BetData ON CACHE BOOL "" FORCE) +#set(MITK_USE_DCMQI ON CACHE BOOL "" FORCE) +#set(MITK_USE_Python ON CACHE BOOL "" FORCE) +#set(MITK_USE_BetData ON CACHE BOOL "" FORCE) # Disable all apps but MITK Diffusion set(MITK_BUILD_ALL_APPS OFF CACHE BOOL "Build all MITK applications" FORCE) set(MITK_BUILD_APP_CoreApp OFF CACHE BOOL "Build the MITK CoreApp" FORCE) set(MITK_BUILD_APP_Diffusion ON CACHE BOOL "Build MITK Diffusion" FORCE) # Activate Diffusion Mini Apps set(BUILD_DiffusionCoreCmdApps ON CACHE BOOL "Build commandline tools for diffusion" FORCE) set(BUILD_DiffusionFiberProcessingCmdApps ON CACHE BOOL "Build commandline tools for diffusion fiber processing" FORCE) set(BUILD_DiffusionFiberfoxCmdApps ON CACHE BOOL "Build commandline tools for diffusion data simulation (Fiberfox)" FORCE) set(BUILD_DiffusionMiscCmdApps ON CACHE BOOL "Build miscellaneous commandline tools for diffusion" FORCE) set(BUILD_DiffusionQuantificationCmdApps ON CACHE BOOL "Build commandline tools for diffusion quantification (IVIM, ADC, ...)" FORCE) set(BUILD_DiffusionTractographyCmdApps ON CACHE BOOL "Build commandline tools for diffusion fiber tractography" FORCE) set(BUILD_DiffusionTractographyEvaluationCmdApps ON CACHE BOOL "Build commandline tools for diffusion fiber tractography evaluation" FORCE) set(BUILD_DiffusionConnectomicsCmdApps ON CACHE BOOL "Build commandline tools for diffusion connectomics" FORCE) # Build neither all plugins nor examples set(MITK_BUILD_ALL_PLUGINS OFF CACHE BOOL "Build all MITK plugins" FORCE) set(MITK_BUILD_EXAMPLES OFF CACHE BOOL "Build the MITK examples" FORCE) set(BUILD_TESTING ON CACHE BOOL "Build the MITK tests" FORCE) # Activate in-application help generation set(MITK_DOXYGEN_GENERATE_QCH_FILES ON CACHE BOOL "Use doxygen to generate Qt compressed help files for MITK docs" FORCE) set(BLUEBERRY_USE_QT_HELP ON CACHE BOOL "Enable support for integrating bundle documentation into Qt Help" FORCE) # Disable console window set(MITK_SHOW_CONSOLE_WINDOW ON CACHE BOOL "Use this to enable or disable the console window when starting MITK GUI Applications" FORCE) diff --git a/CMakeExternals/MITKData.cmake b/CMakeExternals/MITKData.cmake index 5eedb42547..d0987a8d8b 100644 --- a/CMakeExternals/MITKData.cmake +++ b/CMakeExternals/MITKData.cmake @@ -1,37 +1,37 @@ #----------------------------------------------------------------------------- # MITK Data #----------------------------------------------------------------------------- # Sanity checks if(DEFINED MITK_DATA_DIR AND NOT EXISTS ${MITK_DATA_DIR}) message(FATAL_ERROR "MITK_DATA_DIR variable is defined but corresponds to non-existing directory") endif() set(proj MITK-Data) set(proj_DEPENDENCIES) set(MITK-Data_DEPENDS ${proj}) if(BUILD_TESTING) - set(revision_tag da5dd4ff) # first 8 characters of hash-tag +# set(revision_tag da5dd4ff) # first 8 characters of hash-tag # ^^^^^^^^ these are just to check correct length of hash part ExternalProject_Add(${proj} SOURCE_DIR ${proj} GIT_REPOSITORY https://phabricator.mitk.org/source/mitkdata.git - GIT_TAG ${revision_tag} +# GIT_TAG ${revision_tag} # URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/mitk-data_${revision_tag}.tar.gz # UPDATE_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" DEPENDS ${proj_DEPENDENCIES} ) set(MITK_DATA_DIR ${CMAKE_CURRENT_BINARY_DIR}/${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif(BUILD_TESTING) diff --git a/CMakeLists.txt b/CMakeLists.txt index 39c5f3c21f..bbeefc4676 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,1335 +1,1347 @@ set(MITK_CMAKE_MINIMUM_REQUIRED_VERSION 3.10) cmake_minimum_required(VERSION ${MITK_CMAKE_MINIMUM_REQUIRED_VERSION}) #----------------------------------------------------------------------------- # See https://cmake.org/cmake/help/v3.10/manual/cmake-policies.7.html for details #----------------------------------------------------------------------------- set(project_policies ) foreach(policy ${project_policies}) if(POLICY ${policy}) cmake_policy(SET ${policy} NEW) endif() endforeach() #----------------------------------------------------------------------------- # MITK Extension Feature #----------------------------------------------------------------------------- set(MITK_EXTENSION_DIRS "" CACHE STRING "") mark_as_advanced(MITK_EXTENSION_DIRS) #----------------------------------------------------------------------------- # 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.11.99) include_directories(SYSTEM ${MITK_SUPERBUILD_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # Update CMake module path #----------------------------------------------------------------------------- set(MITK_CMAKE_DIR ${MITK_SOURCE_DIR}/CMake) set(CMAKE_MODULE_PATH ${MITK_CMAKE_DIR}) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_CMAKE_EXTENSION_DIR ${MITK_EXTENSION_DIR}/CMake) get_filename_component(MITK_CMAKE_EXTENSION_DIR ${MITK_CMAKE_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_CMAKE_EXTENSION_DIR}) list(APPEND CMAKE_MODULE_PATH ${MITK_CMAKE_EXTENSION_DIR}) endif() endforeach() #----------------------------------------------------------------------------- # 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.9 as provided by ppa:ubuntu-toolchain-r/test for Ubuntu 14.04 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) message(FATAL_ERROR "GCC version must be at least 4.9 If you are using Ubuntu 14.04, you can easily install gcc and g++ 4.9 (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.9 g++-4.9 Make sure to explicitly specify these compilers when configuring MITK: CMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc-4.9 CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/g++-4.9 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 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 2015 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19) message(FATAL_ERROR "Microsoft Visual Studio 2015 Update 3 or newer required") 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 14) 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++14 flag for targets. # However, compile flag checks also need to be done with -std=c++14. # The MITK_CXX14_FLAG variable is also used for external projects # build during the MITK super-build. mitkFunctionCheckCompilerFlags("-std=c++14" MITK_CXX14_FLAG) #----------------------------------------------------------------------------- # 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_Qt5 "Use Qt 5 library" ON) if(MITK_USE_Qt5) set(MITK_QT5_MINIMUM_VERSION 5.6.0) set(MITK_QT5_COMPONENTS Concurrent OpenGL PrintSupport Script Sql Svg Widgets Xml XmlPatterns WebEngineWidgets 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) endif() set_property(GLOBAL PROPERTY MITK_EXTERNAL_PROJECTS "") include(CMakeExternals/ExternalProjectList.cmake) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_CMAKE_EXTERNALS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/CMakeExternals) get_filename_component(MITK_CMAKE_EXTERNALS_EXTENSION_DIR ${MITK_CMAKE_EXTERNALS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_CMAKE_EXTERNALS_EXTENSION_DIR}/ExternalProjectList.cmake) include(${MITK_CMAKE_EXTERNALS_EXTENSION_DIR}/ExternalProjectList.cmake) endif() endforeach() # ----------------------------------------- # 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") # 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() find_package(PythonLibs REQUIRED) find_package(PythonInterp REQUIRED) 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-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(mitkFunctionGetLibrarySearchPaths) include(mitkFunctionGetVersion) include(mitkFunctionGetVersionDescription) include(mitkFunctionInstallAutoLoadModules) include(mitkFunctionInstallCTKPlugin) include(mitkFunctionInstallProvisioningFiles) include(mitkFunctionInstallThirdPartyCTKPlugins) include(mitkFunctionOrganizeSources) include(mitkFunctionTestPlugin) include(mitkFunctionUseModules) if( ${MITK_USE_MatchPoint} ) include(mitkFunctionCreateMatchPointDeployedAlgorithm) endif() 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++14 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) 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_DEFAULT_MODULE_NAME_PREFIX "Mitk") set(MITK_MODULE_NAME_PREFIX ${MITK_DEFAULT_MODULE_NAME_PREFIX}) 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_CXX14_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) 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}) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_PACKAGE_DEPENDS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/CMake/PackageDepends) get_filename_component(MITK_PACKAGE_DEPENDS_EXTENSION_DIR ${MITK_PACKAGE_DEPENDS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_PACKAGE_DEPENDS_EXTENSION_DIR}) list(APPEND MODULES_PACKAGE_DEPENDS_DIRS ${MITK_PACKAGE_DEPENDS_EXTENSION_DIR}) endif() endforeach() 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.65" "1.65.1") # 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. + + if(DEFINED ${_package}_DIR) + #we store the information because it will be overwritten by find_package + #and would get lost for all EPs that use on Find.cmake instead of config + #files. + set(_temp_EP_${_package}_dir ${${_package}_DIR}) + endif(DEFINED ${_package}_DIR) + find_package(${_package} QUIET CONFIG) string(TOUPPER "${_package}" _package_uc) if(NOT (${_package}_FOUND OR ${_package_uc}_FOUND)) + if(DEFINED _temp_EP_${_package}_dir) + set(${_package}_DIR ${_temp_EP_${_package}_dir} CACHE PATH "externaly set dir of the package ${_package}" FORCE) + endif(DEFINED _temp_EP_${_package}_dir) + 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_DCMQI) # Due to the preferred CONFIG mode in find_package calls above, # the DCMQIConfig.cmake file is read, which does not provide useful # package information. We explictly need MODULE mode to find DCMQI. # Help our FindDCMQI.cmake script find our super-build DCMQI set(DCMQI_DIR ${MITK_EXTERNAL_PROJECT_PREFIX}) find_package(DCMQI REQUIRED) endif() if(MITK_USE_Python) find_package(PythonLibs REQUIRED) find_package(PythonInterp REQUIRED) if(MITK_USE_Numpy) find_package(Numpy REQUIRED) endif() endif() link_directories(${Boost_LIBRARY_DIRS}) if(MITK_USE_OpenIGTLink) 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_Qt5) 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 MITK_USE_Qt5) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because MITK_USE_Qt5 is OFF.") 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) include("${CMAKE_CURRENT_SOURCE_DIR}/Modules/ModuleList.cmake") mitkFunctionWhitelistModules(MITK MITK_MODULES) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_MODULES_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Modules) get_filename_component(MITK_MODULES_EXTENSION_DIR ${MITK_MODULES_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_MODULES_EXTENSION_DIR}/ModuleList.cmake) set(MITK_MODULES "") include(${MITK_MODULES_EXTENSION_DIR}/ModuleList.cmake) foreach(mitk_module ${MITK_MODULES}) add_subdirectory(${MITK_MODULES_EXTENSION_DIR}/${mitk_module} Modules/${mitk_module}) endforeach() endif() set(MITK_MODULE_NAME_PREFIX ${MITK_DEFAULT_MODULE_NAME_PREFIX}) endforeach() add_subdirectory(Wrapping) if(MITK_USE_BLUEBERRY) set(BLUEBERRY_XPDOC_OUTPUT_DIR ${MITK_DOXYGEN_OUTPUT_DIR}/html/extension-points/html/) # 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() set(MITK_PLUGIN_REGEX_LIST "") foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_PLUGINS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Plugins) get_filename_component(MITK_PLUGINS_EXTENSION_DIR ${MITK_PLUGINS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_PLUGINS_EXTENSION_DIR}/PluginList.cmake) set(MITK_PLUGINS "") include(${MITK_PLUGINS_EXTENSION_DIR}/PluginList.cmake) foreach(mitk_plugin ${MITK_PLUGINS}) list(APPEND mitk_plugins_fullpath ${MITK_PLUGINS_EXTENSION_DIR}/${mitk_plugin}) endforeach() endif() 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 MITK_PLUGIN_REGEX_LIST 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) #----------------------------------------------------------------------------- # MITK Applications #----------------------------------------------------------------------------- # This must come after MITKConfig.h was generated, since applications # might do a find_package(MITK REQUIRED). add_subdirectory(Applications) if(MSVC AND TARGET MitkWorkbench) set_directory_properties(PROPERTIES VS_STARTUP_PROJECT MitkWorkbench) endif() #----------------------------------------------------------------------------- # 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/DiffusionImaging/DiffusionCore/include/mitkDiffusionFunctionCollection.h b/Modules/DiffusionImaging/DiffusionCore/include/mitkDiffusionFunctionCollection.h index ab1930a3ba..3850182022 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/mitkDiffusionFunctionCollection.h +++ b/Modules/DiffusionImaging/DiffusionCore/include/mitkDiffusionFunctionCollection.h @@ -1,119 +1,121 @@ /*=================================================================== 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 __mitkDiffusionFunctionCollection_h_ #define __mitkDiffusionFunctionCollection_h_ #include #include #include #include #include #include #include namespace mitk{ -class imv +class MITKDIFFUSIONCORE_EXPORT imv { public: + static std::vector< std::pair< itk::Index<3>, double > > IntersectImage(itk::Vector& spacing, itk::Index<3>& si, itk::Index<3>& ei, itk::ContinuousIndex& sf, itk::ContinuousIndex& ef); + template< class TPixelType, class TOutPixelType=TPixelType > static TOutPixelType GetImageValue(const itk::Point& itkP, bool interpolate, typename itk::LinearInterpolateImageFunction< itk::Image< TPixelType, 3 >, float >::Pointer interpolator) { if (interpolator==nullptr) return 0.0; itk::ContinuousIndex< float, 3> cIdx; interpolator->ConvertPointToContinuousIndex(itkP, cIdx); if (interpolator->IsInsideBuffer(cIdx)) { if (interpolate) return interpolator->EvaluateAtContinuousIndex(cIdx); else { itk::Index<3> idx; interpolator->ConvertContinuousIndexToNearestIndex(cIdx, idx); return interpolator->EvaluateAtIndex(idx); } } else return 0.0; } template< class TPixelType=unsigned char > static bool IsInsideMask(const itk::Point& itkP, bool interpolate, typename itk::LinearInterpolateImageFunction< itk::Image< TPixelType, 3 >, float >::Pointer interpolator, float threshold=0.5) { if (interpolator==nullptr) return false; itk::ContinuousIndex< float, 3> cIdx; interpolator->ConvertPointToContinuousIndex(itkP, cIdx); if (interpolator->IsInsideBuffer(cIdx)) { double value = 0.0; if (interpolate) value = interpolator->EvaluateAtContinuousIndex(cIdx); else { itk::Index<3> idx; interpolator->ConvertContinuousIndexToNearestIndex(cIdx, idx); value = interpolator->EvaluateAtIndex(idx); } if (value>=threshold) return true; } return false; } }; class MITKDIFFUSIONCORE_EXPORT sh { public: static double factorial(int number); static void Cart2Sph(double x, double y, double z, double* spherical); static double legendre0(int l); static double spherical_harmonic(int m,int l,double theta,double phi, bool complexPart); static double Yj(int m, int k, float theta, float phi, bool mrtrix=true); static vnl_matrix CalcShBasisForDirections(int sh_order, vnl_matrix U, bool mrtrix=true); }; class MITKDIFFUSIONCORE_EXPORT gradients { private: typedef std::vector IndiciesVector; typedef std::map BValueMap; typedef itk::VectorContainer< unsigned int, vnl_vector_fixed< double, 3 > > GradientDirectionContainerType; typedef vnl_vector_fixed GradientDirectionType; public: static std::vector GetAllUniqueDirections(const BValueMap &bValueMap, GradientDirectionContainerType *refGradientsContainer ); static bool CheckForDifferingShellDirections(const BValueMap &bValueMap, GradientDirectionContainerType::ConstPointer refGradientsContainer); static vnl_matrix ComputeSphericalHarmonicsBasis(const vnl_matrix & QBallReference, const unsigned int & LOrder); static vnl_matrix ComputeSphericalFromCartesian(const IndiciesVector & refShell, const GradientDirectionContainerType * refGradientsContainer); static mitk::gradients::GradientDirectionContainerType::Pointer CreateNormalizedUniqueGradientDirectionContainer(const BValueMap &bValueMap, const GradientDirectionContainerType * origninalGradentcontainer); }; } #endif //__mitkDiffusionFunctionCollection_h_ diff --git a/Modules/DiffusionImaging/DiffusionCore/src/mitkDiffusionFunctionCollection.cpp b/Modules/DiffusionImaging/DiffusionCore/src/mitkDiffusionFunctionCollection.cpp index 20e2350431..66f7abfc17 100644 --- a/Modules/DiffusionImaging/DiffusionCore/src/mitkDiffusionFunctionCollection.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/src/mitkDiffusionFunctionCollection.cpp @@ -1,282 +1,381 @@ /*=================================================================== 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 "mitkDiffusionFunctionCollection.h" #include "mitkNumericTypes.h" // Namespace ::SH #include #include #include #include // Namespace ::Gradients #include "itkVectorContainer.h" #include "vnl/vnl_vector.h" +#include +#include + +// Intersect a finite line (with end points p0 and p1) with all of the +// cells of a vtkImageData +std::vector< std::pair< itk::Index<3>, double > > mitk::imv::IntersectImage(itk::Vector& spacing, itk::Index<3>& si, itk::Index<3>& ei, itk::ContinuousIndex& sf, itk::ContinuousIndex& ef) +{ + std::vector< std::pair< itk::Index<3>, double > > out; + if (si == ei) + { + double d[3]; + for (int i=0; i<3; ++i) + d[i] = (sf[i]-ef[i])*spacing[i]; + double len = std::sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ); + out.push_back( std::pair< itk::Index<3>, double >(si, len) ); + return out; + } + + double bounds[6]; + + double entrancePoint[3]; + double exitPoint[3]; + + double startPoint[3]; + double endPoint[3]; + + double t0, t1; + for (int i=0; i<3; ++i) + { + startPoint[i] = sf[i]; + endPoint[i] = ef[i]; + + if (si[i]>ei[i]) + { + int t = si[i]; + si[i] = ei[i]; + ei[i] = t; + } + } + + for (int x = si[0]; x<=ei[0]; ++x) + for (int y = si[1]; y<=ei[1]; ++y) + for (int z = si[2]; z<=ei[2]; ++z) + { + bounds[0] = (double)x - 0.5; + bounds[1] = (double)x + 0.5; + bounds[2] = (double)y - 0.5; + bounds[3] = (double)y + 0.5; + bounds[4] = (double)z - 0.5; + bounds[5] = (double)z + 0.5; + + int entryPlane; + int exitPlane; + int hit = vtkBox::IntersectWithLine(bounds, + startPoint, + endPoint, + t0, + t1, + entrancePoint, + exitPoint, + entryPlane, + exitPlane); + if (hit) + { + if (entryPlane>=0 && exitPlane>=0) + { + double d[3]; + for (int i=0; i<3; ++i) + d[i] = (exitPoint[i] - entrancePoint[i])*spacing[i]; + double len = std::sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ); + + itk::Index<3> idx; idx[0] = x; idx[1] = y; idx[2] = z; + out.push_back( std::pair< itk::Index<3>, double >(idx, len) ); + } + else if (entryPlane>=0) + { + double d[3]; + for (int i=0; i<3; ++i) + d[i] = (ef[i] - entrancePoint[i])*spacing[i]; + double len = std::sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ); + + itk::Index<3> idx; idx[0] = x; idx[1] = y; idx[2] = z; + out.push_back( std::pair< itk::Index<3>, double >(idx, len) ); + } + else if (exitPlane>=0) + { + double d[3]; + for (int i=0; i<3; ++i) + d[i] = (exitPoint[i]-sf[i])*spacing[i]; + double len = std::sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ); + + itk::Index<3> idx; idx[0] = x; idx[1] = y; idx[2] = z; + out.push_back( std::pair< itk::Index<3>, double >(idx, len) ); + } + } + } + return out; +} + //------------------------- SH-function ------------------------------------ double mitk::sh::factorial(int number) { if(number <= 1) return 1; double result = 1.0; for(int i=1; i<=number; i++) result *= i; return result; } void mitk::sh::Cart2Sph(double x, double y, double z, double *spherical) { double phi, th, rad; rad = sqrt(x*x+y*y+z*z); if( rad < mitk::eps ) { th = itk::Math::pi/2; phi = itk::Math::pi/2; } else { th = acos(z/rad); phi = atan2(y, x); } spherical[0] = phi; spherical[1] = th; spherical[2] = rad; } double mitk::sh::legendre0(int l) { if( l%2 != 0 ) { return 0; } else { double prod1 = 1.0; for(int i=1;i(l,abs(m),-cos(theta)); double mag = sqrt((double)(2*l+1)/(4.0*itk::Math::pi)*::boost::math::factorial(l-abs(m))/::boost::math::factorial(l+abs(m)))*plm; if (m>0) return mag*cos(m*phi); else if (m==0) return mag; else return mag*sin(-m*phi); } return 0; } vnl_matrix mitk::sh::CalcShBasisForDirections(int sh_order, vnl_matrix U, bool mrtrix) { vnl_matrix sh_basis = vnl_matrix(U.cols(), (sh_order*sh_order + sh_order + 2)/2 + sh_order ); for(unsigned int i=0; i mitk::gradients::GetAllUniqueDirections(const BValueMap & refBValueMap, GradientDirectionContainerType *refGradientsContainer ) { IndiciesVector directioncontainer; auto mapIterator = refBValueMap.begin(); if(refBValueMap.find(0) != refBValueMap.end() && refBValueMap.size() > 1) mapIterator++; //skip bzero Values for( ; mapIterator != refBValueMap.end(); mapIterator++){ IndiciesVector currentShell = mapIterator->second; while(currentShell.size()>0) { unsigned int wntIndex = currentShell.back(); currentShell.pop_back(); auto containerIt = directioncontainer.begin(); bool directionExist = false; while(containerIt != directioncontainer.end()) { if (fabs(dot_product(refGradientsContainer->ElementAt(*containerIt), refGradientsContainer->ElementAt(wntIndex))) > 0.9998) { directionExist = true; break; } containerIt++; } if(!directionExist) { directioncontainer.push_back(wntIndex); } } } return directioncontainer; } bool mitk::gradients::CheckForDifferingShellDirections(const BValueMap & refBValueMap, GradientDirectionContainerType::ConstPointer refGradientsContainer) { auto mapIterator = refBValueMap.begin(); if(refBValueMap.find(0) != refBValueMap.end() && refBValueMap.size() > 1) mapIterator++; //skip bzero Values for( ; mapIterator != refBValueMap.end(); mapIterator++){ auto mapIterator_2 = refBValueMap.begin(); if(refBValueMap.find(0) != refBValueMap.end() && refBValueMap.size() > 1) mapIterator_2++; //skip bzero Values for( ; mapIterator_2 != refBValueMap.end(); mapIterator_2++){ if(mapIterator_2 == mapIterator) continue; IndiciesVector currentShell = mapIterator->second; IndiciesVector testShell = mapIterator_2->second; for (unsigned int i = 0; i< currentShell.size(); i++) if (fabs(dot_product(refGradientsContainer->ElementAt(currentShell[i]), refGradientsContainer->ElementAt(testShell[i]))) <= 0.9998) { return true; } } } return false; } vnl_matrix mitk::gradients::ComputeSphericalFromCartesian(const IndiciesVector & refShell, const GradientDirectionContainerType * refGradientsContainer) { vnl_matrix Q(3, refShell.size()); Q.fill(0.0); for(unsigned int i = 0; i < refShell.size(); i++) { GradientDirectionType dir = refGradientsContainer->ElementAt(refShell[i]); double x = dir.normalize().get(0); double y = dir.normalize().get(1); double z = dir.normalize().get(2); double cart[3]; mitk::sh::Cart2Sph(x,y,z,cart); Q(0,i) = cart[0]; Q(1,i) = cart[1]; Q(2,i) = cart[2]; } return Q; } vnl_matrix mitk::gradients::ComputeSphericalHarmonicsBasis(const vnl_matrix & QBallReference, const unsigned int & LOrder) { vnl_matrix SHBasisOutput(QBallReference.cols(), (LOrder+1)*(LOrder+2)*0.5); SHBasisOutput.fill(0.0); for(int i=0; i< (int)SHBasisOutput.rows(); i++) for(int k = 0; k <= (int)LOrder; k += 2) for(int m =- k; m <= k; m++) { int j = ( k * k + k + 2 ) / 2.0 + m - 1; double phi = QBallReference(0,i); double th = QBallReference(1,i); double val = mitk::sh::Yj(m,k,th,phi); SHBasisOutput(i,j) = val; } return SHBasisOutput; } mitk::gradients::GradientDirectionContainerType::Pointer mitk::gradients::CreateNormalizedUniqueGradientDirectionContainer(const mitk::gradients::BValueMap & bValueMap, - const GradientDirectionContainerType *origninalGradentcontainer) + const GradientDirectionContainerType *origninalGradentcontainer) { mitk::gradients::GradientDirectionContainerType::Pointer directioncontainer = mitk::gradients::GradientDirectionContainerType::New(); auto mapIterator = bValueMap.begin(); if(bValueMap.find(0) != bValueMap.end() && bValueMap.size() > 1){ mapIterator++; //skip bzero Values vnl_vector_fixed vec; vec.fill(0.0); directioncontainer->push_back(vec); } for( ; mapIterator != bValueMap.end(); mapIterator++){ IndiciesVector currentShell = mapIterator->second; while(currentShell.size()>0) { unsigned int wntIndex = currentShell.back(); currentShell.pop_back(); mitk::gradients::GradientDirectionContainerType::Iterator containerIt = directioncontainer->Begin(); bool directionExist = false; while(containerIt != directioncontainer->End()) { if (fabs(dot_product(containerIt.Value(), origninalGradentcontainer->ElementAt(wntIndex))) > 0.9998) { directionExist = true; break; } containerIt++; } if(!directionExist) { GradientDirectionType dir(origninalGradentcontainer->ElementAt(wntIndex)); directioncontainer->push_back(dir.normalize()); } } } return directioncontainer; } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.cpp index 2d9645a07a..3c7f599a2d 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.cpp @@ -1,971 +1,997 @@ #include "itkFitFibersToImageFilter.h" #include +#include namespace itk{ FitFibersToImageFilter::FitFibersToImageFilter() : m_PeakImage(nullptr) , m_DiffImage(nullptr) , m_ScalarImage(nullptr) , m_MaskImage(nullptr) , m_FitIndividualFibers(true) , m_GradientTolerance(1e-5) , m_Lambda(0.1) , m_MaxIterations(20) - , m_FiberSampling(10) , m_Coverage(0) , m_Overshoot(0) , m_RMSE(0.0) , m_FilterOutliers(false) , m_MeanWeight(1.0) , m_MedianWeight(1.0) , m_MinWeight(1.0) , m_MaxWeight(1.0) , m_Verbose(true) - , m_DeepCopy(true) - , m_ResampleFibers(true) , m_NumUnknowns(0) , m_NumResiduals(0) , m_NumCoveredDirections(0) , m_SignalModel(nullptr) , sz_x(0) , sz_y(0) , sz_z(0) , m_MeanTractDensity(0) , m_MeanSignal(0) , fiber_count(0) , m_Regularization(VnlCostFunction::REGU::VOXEL_VARIANCE) { this->SetNumberOfRequiredOutputs(3); } FitFibersToImageFilter::~FitFibersToImageFilter() { } +itk::Point FitFibersToImageFilter::GetItkPoint(double point[3]) +{ + itk::Point itkPoint; + itkPoint[0] = point[0]; + itkPoint[1] = point[1]; + itkPoint[2] = point[2]; + return itkPoint; +} + void FitFibersToImageFilter::CreateDiffSystem() { sz_x = m_DiffImage->GetLargestPossibleRegion().GetSize(0); sz_y = m_DiffImage->GetLargestPossibleRegion().GetSize(1); sz_z = m_DiffImage->GetLargestPossibleRegion().GetSize(2); dim_four_size = m_DiffImage->GetVectorLength(); int num_voxels = sz_x*sz_y*sz_z; - float minSpacing = 1; - if(m_DiffImage->GetSpacing()[0]GetSpacing()[1] && m_DiffImage->GetSpacing()[0]GetSpacing()[2]) - minSpacing = m_DiffImage->GetSpacing()[0]; - else if (m_DiffImage->GetSpacing()[1] < m_DiffImage->GetSpacing()[2]) - minSpacing = m_DiffImage->GetSpacing()[1]; - else - minSpacing = m_DiffImage->GetSpacing()[2]; - - if (m_ResampleFibers) - for (unsigned int bundle=0; bundleGetDeepCopy(); - m_Tractograms.at(bundle)->ResampleLinear(minSpacing/m_FiberSampling); - std::cout.rdbuf (old); - } + auto spacing = m_DiffImage->GetSpacing(); m_NumResiduals = num_voxels * dim_four_size; MITK_INFO << "Num. unknowns: " << m_NumUnknowns; MITK_INFO << "Num. residuals: " << m_NumResiduals; MITK_INFO << "Creating system ..."; A.set_size(m_NumResiduals, m_NumUnknowns); b.set_size(m_NumResiduals); b.fill(0.0); m_MeanTractDensity = 0; m_MeanSignal = 0; m_NumCoveredDirections = 0; fiber_count = 0; vnl_vector voxel_indicator; voxel_indicator.set_size(sz_x*sz_y*sz_z); voxel_indicator.fill(0); + int numFibers = 0; + for (unsigned int bundle=0; bundleGetNumFibers(); + boost::progress_display disp(numFibers); m_GroupSizes.clear(); for (unsigned int bundle=0; bundle polydata = m_Tractograms.at(bundle)->GetFiberPolyData(); m_GroupSizes.push_back(m_Tractograms.at(bundle)->GetNumFibers()); for (int i=0; iGetNumFibers(); ++i) { + ++disp; vtkCell* cell = polydata->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (numPoints<2) MITK_INFO << "FIBER WITH ONLY ONE POINT ENCOUNTERED!"; for (int j=0; jGetPoint(j); - PointType3 p; - p[0]=p1[0]; - p[1]=p1[1]; - p[2]=p1[2]; - - itk::Index<3> idx3; - m_DiffImage->TransformPhysicalPointToIndex(p, idx3); - if (!m_DiffImage->GetLargestPossibleRegion().IsInside(idx3) || (m_MaskImage.IsNotNull() && m_MaskImage->GetPixel(idx3)==0)) - continue; + PointType3 startVertex = GetItkPoint(points->GetPoint(j)); + itk::Index<3> startIndex; + itk::ContinuousIndex startIndexCont; + m_DiffImage->TransformPhysicalPointToIndex(startVertex, startIndex); + m_DiffImage->TransformPhysicalPointToContinuousIndex(startVertex, startIndexCont); + + PointType3 endVertex = GetItkPoint(points->GetPoint(j+1)); + itk::Index<3> endIndex; + itk::ContinuousIndex endIndexCont; + m_DiffImage->TransformPhysicalPointToIndex(endVertex, endIndex); + m_DiffImage->TransformPhysicalPointToContinuousIndex(endVertex, endIndexCont); - double* p2 = points->GetPoint(j+1); mitk::DiffusionSignalModel<>::GradientType fiber_dir; - fiber_dir[0] = p[0]-p2[0]; - fiber_dir[1] = p[1]-p2[1]; - fiber_dir[2] = p[2]-p2[2]; + fiber_dir[0] = endVertex[0]-startVertex[0]; + fiber_dir[1] = endVertex[1]-startVertex[1]; + fiber_dir[2] = endVertex[2]-startVertex[2]; fiber_dir.Normalize(); - int x = idx3[0]; - int y = idx3[1]; - int z = idx3[2]; - - mitk::DiffusionSignalModel<>::PixelType simulated_pixel = m_SignalModel->SimulateMeasurement(fiber_dir); - VectorImgType::PixelType measured_pixel = m_DiffImage->GetPixel(idx3); - - double simulated_mean = 0; - double measured_mean = 0; - int num_nonzero_g = 0; - for (int g=0; g, double > > segments = mitk::imv::IntersectImage(spacing, startIndex, endIndex, startIndexCont, endIndexCont); + for (std::pair< itk::Index<3>, double > seg : segments) { - if( m_SignalModel->GetGradientDirection(g).GetNorm()GetLargestPossibleRegion().IsInside(seg.first) || (m_MaskImage.IsNotNull() && m_MaskImage->GetPixel(seg.first)==0)) continue; - simulated_mean += simulated_pixel[g]; - measured_mean += (double)measured_pixel[g]; - ++num_nonzero_g; - } - simulated_mean /= num_nonzero_g; - measured_mean /= num_nonzero_g; - simulated_pixel -= simulated_mean; - if (voxel_indicator[x + sz_x*y + sz_x*sz_y*z]==0) - m_MeanSignal += measured_mean; - m_MeanTractDensity += simulated_mean; - voxel_indicator[x + sz_x*y + sz_x*sz_y*z] = 1; + int x = seg.first[0]; + int y = seg.first[1]; + int z = seg.first[2]; - for (int g=0; g::PixelType simulated_pixel = m_SignalModel->SimulateMeasurement(fiber_dir)*seg.second; + VectorImgType::PixelType measured_pixel = m_DiffImage->GetPixel(seg.first); - if (m_FitIndividualFibers) + double simulated_mean = 0; + double measured_mean = 0; + int num_nonzero_g = 0; + for (int g=0; gGetGradientDirection(g).GetNorm()GetLargestPossibleRegion().GetSize(0); sz_y = m_PeakImage->GetLargestPossibleRegion().GetSize(1); sz_z = m_PeakImage->GetLargestPossibleRegion().GetSize(2); dim_four_size = m_PeakImage->GetLargestPossibleRegion().GetSize(3)/3 + 1; // +1 for zero - peak int num_voxels = sz_x*sz_y*sz_z; - float minSpacing = 1; - if(m_PeakImage->GetSpacing()[0]GetSpacing()[1] && m_PeakImage->GetSpacing()[0]GetSpacing()[2]) - minSpacing = m_PeakImage->GetSpacing()[0]; - else if (m_PeakImage->GetSpacing()[1] < m_PeakImage->GetSpacing()[2]) - minSpacing = m_PeakImage->GetSpacing()[1]; - else - minSpacing = m_PeakImage->GetSpacing()[2]; + itk::Vector< double, 3 > spacing; + spacing[0] = m_PeakImage->GetSpacing()[0]; + spacing[1] = m_PeakImage->GetSpacing()[1]; + spacing[2] = m_PeakImage->GetSpacing()[2]; - if (m_ResampleFibers) - for (unsigned int bundle=0; bundleGetDeepCopy(); - m_Tractograms.at(bundle)->ResampleLinear(minSpacing/m_FiberSampling); - std::cout.rdbuf (old); - } + PointType3 origin; + origin[0] = m_PeakImage->GetOrigin()[0]; + origin[1] = m_PeakImage->GetOrigin()[1]; + origin[2] = m_PeakImage->GetOrigin()[2]; + + UcharImgType::RegionType::SizeType size; + size[0] = m_PeakImage->GetLargestPossibleRegion().GetSize()[0]; + size[1] = m_PeakImage->GetLargestPossibleRegion().GetSize()[1]; + size[2] = m_PeakImage->GetLargestPossibleRegion().GetSize()[2]; + UcharImgType::RegionType imageRegion; imageRegion.SetSize(size); + + itk::Matrix direction; + for (int r=0; r<3; r++) + for (int c=0; c<3; c++) + direction[r][c] = m_PeakImage->GetDirection()[r][c]; + + if (m_MaskImage.IsNull()) + { + m_MaskImage = UcharImgType::New(); + m_MaskImage->SetSpacing( spacing ); + m_MaskImage->SetOrigin( origin ); + m_MaskImage->SetDirection( direction ); + m_MaskImage->SetRegions( imageRegion ); + m_MaskImage->Allocate(); + m_MaskImage->FillBuffer(1); + } m_NumResiduals = num_voxels * dim_four_size; MITK_INFO << "Num. unknowns: " << m_NumUnknowns; MITK_INFO << "Num. residuals: " << m_NumResiduals; MITK_INFO << "Creating system ..."; A.set_size(m_NumResiduals, m_NumUnknowns); b.set_size(m_NumResiduals); b.fill(0.0); m_MeanTractDensity = 0; m_MeanSignal = 0; m_NumCoveredDirections = 0; fiber_count = 0; m_GroupSizes.clear(); + + int numFibers = 0; + for (unsigned int bundle=0; bundleGetNumFibers(); + boost::progress_display disp(numFibers); for (unsigned int bundle=0; bundle polydata = m_Tractograms.at(bundle)->GetFiberPolyData(); m_GroupSizes.push_back(m_Tractograms.at(bundle)->GetNumFibers()); for (int i=0; iGetNumFibers(); ++i) { + ++disp; vtkCell* cell = polydata->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (numPoints<2) MITK_INFO << "FIBER WITH ONLY ONE POINT ENCOUNTERED!"; for (int j=0; jGetPoint(j); - PointType4 p; - p[0]=p1[0]; - p[1]=p1[1]; - p[2]=p1[2]; - p[3]=0; - - itk::Index<4> idx4; - m_PeakImage->TransformPhysicalPointToIndex(p, idx4); - itk::Index<3> idx3; idx3[0] = idx4[0]; idx3[1] = idx4[1]; idx3[2] = idx4[2]; - if (!m_PeakImage->GetLargestPossibleRegion().IsInside(idx4) || (m_MaskImage.IsNotNull() && m_MaskImage->GetPixel(idx3)==0)) - continue; + PointType3 startVertex = GetItkPoint(points->GetPoint(j)); + itk::Index<3> startIndex; + itk::ContinuousIndex startIndexCont; + m_MaskImage->TransformPhysicalPointToIndex(startVertex, startIndex); + m_MaskImage->TransformPhysicalPointToContinuousIndex(startVertex, startIndexCont); + + PointType3 endVertex = GetItkPoint(points->GetPoint(j+1)); + itk::Index<3> endIndex; + itk::ContinuousIndex endIndexCont; + m_MaskImage->TransformPhysicalPointToIndex(endVertex, endIndex); + m_MaskImage->TransformPhysicalPointToContinuousIndex(endVertex, endIndexCont); - double* p2 = points->GetPoint(j+1); vnl_vector_fixed fiber_dir; - fiber_dir[0] = p[0]-p2[0]; - fiber_dir[1] = p[1]-p2[1]; - fiber_dir[2] = p[2]-p2[2]; + fiber_dir[0] = endVertex[0]-startVertex[0]; + fiber_dir[1] = endVertex[1]-startVertex[1]; + fiber_dir[2] = endVertex[2]-startVertex[2]; fiber_dir.normalize(); - double w = 1; - int peak_id = dim_four_size-1; + std::vector< std::pair< itk::Index<3>, double > > segments = mitk::imv::IntersectImage(spacing, startIndex, endIndex, startIndexCont, endIndexCont); + for (std::pair< itk::Index<3>, double > seg : segments) + { + if (!m_MaskImage->GetLargestPossibleRegion().IsInside(seg.first) || m_MaskImage->GetPixel(seg.first)==0) + continue; + + itk::Index<4> idx4; + idx4[0]=seg.first[0]; + idx4[1]=seg.first[1]; + idx4[2]=seg.first[2]; + idx4[3]=0; - double peak_mag = 0; - GetClosestPeak(idx4, m_PeakImage, fiber_dir, peak_id, w, peak_mag); + double w = 1; + int peak_id = dim_four_size-1; - int x = idx4[0]; - int y = idx4[1]; - int z = idx4[2]; + double peak_mag = 0; + GetClosestPeak(idx4, m_PeakImage, fiber_dir, peak_id, w, peak_mag); + w *= seg.second; - unsigned int linear_index = x + sz_x*y + sz_x*sz_y*z + sz_x*sz_y*sz_z*peak_id; + int x = idx4[0]; + int y = idx4[1]; + int z = idx4[2]; - if (b[linear_index] == 0 && peak_idGetLargestPossibleRegion().GetSize(0); sz_y = m_ScalarImage->GetLargestPossibleRegion().GetSize(1); sz_z = m_ScalarImage->GetLargestPossibleRegion().GetSize(2); int num_voxels = sz_x*sz_y*sz_z; - float minSpacing = 1; - if(m_ScalarImage->GetSpacing()[0]GetSpacing()[1] && m_ScalarImage->GetSpacing()[0]GetSpacing()[2]) - minSpacing = m_ScalarImage->GetSpacing()[0]; - else if (m_ScalarImage->GetSpacing()[1] < m_ScalarImage->GetSpacing()[2]) - minSpacing = m_ScalarImage->GetSpacing()[1]; - else - minSpacing = m_ScalarImage->GetSpacing()[2]; - - if (m_ResampleFibers) - for (unsigned int bundle=0; bundleGetDeepCopy(); - m_Tractograms.at(bundle)->ResampleLinear(minSpacing/m_FiberSampling); - std::cout.rdbuf (old); - } - + auto spacing = m_ScalarImage->GetSpacing(); m_NumResiduals = num_voxels; MITK_INFO << "Num. unknowns: " << m_NumUnknowns; MITK_INFO << "Num. residuals: " << m_NumResiduals; MITK_INFO << "Creating system ..."; A.set_size(m_NumResiduals, m_NumUnknowns); b.set_size(m_NumResiduals); b.fill(0.0); m_MeanTractDensity = 0; m_MeanSignal = 0; int numCoveredVoxels = 0; fiber_count = 0; + int numFibers = 0; + for (unsigned int bundle=0; bundleGetNumFibers(); + boost::progress_display disp(numFibers); m_GroupSizes.clear(); for (unsigned int bundle=0; bundle polydata = m_Tractograms.at(bundle)->GetFiberPolyData(); m_GroupSizes.push_back(m_Tractograms.at(bundle)->GetNumFibers()); for (int i=0; iGetNumFibers(); ++i) { + ++disp; vtkCell* cell = polydata->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); - for (int j=0; jGetPoint(j); - PointType3 p; - p[0]=p1[0]; - p[1]=p1[1]; - p[2]=p1[2]; - - itk::Index<3> idx3; - m_ScalarImage->TransformPhysicalPointToIndex(p, idx3); - if (!m_ScalarImage->GetLargestPossibleRegion().IsInside(idx3) || (m_MaskImage.IsNotNull() && m_MaskImage->GetPixel(idx3)==0)) - continue; + PointType3 startVertex = GetItkPoint(points->GetPoint(j)); + itk::Index<3> startIndex; + itk::ContinuousIndex startIndexCont; + m_ScalarImage->TransformPhysicalPointToIndex(startVertex, startIndex); + m_ScalarImage->TransformPhysicalPointToContinuousIndex(startVertex, startIndexCont); + + PointType3 endVertex = GetItkPoint(points->GetPoint(j+1)); + itk::Index<3> endIndex; + itk::ContinuousIndex endIndexCont; + m_ScalarImage->TransformPhysicalPointToIndex(endVertex, endIndex); + m_ScalarImage->TransformPhysicalPointToContinuousIndex(endVertex, endIndexCont); + + std::vector< std::pair< itk::Index<3>, double > > segments = mitk::imv::IntersectImage(spacing, startIndex, endIndex, startIndexCont, endIndexCont); + for (std::pair< itk::Index<3>, double > seg : segments) + { + if (!m_ScalarImage->GetLargestPossibleRegion().IsInside(seg.first) || (m_MaskImage.IsNotNull() && m_MaskImage->GetPixel(seg.first)==0)) + continue; - float image_value = m_ScalarImage->GetPixel(idx3); - int x = idx3[0]; - int y = idx3[1]; - int z = idx3[2]; + float image_value = m_ScalarImage->GetPixel(seg.first); + int x = seg.first[0]; + int y = seg.first[1]; + int z = seg.first[2]; - unsigned int linear_index = x + sz_x*y + sz_x*sz_y*z; + unsigned int linear_index = x + sz_x*y + sz_x*sz_y*z; - if (b[linear_index] == 0) - { - numCoveredVoxels++; - m_MeanSignal += image_value; - } - m_MeanTractDensity += 1; + if (b[linear_index] == 0) + { + numCoveredVoxels++; + m_MeanSignal += image_value; + } + m_MeanTractDensity += seg.second; - if (m_FitIndividualFibers) - { - b[linear_index] = image_value; - A.put(linear_index, fiber_count, A.get(linear_index, fiber_count) + 1); - } - else - { - b[linear_index] = image_value; - A.put(linear_index, bundle, A.get(linear_index, bundle) + 1); + if (m_FitIndividualFibers) + { + b[linear_index] = image_value; + A.put(linear_index, fiber_count, A.get(linear_index, fiber_count) + seg.second); + } + else + { + b[linear_index] = image_value; + A.put(linear_index, bundle, A.get(linear_index, bundle) + seg.second); + } } } ++fiber_count; } } m_MeanTractDensity /= (numCoveredVoxels*fiber_count); m_MeanSignal /= numCoveredVoxels; A /= m_MeanTractDensity; b *= 100.0/m_MeanSignal; // times 100 because we want to avoid too small values for computational reasons // NEW FIT // m_MeanTractDensity /= numCoveredVoxels; // m_MeanSignal /= numCoveredVoxels; // b /= m_MeanSignal; // b *= m_MeanTractDensity; } void FitFibersToImageFilter::GenerateData() { m_NumUnknowns = m_Tractograms.size(); if (m_FitIndividualFibers) { m_NumUnknowns = 0; for (unsigned int bundle=0; bundleGetNumFibers(); } else m_FilterOutliers = false; if (m_NumUnknowns<1) { MITK_INFO << "No fibers in tractogram."; return; } fiber_count = 0; sz_x = 0; sz_y = 0; sz_z = 0; m_MeanTractDensity = 0; m_MeanSignal = 0; if (m_PeakImage.IsNotNull()) CreatePeakSystem(); else if (m_DiffImage.IsNotNull()) CreateDiffSystem(); else if (m_ScalarImage.IsNotNull()) CreateScalarSystem(); else mitkThrow() << "No input image set!"; + MITK_INFO << "Initializing optimizer"; double init_lambda = fiber_count; // initialization for lambda estimation itk::TimeProbe clock; clock.Start(); cost = VnlCostFunction(m_NumUnknowns); cost.SetProblem(A, b, init_lambda, m_Regularization); cost.SetGroupSizes(m_GroupSizes); m_Weights.set_size(m_NumUnknowns); m_Weights.fill( 1.0/m_NumUnknowns ); vnl_lbfgsb minimizer(cost); vnl_vector l; l.set_size(m_NumUnknowns); l.fill(0); vnl_vector bound_selection; bound_selection.set_size(m_NumUnknowns); bound_selection.fill(1); minimizer.set_bound_selection(bound_selection); minimizer.set_lower_bound(l); minimizer.set_projected_gradient_tolerance(m_GradientTolerance); if (m_Regularization==VnlCostFunction::REGU::MSM) MITK_INFO << "Regularization type: MSM"; else if (m_Regularization==VnlCostFunction::REGU::VARIANCE) MITK_INFO << "Regularization type: VARIANCE"; else if (m_Regularization==VnlCostFunction::REGU::LASSO) MITK_INFO << "Regularization type: LASSO"; else if (m_Regularization==VnlCostFunction::REGU::VOXEL_VARIANCE) MITK_INFO << "Regularization type: VOXEL_VARIANCE"; else if (m_Regularization==VnlCostFunction::REGU::GROUP_LASSO) MITK_INFO << "Regularization type: GROUP_LASSO"; else if (m_Regularization==VnlCostFunction::REGU::GROUP_VARIANCE) MITK_INFO << "Regularization type: GROUP_VARIANCE"; else if (m_Regularization==VnlCostFunction::REGU::NONE) MITK_INFO << "Regularization type: NONE"; if (m_Regularization!=VnlCostFunction::REGU::NONE) // REMOVE FOR NEW FIT AND SET cost.m_Lambda = m_Lambda { MITK_INFO << "Estimating regularization"; minimizer.set_trace(false); minimizer.set_max_function_evals(2); minimizer.minimize(m_Weights); vnl_vector dx; dx.set_size(m_NumUnknowns); dx.fill(0.0); cost.calc_regularization_gradient(m_Weights, dx); if (m_Weights.magnitude()==0) { MITK_INFO << "Regularization estimation failed. Using default value."; cost.m_Lambda = fiber_count*m_Lambda; } else { double r = dx.magnitude()/m_Weights.magnitude(); // wtf??? cost.m_Lambda *= m_Lambda*55.0/r; MITK_INFO << r << " - " << m_Lambda*55.0/r; if (cost.m_Lambda>10e7) { MITK_INFO << "Regularization estimation failed. Using default value."; cost.m_Lambda = fiber_count*m_Lambda; } } } else cost.m_Lambda = 0; MITK_INFO << "Using regularization factor of " << cost.m_Lambda << " (λ: " << m_Lambda << ")"; MITK_INFO << "Fitting fibers"; minimizer.set_trace(m_Verbose); minimizer.set_max_function_evals(m_MaxIterations); minimizer.minimize(m_Weights); std::vector< double > weights; if (m_FilterOutliers) { for (auto w : m_Weights) weights.push_back(w); std::sort(weights.begin(), weights.end()); MITK_INFO << "Setting upper weight bound to " << weights.at(m_NumUnknowns*0.99); vnl_vector u; u.set_size(m_NumUnknowns); u.fill(weights.at(m_NumUnknowns*0.99)); minimizer.set_upper_bound(u); bound_selection.fill(2); minimizer.set_bound_selection(bound_selection); minimizer.minimize(m_Weights); weights.clear(); } for (auto w : m_Weights) weights.push_back(w); std::sort(weights.begin(), weights.end()); m_MeanWeight = m_Weights.mean(); m_MedianWeight = weights.at(m_NumUnknowns*0.5); m_MinWeight = weights.at(0); m_MaxWeight = weights.at(m_NumUnknowns-1); MITK_INFO << "*************************"; MITK_INFO << "Weight statistics"; MITK_INFO << "Sum: " << m_Weights.sum(); MITK_INFO << "Mean: " << m_MeanWeight; MITK_INFO << "1% quantile: " << weights.at(m_NumUnknowns*0.01); MITK_INFO << "5% quantile: " << weights.at(m_NumUnknowns*0.05); MITK_INFO << "25% quantile: " << weights.at(m_NumUnknowns*0.25); MITK_INFO << "Median: " << m_MedianWeight; MITK_INFO << "75% quantile: " << weights.at(m_NumUnknowns*0.75); MITK_INFO << "95% quantile: " << weights.at(m_NumUnknowns*0.95); MITK_INFO << "99% quantile: " << weights.at(m_NumUnknowns*0.99); MITK_INFO << "Min: " << m_MinWeight; MITK_INFO << "Max: " << m_MaxWeight; MITK_INFO << "*************************"; MITK_INFO << "NumEvals: " << minimizer.get_num_evaluations(); MITK_INFO << "NumIterations: " << minimizer.get_num_iterations(); MITK_INFO << "Residual cost: " << minimizer.get_end_error(); m_RMSE = cost.S->get_rms_error(m_Weights); MITK_INFO << "Final RMSE: " << m_RMSE; clock.Stop(); int h = clock.GetTotal()/3600; int m = ((int)clock.GetTotal()%3600)/60; int s = (int)clock.GetTotal()%60; MITK_INFO << "Optimization took " << h << "h, " << m << "m and " << s << "s"; MITK_INFO << "Weighting fibers"; m_RmsDiffPerBundle.set_size(m_Tractograms.size()); std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); if (m_FitIndividualFibers) { unsigned int fiber_count = 0; for (unsigned int bundle=0; bundle temp_weights; temp_weights.set_size(m_Weights.size()); temp_weights.copy_in(m_Weights.data_block()); for (int i=0; iGetNumFibers(); i++) { m_Tractograms.at(bundle)->SetFiberWeight(i, m_Weights[fiber_count]); temp_weights[fiber_count] = 0; ++fiber_count; } double d_rms = cost.S->get_rms_error(temp_weights) - m_RMSE; m_RmsDiffPerBundle[bundle] = d_rms; m_Tractograms.at(bundle)->Compress(0.1); m_Tractograms.at(bundle)->ColorFibersByFiberWeights(false, true); } } else { for (unsigned int i=0; i temp_weights; temp_weights.set_size(m_Weights.size()); temp_weights.copy_in(m_Weights.data_block()); temp_weights[i] = 0; double d_rms = cost.S->get_rms_error(temp_weights) - m_RMSE; m_RmsDiffPerBundle[i] = d_rms; m_Tractograms.at(i)->SetFiberWeights(m_Weights[i]); m_Tractograms.at(i)->Compress(0.1); m_Tractograms.at(i)->ColorFibersByFiberWeights(false, true); } } std::cout.rdbuf (old); // transform back A *= m_MeanSignal/100.0; b *= m_MeanSignal/100.0; MITK_INFO << "Generating output images ..."; if (m_PeakImage.IsNotNull()) GenerateOutputPeakImages(); else if (m_DiffImage.IsNotNull()) GenerateOutputDiffImages(); else if (m_ScalarImage.IsNotNull()) GenerateOutputScalarImages(); m_Coverage = m_Coverage/m_MeanSignal; m_Overshoot = m_Overshoot/m_MeanSignal; MITK_INFO << std::fixed << "Coverage: " << setprecision(2) << 100.0*m_Coverage << "%"; MITK_INFO << std::fixed << "Overshoot: " << setprecision(2) << 100.0*m_Overshoot << "%"; } void FitFibersToImageFilter::GenerateOutputDiffImages() { VectorImgType::PixelType pix; pix.SetSize(m_DiffImage->GetVectorLength()); pix.Fill(0); itk::ImageDuplicator< VectorImgType >::Pointer duplicator = itk::ImageDuplicator< VectorImgType >::New(); duplicator->SetInputImage(m_DiffImage); duplicator->Update(); m_UnderexplainedImageDiff = duplicator->GetOutput(); m_UnderexplainedImageDiff->FillBuffer(pix); duplicator->SetInputImage(m_UnderexplainedImageDiff); duplicator->Update(); m_OverexplainedImageDiff = duplicator->GetOutput(); m_OverexplainedImageDiff->FillBuffer(pix); duplicator->SetInputImage(m_OverexplainedImageDiff); duplicator->Update(); m_ResidualImageDiff = duplicator->GetOutput(); m_ResidualImageDiff->FillBuffer(pix); duplicator->SetInputImage(m_ResidualImageDiff); duplicator->Update(); m_FittedImageDiff = duplicator->GetOutput(); m_FittedImageDiff->FillBuffer(pix); vnl_vector fitted_b; fitted_b.set_size(b.size()); cost.S->multiply(m_Weights, fitted_b); itk::ImageRegionIterator it1 = itk::ImageRegionIterator(m_DiffImage, m_DiffImage->GetLargestPossibleRegion()); itk::ImageRegionIterator it2 = itk::ImageRegionIterator(m_FittedImageDiff, m_FittedImageDiff->GetLargestPossibleRegion()); itk::ImageRegionIterator it3 = itk::ImageRegionIterator(m_ResidualImageDiff, m_ResidualImageDiff->GetLargestPossibleRegion()); itk::ImageRegionIterator it4 = itk::ImageRegionIterator(m_UnderexplainedImageDiff, m_UnderexplainedImageDiff->GetLargestPossibleRegion()); itk::ImageRegionIterator it5 = itk::ImageRegionIterator(m_OverexplainedImageDiff, m_OverexplainedImageDiff->GetLargestPossibleRegion()); m_MeanSignal = 0; m_Coverage = 0; m_Overshoot = 0; while( !it2.IsAtEnd() ) { itk::Index<3> idx3 = it2.GetIndex(); VectorImgType::PixelType original_pix =it1.Get(); VectorImgType::PixelType fitted_pix =it2.Get(); VectorImgType::PixelType residual_pix =it3.Get(); VectorImgType::PixelType underexplained_pix =it4.Get(); VectorImgType::PixelType overexplained_pix =it5.Get(); int num_nonzero_g = 0; double original_mean = 0; for (int g=0; gGetGradientDirection(g).GetNorm()>=mitk::eps ) { original_mean += original_pix[g]; ++num_nonzero_g; } } original_mean /= num_nonzero_g; for (int g=0; g=0) { underexplained_pix[g] = residual_pix[g]; m_Coverage += fitted_b[linear_index] + original_mean; } m_MeanSignal += b[linear_index] + original_mean; } it2.Set(fitted_pix); it3.Set(residual_pix); it4.Set(underexplained_pix); it5.Set(overexplained_pix); ++it1; ++it2; ++it3; ++it4; ++it5; } } void FitFibersToImageFilter::GenerateOutputScalarImages() { itk::ImageDuplicator< DoubleImgType >::Pointer duplicator = itk::ImageDuplicator< DoubleImgType >::New(); duplicator->SetInputImage(m_ScalarImage); duplicator->Update(); m_UnderexplainedImageScalar = duplicator->GetOutput(); m_UnderexplainedImageScalar->FillBuffer(0); duplicator->SetInputImage(m_UnderexplainedImageScalar); duplicator->Update(); m_OverexplainedImageScalar = duplicator->GetOutput(); m_OverexplainedImageScalar->FillBuffer(0); duplicator->SetInputImage(m_OverexplainedImageScalar); duplicator->Update(); m_ResidualImageScalar = duplicator->GetOutput(); m_ResidualImageScalar->FillBuffer(0); duplicator->SetInputImage(m_ResidualImageScalar); duplicator->Update(); m_FittedImageScalar = duplicator->GetOutput(); m_FittedImageScalar->FillBuffer(0); vnl_vector fitted_b; fitted_b.set_size(b.size()); cost.S->multiply(m_Weights, fitted_b); itk::ImageRegionIterator it1 = itk::ImageRegionIterator(m_ScalarImage, m_ScalarImage->GetLargestPossibleRegion()); itk::ImageRegionIterator it2 = itk::ImageRegionIterator(m_FittedImageScalar, m_FittedImageScalar->GetLargestPossibleRegion()); itk::ImageRegionIterator it3 = itk::ImageRegionIterator(m_ResidualImageScalar, m_ResidualImageScalar->GetLargestPossibleRegion()); itk::ImageRegionIterator it4 = itk::ImageRegionIterator(m_UnderexplainedImageScalar, m_UnderexplainedImageScalar->GetLargestPossibleRegion()); itk::ImageRegionIterator it5 = itk::ImageRegionIterator(m_OverexplainedImageScalar, m_OverexplainedImageScalar->GetLargestPossibleRegion()); m_MeanSignal = 0; m_Coverage = 0; m_Overshoot = 0; while( !it2.IsAtEnd() ) { itk::Index<3> idx3 = it2.GetIndex(); DoubleImgType::PixelType original_pix =it1.Get(); DoubleImgType::PixelType fitted_pix =it2.Get(); DoubleImgType::PixelType residual_pix =it3.Get(); DoubleImgType::PixelType underexplained_pix =it4.Get(); DoubleImgType::PixelType overexplained_pix =it5.Get(); unsigned int linear_index = idx3[0] + sz_x*idx3[1] + sz_x*sz_y*idx3[2]; fitted_pix = fitted_b[linear_index]; residual_pix = original_pix - fitted_pix; if (residual_pix<0) { overexplained_pix = residual_pix; m_Coverage += b[linear_index]; m_Overshoot -= residual_pix; } else if (residual_pix>=0) { underexplained_pix = residual_pix; m_Coverage += fitted_b[linear_index]; } m_MeanSignal += b[linear_index]; it2.Set(fitted_pix); it3.Set(residual_pix); it4.Set(underexplained_pix); it5.Set(overexplained_pix); ++it1; ++it2; ++it3; ++it4; ++it5; } } VnlCostFunction::REGU FitFibersToImageFilter::GetRegularization() const { return m_Regularization; } void FitFibersToImageFilter::SetRegularization(const VnlCostFunction::REGU &Regularization) { m_Regularization = Regularization; } void FitFibersToImageFilter::GenerateOutputPeakImages() { itk::ImageDuplicator< PeakImgType >::Pointer duplicator = itk::ImageDuplicator< PeakImgType >::New(); duplicator->SetInputImage(m_PeakImage); duplicator->Update(); m_UnderexplainedImage = duplicator->GetOutput(); m_UnderexplainedImage->FillBuffer(0.0); duplicator->SetInputImage(m_UnderexplainedImage); duplicator->Update(); m_OverexplainedImage = duplicator->GetOutput(); m_OverexplainedImage->FillBuffer(0.0); duplicator->SetInputImage(m_OverexplainedImage); duplicator->Update(); m_ResidualImage = duplicator->GetOutput(); m_ResidualImage->FillBuffer(0.0); duplicator->SetInputImage(m_ResidualImage); duplicator->Update(); m_FittedImage = duplicator->GetOutput(); m_FittedImage->FillBuffer(0.0); vnl_vector fitted_b; fitted_b.set_size(b.size()); cost.S->multiply(m_Weights, fitted_b); for (unsigned int r=0; r idx4; unsigned int linear_index = r; idx4[0] = linear_index % sz_x; linear_index /= sz_x; idx4[1] = linear_index % sz_y; linear_index /= sz_y; idx4[2] = linear_index % sz_z; linear_index /= sz_z; int peak_id = linear_index % dim_four_size; if (peak_id peak_dir; idx4[3] = peak_id*3; peak_dir[0] = m_PeakImage->GetPixel(idx4); idx4[3] += 1; peak_dir[1] = m_PeakImage->GetPixel(idx4); idx4[3] += 1; peak_dir[2] = m_PeakImage->GetPixel(idx4); peak_dir.normalize(); peak_dir *= fitted_b[r]; idx4[3] = peak_id*3; m_FittedImage->SetPixel(idx4, peak_dir[0]); idx4[3] += 1; m_FittedImage->SetPixel(idx4, peak_dir[1]); idx4[3] += 1; m_FittedImage->SetPixel(idx4, peak_dir[2]); } } m_MeanSignal = 0; m_Coverage = 0; m_Overshoot = 0; itk::Index<4> idx4; for (idx4[0]=0; idx4[0] idx3; idx3[0] = idx4[0]; idx3[1] = idx4[1]; idx3[2] = idx4[2]; if (m_MaskImage.IsNotNull() && m_MaskImage->GetPixel(idx3)==0) continue; vnl_vector_fixed peak_dir; vnl_vector_fixed fitted_dir; vnl_vector_fixed overshoot_dir; for (idx4[3]=0; idx4[3]<(itk::IndexValueType)m_PeakImage->GetLargestPossibleRegion().GetSize(3); ++idx4[3]) { peak_dir[idx4[3]%3] = m_PeakImage->GetPixel(idx4); fitted_dir[idx4[3]%3] = m_FittedImage->GetPixel(idx4); m_ResidualImage->SetPixel(idx4, m_PeakImage->GetPixel(idx4) - m_FittedImage->GetPixel(idx4)); if (idx4[3]%3==2) { m_MeanSignal += peak_dir.magnitude(); itk::Index<4> tidx= idx4; if (peak_dir.magnitude()>fitted_dir.magnitude()) { m_Coverage += fitted_dir.magnitude(); m_UnderexplainedImage->SetPixel(tidx, peak_dir[2]-fitted_dir[2]); tidx[3]--; m_UnderexplainedImage->SetPixel(tidx, peak_dir[1]-fitted_dir[1]); tidx[3]--; m_UnderexplainedImage->SetPixel(tidx, peak_dir[0]-fitted_dir[0]); } else { overshoot_dir[0] = fitted_dir[0]-peak_dir[0]; overshoot_dir[1] = fitted_dir[1]-peak_dir[1]; overshoot_dir[2] = fitted_dir[2]-peak_dir[2]; m_Coverage += peak_dir.magnitude(); m_Overshoot += overshoot_dir.magnitude(); m_OverexplainedImage->SetPixel(tidx, overshoot_dir[2]); tidx[3]--; m_OverexplainedImage->SetPixel(tidx, overshoot_dir[1]); tidx[3]--; m_OverexplainedImage->SetPixel(tidx, overshoot_dir[0]); } } } } } void FitFibersToImageFilter::GetClosestPeak(itk::Index<4> idx, PeakImgType::Pointer peak_image , vnl_vector_fixed fiber_dir, int& id, double& w, double& peak_mag ) { int m_NumDirs = peak_image->GetLargestPossibleRegion().GetSize()[3]/3; vnl_vector_fixed out_dir; out_dir.fill(0); float angle = 0.9; for (int i=0; i dir; idx[3] = i*3; dir[0] = peak_image->GetPixel(idx); idx[3] += 1; dir[1] = peak_image->GetPixel(idx); idx[3] += 1; dir[2] = peak_image->GetPixel(idx); float mag = dir.magnitude(); if (magangle) { angle = a; w = angle; peak_mag = mag; id = i; } } } std::vector FitFibersToImageFilter::GetTractograms() const { return m_Tractograms; } void FitFibersToImageFilter::SetTractograms(const std::vector &tractograms) { m_Tractograms = tractograms; } void FitFibersToImageFilter::SetSignalModel(mitk::DiffusionSignalModel<> *SignalModel) { m_SignalModel = SignalModel; } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.h index e5d56fe256..e5f1259749 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFitFibersToImageFilter.h @@ -1,483 +1,475 @@ #ifndef __itkFitFibersToImageFilter_h__ #define __itkFitFibersToImageFilter_h__ // MITK #include #include #include #include #include #include #include #include #include #include #include class VnlCostFunction : public vnl_cost_function { public: enum REGU { MSM, VARIANCE, LASSO, VOXEL_VARIANCE, GROUP_LASSO, GROUP_VARIANCE, NONE }; vnl_sparse_matrix_linear_system< double >* S; vnl_sparse_matrix< double > m_A; vnl_sparse_matrix< double > m_A_Ones; // matrix indicating active weights with 1 vnl_vector< double > m_b; double m_Lambda; // regularization factor vnl_vector row_sums; // number of active weights per row vnl_vector local_weight_means; // mean weight of each row REGU regularization; std::vector group_sizes; void SetProblem(vnl_sparse_matrix< double >& A, vnl_vector& b, double lambda, REGU regu) { S = new vnl_sparse_matrix_linear_system(A, b); m_A = A; m_b = b; m_Lambda = lambda; m_A_Ones.set_size(m_A.rows(), m_A.cols()); m_A.reset(); while (m_A.next()) m_A_Ones.put(m_A.getrow(), m_A.getcolumn(), 1); unsigned int N = m_b.size(); vnl_vector ones; ones.set_size(dim); ones.fill(1.0); row_sums.set_size(N); m_A_Ones.mult(ones, row_sums); local_weight_means.set_size(N); regularization = regu; } void SetGroupSizes(std::vector sizes) { unsigned int sum = 0; for (auto s : sizes) sum += s; if (sum!=m_A.cols()) { MITK_INFO << "Group sizes do not match number of unknowns (" << sum << " vs. " << m_A.cols() << ")"; return; } group_sizes = sizes; } VnlCostFunction(const int NumVars=0) : vnl_cost_function(NumVars) { } // Regularization: mean squared magnitude of weight vectors (small weights) void regu_MSM(vnl_vector const &x, double& cost) { cost += 10000.0*m_Lambda*x.squared_magnitude()/dim; } // Regularization: mean squared deaviation of weights from mean weight (enforce uniform weights) void regu_Variance(vnl_vector const &x, double& cost) { double mean = x.mean(); vnl_vector tx = x-mean; cost += 10000.0*m_Lambda*tx.squared_magnitude()/dim; } // Regularization: mean absolute magnitude of weight vectors (small weights) L1 void regu_Lasso(vnl_vector const &x, double& cost) { cost += m_Lambda*x.one_norm()/dim; } // Regularization: mean squared deaviation of weights from bundle mean weight (enforce uniform weights PER BUNDLE) void regu_GroupVariance(vnl_vector const &x, double& cost) { vnl_vector tx(x); unsigned int offset = 0; for (auto g : group_sizes) { double group_mean = 0; for (unsigned int i=0; i const &x, double& cost) { m_A_Ones.mult(x, local_weight_means); local_weight_means = element_quotient(local_weight_means, row_sums); m_A_Ones.reset(); double regu = 0; while (m_A_Ones.next()) { double d = 0; if (x[m_A_Ones.getcolumn()]>local_weight_means[m_A_Ones.getrow()]) d = std::exp(x[m_A_Ones.getcolumn()]) - std::exp(local_weight_means[m_A_Ones.getrow()]); else d = x[m_A_Ones.getcolumn()] - local_weight_means[m_A_Ones.getrow()]; regu += d*d; } cost += m_Lambda*regu/dim; } // Regularization: group Lasso: sum_g(lambda_g * ||x_g||_2) void regu_GroupLasso(vnl_vector const &x, double& cost) { unsigned int offset = 0; for (auto g : group_sizes) { double group_cost = 0; for (unsigned int i=0; i const &x, vnl_vector &dx) { dx += 10000.0*m_Lambda*2.0*x/dim; } void grad_regu_Variance(vnl_vector const &x, vnl_vector &dx) { double mean = x.mean(); vnl_vector tx = x-mean; // difference to mean dx += 10000.0*tx*(2.0-2.0/dim)/dim; } void grad_regu_Lasso(vnl_vector const &x, vnl_vector &dx) { for (int i=0; i0) dx[i] += m_Lambda/dim; } void grad_regu_GroupVariance(vnl_vector const &x, vnl_vector &dx) { vnl_vector tx(x); unsigned int offset = 0; for (auto g : group_sizes) { double group_mean = 0; for (unsigned int i=0; i const &x, vnl_vector &dx) { m_A_Ones.mult(x, local_weight_means); local_weight_means = element_quotient(local_weight_means, row_sums); vnl_vector exp_x = x.apply(std::exp); vnl_vector exp_means = local_weight_means.apply(std::exp); vnl_vector tdx(dim, 0); m_A_Ones.reset(); while (m_A_Ones.next()) { int c = m_A_Ones.getcolumn(); int r = m_A_Ones.getrow(); if (x[c]>local_weight_means[r]) tdx[c] += exp_x[c] * ( exp_x[c] - exp_means[r] ); else tdx[c] += x[c] - local_weight_means[r]; } dx += tdx*2.0*m_Lambda/dim; } void grad_regu_GroupLasso(vnl_vector const &x, vnl_vector &dx) { unsigned int offset = 0; for (auto g : group_sizes) { double group_lambda = m_Lambda*std::sqrt(g)/dim; double group_l2 = 0; for (unsigned int i=0; i0.0) { for (unsigned int i=0; i const &x, double& cost) { if (regularization==VOXEL_VARIANCE) regu_VoxelVariance(x, cost); else if (regularization==VARIANCE) regu_Variance(x, cost); else if (regularization==MSM) regu_MSM(x, cost); else if (regularization==LASSO) regu_Lasso(x, cost); else if (regularization==GROUP_LASSO) regu_GroupLasso(x, cost); else if (regularization==GROUP_VARIANCE) regu_GroupVariance(x, cost); } void calc_regularization_gradient(vnl_vector const &x, vnl_vector &dx) { if (regularization==VOXEL_VARIANCE) grad_regu_VoxelVariance(x,dx); else if (regularization==VARIANCE) grad_regu_Variance(x,dx); else if (regularization==MSM) grad_regu_MSM(x,dx); else if (regularization==LASSO) grad_regu_Lasso(x,dx); else if (regularization==GROUP_LASSO) grad_regu_GroupLasso(x, dx); else if (regularization==GROUP_VARIANCE) grad_regu_GroupVariance(x, dx); } // cost function double f(vnl_vector const &x) { // RMS error unsigned int N = m_b.size(); vnl_vector d; d.set_size(N); S->multiply(x,d); double cost = (d - m_b).squared_magnitude()/N; // regularize calc_regularization(x, cost); return cost; } // gradient of cost function void gradf(vnl_vector const &x, vnl_vector &dx) { dx.fill(0.0); unsigned int N = m_b.size(); // calculate output difference d vnl_vector d; d.set_size(N); S->multiply(x,d); d -= m_b; // (f(u(x)))' = f'(u(x)) * u'(x) // d/dx_j = 1/N * Sum_i A_i,j * 2*(A_i,j * x_j - b_i) S->transpose_multiply(d, dx); dx *= 2.0/N; calc_regularization_gradient(x,dx); } }; namespace itk{ /** * \brief Fits the tractogram to the input image by assigning a weight to each fiber (similar to https://doi.org/10.1016/j.neuroimage.2015.06.092). */ class FitFibersToImageFilter : public ImageSource< mitk::PeakImage::ItkPeakImageType > { public: typedef FitFibersToImageFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef itk::Point PointType3; typedef itk::Point PointType4; typedef mitk::DiffusionPropertyHelper::ImageType VectorImgType; typedef mitk::PeakImage::ItkPeakImageType PeakImgType; typedef itk::Image UcharImgType; typedef itk::Image DoubleImgType; itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkTypeMacro( FitFibersToImageFilter, ImageSource ) itkSetMacro( ScalarImage, DoubleImgType::Pointer) itkGetMacro( ScalarImage, DoubleImgType::Pointer) itkSetMacro( PeakImage, PeakImgType::Pointer) itkGetMacro( PeakImage, PeakImgType::Pointer) itkSetMacro( DiffImage, VectorImgType::Pointer) itkGetMacro( DiffImage, VectorImgType::Pointer) itkSetMacro( MaskImage, UcharImgType::Pointer) itkGetMacro( MaskImage, UcharImgType::Pointer) itkSetMacro( FitIndividualFibers, bool) itkGetMacro( FitIndividualFibers, bool) itkSetMacro( GradientTolerance, double) itkGetMacro( GradientTolerance, double) itkSetMacro( Lambda, double) itkGetMacro( Lambda, double) itkSetMacro( MaxIterations, int) itkGetMacro( MaxIterations, int) - itkSetMacro( FiberSampling, float) - itkGetMacro( FiberSampling, float) itkSetMacro( FilterOutliers, bool) itkGetMacro( FilterOutliers, bool) itkSetMacro( Verbose, bool) itkGetMacro( Verbose, bool) - itkSetMacro( DeepCopy, bool) - itkGetMacro( DeepCopy, bool) - itkSetMacro( ResampleFibers, bool) - itkGetMacro( ResampleFibers, bool) itkGetMacro( Weights, vnl_vector) itkGetMacro( RmsDiffPerBundle, vnl_vector) itkGetMacro( FittedImage, PeakImgType::Pointer) itkGetMacro( ResidualImage, PeakImgType::Pointer) itkGetMacro( OverexplainedImage, PeakImgType::Pointer) itkGetMacro( UnderexplainedImage, PeakImgType::Pointer) itkGetMacro( FittedImageDiff, VectorImgType::Pointer) itkGetMacro( ResidualImageDiff, VectorImgType::Pointer) itkGetMacro( OverexplainedImageDiff, VectorImgType::Pointer) itkGetMacro( UnderexplainedImageDiff, VectorImgType::Pointer) itkGetMacro( FittedImageScalar, DoubleImgType::Pointer) itkGetMacro( ResidualImageScalar, DoubleImgType::Pointer) itkGetMacro( OverexplainedImageScalar, DoubleImgType::Pointer) itkGetMacro( UnderexplainedImageScalar, DoubleImgType::Pointer) itkGetMacro( Coverage, double) itkGetMacro( Overshoot, double) itkGetMacro( RMSE, double) itkGetMacro( MeanWeight, double) itkGetMacro( MedianWeight, double) itkGetMacro( MinWeight, double) itkGetMacro( MaxWeight, double) itkGetMacro( NumUnknowns, unsigned int) itkGetMacro( NumResiduals, unsigned int) itkGetMacro( NumCoveredDirections, unsigned int) void SetTractograms(const std::vector &tractograms); void GenerateData() override; std::vector GetTractograms() const; void SetSignalModel(mitk::DiffusionSignalModel<> *SignalModel); VnlCostFunction::REGU GetRegularization() const; void SetRegularization(const VnlCostFunction::REGU &GetRegularization); protected: FitFibersToImageFilter(); virtual ~FitFibersToImageFilter(); + itk::Point GetItkPoint(double point[3]); void GetClosestPeak(itk::Index<4> idx, PeakImgType::Pointer m_PeakImage , vnl_vector_fixed fiber_dir, int& id, double& w, double& peak_mag ); void CreatePeakSystem(); void CreateDiffSystem(); void CreateScalarSystem(); void GenerateOutputPeakImages(); void GenerateOutputDiffImages(); void GenerateOutputScalarImages(); std::vector< mitk::FiberBundle::Pointer > m_Tractograms; PeakImgType::Pointer m_PeakImage; VectorImgType::Pointer m_DiffImage; DoubleImgType::Pointer m_ScalarImage; UcharImgType::Pointer m_MaskImage; bool m_FitIndividualFibers; double m_GradientTolerance; double m_Lambda; int m_MaxIterations; - float m_FiberSampling; double m_Coverage; double m_Overshoot; double m_RMSE; bool m_FilterOutliers; double m_MeanWeight; double m_MedianWeight; double m_MinWeight; double m_MaxWeight; bool m_Verbose; - bool m_DeepCopy; - bool m_ResampleFibers; unsigned int m_NumUnknowns; unsigned int m_NumResiduals; unsigned int m_NumCoveredDirections; // output vnl_vector m_RmsDiffPerBundle; vnl_vector m_Weights; PeakImgType::Pointer m_UnderexplainedImage; PeakImgType::Pointer m_OverexplainedImage; PeakImgType::Pointer m_ResidualImage; PeakImgType::Pointer m_FittedImage; VectorImgType::Pointer m_UnderexplainedImageDiff; VectorImgType::Pointer m_OverexplainedImageDiff; VectorImgType::Pointer m_ResidualImageDiff; VectorImgType::Pointer m_FittedImageDiff; DoubleImgType::Pointer m_UnderexplainedImageScalar; DoubleImgType::Pointer m_OverexplainedImageScalar; DoubleImgType::Pointer m_ResidualImageScalar; DoubleImgType::Pointer m_FittedImageScalar; mitk::DiffusionSignalModel<>* m_SignalModel; vnl_sparse_matrix A; vnl_vector b; VnlCostFunction cost; int sz_x; int sz_y; int sz_z; int dim_four_size; double m_MeanTractDensity; double m_MeanSignal; unsigned int fiber_count; VnlCostFunction::REGU m_Regularization; std::vector m_GroupSizes; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkFitFibersToImageFilter.cpp" #endif #endif // __itkFitFibersToImageFilter_h__ diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp index 3938627d56..254c0a41f9 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractDensityImageFilter.cpp @@ -1,273 +1,187 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Coindex[1]right (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 "itkTractDensityImageFilter.h" // VTK #include #include #include #include // misc #include #include +#include +#include namespace itk{ template< class OutputImageType > TractDensityImageFilter< OutputImageType >::TractDensityImageFilter() : m_UpsamplingFactor(1) , m_InvertImage(false) , m_BinaryOutput(false) , m_UseImageGeometry(false) , m_OutputAbsoluteValues(false) - , m_UseTrilinearInterpolation(false) - , m_DoFiberResampling(true) - , m_WorkOnFiberCopy(true) , m_MaxDensity(0) , m_NumCoveredVoxels(0) { } template< class OutputImageType > TractDensityImageFilter< OutputImageType >::~TractDensityImageFilter() { } template< class OutputImageType > itk::Point TractDensityImageFilter< OutputImageType >::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } template< class OutputImageType > void TractDensityImageFilter< OutputImageType >::GenerateData() { // generate upsampled image mitk::BaseGeometry::Pointer geometry = m_FiberBundle->GetGeometry(); typename OutputImageType::Pointer outImage = this->GetOutput(); // calculate new image parameters itk::Vector newSpacing; mitk::Point3D newOrigin; itk::Matrix newDirection; ImageRegion<3> upsampledRegion; if (m_UseImageGeometry && !m_InputImage.IsNull()) { MITK_INFO << "TractDensityImageFilter: using image geometry"; newSpacing = m_InputImage->GetSpacing()/m_UpsamplingFactor; upsampledRegion = m_InputImage->GetLargestPossibleRegion(); newOrigin = m_InputImage->GetOrigin(); typename OutputImageType::RegionType::SizeType size = upsampledRegion.GetSize(); size[0] *= m_UpsamplingFactor; size[1] *= m_UpsamplingFactor; size[2] *= m_UpsamplingFactor; upsampledRegion.SetSize(size); newDirection = m_InputImage->GetDirection(); } else { MITK_INFO << "TractDensityImageFilter: using fiber bundle geometry"; newSpacing = geometry->GetSpacing()/m_UpsamplingFactor; newOrigin = geometry->GetOrigin(); mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds(); // we retrieve the origin from a vtk-polydata (corner-based) and hance have to translate it to an image geometry // i.e. center-based newOrigin[0] += bounds.GetElement(0) + 0.5 * newSpacing[0]; newOrigin[1] += bounds.GetElement(2) + 0.5 * newSpacing[1]; newOrigin[2] += bounds.GetElement(4) + 0.5 * newSpacing[2]; for (int i=0; i<3; i++) for (int j=0; j<3; j++) newDirection[j][i] = geometry->GetMatrixColumn(i)[j]; upsampledRegion.SetSize(0, ceil( geometry->GetExtent(0)*m_UpsamplingFactor ) ); upsampledRegion.SetSize(1, ceil( geometry->GetExtent(1)*m_UpsamplingFactor ) ); upsampledRegion.SetSize(2, ceil( geometry->GetExtent(2)*m_UpsamplingFactor ) ); } typename OutputImageType::RegionType::SizeType upsampledSize = upsampledRegion.GetSize(); // apply new image parameters outImage->SetSpacing( newSpacing ); outImage->SetOrigin( newOrigin ); outImage->SetDirection( newDirection ); outImage->SetLargestPossibleRegion( upsampledRegion ); outImage->SetBufferedRegion( upsampledRegion ); outImage->SetRequestedRegion( upsampledRegion ); outImage->Allocate(); outImage->FillBuffer(0.0); int w = upsampledSize[0]; int h = upsampledSize[1]; int d = upsampledSize[2]; // set/initialize output OutPixelType* outImageBufferPointer = (OutPixelType*)outImage->GetBufferPointer(); - // resample fiber bundle - float minSpacing = 1; - if(newSpacing[0]GetDeepCopy(); - m_FiberBundle->ResampleLinear(minSpacing/10); - } - MITK_INFO << "TractDensityImageFilter: starting image generation"; - vtkSmartPointer fiberPolyData = m_FiberBundle->GetFiberPolyData(); int numFibers = m_FiberBundle->GetNumFibers(); boost::progress_display disp(numFibers); for( int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); float weight = m_FiberBundle->GetFiberWeight(i); // fill output image - for( int j=0; j vertex = GetItkPoint(points->GetPoint(j)); - itk::Index<3> index; - itk::ContinuousIndex contIndex; - outImage->TransformPhysicalPointToIndex(vertex, index); - outImage->TransformPhysicalPointToContinuousIndex(vertex, contIndex); - - if (!m_UseTrilinearInterpolation && outImage->GetLargestPossibleRegion().IsInside(index)) + itk::Point startVertex = GetItkPoint(points->GetPoint(j)); + itk::Index<3> startIndex; + itk::ContinuousIndex startIndexCont; + outImage->TransformPhysicalPointToIndex(startVertex, startIndex); + outImage->TransformPhysicalPointToContinuousIndex(startVertex, startIndexCont); + + itk::Point endVertex = GetItkPoint(points->GetPoint(j + 1)); + itk::Index<3> endIndex; + itk::ContinuousIndex endIndexCont; + outImage->TransformPhysicalPointToIndex(endVertex, endIndex); + outImage->TransformPhysicalPointToContinuousIndex(endVertex, endIndexCont); + + std::vector< std::pair< itk::Index<3>, double > > segments = mitk::imv::IntersectImage(newSpacing, startIndex, endIndex, startIndexCont, endIndexCont); + for (std::pair< itk::Index<3>, double > segment : segments) { - if (outImage->GetPixel(index)==0) + if (outImage->GetPixel(segment.first)==0) m_NumCoveredVoxels++; if (m_BinaryOutput) - outImage->SetPixel(index, 1); + outImage->SetPixel(segment.first, 1); else - outImage->SetPixel(index, outImage->GetPixel(index)+weight); - continue; - } - - float frac_x = contIndex[0] - index[0]; - float frac_y = contIndex[1] - index[1]; - float frac_z = contIndex[2] - index[2]; - - if (frac_x<0) - { - index[0] -= 1; - frac_x += 1; - } - if (frac_y<0) - { - index[1] -= 1; - frac_y += 1; - } - if (frac_z<0) - { - index[2] -= 1; - frac_z += 1; - } - - frac_x = 1-frac_x; - frac_y = 1-frac_y; - frac_z = 1-frac_z; - - // int coordinates inside image? - if (index[0] < 0 || index[0] >= w-1) - continue; - if (index[1] < 0 || index[1] >= h-1) - continue; - if (index[2] < 0 || index[2] >= d-1) - continue; - - - if (outImageBufferPointer[( index[0] + w*(index[1] + h*index[2] ))]==0) - m_NumCoveredVoxels++; - if (outImageBufferPointer[( index[0] + w*(index[1]+1+ h*index[2] ))]==0) - m_NumCoveredVoxels++; - if (outImageBufferPointer[( index[0] + w*(index[1] + h*index[2]+h))]==0) - m_NumCoveredVoxels++; - if (outImageBufferPointer[( index[0] + w*(index[1]+1+ h*index[2]+h))]==0) - m_NumCoveredVoxels++; - if (outImageBufferPointer[( index[0]+1 + w*(index[1] + h*index[2] ))]==0) - m_NumCoveredVoxels++; - if (outImageBufferPointer[( index[0]+1 + w*(index[1] + h*index[2]+h))]==0) - m_NumCoveredVoxels++; - if (outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2] ))]==0) - m_NumCoveredVoxels++; - if (outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]+h))]==0) - m_NumCoveredVoxels++; - - if (m_BinaryOutput) - { - outImageBufferPointer[( index[0] + w*(index[1] + h*index[2] ))] = 1; - outImageBufferPointer[( index[0] + w*(index[1]+1+ h*index[2] ))] = 1; - outImageBufferPointer[( index[0] + w*(index[1] + h*index[2]+h))] = 1; - outImageBufferPointer[( index[0] + w*(index[1]+1+ h*index[2]+h))] = 1; - outImageBufferPointer[( index[0]+1 + w*(index[1] + h*index[2] ))] = 1; - outImageBufferPointer[( index[0]+1 + w*(index[1] + h*index[2]+h))] = 1; - outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2] ))] = 1; - outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]+h))] = 1; - } - else - { - outImageBufferPointer[( index[0] + w*(index[1] + h*index[2] ))] += ( frac_x)*( frac_y)*( frac_z); - outImageBufferPointer[( index[0] + w*(index[1]+1+ h*index[2] ))] += ( frac_x)*(1-frac_y)*( frac_z); - outImageBufferPointer[( index[0] + w*(index[1] + h*index[2]+h))] += ( frac_x)*( frac_y)*(1-frac_z); - outImageBufferPointer[( index[0] + w*(index[1]+1+ h*index[2]+h))] += ( frac_x)*(1-frac_y)*(1-frac_z); - outImageBufferPointer[( index[0]+1 + w*(index[1] + h*index[2] ))] += (1-frac_x)*( frac_y)*( frac_z); - outImageBufferPointer[( index[0]+1 + w*(index[1] + h*index[2]+h))] += (1-frac_x)*( frac_y)*(1-frac_z); - outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2] ))] += (1-frac_x)*(1-frac_y)*( frac_z); - outImageBufferPointer[( index[0]+1 + w*(index[1]+1+ h*index[2]+h))] += (1-frac_x)*(1-frac_y)*(1-frac_z); + outImage->SetPixel(segment.first, outImage->GetPixel(segment.first)+segment.second * weight); } } } m_MaxDensity = 0; for (int i=0; i0) for (int i=0; i #include #include #include #include namespace itk{ /** * \brief Generates tract density images from input fiberbundles (Calamante 2010). */ template< class OutputImageType > class TractDensityImageFilter : public ImageSource< OutputImageType > { public: typedef TractDensityImageFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef typename OutputImageType::PixelType OutPixelType; itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkTypeMacro( TractDensityImageFilter, ImageSource ) itkSetMacro( UpsamplingFactor, float) ///< use higher resolution for ouput image itkGetMacro( UpsamplingFactor, float) ///< use higher resolution for ouput image itkSetMacro( InvertImage, bool) ///< voxelvalue = 1-voxelvalue itkGetMacro( InvertImage, bool) ///< voxelvalue = 1-voxelvalue itkSetMacro( BinaryOutput, bool) ///< generate binary fiber envelope itkGetMacro( BinaryOutput, bool) ///< generate binary fiber envelope itkSetMacro( OutputAbsoluteValues, bool) ///< output absolute values of the number of fibers per voxel itkGetMacro( OutputAbsoluteValues, bool) ///< output absolute values of the number of fibers per voxel itkSetMacro( UseImageGeometry, bool) ///< use input image geometry to initialize output image itkGetMacro( UseImageGeometry, bool) ///< use input image geometry to initialize output image itkSetMacro( FiberBundle, mitk::FiberBundle::Pointer) ///< input fiber bundle itkSetMacro( InputImage, typename OutputImageType::Pointer) ///< use input image geometry to initialize output image - itkSetMacro( UseTrilinearInterpolation, bool ) - itkSetMacro( DoFiberResampling, bool ) - itkSetMacro( WorkOnFiberCopy, bool ) itkGetMacro( MaxDensity, OutPixelType) itkGetMacro( NumCoveredVoxels, unsigned int) void GenerateData() override; protected: itk::Point GetItkPoint(double point[3]); TractDensityImageFilter(); ~TractDensityImageFilter() override; typename OutputImageType::Pointer m_InputImage; ///< use input image geometry to initialize output image mitk::FiberBundle::Pointer m_FiberBundle; ///< input fiber bundle float m_UpsamplingFactor; ///< use higher resolution for ouput image bool m_InvertImage; ///< voxelvalue = 1-voxelvalue bool m_BinaryOutput; ///< generate binary fiber envelope bool m_UseImageGeometry; ///< use input image geometry to initialize output image bool m_OutputAbsoluteValues; ///< do not normalize image values to 0-1 bool m_UseTrilinearInterpolation; bool m_DoFiberResampling; bool m_WorkOnFiberCopy; OutPixelType m_MaxDensity; unsigned int m_NumCoveredVoxels; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkTractDensityImageFilter.cpp" #endif #endif // __itkTractDensityImageFilter_h__ diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToRgbaImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToRgbaImageFilter.cpp index 1d68533729..044a6a265c 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToRgbaImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToRgbaImageFilter.cpp @@ -1,284 +1,197 @@ /*=================================================================== 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 "itkTractsToRgbaImageFilter.h" // VTK #include #include #include // misc #include #include +#include namespace itk{ - template< class OutputImageType > - TractsToRgbaImageFilter< OutputImageType >::TractsToRgbaImageFilter() - : m_UpsamplingFactor(1) - , m_UseImageGeometry(false) - , m_InputImage(nullptr) - { +template< class OutputImageType > +TractsToRgbaImageFilter< OutputImageType >::TractsToRgbaImageFilter() + : m_UpsamplingFactor(1) + , m_UseImageGeometry(false) + , m_InputImage(nullptr) +{ - } +} + +template< class OutputImageType > +TractsToRgbaImageFilter< OutputImageType >::~TractsToRgbaImageFilter() +{ +} + +template< class OutputImageType > +itk::Point TractsToRgbaImageFilter< OutputImageType >::GetItkPoint(double point[3]) +{ + itk::Point itkPoint; + itkPoint[0] = point[0]; + itkPoint[1] = point[1]; + itkPoint[2] = point[2]; + return itkPoint; +} - template< class OutputImageType > - TractsToRgbaImageFilter< OutputImageType >::~TractsToRgbaImageFilter() +template< class OutputImageType > +void TractsToRgbaImageFilter< OutputImageType >::GenerateData() +{ + if(&typeid(OutPixelType) != &typeid(itk::RGBAPixel)) + return; + + // generate upsampled image + mitk::BaseGeometry::Pointer geometry = m_FiberBundle->GetGeometry(); + typename OutputImageType::Pointer outImage = this->GetOutput(); + + // calculate new image parameters + itk::Vector newSpacing; + mitk::Point3D newOrigin; + itk::Matrix newDirection; + ImageRegion<3> upsampledRegion; + if (m_UseImageGeometry && !m_InputImage.IsNull()) { + newSpacing = m_InputImage->GetSpacing()/m_UpsamplingFactor; + upsampledRegion = m_InputImage->GetLargestPossibleRegion(); + newOrigin = m_InputImage->GetOrigin(); + typename OutputImageType::RegionType::SizeType size = upsampledRegion.GetSize(); + size[0] *= m_UpsamplingFactor; + size[1] *= m_UpsamplingFactor; + size[2] *= m_UpsamplingFactor; + upsampledRegion.SetSize(size); + newDirection = m_InputImage->GetDirection(); } - - template< class OutputImageType > - itk::Point TractsToRgbaImageFilter< OutputImageType >::GetItkPoint(double point[3]) + else { - itk::Point itkPoint; - itkPoint[0] = point[0]; - itkPoint[1] = point[1]; - itkPoint[2] = point[2]; - return itkPoint; + newSpacing = geometry->GetSpacing()/m_UpsamplingFactor; + newOrigin = geometry->GetOrigin(); + mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds(); + newOrigin[0] += bounds.GetElement(0); + newOrigin[1] += bounds.GetElement(2); + newOrigin[2] += bounds.GetElement(4); + + for (int i=0; i<3; i++) + for (int j=0; j<3; j++) + newDirection[j][i] = geometry->GetMatrixColumn(i)[j]; + upsampledRegion.SetSize(0, geometry->GetExtent(0)*m_UpsamplingFactor); + upsampledRegion.SetSize(1, geometry->GetExtent(1)*m_UpsamplingFactor); + upsampledRegion.SetSize(2, geometry->GetExtent(2)*m_UpsamplingFactor); } - - template< class OutputImageType > - void TractsToRgbaImageFilter< OutputImageType >::GenerateData() + typename OutputImageType::RegionType::SizeType upsampledSize = upsampledRegion.GetSize(); + + // apply new image parameters + outImage->SetSpacing( newSpacing ); + outImage->SetOrigin( newOrigin ); + outImage->SetDirection( newDirection ); + outImage->SetRegions( upsampledRegion ); + outImage->Allocate(); + outImage->FillBuffer(0.0); + + itk::Image< itk::RGBAPixel, 3 >::Pointer double_out = itk::Image< itk::RGBAPixel, 3 >::New(); + double_out->SetSpacing( newSpacing ); + double_out->SetOrigin( newOrigin ); + double_out->SetDirection( newDirection ); + double_out->SetRegions( upsampledRegion ); + double_out->Allocate(); + double_out->FillBuffer(0.0); + + vtkSmartPointer fiberPolyData = m_FiberBundle->GetFiberPolyData(); + int numFibers = m_FiberBundle->GetNumFibers(); + + float scale = 100 * pow((float)m_UpsamplingFactor,3); + boost::progress_display disp(numFibers); + for( int i=0; i)) - return; - - // generate upsampled image - mitk::BaseGeometry::Pointer geometry = m_FiberBundle->GetGeometry(); - typename OutputImageType::Pointer outImage = this->GetOutput(); - - // calculate new image parameters - itk::Vector newSpacing; - mitk::Point3D newOrigin; - itk::Matrix newDirection; - ImageRegion<3> upsampledRegion; - if (m_UseImageGeometry && !m_InputImage.IsNull()) - { - newSpacing = m_InputImage->GetSpacing()/m_UpsamplingFactor; - upsampledRegion = m_InputImage->GetLargestPossibleRegion(); - newOrigin = m_InputImage->GetOrigin(); - typename OutputImageType::RegionType::SizeType size = upsampledRegion.GetSize(); - size[0] *= m_UpsamplingFactor; - size[1] *= m_UpsamplingFactor; - size[2] *= m_UpsamplingFactor; - upsampledRegion.SetSize(size); - newDirection = m_InputImage->GetDirection(); - } - else - { - newSpacing = geometry->GetSpacing()/m_UpsamplingFactor; - newOrigin = geometry->GetOrigin(); - mitk::Geometry3D::BoundsArrayType bounds = geometry->GetBounds(); - newOrigin[0] += bounds.GetElement(0); - newOrigin[1] += bounds.GetElement(2); - newOrigin[2] += bounds.GetElement(4); - - for (int i=0; i<3; i++) - for (int j=0; j<3; j++) - newDirection[j][i] = geometry->GetMatrixColumn(i)[j]; - upsampledRegion.SetSize(0, geometry->GetExtent(0)*m_UpsamplingFactor); - upsampledRegion.SetSize(1, geometry->GetExtent(1)*m_UpsamplingFactor); - upsampledRegion.SetSize(2, geometry->GetExtent(2)*m_UpsamplingFactor); - } - typename OutputImageType::RegionType::SizeType upsampledSize = upsampledRegion.GetSize(); - - // apply new image parameters - outImage->SetSpacing( newSpacing ); - outImage->SetOrigin( newOrigin ); - outImage->SetDirection( newDirection ); - outImage->SetRegions( upsampledRegion ); - outImage->Allocate(); - - int w = upsampledSize[0]; - int h = upsampledSize[1]; - int d = upsampledSize[2]; - - // set/initialize output - unsigned char* outImageBufferPointer = (unsigned char*)outImage->GetBufferPointer(); - float* buffer = new float[w*h*d*4]; - for (int i=0; iGetDeepCopy(); - m_FiberBundle->ResampleLinear(minSpacing); - - vtkSmartPointer fiberPolyData = m_FiberBundle->GetFiberPolyData(); + ++disp; + vtkCell* cell = fiberPolyData->GetCell(i); + int numPoints = cell->GetNumberOfPoints(); + vtkPoints* points = cell->GetPoints(); - int numFibers = m_FiberBundle->GetNumFibers(); - boost::progress_display disp(numFibers); - for( int i=0; iGetCell(i); - int numPoints = cell->GetNumberOfPoints(); - vtkPoints* points = cell->GetPoints(); - - // calc directions (which are used as weights) - std::list< itk::Point > rgbweights; - std::list intensities; - - for( int j=0; j startVertex = GetItkPoint(points->GetPoint(j)); + Index<3> startIndex; + ContinuousIndex startIndexCont; + double_out->TransformPhysicalPointToIndex(startVertex, startIndex); + double_out->TransformPhysicalPointToContinuousIndex(startVertex, startIndexCont); + + Point endVertex = GetItkPoint(points->GetPoint(j + 1)); + Index<3> endIndex; + ContinuousIndex endIndexCont; + double_out->TransformPhysicalPointToIndex(endVertex, endIndex); + double_out->TransformPhysicalPointToContinuousIndex(endVertex, endIndexCont); + + Vector dir; + dir[0] = fabs(endVertex[0]-startVertex[0]); + dir[1] = fabs(endVertex[1]-startVertex[1]); + dir[2] = fabs(endVertex[2]-startVertex[2]); + dir.Normalize(); + + std::vector< std::pair< itk::Index<3>, double > > segments = mitk::imv::IntersectImage(newSpacing, startIndex, endIndex, startIndexCont, endIndexCont); + for (std::pair< itk::Index<3>, double > segment : segments) { - - itk::Point vertex = GetItkPoint(points->GetPoint(j)); - itk::Point vertexPost = GetItkPoint(points->GetPoint(j+1)); - - itk::Point dir; - dir[0] = fabs((vertexPost[0] - vertex[0]) * outImage->GetSpacing()[0]); - dir[1] = fabs((vertexPost[1] - vertex[1]) * outImage->GetSpacing()[1]); - dir[2] = fabs((vertexPost[2] - vertex[2]) * outImage->GetSpacing()[2]); - - rgbweights.push_back(dir); - - float intensity = sqrt(dir[0]*dir[0]+dir[1]*dir[1]+dir[2]*dir[2]); - intensities.push_back(intensity); - - // last point gets same as previous one - if(j==numPoints-2) - { - rgbweights.push_back(dir); - intensities.push_back(intensity); - } - } - - // fill output image - for( int j=0; j vertex = GetItkPoint(points->GetPoint(j)); - itk::Index<3> index; - itk::ContinuousIndex contIndex; - outImage->TransformPhysicalPointToIndex(vertex, index); - outImage->TransformPhysicalPointToContinuousIndex(vertex, contIndex); - - float frac_x = contIndex[0] - index[0]; - float frac_y = contIndex[1] - index[1]; - float frac_z = contIndex[2] - index[2]; - - int px = index[0]; - if (frac_x<0) - { - px -= 1; - frac_x += 1; - } - - int py = index[1]; - if (frac_y<0) - { - py -= 1; - frac_y += 1; - } - - int pz = index[2]; - if (frac_z<0) - { - pz -= 1; - frac_z += 1; - } - - // int coordinates inside image? - if (px < 0 || px >= w-1) - continue; - if (py < 0 || py >= h-1) - continue; - if (pz < 0 || pz >= d-1) + if (!double_out->GetLargestPossibleRegion().IsInside(segment.first)) continue; - float scale = 100 * pow((float)m_UpsamplingFactor,3); - itk::Point rgbweight = rgbweights.front(); - rgbweights.pop_front(); - float intweight = intensities.front(); - intensities.pop_front(); - - // add to r-channel in output image - buffer[0+4*( px + w*(py + h*pz ))] += (1-frac_x)*(1-frac_y)*(1-frac_z) * rgbweight[0] * scale; - buffer[0+4*( px + w*(py+1+ h*pz ))] += (1-frac_x)*( frac_y)*(1-frac_z) * rgbweight[0] * scale; - buffer[0+4*( px + w*(py + h*pz+h))] += (1-frac_x)*(1-frac_y)*( frac_z) * rgbweight[0] * scale; - buffer[0+4*( px + w*(py+1+ h*pz+h))] += (1-frac_x)*( frac_y)*( frac_z) * rgbweight[0] * scale; - buffer[0+4*( px+1 + w*(py + h*pz ))] += ( frac_x)*(1-frac_y)*(1-frac_z) * rgbweight[0] * scale; - buffer[0+4*( px+1 + w*(py + h*pz+h))] += ( frac_x)*(1-frac_y)*( frac_z) * rgbweight[0] * scale; - buffer[0+4*( px+1 + w*(py+1+ h*pz ))] += ( frac_x)*( frac_y)*(1-frac_z) * rgbweight[0] * scale; - buffer[0+4*( px+1 + w*(py+1+ h*pz+h))] += ( frac_x)*( frac_y)*( frac_z) * rgbweight[0] * scale; - - // add to g-channel in output image - buffer[1+4*( px + w*(py + h*pz ))] += (1-frac_x)*(1-frac_y)*(1-frac_z) * rgbweight[1] * scale; - buffer[1+4*( px + w*(py+1+ h*pz ))] += (1-frac_x)*( frac_y)*(1-frac_z) * rgbweight[1] * scale; - buffer[1+4*( px + w*(py + h*pz+h))] += (1-frac_x)*(1-frac_y)*( frac_z) * rgbweight[1] * scale; - buffer[1+4*( px + w*(py+1+ h*pz+h))] += (1-frac_x)*( frac_y)*( frac_z) * rgbweight[1] * scale; - buffer[1+4*( px+1 + w*(py + h*pz ))] += ( frac_x)*(1-frac_y)*(1-frac_z) * rgbweight[1] * scale; - buffer[1+4*( px+1 + w*(py + h*pz+h))] += ( frac_x)*(1-frac_y)*( frac_z) * rgbweight[1] * scale; - buffer[1+4*( px+1 + w*(py+1+ h*pz ))] += ( frac_x)*( frac_y)*(1-frac_z) * rgbweight[1] * scale; - buffer[1+4*( px+1 + w*(py+1+ h*pz+h))] += ( frac_x)*( frac_y)*( frac_z) * rgbweight[1] * scale; - - // add to b-channel in output image - buffer[2+4*( px + w*(py + h*pz ))] += (1-frac_x)*(1-frac_y)*(1-frac_z) * rgbweight[2] * scale; - buffer[2+4*( px + w*(py+1+ h*pz ))] += (1-frac_x)*( frac_y)*(1-frac_z) * rgbweight[2] * scale; - buffer[2+4*( px + w*(py + h*pz+h))] += (1-frac_x)*(1-frac_y)*( frac_z) * rgbweight[2] * scale; - buffer[2+4*( px + w*(py+1+ h*pz+h))] += (1-frac_x)*( frac_y)*( frac_z) * rgbweight[2] * scale; - buffer[2+4*( px+1 + w*(py + h*pz ))] += ( frac_x)*(1-frac_y)*(1-frac_z) * rgbweight[2] * scale; - buffer[2+4*( px+1 + w*(py + h*pz+h))] += ( frac_x)*(1-frac_y)*( frac_z) * rgbweight[2] * scale; - buffer[2+4*( px+1 + w*(py+1+ h*pz ))] += ( frac_x)*( frac_y)*(1-frac_z) * rgbweight[2] * scale; - buffer[2+4*( px+1 + w*(py+1+ h*pz+h))] += ( frac_x)*( frac_y)*( frac_z) * rgbweight[2] * scale; + itk::RGBAPixel pix = double_out->GetPixel(segment.first); + pix[0] += dir[0] * scale; + pix[1] += dir[1] * scale; + pix[2] += dir[2] * scale; + pix[3] += segment.second * scale; - // add to a-channel in output image - buffer[3+4*( px + w*(py + h*pz ))] += (1-frac_x)*(1-frac_y)*(1-frac_z) * intweight * scale; - buffer[3+4*( px + w*(py+1+ h*pz ))] += (1-frac_x)*( frac_y)*(1-frac_z) * intweight * scale; - buffer[3+4*( px + w*(py + h*pz+h))] += (1-frac_x)*(1-frac_y)*( frac_z) * intweight * scale; - buffer[3+4*( px + w*(py+1+ h*pz+h))] += (1-frac_x)*( frac_y)*( frac_z) * intweight * scale; - buffer[3+4*( px+1 + w*(py + h*pz ))] += ( frac_x)*(1-frac_y)*(1-frac_z) * intweight * scale; - buffer[3+4*( px+1 + w*(py + h*pz+h))] += ( frac_x)*(1-frac_y)*( frac_z) * intweight * scale; - buffer[3+4*( px+1 + w*(py+1+ h*pz ))] += ( frac_x)*( frac_y)*(1-frac_z) * intweight * scale; - buffer[3+4*( px+1 + w*(py+1+ h*pz+h))] += ( frac_x)*( frac_y)*( frac_z) * intweight * scale; + double_out->SetPixel(segment.first, pix); } } + float maxRgb = 0.000000001; float maxInt = 0.000000001; - int numPix; + int w = upsampledSize[0]; + int h = upsampledSize[1]; + int d = upsampledSize[2]; + int numPix = w*h*d*4; - numPix = w*h*d*4; + double* buffer = (double*)double_out->GetBufferPointer(); // calc maxima for(int i=0; i maxRgb) maxRgb = buffer[i]; } else { if(buffer[i] > maxInt) maxInt = buffer[i]; } } // write output, normalized uchar 0..255 + unsigned char* outImageBufferPointer = (unsigned char*)outImage->GetBufferPointer(); for(int i=0; i #include #include // ITK #include #include // misc #define _USE_MATH_DEFINES #include #include - +#include namespace itk{ static inline bool CompareVectorLengths(const vnl_vector_fixed< double, 3 >& v1, const vnl_vector_fixed< double, 3 >& v2) { return (v1.magnitude()>v2.magnitude()); } template< class PixelType > TractsToVectorImageFilter< PixelType >::TractsToVectorImageFilter(): m_NormalizationMethod(GLOBAL_MAX), m_AngularThreshold(0.7), m_Epsilon(0.999), - m_UseWorkingCopy(true), m_MaxNumDirections(3), m_SizeThreshold(0.3) { this->SetNumberOfRequiredOutputs(1); } template< class PixelType > TractsToVectorImageFilter< PixelType >::~TractsToVectorImageFilter() { } template< class PixelType > vnl_vector_fixed TractsToVectorImageFilter< PixelType >::GetVnlVector(double point[]) { vnl_vector_fixed vnlVector; vnlVector[0] = point[0]; vnlVector[1] = point[1]; vnlVector[2] = point[2]; return vnlVector; } template< class PixelType > itk::Point TractsToVectorImageFilter< PixelType >::GetItkPoint(double point[]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } template< class PixelType > void TractsToVectorImageFilter< PixelType >::GenerateData() { mitk::BaseGeometry::Pointer geometry = m_FiberBundle->GetGeometry(); // calculate new image parameters itk::Vector spacing3; itk::Point origin3; itk::Matrix direction3; ImageRegion<3> imageRegion3; if (!m_MaskImage.IsNull()) { spacing3 = m_MaskImage->GetSpacing(); imageRegion3 = m_MaskImage->GetLargestPossibleRegion(); origin3 = m_MaskImage->GetOrigin(); direction3 = m_MaskImage->GetDirection(); } else { spacing3 = geometry->GetSpacing(); origin3 = geometry->GetOrigin(); mitk::BaseGeometry::BoundsArrayType bounds = geometry->GetBounds(); origin3[0] += bounds.GetElement(0); origin3[1] += bounds.GetElement(2); origin3[2] += bounds.GetElement(4); for (int i=0; i<3; i++) for (int j=0; j<3; j++) direction3[j][i] = geometry->GetMatrixColumn(i)[j]; imageRegion3.SetSize(0, geometry->GetExtent(0)+1); imageRegion3.SetSize(1, geometry->GetExtent(1)+1); imageRegion3.SetSize(2, geometry->GetExtent(2)+1); m_MaskImage = ItkUcharImgType::New(); m_MaskImage->SetSpacing( spacing3 ); m_MaskImage->SetOrigin( origin3 ); m_MaskImage->SetDirection( direction3 ); m_MaskImage->SetRegions( imageRegion3 ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } OutputImageType::RegionType::SizeType outImageSize = imageRegion3.GetSize(); m_OutImageSpacing = m_MaskImage->GetSpacing(); m_ClusteredDirectionsContainer = ContainerType::New(); // initialize num directions image m_NumDirectionsImage = ItkUcharImgType::New(); m_NumDirectionsImage->SetSpacing( spacing3 ); m_NumDirectionsImage->SetOrigin( origin3 ); m_NumDirectionsImage->SetDirection( direction3 ); m_NumDirectionsImage->SetRegions( imageRegion3 ); m_NumDirectionsImage->Allocate(); m_NumDirectionsImage->FillBuffer(0); itk::Vector spacing4; itk::Point origin4; itk::Matrix direction4; itk::ImageRegion<4> imageRegion4; spacing4[0] = spacing3[0]; spacing4[1] = spacing3[1]; spacing4[2] = spacing3[2]; spacing4[3] = 1; origin4[0] = origin3[0]; origin4[1] = origin3[1]; origin4[2] = origin3[2]; origin3[3] = 0; for (int r=0; r<3; r++) for (int c=0; c<3; c++) direction4[r][c] = direction3[r][c]; direction4[3][3] = 1; imageRegion4.SetSize(0, imageRegion3.GetSize()[0]); imageRegion4.SetSize(1, imageRegion3.GetSize()[1]); imageRegion4.SetSize(2, imageRegion3.GetSize()[2]); imageRegion4.SetSize(3, m_MaxNumDirections*3); m_DirectionImage = ItkDirectionImageType::New(); m_DirectionImage->SetSpacing( spacing4 ); m_DirectionImage->SetOrigin( origin4 ); m_DirectionImage->SetDirection( direction4 ); m_DirectionImage->SetRegions( imageRegion4 ); m_DirectionImage->Allocate(); m_DirectionImage->FillBuffer(0.0); - // resample fiber bundle - double minSpacing = 1; - if(m_OutImageSpacing[0]GetDeepCopy(); - - // resample fiber bundle for sufficient voxel coverage - m_FiberBundle->ResampleLinear(minSpacing/10); - // iterate over all fibers vtkSmartPointer fiberPolyData = m_FiberBundle->GetFiberPolyData(); int numFibers = m_FiberBundle->GetNumFibers(); m_DirectionsContainer = ContainerType::New(); VectorContainer< unsigned int, std::vector< double > >::Pointer peakLengths = VectorContainer< unsigned int, std::vector< double > >::New(); MITK_INFO << "Generating directions from tractogram"; boost::progress_display disp(numFibers); for( int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (numPoints<2) continue; vnl_vector_fixed dir; - itk::Point worldPos; vnl_vector v; - float fiberWeight = m_FiberBundle->GetFiberWeight(i); for( int j=0; jGetPoint(j); - worldPos = GetItkPoint(temp); - itk::Index<3> index; - m_MaskImage->TransformPhysicalPointToIndex(worldPos, index); - if (!m_MaskImage->GetLargestPossibleRegion().IsInside(index) || m_MaskImage->GetPixel(index)==0) - continue; - - // get fiber tangent direction at this position - v = GetVnlVector(temp); - dir = GetVnlVector(points->GetPoint(j+1))-v; + itk::Point startVertex = GetItkPoint(points->GetPoint(j)); + itk::Index<3> startIndex; + itk::ContinuousIndex startIndexCont; + m_MaskImage->TransformPhysicalPointToIndex(startVertex, startIndex); + m_MaskImage->TransformPhysicalPointToContinuousIndex(startVertex, startIndexCont); + + itk::Point endVertex = GetItkPoint(points->GetPoint(j + 1)); + itk::Index<3> endIndex; + itk::ContinuousIndex endIndexCont; + m_MaskImage->TransformPhysicalPointToIndex(endVertex, endIndex); + m_MaskImage->TransformPhysicalPointToContinuousIndex(endVertex, endIndexCont); + + dir[0] = endVertex[0]-startVertex[0]; + dir[1] = endVertex[1]-startVertex[1]; + dir[2] = endVertex[2]-startVertex[2]; if (dir.is_zero()) continue; dir.normalize(); - // add direction to container - unsigned int idx = index[0] + outImageSize[0]*(index[1] + outImageSize[1]*index[2]); - DirectionContainerType::Pointer dirCont; - if (m_DirectionsContainer->IndexExists(idx)) + std::vector< std::pair< itk::Index<3>, double > > segments = mitk::imv::IntersectImage(spacing3, startIndex, endIndex, startIndexCont, endIndexCont); + for (std::pair< itk::Index<3>, double > segment : segments) { - peakLengths->ElementAt(idx).push_back(fiberWeight); + if (!m_MaskImage->GetLargestPossibleRegion().IsInside(segment.first) || m_MaskImage->GetPixel(segment.first)==0) + continue; - dirCont = m_DirectionsContainer->GetElement(idx); - if (dirCont.IsNull()) + // add direction to container + unsigned int idx = segment.first[0] + outImageSize[0]*(segment.first[1] + outImageSize[1]*segment.first[2]); + DirectionContainerType::Pointer dirCont; + if (m_DirectionsContainer->IndexExists(idx)) + { + peakLengths->ElementAt(idx).push_back(fiberWeight*segment.second); + + dirCont = m_DirectionsContainer->GetElement(idx); + if (dirCont.IsNull()) + { + dirCont = DirectionContainerType::New(); + dirCont->push_back(dir); + m_DirectionsContainer->InsertElement(idx, dirCont); + } + else + dirCont->push_back(dir); + } + else { dirCont = DirectionContainerType::New(); dirCont->push_back(dir); m_DirectionsContainer->InsertElement(idx, dirCont); + + std::vector< double > lengths; lengths.push_back(fiberWeight*segment.second); + peakLengths->InsertElement(idx, lengths); } - else - dirCont->push_back(dir); } - else - { - dirCont = DirectionContainerType::New(); - dirCont->push_back(dir); - m_DirectionsContainer->InsertElement(idx, dirCont); - std::vector< double > lengths; lengths.push_back(fiberWeight); - peakLengths->InsertElement(idx, lengths); - } } } itk::ImageRegionIterator dirIt(m_NumDirectionsImage, m_NumDirectionsImage->GetLargestPossibleRegion()); MITK_INFO << "Clustering directions"; float max_dir_mag = 0; boost::progress_display disp2(outImageSize[0]*outImageSize[1]*outImageSize[2]); while(!dirIt.IsAtEnd()) { ++disp2; OutputImageType::IndexType idx3 = dirIt.GetIndex(); int idx_lin = idx3[0]+(idx3[1]+idx3[2]*outImageSize[1])*outImageSize[0]; itk::Index<4> idx4; idx4[0] = idx3[0]; idx4[1] = idx3[1]; idx4[2] = idx3[2]; if (!m_DirectionsContainer->IndexExists(idx_lin)) { ++dirIt; continue; } DirectionContainerType::Pointer dirCont = m_DirectionsContainer->GetElement(idx_lin); if (dirCont.IsNull() || dirCont->empty()) { ++dirIt; continue; } DirectionContainerType::Pointer directions; if (m_MaxNumDirections>0) { directions = FastClustering(dirCont, peakLengths->GetElement(idx_lin)); std::sort( directions->begin(), directions->end(), CompareVectorLengths ); } else directions = dirCont; unsigned int numDir = directions->size(); if (m_MaxNumDirections>0 && numDir>m_MaxNumDirections) numDir = m_MaxNumDirections; float voxel_max_mag = 0; for (unsigned int i=0; iat(i); float mag = dir.magnitude(); if (mag>voxel_max_mag) voxel_max_mag = mag; if (mag>max_dir_mag) max_dir_mag = mag; } int count = 0; for (unsigned int i=0; iat(i); count++; float mag = dir.magnitude(); if (m_NormalizationMethod==MAX_VEC_NORM && voxel_max_mag>mitk::eps) dir /= voxel_max_mag; else if (m_NormalizationMethod==SINGLE_VEC_NORM && mag>mitk::eps) dir.normalize(); for (unsigned int j = 0; j<3; j++) { idx4[3] = i*3 + j; m_DirectionImage->SetPixel(idx4, dir[j]); } } dirIt.Set(count); ++dirIt; } if (m_NormalizationMethod==GLOBAL_MAX && max_dir_mag>0) { itk::ImageRegionIterator dirImgIt(m_DirectionImage, m_DirectionImage->GetLargestPossibleRegion()); while(!dirImgIt.IsAtEnd()) { dirImgIt.Set(dirImgIt.Get()/max_dir_mag); ++dirImgIt; } } } template< class PixelType > TractsToVectorImageFilter< PixelType >::DirectionContainerType::Pointer TractsToVectorImageFilter< PixelType >::FastClustering(DirectionContainerType::Pointer inDirs, std::vector< double > lengths) { DirectionContainerType::Pointer outDirs = DirectionContainerType::New(); if (inDirs->size()<2) { if (inDirs->size()==1) inDirs->SetElement(0, inDirs->at(0)*lengths.at(0)); return inDirs; } DirectionType oldMean, currentMean; std::vector< int > touched; // initialize touched.resize(inDirs->size(), 0); bool free = true; currentMean = inDirs->at(0); // initialize first seed currentMean.normalize(); double length = lengths.at(0); touched[0] = 1; std::vector< double > newLengths; bool meanChanged = false; double max = 0; while (free) { oldMean.fill(0.0); // start mean-shift clustering double angle = 0; while (fabs(dot_product(currentMean, oldMean))<0.99) { oldMean = currentMean; currentMean.fill(0.0); for (unsigned int i=0; isize(); i++) { angle = dot_product(oldMean, inDirs->at(i)); if (angle>=m_AngularThreshold) { currentMean += inDirs->at(i); if (meanChanged) length += lengths.at(i); touched[i] = 1; meanChanged = true; } else if (-angle>=m_AngularThreshold) { currentMean -= inDirs->at(i); if (meanChanged) length += lengths.at(i); touched[i] = 1; meanChanged = true; } } if(!meanChanged) currentMean = oldMean; else currentMean.normalize(); } // found stable mean outDirs->push_back(currentMean); newLengths.push_back(length); if (length>max) max = length; // find next unused seed free = false; for (unsigned int i=0; iat(i); free = true; meanChanged = false; length = lengths.at(i); touched[i] = 1; break; } } if (inDirs->size()==outDirs->size()) { if (max>0) { for (unsigned int i=0; isize(); i++) outDirs->SetElement(i, outDirs->at(i)*newLengths.at(i)); } return outDirs; } else return FastClustering(outDirs, newLengths); } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.h index 7e2ee9198c..e8c9f4a0b7 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkTractsToVectorImageFilter.h @@ -1,106 +1,103 @@ #ifndef __itkTractsToVectorImageFilter_h__ #define __itkTractsToVectorImageFilter_h__ // MITK #include // ITK #include #include // VTK #include #include #include #include #include namespace itk{ /** * \brief Extracts the voxel-wise main directions of the input fiber bundle. */ template< class PixelType > class TractsToVectorImageFilter : public ImageSource< Image< PixelType, 4 > > { public: enum NormalizationMethods { GLOBAL_MAX, ///< global maximum normalization SINGLE_VEC_NORM, ///< normalize the single peaks to length 1 MAX_VEC_NORM ///< normalize all peaks according to their length in comparison to the largest peak in the voxel (0-1) }; typedef TractsToVectorImageFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef itk::Vector OutputVectorType; typedef itk::Image OutputImageType; typedef std::vector< OutputImageType::Pointer > OutputImageContainerType; typedef vnl_vector_fixed< double, 3 > DirectionType; typedef VectorContainer< unsigned int, DirectionType > DirectionContainerType; typedef VectorContainer< unsigned int, DirectionContainerType::Pointer > ContainerType; typedef Image< PixelType, 4 > ItkDirectionImageType; typedef itk::Image ItkUcharImgType; typedef itk::Image ItkDoubleImgType; itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkTypeMacro( TractsToVectorImageFilter, ImageSource ) itkSetMacro( SizeThreshold, float) itkGetMacro( SizeThreshold, float) itkSetMacro( AngularThreshold, float) ///< cluster directions that are closer together than the specified threshold itkGetMacro( AngularThreshold, float) ///< cluster directions that are closer together than the specified threshold itkSetMacro( NormalizationMethod, NormalizationMethods) ///< normalization method of peaks - itkSetMacro( UseWorkingCopy, bool) ///< Do not modify input fiber bundle. Use a copy. - itkGetMacro( UseWorkingCopy, bool) ///< Do not modify input fiber bundle. Use a copy. itkSetMacro( MaxNumDirections, unsigned long) ///< If more directions are extracted, only the largest are kept. itkGetMacro( MaxNumDirections, unsigned long) ///< If more directions are extracted, only the largest are kept. itkSetMacro( MaskImage, ItkUcharImgType::Pointer) ///< only process voxels inside mask itkSetMacro( FiberBundle, mitk::FiberBundle::Pointer) ///< input fiber bundle itkGetMacro( ClusteredDirectionsContainer, ContainerType::Pointer) ///< output directions itkGetMacro( NumDirectionsImage, ItkUcharImgType::Pointer) ///< number of directions per voxel itkGetMacro( DirectionImage, typename ItkDirectionImageType::Pointer) ///< output directions void GenerateData() override; protected: DirectionContainerType::Pointer FastClustering(DirectionContainerType::Pointer inDirs, std::vector< double > lengths); ///< cluster fiber directions vnl_vector_fixed GetVnlVector(double point[3]); itk::Point GetItkPoint(double point[3]); TractsToVectorImageFilter(); ~TractsToVectorImageFilter() override; NormalizationMethods m_NormalizationMethod; ///< normalization method of peaks mitk::FiberBundle::Pointer m_FiberBundle; ///< input fiber bundle float m_AngularThreshold; ///< cluster directions that are closer together than the specified threshold float m_Epsilon; ///< epsilon for vector equality check ItkUcharImgType::Pointer m_MaskImage; ///< only voxels inside the binary mask are processed itk::Vector m_OutImageSpacing; ///< spacing of output image ContainerType::Pointer m_DirectionsContainer; ///< container for fiber directions - bool m_UseWorkingCopy; ///< do not modify input fiber bundle but work on copy unsigned long m_MaxNumDirections; ///< if more directions per voxel are extracted, only the largest are kept float m_SizeThreshold; // output datastructures typename ItkDirectionImageType::Pointer m_DirectionImage; ContainerType::Pointer m_ClusteredDirectionsContainer; ///< contains direction vectors for each voxel ItkUcharImgType::Pointer m_NumDirectionsImage; ///< shows number of fibers per voxel }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkTractsToVectorImageFilter.cpp" #endif #endif // __itkTractsToVectorImageFilter_h__ diff --git a/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp index c246971545..32b66414a7 100755 --- a/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp @@ -1,1742 +1,1732 @@ /*=================================================================== 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 "itkTractsToDWIImageFilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace itk { template< class PixelType > TractsToDWIImageFilter< PixelType >::TractsToDWIImageFilter() - : m_FiberBundle(nullptr) - , m_StatusText("") + : m_StatusText("") , m_UseConstantRandSeed(false) , m_RandGen(itk::Statistics::MersenneTwisterRandomVariateGenerator::New()) { m_RandGen->SetSeed(); m_DoubleInterpolator = itk::LinearInterpolateImageFunction< ItkDoubleImgType, float >::New(); m_NullDir.Fill(0); } template< class PixelType > TractsToDWIImageFilter< PixelType >::~TractsToDWIImageFilter() { } template< class PixelType > TractsToDWIImageFilter< PixelType >::DoubleDwiType::Pointer TractsToDWIImageFilter< PixelType >:: SimulateKspaceAcquisition( std::vector< DoubleDwiType::Pointer >& compartment_images ) { unsigned int numFiberCompartments = m_Parameters.m_FiberModelList.size(); // create slice object ImageRegion<2> sliceRegion; sliceRegion.SetSize(0, m_WorkingImageRegion.GetSize()[0]); sliceRegion.SetSize(1, m_WorkingImageRegion.GetSize()[1]); Vector< double, 2 > sliceSpacing; sliceSpacing[0] = m_WorkingSpacing[0]; sliceSpacing[1] = m_WorkingSpacing[1]; DoubleDwiType::PixelType nullPix; nullPix.SetSize(compartment_images.at(0)->GetVectorLength()); nullPix.Fill(0.0); auto magnitudeDwiImage = DoubleDwiType::New(); magnitudeDwiImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); magnitudeDwiImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); magnitudeDwiImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); magnitudeDwiImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); magnitudeDwiImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); magnitudeDwiImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); magnitudeDwiImage->SetVectorLength( compartment_images.at(0)->GetVectorLength() ); magnitudeDwiImage->Allocate(); magnitudeDwiImage->FillBuffer(nullPix); m_PhaseImage = DoubleDwiType::New(); m_PhaseImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); m_PhaseImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); m_PhaseImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_PhaseImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_PhaseImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_PhaseImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_PhaseImage->SetVectorLength( compartment_images.at(0)->GetVectorLength() ); m_PhaseImage->Allocate(); m_PhaseImage->FillBuffer(nullPix); m_KspaceImage = DoubleDwiType::New(); m_KspaceImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); m_KspaceImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); m_KspaceImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_KspaceImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_KspaceImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_KspaceImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_KspaceImage->SetVectorLength( m_Parameters.m_SignalGen.m_NumberOfCoils ); m_KspaceImage->Allocate(); m_KspaceImage->FillBuffer(nullPix); std::vector< unsigned int > spikeVolume; for (unsigned int i=0; iGetIntegerVariate()%(compartment_images.at(0)->GetVectorLength())); std::sort (spikeVolume.begin(), spikeVolume.end()); std::reverse (spikeVolume.begin(), spikeVolume.end()); // calculate coil positions double a = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(0)*m_Parameters.m_SignalGen.m_ImageSpacing[0]; double b = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(1)*m_Parameters.m_SignalGen.m_ImageSpacing[1]; double c = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(2)*m_Parameters.m_SignalGen.m_ImageSpacing[2]; double diagonal = sqrt(a*a+b*b)/1000; // image diagonal in m m_CoilPointset = mitk::PointSet::New(); std::vector< itk::Vector > coilPositions; itk::Vector pos; pos.Fill(0.0); pos[1] = -diagonal/2; itk::Vector center; center[0] = a/2-m_Parameters.m_SignalGen.m_ImageSpacing[0]/2; center[1] = b/2-m_Parameters.m_SignalGen.m_ImageSpacing[2]/2; center[2] = c/2-m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; for (int c=0; cInsertPoint(c, pos*1000 + m_Parameters.m_SignalGen.m_ImageOrigin.GetVectorFromOrigin() + center ); double rz = 360.0/m_Parameters.m_SignalGen.m_NumberOfCoils * itk::Math::pi/180; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; pos.SetVnlVector(rotZ*pos.GetVnlVector()); } PrintToLog("0% 10 20 30 40 50 60 70 80 90 100%", false, true, false); PrintToLog("|----|----|----|----|----|----|----|----|----|----|\n*", false, false, false); unsigned long lastTick = 0; boost::progress_display disp(compartment_images.at(0)->GetVectorLength()*compartment_images.at(0)->GetLargestPossibleRegion().GetSize(2)); #pragma omp parallel for for (int g=0; g<(int)compartment_images.at(0)->GetVectorLength(); g++) { if (this->GetAbortGenerateData()) continue; std::vector< unsigned int > spikeSlice; #pragma omp critical while (!spikeVolume.empty() && (int)spikeVolume.back()==g) { spikeSlice.push_back(m_RandGen->GetIntegerVariate()%compartment_images.at(0)->GetLargestPossibleRegion().GetSize(2)); spikeVolume.pop_back(); } std::sort (spikeSlice.begin(), spikeSlice.end()); std::reverse (spikeSlice.begin(), spikeSlice.end()); for (unsigned int z=0; zGetLargestPossibleRegion().GetSize(2); z++) { std::vector< Float2DImageType::Pointer > compartment_slices; std::vector< float > t2Vector; std::vector< float > t1Vector; for (unsigned int i=0; i* signalModel; if (iSetLargestPossibleRegion( sliceRegion ); slice->SetBufferedRegion( sliceRegion ); slice->SetRequestedRegion( sliceRegion ); slice->SetSpacing(sliceSpacing); slice->Allocate(); slice->FillBuffer(0.0); // extract slice from channel g for (unsigned int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (unsigned int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { Float2DImageType::IndexType index2D; index2D[0]=x; index2D[1]=y; DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; slice->SetPixel(index2D, compartment_images.at(i)->GetPixel(index3D)[g]); } compartment_slices.push_back(slice); t2Vector.push_back(signalModel->GetT2()); t1Vector.push_back(signalModel->GetT1()); } int numSpikes = 0; while (!spikeSlice.empty() && spikeSlice.back()==z) { numSpikes++; spikeSlice.pop_back(); } int spikeCoil = m_RandGen->GetIntegerVariate()%m_Parameters.m_SignalGen.m_NumberOfCoils; if (this->GetAbortGenerateData()) continue; for (int c=0; c::New(); idft->SetCompartmentImages(compartment_slices); idft->SetT2(t2Vector); idft->SetT1(t1Vector); idft->SetUseConstantRandSeed(m_UseConstantRandSeed); idft->SetParameters(&m_Parameters); idft->SetZ((float)z-(float)( compartment_images.at(0)->GetLargestPossibleRegion().GetSize(2) -compartment_images.at(0)->GetLargestPossibleRegion().GetSize(2)%2 ) / 2.0); idft->SetZidx(z); idft->SetCoilPosition(coilPositions.at(c)); - idft->SetFiberBundle(m_FiberBundleWorkingCopy); + idft->SetFiberBundle(m_FiberBundle); idft->SetTranslation(m_Translations.at(g)); idft->SetRotation(m_Rotations.at(g)); idft->SetDiffusionGradientDirection(m_Parameters.m_SignalGen.GetGradientDirection(g)); if (c==spikeCoil) idft->SetSpikesPerSlice(numSpikes); idft->Update(); #pragma omp critical if (c==spikeCoil && numSpikes>0) { m_SpikeLog += "Volume " + boost::lexical_cast(g) + " Coil " + boost::lexical_cast(c) + "\n"; m_SpikeLog += idft->GetSpikeLog(); } Complex2DImageType::Pointer fSlice; fSlice = idft->GetOutput(); // fourier transform slice Complex2DImageType::Pointer newSlice; auto dft = itk::DftImageFilter< Float2DImageType::PixelType >::New(); dft->SetInput(fSlice); dft->SetParameters(m_Parameters); dft->Update(); newSlice = dft->GetOutput(); // put slice back into channel g for (unsigned int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (unsigned int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; Complex2DImageType::IndexType index2D; index2D[0]=x; index2D[1]=y; Complex2DImageType::PixelType cPix = newSlice->GetPixel(index2D); double magn = sqrt(cPix.real()*cPix.real()+cPix.imag()*cPix.imag()); double phase = 0; if (cPix.real()!=0) phase = atan( cPix.imag()/cPix.real() ); DoubleDwiType::PixelType real_pix = m_OutputImagesReal.at(c)->GetPixel(index3D); real_pix[g] = cPix.real(); m_OutputImagesReal.at(c)->SetPixel(index3D, real_pix); DoubleDwiType::PixelType imag_pix = m_OutputImagesImag.at(c)->GetPixel(index3D); imag_pix[g] = cPix.imag(); m_OutputImagesImag.at(c)->SetPixel(index3D, imag_pix); DoubleDwiType::PixelType dwiPix = magnitudeDwiImage->GetPixel(index3D); DoubleDwiType::PixelType phasePix = m_PhaseImage->GetPixel(index3D); if (m_Parameters.m_SignalGen.m_NumberOfCoils>1) { dwiPix[g] += magn*magn; phasePix[g] += phase*phase; } else { dwiPix[g] = magn; phasePix[g] = phase; } //#pragma omp critical { magnitudeDwiImage->SetPixel(index3D, dwiPix); m_PhaseImage->SetPixel(index3D, phasePix); // k-space image if (g==0) { DoubleDwiType::PixelType kspacePix = m_KspaceImage->GetPixel(index3D); kspacePix[c] = idft->GetKSpaceImage()->GetPixel(index2D); m_KspaceImage->SetPixel(index3D, kspacePix); } } } } if (m_Parameters.m_SignalGen.m_NumberOfCoils>1) { for (int y=0; y(magnitudeDwiImage->GetLargestPossibleRegion().GetSize(1)); y++) for (int x=0; x(magnitudeDwiImage->GetLargestPossibleRegion().GetSize(0)); x++) { DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; DoubleDwiType::PixelType magPix = magnitudeDwiImage->GetPixel(index3D); magPix[g] = sqrt(magPix[g]/m_Parameters.m_SignalGen.m_NumberOfCoils); DoubleDwiType::PixelType phasePix = m_PhaseImage->GetPixel(index3D); phasePix[g] = sqrt(phasePix[g]/m_Parameters.m_SignalGen.m_NumberOfCoils); //#pragma omp critical { magnitudeDwiImage->SetPixel(index3D, magPix); m_PhaseImage->SetPixel(index3D, phasePix); } } } ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); for (unsigned long tick = 0; tick<(newTick-lastTick); tick++) PrintToLog("*", false, false, false); lastTick = newTick; } } PrintToLog("\n", false); return magnitudeDwiImage; } template< class PixelType > TractsToDWIImageFilter< PixelType >::ItkDoubleImgType::Pointer TractsToDWIImageFilter< PixelType >:: NormalizeInsideMask(ItkDoubleImgType::Pointer image) { double max = itk::NumericTraits< double >::min(); double min = itk::NumericTraits< double >::max(); itk::ImageRegionIterator< ItkDoubleImgType > it(image, image->GetLargestPossibleRegion()); while(!it.IsAtEnd()) { if (m_Parameters.m_SignalGen.m_MaskImage.IsNotNull() && m_Parameters.m_SignalGen.m_MaskImage->GetPixel(it.GetIndex())<=0) { it.Set(0.0); ++it; continue; } if (it.Get()>max) max = it.Get(); if (it.Get()::New(); scaler->SetInput(image); scaler->SetShift(-min); scaler->SetScale(1.0/(max-min)); scaler->Update(); return scaler->GetOutput(); } template< class PixelType > void TractsToDWIImageFilter< PixelType >::CheckVolumeFractionImages() { m_UseRelativeNonFiberVolumeFractions = false; // check for fiber volume fraction maps unsigned int fibVolImages = 0; for (std::size_t i=0; iGetVolumeFractionImage().IsNotNull()) { PrintToLog("Using volume fraction map for fiber compartment " + boost::lexical_cast(i+1)); fibVolImages++; } } // check for non-fiber volume fraction maps unsigned int nonfibVolImages = 0; for (std::size_t i=0; iGetVolumeFractionImage().IsNotNull()) { PrintToLog("Using volume fraction map for non-fiber compartment " + boost::lexical_cast(i+1)); nonfibVolImages++; } } // not all fiber compartments are using volume fraction maps // --> non-fiber volume fractions are assumed to be relative to the // non-fiber volume and not absolute voxel-volume fractions. // this means if two non-fiber compartments are used but only one of them // has an associated volume fraction map, the repesctive other volume fraction map // can be determined as inverse (1-val) of the present volume fraction map- if ( fibVolImages::New(); inverter->SetMaximum(1.0); if ( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage().IsNull() && m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage().IsNotNull() ) { // m_Parameters.m_NonFiberModelList[1]->SetVolumeFractionImage( // NormalizeInsideMask( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage() ) ); inverter->SetInput( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage() ); inverter->Update(); m_Parameters.m_NonFiberModelList[0]->SetVolumeFractionImage(inverter->GetOutput()); } else if ( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage().IsNull() && m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage().IsNotNull() ) { // m_Parameters.m_NonFiberModelList[0]->SetVolumeFractionImage( // NormalizeInsideMask( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage() ) ); inverter->SetInput( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage() ); inverter->Update(); m_Parameters.m_NonFiberModelList[1]->SetVolumeFractionImage(inverter->GetOutput()); } else { itkExceptionMacro("Something went wrong in automatically calculating the missing non-fiber volume fraction image!" " Did you use two non fiber compartments but only one volume fraction image?" " Then it should work and this error is really strange."); } m_UseRelativeNonFiberVolumeFractions = true; nonfibVolImages++; } // Up to two fiber compartments are allowed without volume fraction maps since the volume fractions can then be determined automatically if (m_Parameters.m_FiberModelList.size()>2 && fibVolImages!=m_Parameters.m_FiberModelList.size()) itkExceptionMacro("More than two fiber compartment selected but no corresponding volume fraction maps set!"); // One non-fiber compartment is allowed without volume fraction map since the volume fraction can then be determined automatically if (m_Parameters.m_NonFiberModelList.size()>1 && nonfibVolImages!=m_Parameters.m_NonFiberModelList.size()) itkExceptionMacro("More than one non-fiber compartment selected but no volume fraction maps set!"); if (fibVolImages0) { PrintToLog("Not all fiber compartments are using an associated volume fraction image.\n" "Assuming non-fiber volume fraction images to contain values relative to the" " remaining non-fiber volume, not absolute values."); m_UseRelativeNonFiberVolumeFractions = true; // itk::ImageFileWriter::Pointer wr = itk::ImageFileWriter::New(); // wr->SetInput(m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage()); // wr->SetFileName("/local/volumefraction.nrrd"); // wr->Update(); } // initialize the images that store the output volume fraction of each compartment m_VolumeFractions.clear(); for (std::size_t i=0; iSetSpacing( m_WorkingSpacing ); doubleImg->SetOrigin( m_WorkingOrigin ); doubleImg->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); doubleImg->SetLargestPossibleRegion( m_WorkingImageRegion ); doubleImg->SetBufferedRegion( m_WorkingImageRegion ); doubleImg->SetRequestedRegion( m_WorkingImageRegion ); doubleImg->Allocate(); doubleImg->FillBuffer(0); m_VolumeFractions.push_back(doubleImg); } } template< class PixelType > void TractsToDWIImageFilter< PixelType >::InitializeData() { m_Rotations.clear(); m_Translations.clear(); m_MotionLog = ""; m_SpikeLog = ""; // initialize output dwi image m_Parameters.m_SignalGen.m_CroppedRegion = m_Parameters.m_SignalGen.m_ImageRegion; m_Parameters.m_SignalGen.m_CroppedRegion.SetSize( 1, m_Parameters.m_SignalGen.m_CroppedRegion.GetSize(1) *m_Parameters.m_SignalGen.m_CroppingFactor); itk::Point shiftedOrigin = m_Parameters.m_SignalGen.m_ImageOrigin; shiftedOrigin[1] += (m_Parameters.m_SignalGen.m_ImageRegion.GetSize(1) -m_Parameters.m_SignalGen.m_CroppedRegion.GetSize(1))*m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; m_OutputImage = OutputImageType::New(); m_OutputImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); m_OutputImage->SetOrigin( shiftedOrigin ); m_OutputImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_OutputImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_OutputImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_OutputImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_OutputImage->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); m_OutputImage->Allocate(); typename OutputImageType::PixelType temp; temp.SetSize(m_Parameters.m_SignalGen.GetNumVolumes()); temp.Fill(0.0); m_OutputImage->FillBuffer(temp); // images containing real and imaginary part of the dMRI signal for each coil m_OutputImagesReal.clear(); m_OutputImagesImag.clear(); for (int i=0; iSetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); outputImageReal->SetOrigin( shiftedOrigin ); outputImageReal->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); outputImageReal->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageReal->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageReal->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageReal->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); outputImageReal->Allocate(); outputImageReal->FillBuffer(temp); m_OutputImagesReal.push_back(outputImageReal); typename DoubleDwiType::Pointer outputImageImag = DoubleDwiType::New(); outputImageImag->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); outputImageImag->SetOrigin( shiftedOrigin ); outputImageImag->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); outputImageImag->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageImag->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageImag->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageImag->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); outputImageImag->Allocate(); outputImageImag->FillBuffer(temp); m_OutputImagesImag.push_back(outputImageImag); } // Apply in-plane upsampling for Gibbs ringing artifact double upsampling = 1; if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging) upsampling = 2; m_WorkingSpacing = m_Parameters.m_SignalGen.m_ImageSpacing; m_WorkingSpacing[0] /= upsampling; m_WorkingSpacing[1] /= upsampling; m_WorkingImageRegion = m_Parameters.m_SignalGen.m_ImageRegion; m_WorkingImageRegion.SetSize(0, m_Parameters.m_SignalGen.m_ImageRegion.GetSize()[0]*upsampling); m_WorkingImageRegion.SetSize(1, m_Parameters.m_SignalGen.m_ImageRegion.GetSize()[1]*upsampling); m_WorkingOrigin = m_Parameters.m_SignalGen.m_ImageOrigin; m_WorkingOrigin[0] -= m_Parameters.m_SignalGen.m_ImageSpacing[0]/2; m_WorkingOrigin[0] += m_WorkingSpacing[0]/2; m_WorkingOrigin[1] -= m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; m_WorkingOrigin[1] += m_WorkingSpacing[1]/2; m_WorkingOrigin[2] -= m_Parameters.m_SignalGen.m_ImageSpacing[2]/2; m_WorkingOrigin[2] += m_WorkingSpacing[2]/2; m_VoxelVolume = m_WorkingSpacing[0]*m_WorkingSpacing[1]*m_WorkingSpacing[2]; // generate double images to store the individual compartment signals m_CompartmentImages.clear(); int numFiberCompartments = m_Parameters.m_FiberModelList.size(); int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size(); for (int i=0; iSetSpacing( m_WorkingSpacing ); doubleDwi->SetOrigin( m_WorkingOrigin ); doubleDwi->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); doubleDwi->SetLargestPossibleRegion( m_WorkingImageRegion ); doubleDwi->SetBufferedRegion( m_WorkingImageRegion ); doubleDwi->SetRequestedRegion( m_WorkingImageRegion ); doubleDwi->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); doubleDwi->Allocate(); DoubleDwiType::PixelType pix; pix.SetSize(m_Parameters.m_SignalGen.GetNumVolumes()); pix.Fill(0.0); doubleDwi->FillBuffer(pix); m_CompartmentImages.push_back(doubleDwi); } if (m_FiberBundle.IsNull() && m_InputImage.IsNotNull()) { m_CompartmentImages.clear(); m_Parameters.m_SignalGen.m_DoAddMotion = false; m_Parameters.m_SignalGen.m_DoSimulateRelaxation = false; PrintToLog("Simulating acquisition for input diffusion-weighted image.", false); auto caster = itk::CastImageFilter< OutputImageType, DoubleDwiType >::New(); caster->SetInput(m_InputImage); caster->Update(); if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging) { PrintToLog("Upsampling input diffusion-weighted image for Gibbs ringing simulation.", false); auto resampler = itk::ResampleDwiImageFilter< double >::New(); resampler->SetInput(caster->GetOutput()); itk::Vector< double, 3 > samplingFactor; samplingFactor[0] = upsampling; samplingFactor[1] = upsampling; samplingFactor[2] = 1; resampler->SetSamplingFactor(samplingFactor); resampler->SetInterpolation(itk::ResampleDwiImageFilter< double >::Interpolate_WindowedSinc); resampler->Update(); m_CompartmentImages.push_back(resampler->GetOutput()); } else m_CompartmentImages.push_back(caster->GetOutput()); for (unsigned int g=0; g::New(); rescaler->SetInput(0,m_Parameters.m_SignalGen.m_MaskImage); rescaler->SetOutputMaximum(100); rescaler->SetOutputMinimum(0); rescaler->Update(); // resample mask image auto resampler = itk::ResampleImageFilter::New(); resampler->SetInput(rescaler->GetOutput()); resampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_MaskImage); resampler->SetSize(m_WorkingImageRegion.GetSize()); resampler->SetOutputSpacing(m_WorkingSpacing); resampler->SetOutputOrigin(m_WorkingOrigin); auto nn_interpolator = itk::NearestNeighborInterpolateImageFunction::New(); resampler->SetInterpolator(nn_interpolator); resampler->Update(); m_Parameters.m_SignalGen.m_MaskImage = resampler->GetOutput(); } // resample frequency map if (m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull()) { auto resampler = itk::ResampleImageFilter::New(); resampler->SetInput(m_Parameters.m_SignalGen.m_FrequencyMap); resampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_FrequencyMap); resampler->SetSize(m_WorkingImageRegion.GetSize()); resampler->SetOutputSpacing(m_WorkingSpacing); resampler->SetOutputOrigin(m_WorkingOrigin); auto nn_interpolator = itk::NearestNeighborInterpolateImageFunction::New(); resampler->SetInterpolator(nn_interpolator); resampler->Update(); m_Parameters.m_SignalGen.m_FrequencyMap = resampler->GetOutput(); } } m_MaskImageSet = true; if (m_Parameters.m_SignalGen.m_MaskImage.IsNull()) { // no input tissue mask is set -> create default PrintToLog("No tissue mask set", false); m_Parameters.m_SignalGen.m_MaskImage = ItkUcharImgType::New(); m_Parameters.m_SignalGen.m_MaskImage->SetSpacing( m_WorkingSpacing ); m_Parameters.m_SignalGen.m_MaskImage->SetOrigin( m_WorkingOrigin ); m_Parameters.m_SignalGen.m_MaskImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_Parameters.m_SignalGen.m_MaskImage->SetLargestPossibleRegion( m_WorkingImageRegion ); m_Parameters.m_SignalGen.m_MaskImage->SetBufferedRegion( m_WorkingImageRegion ); m_Parameters.m_SignalGen.m_MaskImage->SetRequestedRegion( m_WorkingImageRegion ); m_Parameters.m_SignalGen.m_MaskImage->Allocate(); m_Parameters.m_SignalGen.m_MaskImage->FillBuffer(100); m_MaskImageSet = false; } else { if (m_Parameters.m_SignalGen.m_MaskImage->GetLargestPossibleRegion()!=m_WorkingImageRegion) { itkExceptionMacro("Mask image and specified DWI geometry are not matching!"); } PrintToLog("Using tissue mask", false); } if (m_Parameters.m_SignalGen.m_DoAddMotion) { if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { PrintToLog("Random motion artifacts:", false); PrintToLog("Maximum rotation: +/-" + boost::lexical_cast(m_Parameters.m_SignalGen.m_Rotation) + "°", false); PrintToLog("Maximum translation: +/-" + boost::lexical_cast(m_Parameters.m_SignalGen.m_Translation) + "mm", false); } else { PrintToLog("Linear motion artifacts:", false); PrintToLog("Maximum rotation: " + boost::lexical_cast(m_Parameters.m_SignalGen.m_Rotation) + "°", false); PrintToLog("Maximum translation: " + boost::lexical_cast(m_Parameters.m_SignalGen.m_Translation) + "mm", false); } } if ( m_Parameters.m_SignalGen.m_MotionVolumes.empty() ) { // no motion in first volume m_Parameters.m_SignalGen.m_MotionVolumes.push_back(false); // motion in all other volumes while ( m_Parameters.m_SignalGen.m_MotionVolumes.size() < m_Parameters.m_SignalGen.GetNumVolumes() ) { m_Parameters.m_SignalGen.m_MotionVolumes.push_back(true); } } // we need to know for every volume if there is motion. if this information is missing, then set corresponding fal to false while ( m_Parameters.m_SignalGen.m_MotionVolumes.size()::New(); duplicator->SetInputImage(m_Parameters.m_SignalGen.m_MaskImage); duplicator->Update(); m_TransformedMaskImage = duplicator->GetOutput(); // second upsampling needed for motion artifacts ImageRegion<3> upsampledImageRegion = m_WorkingImageRegion; DoubleVectorType upsampledSpacing = m_WorkingSpacing; upsampledSpacing[0] /= 4; upsampledSpacing[1] /= 4; upsampledSpacing[2] /= 4; upsampledImageRegion.SetSize(0, m_WorkingImageRegion.GetSize()[0]*4); upsampledImageRegion.SetSize(1, m_WorkingImageRegion.GetSize()[1]*4); upsampledImageRegion.SetSize(2, m_WorkingImageRegion.GetSize()[2]*4); itk::Point upsampledOrigin = m_WorkingOrigin; upsampledOrigin[0] -= m_WorkingSpacing[0]/2; upsampledOrigin[0] += upsampledSpacing[0]/2; upsampledOrigin[1] -= m_WorkingSpacing[1]/2; upsampledOrigin[1] += upsampledSpacing[1]/2; upsampledOrigin[2] -= m_WorkingSpacing[2]/2; upsampledOrigin[2] += upsampledSpacing[2]/2; m_UpsampledMaskImage = ItkUcharImgType::New(); auto upsampler = itk::ResampleImageFilter::New(); upsampler->SetInput(m_Parameters.m_SignalGen.m_MaskImage); upsampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_MaskImage); upsampler->SetSize(upsampledImageRegion.GetSize()); upsampler->SetOutputSpacing(upsampledSpacing); upsampler->SetOutputOrigin(upsampledOrigin); auto nn_interpolator = itk::NearestNeighborInterpolateImageFunction::New(); upsampler->SetInterpolator(nn_interpolator); upsampler->Update(); m_UpsampledMaskImage = upsampler->GetOutput(); } template< class PixelType > void TractsToDWIImageFilter< PixelType >::InitializeFiberData() { - // resample fiber bundle for sufficient voxel coverage - PrintToLog("Resampling fibers ..."); - m_SegmentVolume = 0.0001; - float minSpacing = 1; - if( m_WorkingSpacing[0]GetDeepCopy(); - double volumeAccuracy = 10; - m_FiberBundleWorkingCopy->ResampleLinear(minSpacing/volumeAccuracy); m_mmRadius = m_Parameters.m_SignalGen.m_AxonRadius/1000; auto caster = itk::CastImageFilter< itk::Image, itk::Image >::New(); caster->SetInput(m_TransformedMaskImage); caster->Update(); - vtkSmartPointer weights = m_FiberBundleWorkingCopy->GetFiberWeights(); + vtkSmartPointer weights = m_FiberBundle->GetFiberWeights(); float mean_weight = 0; for (int i=0; iGetSize(); i++) mean_weight += weights->GetValue(i); mean_weight /= weights->GetSize(); if (mean_weight>0.000001) for (int i=0; iGetSize(); i++) - m_FiberBundleWorkingCopy->SetFiberWeight(i, weights->GetValue(i)/mean_weight); + m_FiberBundle->SetFiberWeight(i, weights->GetValue(i)/mean_weight); else PrintToLog("\nWarning: streamlines have VERY low weights. Average weight: " + boost::lexical_cast(mean_weight) + ". Possible source of calculation errors.", false, true, true); auto density_calculator = itk::TractDensityImageFilter< itk::Image >::New(); - density_calculator->SetFiberBundle(m_FiberBundleWorkingCopy); + density_calculator->SetFiberBundle(m_FiberBundle); density_calculator->SetInputImage(caster->GetOutput()); density_calculator->SetBinaryOutput(false); density_calculator->SetUseImageGeometry(true); - density_calculator->SetDoFiberResampling(false); density_calculator->SetOutputAbsoluteValues(true); - density_calculator->SetWorkOnFiberCopy(false); density_calculator->Update(); float max_density = density_calculator->GetMaxDensity(); + float voxel_volume = m_WorkingSpacing[0]*m_WorkingSpacing[1]*m_WorkingSpacing[2]; if (m_mmRadius>0) { - m_SegmentVolume = itk::Math::pi*m_mmRadius*m_mmRadius*minSpacing/volumeAccuracy; std::stringstream stream; - stream << std::fixed << setprecision(2) << max_density * m_SegmentVolume; + stream << std::fixed << setprecision(2) << itk::Math::pi*m_mmRadius*m_mmRadius*max_density; std::string s = stream.str(); PrintToLog("\nMax. fiber volume: " + s + "mm².", false, true, true); + + { + float full_radius = 1000*std::sqrt(voxel_volume/(max_density*itk::Math::pi)); + std::stringstream stream; + stream << std::fixed << setprecision(2) << full_radius; + std::string s = stream.str(); + PrintToLog("\nA full fiber voxel corresponds to a fiber radius of ~" + s + "µm, given the current fiber configuration.", false, true, true); + } } else { + m_mmRadius = std::sqrt(voxel_volume/(max_density*itk::Math::pi)); std::stringstream stream; - stream << std::fixed << setprecision(2) << max_density * m_SegmentVolume; + stream << std::fixed << setprecision(2) << m_mmRadius*1000; std::string s = stream.str(); - PrintToLog("\nMax. fiber volume: " + s + "mm² (before rescaling to voxel volume).", false, true, true); + PrintToLog("\nSetting fiber radius to " + s + "µm to obtain full voxel.", false, true, true); } - float voxel_volume = m_WorkingSpacing[0]*m_WorkingSpacing[1]*m_WorkingSpacing[2]; - float new_seg_vol = voxel_volume/max_density; - float new_fib_radius = 1000*std::sqrt(new_seg_vol*volumeAccuracy/(minSpacing*itk::Math::pi)); - std::stringstream stream; - stream << std::fixed << setprecision(2) << new_fib_radius; - std::string s = stream.str(); - PrintToLog("\nA full fiber voxel corresponds to a fiber radius of ~" + s + "µm, given the current fiber configuration.", false, true, true); // a second fiber bundle is needed to store the transformed version of the m_FiberBundleWorkingCopy - m_FiberBundleTransformed = m_FiberBundleWorkingCopy; + m_FiberBundleTransformed = m_FiberBundle; } template< class PixelType > bool TractsToDWIImageFilter< PixelType >::PrepareLogFile() { assert( ! m_Logfile.is_open() ); std::string filePath; std::string fileName; // Get directory name: if (m_Parameters.m_Misc.m_OutputPath.size() > 0) { filePath = m_Parameters.m_Misc.m_OutputPath; if( *(--(filePath.cend())) != '/') { filePath.push_back('/'); } } else { filePath = mitk::IOUtil::GetTempPath() + '/'; } // check if directory exists, else use /tmp/: if( itksys::SystemTools::FileIsDirectory( filePath ) ) { while( *(--(filePath.cend())) == '/') { filePath.pop_back(); } filePath = filePath + '/'; } else { filePath = mitk::IOUtil::GetTempPath() + '/'; } // Get file name: if( ! m_Parameters.m_Misc.m_ResultNode->GetName().empty() ) { fileName = m_Parameters.m_Misc.m_ResultNode->GetName(); } else { fileName = ""; } if( ! m_Parameters.m_Misc.m_OutputPrefix.empty() ) { fileName = m_Parameters.m_Misc.m_OutputPrefix + fileName; } else { fileName = "fiberfox"; } // check if file already exists and DO NOT overwrite existing files: std::string NameTest = fileName; int c = 0; while( itksys::SystemTools::FileExists( filePath + '/' + fileName + ".log" ) && c <= std::numeric_limits::max() ) { fileName = NameTest + "_" + boost::lexical_cast(c); ++c; } try { m_Logfile.open( ( filePath + '/' + fileName + ".log" ).c_str() ); } catch (const std::ios_base::failure &fail) { MITK_ERROR << "itkTractsToDWIImageFilter.cpp: Exception " << fail.what() << " while trying to open file" << filePath << '/' << fileName << ".log"; return false; } if ( m_Logfile.is_open() ) { PrintToLog( "Logfile: " + filePath + '/' + fileName + ".log", false ); return true; } else { m_StatusText += "Logfile could not be opened!\n"; MITK_ERROR << "itkTractsToDWIImageFilter.cpp: Logfile could not be opened!"; return false; } } template< class PixelType > void TractsToDWIImageFilter< PixelType >::GenerateData() { // prepare logfile if ( ! PrepareLogFile() ) { this->SetAbortGenerateData( true ); return; } m_TimeProbe.Start(); // check input data if (m_FiberBundle.IsNull() && m_InputImage.IsNull()) itkExceptionMacro("Input fiber bundle and input diffusion-weighted image is nullptr!"); if (m_Parameters.m_FiberModelList.empty() && m_InputImage.IsNull()) itkExceptionMacro("No diffusion model for fiber compartments defined and input diffusion-weighted" " image is nullptr! At least one fiber compartment is necessary to simulate diffusion."); if (m_Parameters.m_NonFiberModelList.empty() && m_InputImage.IsNull()) itkExceptionMacro("No diffusion model for non-fiber compartments defined and input diffusion-weighted" " image is nullptr! At least one non-fiber compartment is necessary to simulate diffusion."); if (m_Parameters.m_SignalGen.m_DoDisablePartialVolume) // no partial volume? remove all but first fiber compartment while (m_Parameters.m_FiberModelList.size()>1) m_Parameters.m_FiberModelList.pop_back(); // int baselineIndex = m_Parameters.m_SignalGen.GetFirstBaselineIndex(); // if (baselineIndex<0) { itkExceptionMacro("No baseline index found!"); } if (!m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition) // No upsampling of input image needed if no k-space simulation is performed m_Parameters.m_SignalGen.m_DoAddGibbsRinging = false; if (m_UseConstantRandSeed) // always generate the same random numbers? m_RandGen->SetSeed(0); else m_RandGen->SetSeed(); InitializeData(); if ( m_FiberBundle.IsNotNull() ) // if no fiber bundle is found, we directly proceed to the k-space acquisition simulation { CheckVolumeFractionImages(); InitializeFiberData(); int numFiberCompartments = m_Parameters.m_FiberModelList.size(); int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size(); double maxVolume = 0; unsigned long lastTick = 0; int signalModelSeed = m_RandGen->GetIntegerVariate(); PrintToLog("\n", false, false); PrintToLog("Generating " + boost::lexical_cast(numFiberCompartments+numNonFiberCompartments) + "-compartment diffusion-weighted signal."); std::vector< int > bVals = m_Parameters.m_SignalGen.GetBvalues(); PrintToLog("b-values: ", false, false, true); for (auto v : bVals) PrintToLog(boost::lexical_cast(v) + " ", false, false, true); PrintToLog("\n", false, false, true); PrintToLog("\n", false, false, true); - int numFibers = m_FiberBundleWorkingCopy->GetNumFibers(); + int numFibers = m_FiberBundle->GetNumFibers(); boost::progress_display disp(numFibers*m_Parameters.m_SignalGen.GetNumVolumes()); if (m_FiberBundle->GetMeanFiberLength()<5.0) omp_set_num_threads(2); PrintToLog("0% 10 20 30 40 50 60 70 80 90 100%", false, true, false); PrintToLog("|----|----|----|----|----|----|----|----|----|----|\n*", false, false, false); for (unsigned int g=0; gSetSeed(signalModelSeed); for (std::size_t i=0; iSetSeed(signalModelSeed); // storing voxel-wise intra-axonal volume in mm³ auto intraAxonalVolumeImage = ItkDoubleImgType::New(); intraAxonalVolumeImage->SetSpacing( m_WorkingSpacing ); intraAxonalVolumeImage->SetOrigin( m_WorkingOrigin ); intraAxonalVolumeImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); intraAxonalVolumeImage->SetLargestPossibleRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->SetBufferedRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->SetRequestedRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->Allocate(); intraAxonalVolumeImage->FillBuffer(0); maxVolume = 0; if (this->GetAbortGenerateData()) continue; vtkPolyData* fiberPolyData = m_FiberBundleTransformed->GetFiberPolyData(); // generate fiber signal (if there are any fiber models present) if (!m_Parameters.m_FiberModelList.empty()) { #pragma omp parallel for for( int i=0; iGetAbortGenerateData()) continue; float fiberWeight = m_FiberBundleTransformed->GetFiberWeight(i); int numPoints = -1; std::vector< itk::Vector > points_copy; #pragma omp critical { vtkCell* cell = fiberPolyData->GetCell(i); numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j))); } if (numPoints<2) continue; - for( int j=0; jGetAbortGenerateData()) { j=numPoints; continue; } - itk::Point vertex = points_copy.at(j); itk::Vector v = points_copy.at(j); - itk::Vector dir(3); - if (j dir = points_copy.at(j+1)-v; if ( dir.GetSquaredNorm()<0.0001 || dir[0]!=dir[0] || dir[1]!=dir[1] || dir[2]!=dir[2] ) continue; + dir.Normalize(); - itk::Index<3> idx; - itk::ContinuousIndex contIndex; - m_TransformedMaskImage->TransformPhysicalPointToIndex(vertex, idx); - m_TransformedMaskImage->TransformPhysicalPointToContinuousIndex(vertex, contIndex); + itk::Point startVertex = points_copy.at(j); + itk::Index<3> startIndex; + itk::ContinuousIndex startIndexCont; + m_TransformedMaskImage->TransformPhysicalPointToIndex(startVertex, startIndex); + m_TransformedMaskImage->TransformPhysicalPointToContinuousIndex(startVertex, startIndexCont); - if (!m_TransformedMaskImage->GetLargestPossibleRegion().IsInside(idx) || m_TransformedMaskImage->GetPixel(idx)<=0) - continue; - dir.Normalize(); + itk::Point endVertex = points_copy.at(j+1); + itk::Index<3> endIndex; + itk::ContinuousIndex endIndexCont; + m_TransformedMaskImage->TransformPhysicalPointToIndex(endVertex, endIndex); + m_TransformedMaskImage->TransformPhysicalPointToContinuousIndex(endVertex, endIndexCont); + + std::vector< std::pair< itk::Index<3>, double > > segments = mitk::imv::IntersectImage(m_WorkingSpacing, startIndex, endIndex, startIndexCont, endIndexCont); - // generate signal for each fiber compartment - for (int k=0; k, double > seg : segments) { - DoubleDwiType::PixelType pix = m_CompartmentImages.at(k)->GetPixel(idx); - pix[g] += fiberWeight*m_SegmentVolume*m_Parameters.m_FiberModelList[k]->SimulateMeasurement(g, dir); - m_CompartmentImages.at(k)->SetPixel(idx, pix); - } + if (!m_TransformedMaskImage->GetLargestPossibleRegion().IsInside(seg.first) || m_TransformedMaskImage->GetPixel(seg.first)<=0) + continue; - // update fiber volume image - double vol = intraAxonalVolumeImage->GetPixel(idx) + m_SegmentVolume*fiberWeight; - intraAxonalVolumeImage->SetPixel(idx, vol); + // generate signal for each fiber compartment + for (int k=0; kGetPixel(seg.first); + + float seg_volume = seg.second*fiberWeight*itk::Math::pi*m_mmRadius*m_mmRadius; + + pix[g] += seg_volume*m_Parameters.m_FiberModelList[k]->SimulateMeasurement(g, dir); + m_CompartmentImages.at(k)->SetPixel(seg.first, pix); - // we assume that the first volume is always unweighted! - if (vol>maxVolume) { maxVolume = vol; } + if (k==0) + { + // update fiber volume image + double vol = intraAxonalVolumeImage->GetPixel(seg.first) + seg_volume; + intraAxonalVolumeImage->SetPixel(seg.first, vol); + if (vol>maxVolume) { maxVolume = vol; } + } + } + + } } #pragma omp critical { // progress report ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); for (unsigned int tick = 0; tick<(newTick-lastTick); ++tick) PrintToLog("*", false, false, false); lastTick = newTick; } } } // axon radius not manually defined --> set fullest voxel (maxVolume) to full fiber voxel double density_correctiony_global = 1.0; if (m_Parameters.m_SignalGen.m_AxonRadius<0.0001) density_correctiony_global = m_VoxelVolume/maxVolume; // generate non-fiber signal ImageRegionIterator it3(m_TransformedMaskImage, m_TransformedMaskImage->GetLargestPossibleRegion()); while(!it3.IsAtEnd()) { if (it3.Get()>0) { DoubleDwiType::IndexType index = it3.GetIndex(); double iAxVolume = intraAxonalVolumeImage->GetPixel(index); // get non-transformed point (remove headmotion tranformation) // this point lives in the volume fraction image space itk::Point volume_fraction_point; if ( m_Parameters.m_SignalGen.m_DoAddMotion && m_Parameters.m_SignalGen.m_MotionVolumes[g] ) volume_fraction_point = GetMovedPoint(index, false); else m_TransformedMaskImage->TransformIndexToPhysicalPoint(index, volume_fraction_point); if (m_Parameters.m_SignalGen.m_DoDisablePartialVolume) { if (iAxVolume>0.0001) // scale fiber compartment to voxel { DoubleDwiType::PixelType pix = m_CompartmentImages.at(0)->GetPixel(index); pix[g] *= m_VoxelVolume/iAxVolume; m_CompartmentImages.at(0)->SetPixel(index, pix); if (g==0) m_VolumeFractions.at(0)->SetPixel(index, 1); } else { DoubleDwiType::PixelType pix = m_CompartmentImages.at(0)->GetPixel(index); pix[g] = 0; m_CompartmentImages.at(0)->SetPixel(index, pix); SimulateExtraAxonalSignal(index, volume_fraction_point, 0, g); } } else { // manually defined axon radius and voxel overflow --> rescale to voxel volume if ( m_Parameters.m_SignalGen.m_AxonRadius>=0.0001 && iAxVolume>m_VoxelVolume ) { for (int i=0; iGetPixel(index); pix[g] *= m_VoxelVolume/iAxVolume; m_CompartmentImages.at(i)->SetPixel(index, pix); } iAxVolume = m_VoxelVolume; } // if volume fraction image is set use it, otherwise use global scaling factor double density_correction_voxel = density_correctiony_global; if ( m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()!=nullptr && iAxVolume>0.0001 ) { m_DoubleInterpolator->SetInputImage(m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()); double volume_fraction = mitk::imv::GetImageValue(volume_fraction_point, true, m_DoubleInterpolator); if (volume_fraction<0) mitkThrow() << "Volume fraction image (index 1) contains negative values (intra-axonal compartment)!"; density_correction_voxel = m_VoxelVolume*volume_fraction/iAxVolume; // remove iAxVolume sclaing and scale to volume_fraction } else if (m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()!=nullptr) density_correction_voxel = 0.0; // adjust intra-axonal compartment volume by density correction factor DoubleDwiType::PixelType pix = m_CompartmentImages.at(0)->GetPixel(index); pix[g] *= density_correction_voxel; m_CompartmentImages.at(0)->SetPixel(index, pix); // normalize remaining fiber volume fractions (they are rescaled in SimulateExtraAxonalSignal) if (iAxVolume>0.0001) { for (int i=1; iGetPixel(index); pix[g] /= iAxVolume; m_CompartmentImages.at(i)->SetPixel(index, pix); } } else { for (int i=1; iGetPixel(index); pix[g] = 0; m_CompartmentImages.at(i)->SetPixel(index, pix); } } iAxVolume = density_correction_voxel*iAxVolume; // new intra-axonal volume = old intra-axonal volume * correction factor // simulate other compartments SimulateExtraAxonalSignal(index, volume_fraction_point, iAxVolume, g); } } ++it3; } } PrintToLog("\n", false); } if (this->GetAbortGenerateData()) { PrintToLog("\n", false, false); PrintToLog("Simulation aborted"); return; } DoubleDwiType::Pointer doubleOutImage; double signalScale = m_Parameters.m_SignalGen.m_SignalScale; if ( m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition ) // do k-space stuff { PrintToLog("\n", false, false); PrintToLog("Simulating k-space acquisition using " +boost::lexical_cast(m_Parameters.m_SignalGen.m_NumberOfCoils) +" coil(s)"); switch (m_Parameters.m_SignalGen.m_AcquisitionType) { case SignalGenerationParameters::SingleShotEpi: { PrintToLog("Acquisition type: single shot EPI", false); break; } case SignalGenerationParameters::SpinEcho: { PrintToLog("Acquisition type: classic spin echo with cartesian k-space trajectory", false); break; } default: { PrintToLog("Acquisition type: single shot EPI", false); break; } } if (m_Parameters.m_SignalGen.m_NoiseVariance>0 && m_Parameters.m_Misc.m_CheckAddNoiseBox) PrintToLog("Simulating complex Gaussian noise", false); if (m_Parameters.m_SignalGen.m_DoSimulateRelaxation) PrintToLog("Simulating signal relaxation", false); if (m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull()) PrintToLog("Simulating distortions", false); if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging) PrintToLog("Simulating ringing artifacts", false); if (m_Parameters.m_SignalGen.m_EddyStrength>0) PrintToLog("Simulating eddy currents", false); if (m_Parameters.m_SignalGen.m_Spikes>0) PrintToLog("Simulating spikes", false); if (m_Parameters.m_SignalGen.m_CroppingFactor<1.0) PrintToLog("Simulating aliasing artifacts", false); if (m_Parameters.m_SignalGen.m_KspaceLineOffset>0) PrintToLog("Simulating ghosts", false); doubleOutImage = SimulateKspaceAcquisition(m_CompartmentImages); signalScale = 1; // already scaled in SimulateKspaceAcquisition() } else // don't do k-space stuff, just sum compartments { PrintToLog("Summing compartments"); doubleOutImage = m_CompartmentImages.at(0); for (unsigned int i=1; i::New(); adder->SetInput1(doubleOutImage); adder->SetInput2(m_CompartmentImages.at(i)); adder->Update(); doubleOutImage = adder->GetOutput(); } } if (this->GetAbortGenerateData()) { PrintToLog("\n", false, false); PrintToLog("Simulation aborted"); return; } PrintToLog("Finalizing image"); if (signalScale>1) PrintToLog(" Scaling signal", false); if (m_Parameters.m_NoiseModel) PrintToLog(" Adding noise", false); unsigned int window = 0; unsigned int min = itk::NumericTraits::max(); ImageRegionIterator it4 (m_OutputImage, m_OutputImage->GetLargestPossibleRegion()); DoubleDwiType::PixelType signal; signal.SetSize(m_Parameters.m_SignalGen.GetNumVolumes()); boost::progress_display disp2(m_OutputImage->GetLargestPossibleRegion().GetNumberOfPixels()); PrintToLog("0% 10 20 30 40 50 60 70 80 90 100%", false, true, false); PrintToLog("|----|----|----|----|----|----|----|----|----|----|\n*", false, false, false); int lastTick = 0; while(!it4.IsAtEnd()) { if (this->GetAbortGenerateData()) { PrintToLog("\n", false, false); PrintToLog("Simulation aborted"); return; } ++disp2; unsigned long newTick = 50*disp2.count()/disp2.expected_count(); for (unsigned long tick = 0; tick<(newTick-lastTick); tick++) PrintToLog("*", false, false, false); lastTick = newTick; typename OutputImageType::IndexType index = it4.GetIndex(); signal = doubleOutImage->GetPixel(index)*signalScale; if (m_Parameters.m_NoiseModel) m_Parameters.m_NoiseModel->AddNoise(signal); for (unsigned int i=0; i0) signal[i] = floor(signal[i]+0.5); else signal[i] = ceil(signal[i]-0.5); if ( (!m_Parameters.m_SignalGen.IsBaselineIndex(i) || signal.Size()==1) && signal[i]>window) window = signal[i]; if ( (!m_Parameters.m_SignalGen.IsBaselineIndex(i) || signal.Size()==1) && signal[i]SetNthOutput(0, m_OutputImage); PrintToLog("\n", false); PrintToLog("Finished simulation"); m_TimeProbe.Stop(); if (m_Parameters.m_SignalGen.m_DoAddMotion) { PrintToLog("\nHead motion log:", false); PrintToLog(m_MotionLog, false, false); } if (m_Parameters.m_SignalGen.m_Spikes>0) { PrintToLog("\nSpike log:", false); PrintToLog(m_SpikeLog, false, false); } if (m_Logfile.is_open()) m_Logfile.close(); } template< class PixelType > void TractsToDWIImageFilter< PixelType >::PrintToLog(std::string m, bool addTime, bool linebreak, bool stdOut) { // timestamp if (addTime) { m_Logfile << this->GetTime() << " > "; m_StatusText += this->GetTime() + " > "; if (stdOut) std::cout << this->GetTime() << " > "; } // message if (m_Logfile.is_open()) m_Logfile << m; m_StatusText += m; if (stdOut) std::cout << m; // new line if (linebreak) { if (m_Logfile.is_open()) m_Logfile << "\n"; m_StatusText += "\n"; if (stdOut) std::cout << "\n"; } } template< class PixelType > void TractsToDWIImageFilter< PixelType >::SimulateMotion(int g) { // is motion artifact enabled? // is the current volume g affected by motion? if ( m_Parameters.m_SignalGen.m_DoAddMotion && m_Parameters.m_SignalGen.m_MotionVolumes[g] && g(m_Parameters.m_SignalGen.GetNumVolumes()) ) { if ( m_Parameters.m_SignalGen.m_DoRandomizeMotion ) { // either undo last transform or work on fresh copy of untransformed fibers - m_FiberBundleTransformed = m_FiberBundleWorkingCopy->GetDeepCopy(); + m_FiberBundleTransformed = m_FiberBundle->GetDeepCopy(); m_Rotation[0] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[0]*2) -m_Parameters.m_SignalGen.m_Rotation[0]; m_Rotation[1] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[1]*2) -m_Parameters.m_SignalGen.m_Rotation[1]; m_Rotation[2] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[2]*2) -m_Parameters.m_SignalGen.m_Rotation[2]; m_Translation[0] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[0]*2) -m_Parameters.m_SignalGen.m_Translation[0]; m_Translation[1] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[1]*2) -m_Parameters.m_SignalGen.m_Translation[1]; m_Translation[2] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[2]*2) -m_Parameters.m_SignalGen.m_Translation[2]; } else { m_Rotation = m_Parameters.m_SignalGen.m_Rotation / m_NumMotionVolumes; m_Translation = m_Parameters.m_SignalGen.m_Translation / m_NumMotionVolumes; m_MotionCounter++; } // move mask image if (m_MaskImageSet) { ImageRegionIterator maskIt(m_UpsampledMaskImage, m_UpsampledMaskImage->GetLargestPossibleRegion()); m_TransformedMaskImage->FillBuffer(0); while(!maskIt.IsAtEnd()) { if (maskIt.Get()<=0) { ++maskIt; continue; } DoubleDwiType::IndexType index = maskIt.GetIndex(); m_TransformedMaskImage->TransformPhysicalPointToIndex(GetMovedPoint(index, true), index); if (m_TransformedMaskImage->GetLargestPossibleRegion().IsInside(index)) m_TransformedMaskImage->SetPixel(index,100); ++maskIt; } } if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { m_Rotations.push_back(m_Rotation); m_Translations.push_back(m_Translation); m_MotionLog += boost::lexical_cast(g) + " rotation: " + boost::lexical_cast(m_Rotation[0]) + "," + boost::lexical_cast(m_Rotation[1]) + "," + boost::lexical_cast(m_Rotation[2]) + ";"; m_MotionLog += " translation: " + boost::lexical_cast(m_Translation[0]) + "," + boost::lexical_cast(m_Translation[1]) + "," + boost::lexical_cast(m_Translation[2]) + "\n"; } else { m_Rotations.push_back(m_Rotation*m_MotionCounter); m_Translations.push_back(m_Translation*m_MotionCounter); m_MotionLog += boost::lexical_cast(g) + " rotation: " + boost::lexical_cast(m_Rotation[0]*m_MotionCounter) + "," + boost::lexical_cast(m_Rotation[1]*m_MotionCounter) + "," + boost::lexical_cast(m_Rotation[2]*m_MotionCounter) + ";"; m_MotionLog += " translation: " + boost::lexical_cast(m_Translation[0]*m_MotionCounter) + "," + boost::lexical_cast(m_Translation[1]*m_MotionCounter) + "," + boost::lexical_cast(m_Translation[2]*m_MotionCounter) + "\n"; } m_FiberBundleTransformed->TransformFibers(m_Rotation[0],m_Rotation[1],m_Rotation[2],m_Translation[0],m_Translation[1],m_Translation[2]); } else { m_Rotation.Fill(0.0); m_Translation.Fill(0.0); m_Rotations.push_back(m_Rotation); m_Translations.push_back(m_Translation); m_MotionLog += boost::lexical_cast(g) + " rotation: " + boost::lexical_cast(m_Rotation[0]) + "," + boost::lexical_cast(m_Rotation[1]) + "," + boost::lexical_cast(m_Rotation[2]) + ";"; m_MotionLog += " translation: " + boost::lexical_cast(m_Translation[0]) + "," + boost::lexical_cast(m_Translation[1]) + "," + boost::lexical_cast(m_Translation[2]) + "\n"; } } template< class PixelType > itk::Point TractsToDWIImageFilter< PixelType >::GetMovedPoint(itk::Index<3>& index, bool forward) { itk::Point transformed_point; if (forward) { m_UpsampledMaskImage->TransformIndexToPhysicalPoint(index, transformed_point); if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { - transformed_point = m_FiberBundleWorkingCopy->TransformPoint(transformed_point.GetVnlVector(), + transformed_point = m_FiberBundle->TransformPoint(transformed_point.GetVnlVector(), m_Rotation[0],m_Rotation[1],m_Rotation[2], m_Translation[0],m_Translation[1],m_Translation[2]); } else { - transformed_point = m_FiberBundleWorkingCopy->TransformPoint(transformed_point.GetVnlVector(), + transformed_point = m_FiberBundle->TransformPoint(transformed_point.GetVnlVector(), m_Rotation[0]*m_MotionCounter,m_Rotation[1]*m_MotionCounter,m_Rotation[2]*m_MotionCounter, m_Translation[0]*m_MotionCounter,m_Translation[1]*m_MotionCounter,m_Translation[2]*m_MotionCounter); } } else { m_TransformedMaskImage->TransformIndexToPhysicalPoint(index, transformed_point); if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { - transformed_point = m_FiberBundleWorkingCopy->TransformPoint( transformed_point.GetVnlVector(), + transformed_point = m_FiberBundle->TransformPoint( transformed_point.GetVnlVector(), -m_Rotation[0], -m_Rotation[1], -m_Rotation[2], -m_Translation[0], -m_Translation[1], -m_Translation[2] ); } else { - transformed_point = m_FiberBundleWorkingCopy->TransformPoint( transformed_point.GetVnlVector(), + transformed_point = m_FiberBundle->TransformPoint( transformed_point.GetVnlVector(), -m_Rotation[0]*m_MotionCounter, -m_Rotation[1]*m_MotionCounter, -m_Rotation[2]*m_MotionCounter, -m_Translation[0]*m_MotionCounter, -m_Translation[1]*m_MotionCounter, -m_Translation[2]*m_MotionCounter ); } } return transformed_point; } template< class PixelType > void TractsToDWIImageFilter< PixelType >:: SimulateExtraAxonalSignal(ItkUcharImgType::IndexType& index, itk::Point& volume_fraction_point, double intraAxonalVolume, int g) { int numFiberCompartments = m_Parameters.m_FiberModelList.size(); int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size(); if (m_Parameters.m_SignalGen.m_DoDisablePartialVolume) { // simulate signal for largest non-fiber compartment int max_compartment_index = 0; double max_fraction = 0; if (numNonFiberCompartments>1) { for (int i=0; iSetInputImage(m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()); double compartment_fraction = mitk::imv::GetImageValue(volume_fraction_point, true, m_DoubleInterpolator); if (compartment_fraction<0) mitkThrow() << "Volume fraction image (index " << i << ") contains values less than zero!"; if (compartment_fraction>max_fraction) { max_fraction = compartment_fraction; max_compartment_index = i; } } } DoubleDwiType::Pointer doubleDwi = m_CompartmentImages.at(max_compartment_index+numFiberCompartments); DoubleDwiType::PixelType pix = doubleDwi->GetPixel(index); pix[g] += m_Parameters.m_NonFiberModelList[max_compartment_index]->SimulateMeasurement(g, m_NullDir)*m_VoxelVolume; doubleDwi->SetPixel(index, pix); if (g==0) m_VolumeFractions.at(max_compartment_index+numFiberCompartments)->SetPixel(index, 1); } else { std::vector< double > fractions; if (g==0) m_VolumeFractions.at(0)->SetPixel(index, intraAxonalVolume/m_VoxelVolume); double extraAxonalVolume = m_VoxelVolume-intraAxonalVolume; // non-fiber volume if (extraAxonalVolume<0) { if (extraAxonalVolume<-0.001) MITK_ERROR << "Corrupted intra-axonal signal voxel detected. Fiber volume larger voxel volume! " << m_VoxelVolume << "<" << intraAxonalVolume; extraAxonalVolume = 0; } double interAxonalVolume = 0; if (numFiberCompartments>1) interAxonalVolume = extraAxonalVolume * intraAxonalVolume/m_VoxelVolume; // inter-axonal fraction of non fiber compartment double nonFiberVolume = extraAxonalVolume - interAxonalVolume; // rest of compartment if (nonFiberVolume<0) { if (nonFiberVolume<-0.001) MITK_ERROR << "Corrupted signal voxel detected. Fiber volume larger voxel volume!"; nonFiberVolume = 0; interAxonalVolume = extraAxonalVolume; } double compartmentSum = intraAxonalVolume; fractions.push_back(intraAxonalVolume/m_VoxelVolume); // rescale extra-axonal fiber signal for (int i=1; iGetVolumeFractionImage()!=nullptr) { m_DoubleInterpolator->SetInputImage(m_Parameters.m_FiberModelList[i]->GetVolumeFractionImage()); interAxonalVolume = mitk::imv::GetImageValue(volume_fraction_point, true, m_DoubleInterpolator)*m_VoxelVolume; if (interAxonalVolume<0) mitkThrow() << "Volume fraction image (index " << i+1 << ") contains negative values!"; } DoubleDwiType::PixelType pix = m_CompartmentImages.at(i)->GetPixel(index); pix[g] *= interAxonalVolume; m_CompartmentImages.at(i)->SetPixel(index, pix); compartmentSum += interAxonalVolume; fractions.push_back(interAxonalVolume/m_VoxelVolume); if (g==0) m_VolumeFractions.at(i)->SetPixel(index, interAxonalVolume/m_VoxelVolume); } for (int i=0; iGetVolumeFractionImage()!=nullptr) { m_DoubleInterpolator->SetInputImage(m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()); volume = mitk::imv::GetImageValue(volume_fraction_point, true, m_DoubleInterpolator)*m_VoxelVolume; if (volume<0) mitkThrow() << "Volume fraction image (index " << numFiberCompartments+i+1 << ") contains negative values (non-fiber compartment)!"; if (m_UseRelativeNonFiberVolumeFractions) volume *= nonFiberVolume/m_VoxelVolume; } DoubleDwiType::PixelType pix = m_CompartmentImages.at(i+numFiberCompartments)->GetPixel(index); pix[g] += m_Parameters.m_NonFiberModelList[i]->SimulateMeasurement(g, m_NullDir)*volume; m_CompartmentImages.at(i+numFiberCompartments)->SetPixel(index, pix); compartmentSum += volume; fractions.push_back(volume/m_VoxelVolume); if (g==0) m_VolumeFractions.at(i+numFiberCompartments)->SetPixel(index, volume/m_VoxelVolume); } if (compartmentSum/m_VoxelVolume>1.05) { MITK_ERROR << "Compartments do not sum to 1 in voxel " << index << " (" << compartmentSum/m_VoxelVolume << ")"; for (auto val : fractions) MITK_ERROR << val; } } } template< class PixelType > itk::Point TractsToDWIImageFilter< PixelType >::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } template< class PixelType > itk::Vector TractsToDWIImageFilter< PixelType >::GetItkVector(double point[3]) { itk::Vector itkVector; itkVector[0] = point[0]; itkVector[1] = point[1]; itkVector[2] = point[2]; return itkVector; } template< class PixelType > vnl_vector_fixed TractsToDWIImageFilter< PixelType >::GetVnlVector(double point[3]) { vnl_vector_fixed vnlVector; vnlVector[0] = point[0]; vnlVector[1] = point[1]; vnlVector[2] = point[2]; return vnlVector; } template< class PixelType > vnl_vector_fixed TractsToDWIImageFilter< PixelType >::GetVnlVector(Vector& vector) { vnl_vector_fixed vnlVector; vnlVector[0] = vector[0]; vnlVector[1] = vector[1]; vnlVector[2] = vector[2]; return vnlVector; } template< class PixelType > double TractsToDWIImageFilter< PixelType >::RoundToNearest(double num) { return (num > 0.0) ? floor(num + 0.5) : ceil(num - 0.5); } template< class PixelType > std::string TractsToDWIImageFilter< PixelType >::GetTime() { m_TimeProbe.Stop(); unsigned long total = RoundToNearest(m_TimeProbe.GetTotal()); unsigned long hours = total/3600; unsigned long minutes = (total%3600)/60; unsigned long seconds = total%60; std::string out = ""; out.append(boost::lexical_cast(hours)); out.append(":"); out.append(boost::lexical_cast(minutes)); out.append(":"); out.append(boost::lexical_cast(seconds)); m_TimeProbe.Start(); return out; } } diff --git a/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.h b/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.h index ce6fc47372..3d4af97ac3 100755 --- a/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.h @@ -1,178 +1,177 @@ /*=================================================================== 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 __itkTractsToDWIImageFilter_h__ #define __itkTractsToDWIImageFilter_h__ #include #include #include #include #include #include #include #include #include #include namespace itk { /** * \brief Generates artificial diffusion weighted image volume from the input fiberbundle using a generic multicompartment model. * See "Fiberfox: Facilitating the creation of realistic white matter software phantoms" (DOI: 10.1002/mrm.25045) for details. */ template< class PixelType > class TractsToDWIImageFilter : public ImageSource< itk::VectorImage< PixelType, 3 > > { public: typedef TractsToDWIImageFilter Self; typedef ImageSource< itk::VectorImage< PixelType, 3 > > Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef typename Superclass::OutputImageType OutputImageType; typedef itk::Image ItkDoubleImgType4D; typedef itk::Image ItkDoubleImgType; typedef itk::Image ItkFloatImgType; typedef itk::Image ItkUcharImgType; typedef mitk::FiberBundle::Pointer FiberBundleType; typedef itk::VectorImage< double, 3 > DoubleDwiType; typedef itk::Matrix MatrixType; typedef itk::Image< float, 2 > Float2DImageType; typedef itk::Image< vcl_complex< float >, 2 > Complex2DImageType; typedef itk::Vector< double,3> DoubleVectorType; itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkTypeMacro( TractsToDWIImageFilter, ImageSource ) /** Input */ itkSetMacro( FiberBundle, FiberBundleType ) ///< Input fiber bundle itkSetMacro( InputImage, typename OutputImageType::Pointer ) ///< Input diffusion-weighted image. If no fiber bundle is set, then the acquisition is simulated for this image without a new diffusion simulation. itkSetMacro( UseConstantRandSeed, bool ) ///< Seed for random generator. void SetParameters( FiberfoxParameters param ) ///< Simulation parameters. { m_Parameters = param; } /** Output */ FiberfoxParameters GetParameters(){ return m_Parameters; } std::vector< ItkDoubleImgType::Pointer > GetVolumeFractions() ///< one double image for each compartment containing the corresponding volume fraction per voxel { return m_VolumeFractions; } mitk::LevelWindow GetLevelWindow() ///< Level window is determined from the output image { return m_LevelWindow; } itkGetMacro( StatusText, std::string ) itkGetMacro( PhaseImage, DoubleDwiType::Pointer ) itkGetMacro( KspaceImage, DoubleDwiType::Pointer ) itkGetMacro( CoilPointset, mitk::PointSet::Pointer ) void GenerateData() override; std::vector GetOutputImagesReal() const { return m_OutputImagesReal; } std::vector GetOutputImagesImag() const { return m_OutputImagesImag; } protected: TractsToDWIImageFilter(); ~TractsToDWIImageFilter() override; itk::Point GetItkPoint(double point[3]); itk::Vector GetItkVector(double point[3]); vnl_vector_fixed GetVnlVector(double point[3]); vnl_vector_fixed GetVnlVector(Vector< float, 3 >& vector); double RoundToNearest(double num); std::string GetTime(); bool PrepareLogFile(); /** Prepares the log file and returns true if successful or false if failed. */ void PrintToLog(std::string m, bool addTime=true, bool linebreak=true, bool stdOut=true); /** Transform generated image compartment by compartment, channel by channel and slice by slice using DFT and add k-space artifacts/effects. */ DoubleDwiType::Pointer SimulateKspaceAcquisition(std::vector< DoubleDwiType::Pointer >& images); /** Generate signal of non-fiber compartments. */ void SimulateExtraAxonalSignal(ItkUcharImgType::IndexType& index, itk::Point& volume_fraction_point, double intraAxonalVolume, int g); /** Move fibers to simulate headmotion */ void SimulateMotion(int g=-1); void CheckVolumeFractionImages(); ItkDoubleImgType::Pointer NormalizeInsideMask(ItkDoubleImgType::Pointer image); void InitializeData(); void InitializeFiberData(); itk::Point GetMovedPoint(itk::Index<3>& index, bool forward); // input mitk::FiberfoxParameters m_Parameters; FiberBundleType m_FiberBundle; typename OutputImageType::Pointer m_InputImage; // output typename OutputImageType::Pointer m_OutputImage; typename DoubleDwiType::Pointer m_PhaseImage; typename DoubleDwiType::Pointer m_KspaceImage; std::vector < typename DoubleDwiType::Pointer > m_OutputImagesReal; std::vector < typename DoubleDwiType::Pointer > m_OutputImagesImag; mitk::LevelWindow m_LevelWindow; std::vector< ItkDoubleImgType::Pointer > m_VolumeFractions; std::string m_StatusText; // MISC itk::TimeProbe m_TimeProbe; bool m_UseConstantRandSeed; bool m_MaskImageSet; ofstream m_Logfile; std::string m_MotionLog; std::string m_SpikeLog; // signal generation - FiberBundleType m_FiberBundleWorkingCopy; ///< we work on an upsampled version of the input bundle FiberBundleType m_FiberBundleTransformed; ///< transformed bundle simulating headmotion itk::Vector m_WorkingSpacing; itk::Point m_WorkingOrigin; ImageRegion<3> m_WorkingImageRegion; double m_VoxelVolume; std::vector< DoubleDwiType::Pointer > m_CompartmentImages; ItkUcharImgType::Pointer m_TransformedMaskImage; ///< copy of mask image (changes for each motion step) ItkUcharImgType::Pointer m_UpsampledMaskImage; ///< helper image for motion simulation DoubleVectorType m_Rotation; DoubleVectorType m_Translation; std::vector< DoubleVectorType > m_Rotations; /// m_Translations; ///::Pointer m_DoubleInterpolator; itk::Vector m_NullDir; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkTractsToDWIImageFilter.cpp" #endif #endif diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp index 39a34e8d82..bc3ff77cdb 100755 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.cpp @@ -1,2643 +1,2653 @@ /*=================================================================== 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 "mitkFiberBundle.h" #include #include #include #include "mitkImagePixelReadAccessor.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include +#include const char* mitk::FiberBundle::FIBER_ID_ARRAY = "Fiber_IDs"; mitk::FiberBundle::FiberBundle( vtkPolyData* fiberPolyData ) : m_NumFibers(0) { m_FiberWeights = vtkSmartPointer::New(); m_FiberWeights->SetName("FIBER_WEIGHTS"); m_FiberPolyData = vtkSmartPointer::New(); if (fiberPolyData != nullptr) m_FiberPolyData = fiberPolyData; else { this->m_FiberPolyData->SetPoints(vtkSmartPointer::New()); this->m_FiberPolyData->SetLines(vtkSmartPointer::New()); } this->UpdateFiberGeometry(); this->GenerateFiberIds(); this->ColorFibersByOrientation(); } mitk::FiberBundle::~FiberBundle() { } mitk::FiberBundle::Pointer mitk::FiberBundle::GetDeepCopy() { mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(m_FiberPolyData); newFib->SetFiberColors(this->m_FiberColors); newFib->SetFiberWeights(this->m_FiberWeights); return newFib; } vtkSmartPointer mitk::FiberBundle::GeneratePolyDataByIds(std::vector fiberIds, vtkSmartPointer weights) { vtkSmartPointer newFiberPolyData = vtkSmartPointer::New(); vtkSmartPointer newLineSet = vtkSmartPointer::New(); vtkSmartPointer newPointSet = vtkSmartPointer::New(); weights->SetNumberOfValues(fiberIds.size()); int counter = 0; auto finIt = fiberIds.begin(); while ( finIt != fiberIds.end() ) { if (*finIt < 0 || *finIt>GetNumFibers()){ MITK_INFO << "FiberID can not be negative or >NumFibers!!! check id Extraction!" << *finIt; break; } vtkSmartPointer fiber = m_FiberIdDataSet->GetCell(*finIt);//->DeepCopy(fiber); vtkSmartPointer fibPoints = fiber->GetPoints(); vtkSmartPointer newFiber = vtkSmartPointer::New(); newFiber->GetPointIds()->SetNumberOfIds( fibPoints->GetNumberOfPoints() ); for(int i=0; iGetNumberOfPoints(); i++) { newFiber->GetPointIds()->SetId(i, newPointSet->GetNumberOfPoints()); newPointSet->InsertNextPoint(fibPoints->GetPoint(i)[0], fibPoints->GetPoint(i)[1], fibPoints->GetPoint(i)[2]); } weights->InsertValue(counter, this->GetFiberWeight(*finIt)); newLineSet->InsertNextCell(newFiber); ++finIt; ++counter; } newFiberPolyData->SetPoints(newPointSet); newFiberPolyData->SetLines(newLineSet); return newFiberPolyData; } // merge two fiber bundles mitk::FiberBundle::Pointer mitk::FiberBundle::AddBundles(std::vector< mitk::FiberBundle::Pointer > fibs) { vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); // add current fiber bundle vtkSmartPointer weights = vtkSmartPointer::New(); int num_weights = this->GetNumFibers(); for (auto fib : fibs) num_weights += fib->GetNumFibers(); weights->SetNumberOfValues(num_weights); unsigned int counter = 0; for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } weights->InsertValue(counter, this->GetFiberWeight(i)); vNewLines->InsertNextCell(container); counter++; } for (auto fib : fibs) { // add new fiber bundle for (int i=0; iGetFiberPolyData()->GetNumberOfCells(); i++) { vtkCell* cell = fib->GetFiberPolyData()->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } weights->InsertValue(counter, fib->GetFiberWeight(i)); vNewLines->InsertNextCell(container); counter++; } } // initialize PolyData vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(vNewPolyData); newFib->SetFiberWeights(weights); return newFib; } // merge two fiber bundles mitk::FiberBundle::Pointer mitk::FiberBundle::AddBundle(mitk::FiberBundle* fib) { if (fib==nullptr) return this->GetDeepCopy(); MITK_INFO << "Adding fibers"; vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); // add current fiber bundle vtkSmartPointer weights = vtkSmartPointer::New(); weights->SetNumberOfValues(this->GetNumFibers()+fib->GetNumFibers()); unsigned int counter = 0; for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } weights->InsertValue(counter, this->GetFiberWeight(i)); vNewLines->InsertNextCell(container); counter++; } // add new fiber bundle for (int i=0; iGetFiberPolyData()->GetNumberOfCells(); i++) { vtkCell* cell = fib->GetFiberPolyData()->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } weights->InsertValue(counter, fib->GetFiberWeight(i)); vNewLines->InsertNextCell(container); counter++; } // initialize PolyData vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(vNewPolyData); newFib->SetFiberWeights(weights); return newFib; } // Only retain fibers with a weight larger than the specified threshold mitk::FiberBundle::Pointer mitk::FiberBundle::FilterByWeights(float weight_thr, bool invert) { vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); std::vector weights; for (int i=0; iGetNumFibers(); i++) { if ( (invert && this->GetFiberWeight(i)>weight_thr) || (!invert && this->GetFiberWeight(i)<=weight_thr)) continue; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); weights.push_back(this->GetFiberWeight(i)); } // initialize PolyData vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(vNewPolyData); for (unsigned int i=0; iSetFiberWeight(i, weights.at(i)); return newFib; } // Only retain a subsample of the fibers mitk::FiberBundle::Pointer mitk::FiberBundle::SubsampleFibers(float factor) { vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); int new_num_fibs = this->GetNumFibers()*factor; MITK_INFO << "Subsampling fibers with factor " << factor << "(" << new_num_fibs << "/" << this->GetNumFibers() << ")"; // add current fiber bundle vtkSmartPointer weights = vtkSmartPointer::New(); weights->SetNumberOfValues(new_num_fibs); std::vector< int > ids; for (int i=0; iGetNumFibers(); i++) ids.push_back(i); std::random_shuffle(ids.begin(), ids.end()); unsigned int counter = 0; for (int i=0; iGetCell(ids.at(i)); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p); vtkIdType id = vNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } weights->InsertValue(counter, this->GetFiberWeight(ids.at(i))); vNewLines->InsertNextCell(container); counter++; } // initialize PolyData vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(vNewPolyData); newFib->SetFiberWeights(weights); return newFib; } // subtract two fiber bundles mitk::FiberBundle::Pointer mitk::FiberBundle::SubtractBundle(mitk::FiberBundle* fib) { if (fib==nullptr) return this->GetDeepCopy(); MITK_INFO << "Subtracting fibers"; vtkSmartPointer vNewPolyData = vtkSmartPointer::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); std::vector< std::vector< itk::Point > > points1; for( int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (points==nullptr || numPoints<=0) continue; itk::Point start = GetItkPoint(points->GetPoint(0)); itk::Point end = GetItkPoint(points->GetPoint(numPoints-1)); points1.push_back( {start, end} ); } std::vector< std::vector< itk::Point > > points2; for( int i=0; iGetNumFibers(); i++ ) { vtkCell* cell = fib->GetFiberPolyData()->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (points==nullptr || numPoints<=0) continue; itk::Point start = GetItkPoint(points->GetPoint(0)); itk::Point end = GetItkPoint(points->GetPoint(numPoints-1)); points2.push_back( {start, end} ); } // int progress = 0; std::vector< int > ids; #pragma omp parallel for for (int i=0; i<(int)points1.size(); i++) { //#pragma omp critical // { // progress++; // std::cout << (int)(100*(float)progress/points1.size()) << "%" << '\r'; // cout.flush(); // } bool match = false; for (unsigned int j=0; jGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (points==nullptr || numPoints<=0) continue; vtkSmartPointer container = vtkSmartPointer::New(); for( int j=0; jInsertNextPoint(points->GetPoint(j)); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } if(vNewLines->GetNumberOfCells()==0) return mitk::FiberBundle::New(); // initialize PolyData vNewPolyData->SetPoints(vNewPoints); vNewPolyData->SetLines(vNewLines); // initialize fiber bundle return mitk::FiberBundle::New(vNewPolyData); } itk::Point mitk::FiberBundle::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } /* * set PolyData (additional flag to recompute fiber geometry, default = true) */ void mitk::FiberBundle::SetFiberPolyData(vtkSmartPointer fiberPD, bool updateGeometry) { if (fiberPD == nullptr) this->m_FiberPolyData = vtkSmartPointer::New(); else m_FiberPolyData->DeepCopy(fiberPD); m_NumFibers = m_FiberPolyData->GetNumberOfLines(); if (updateGeometry) UpdateFiberGeometry(); GenerateFiberIds(); ColorFibersByOrientation(); } /* * return vtkPolyData */ vtkSmartPointer mitk::FiberBundle::GetFiberPolyData() const { return m_FiberPolyData; } void mitk::FiberBundle::ColorFibersByLength(bool opacity, bool normalize) { if (m_MaxFiberLength<=0) return; int numOfPoints = this->GetNumberOfPoints(); //colors and alpha value for each single point, RGBA = 4 components unsigned char rgba[4] = {0,0,0,0}; int componentSize = 4; m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(numOfPoints * componentSize); m_FiberColors->SetNumberOfComponents(componentSize); m_FiberColors->SetName("FIBER_COLORS"); int numOfFibers = m_FiberPolyData->GetNumberOfLines(); if (numOfFibers < 1) return; mitk::LookupTable::Pointer mitkLookup = mitk::LookupTable::New(); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetTableRange(0.0, 0.8); lookupTable->Build(); mitkLookup->SetVtkLookupTable(lookupTable); mitkLookup->SetType(mitk::LookupTable::JET); unsigned int count = 0; for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); float l = m_FiberLengths.at(i)/m_MaxFiberLength; if (!normalize) { l = m_FiberLengths.at(i)/255.0; if (l > 1.0) l = 1.0; } for (int j=0; jGetColor(1.0 - l, color); rgba[0] = (unsigned char) (255.0 * color[0]); rgba[1] = (unsigned char) (255.0 * color[1]); rgba[2] = (unsigned char) (255.0 * color[2]); if (opacity) rgba[3] = (unsigned char) (255.0 * l); else rgba[3] = (unsigned char) (255.0); m_FiberColors->InsertTypedTuple(cell->GetPointId(j), rgba); count++; } } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::ColorFibersByOrientation() { //===== FOR WRITING A TEST ======================== // colorT size == tupelComponents * tupelElements // compare color results // to cover this code 100% also PolyData needed, where colorarray already exists // + one fiber with exactly 1 point // + one fiber with 0 points //================================================= vtkPoints* extrPoints = nullptr; extrPoints = m_FiberPolyData->GetPoints(); int numOfPoints = 0; if (extrPoints!=nullptr) numOfPoints = extrPoints->GetNumberOfPoints(); //colors and alpha value for each single point, RGBA = 4 components unsigned char rgba[4] = {0,0,0,0}; int componentSize = 4; m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(numOfPoints * componentSize); m_FiberColors->SetNumberOfComponents(componentSize); m_FiberColors->SetName("FIBER_COLORS"); int numOfFibers = m_FiberPolyData->GetNumberOfLines(); if (numOfFibers < 1) return; /* extract single fibers of fiberBundle */ vtkCellArray* fiberList = m_FiberPolyData->GetLines(); fiberList->InitTraversal(); for (int fi=0; fiGetNextCell(pointsPerFiber, idList); /* single fiber checkpoints: is number of points valid */ if (pointsPerFiber > 1) { /* operate on points of single fiber */ for (int i=0; i 0) { /* The color value of the current point is influenced by the previous point and next point. */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[i+1])[0], extrPoints->GetPoint(idList[i+1])[1], extrPoints->GetPoint(idList[i+1])[2]); vnl_vector_fixed< double, 3 > prevPntvtk(extrPoints->GetPoint(idList[i-1])[0], extrPoints->GetPoint(idList[i-1])[1], extrPoints->GetPoint(idList[i-1])[2]); vnl_vector_fixed< double, 3 > diff1; diff1 = currentPntvtk - nextPntvtk; vnl_vector_fixed< double, 3 > diff2; diff2 = currentPntvtk - prevPntvtk; vnl_vector_fixed< double, 3 > diff; diff = (diff1 - diff2) / 2.0; diff.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff[2])); rgba[3] = (unsigned char) (255.0); } else if (i==0) { /* First point has no previous point, therefore only diff1 is taken */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > nextPntvtk(extrPoints->GetPoint(idList[i+1])[0], extrPoints->GetPoint(idList[i+1])[1], extrPoints->GetPoint(idList[i+1])[2]); vnl_vector_fixed< double, 3 > diff1; diff1 = currentPntvtk - nextPntvtk; diff1.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff1[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff1[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff1[2])); rgba[3] = (unsigned char) (255.0); } else if (i==pointsPerFiber-1) { /* Last point has no next point, therefore only diff2 is taken */ vnl_vector_fixed< double, 3 > currentPntvtk(extrPoints->GetPoint(idList[i])[0], extrPoints->GetPoint(idList[i])[1],extrPoints->GetPoint(idList[i])[2]); vnl_vector_fixed< double, 3 > prevPntvtk(extrPoints->GetPoint(idList[i-1])[0], extrPoints->GetPoint(idList[i-1])[1], extrPoints->GetPoint(idList[i-1])[2]); vnl_vector_fixed< double, 3 > diff2; diff2 = currentPntvtk - prevPntvtk; diff2.normalize(); rgba[0] = (unsigned char) (255.0 * std::fabs(diff2[0])); rgba[1] = (unsigned char) (255.0 * std::fabs(diff2[1])); rgba[2] = (unsigned char) (255.0 * std::fabs(diff2[2])); rgba[3] = (unsigned char) (255.0); } m_FiberColors->InsertTypedTuple(idList[i], rgba); } } else if (pointsPerFiber == 1) { /* a single point does not define a fiber (use vertex mechanisms instead */ continue; } else { MITK_DEBUG << "Fiber with 0 points detected... please check your tractography algorithm!" ; continue; } } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::ColorFibersByCurvature(bool, bool normalize) { double window = 5; //colors and alpha value for each single point, RGBA = 4 components unsigned char rgba[4] = {0,0,0,0}; int componentSize = 4; m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * componentSize); m_FiberColors->SetNumberOfComponents(componentSize); m_FiberColors->SetName("FIBER_COLORS"); mitk::LookupTable::Pointer mitkLookup = mitk::LookupTable::New(); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetTableRange(0.0, 0.8); lookupTable->Build(); mitkLookup->SetVtkLookupTable(lookupTable); mitkLookup->SetType(mitk::LookupTable::JET); std::vector< double > values; double min = 1; double max = 0; MITK_INFO << "Coloring fibers by curvature"; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); for (int i=0; iGetNumberOfCells(); i++) { ++disp; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); // calculate curvatures for (int j=0; j > vectors; vnl_vector_fixed< float, 3 > meanV; meanV.fill(0.0); while(dist1) { double p1[3]; points->GetPoint(c-1, p1); double p2[3]; points->GetPoint(c, p2); vnl_vector_fixed< float, 3 > v; v[0] = p2[0]-p1[0]; v[1] = p2[1]-p1[1]; v[2] = p2[2]-p1[2]; dist += v.magnitude(); v.normalize(); vectors.push_back(v); meanV += v; c--; } c = j; dist = 0; while(distGetPoint(c, p1); double p2[3]; points->GetPoint(c+1, p2); vnl_vector_fixed< float, 3 > v; v[0] = p2[0]-p1[0]; v[1] = p2[1]-p1[1]; v[2] = p2[2]-p1[2]; dist += v.magnitude(); v.normalize(); vectors.push_back(v); meanV += v; c++; } meanV.normalize(); double dev = 0; for (unsigned int c=0; c1.0) angle = 1.0; if (angle<-1.0) angle = -1.0; dev += acos(angle)*180/itk::Math::pi; } if (vectors.size()>0) dev /= vectors.size(); dev = 1.0-dev/180.0; values.push_back(dev); if (devmax) max = dev; } } unsigned int count = 0; for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); for (int j=0; j1) dev = 1; lookupTable->GetColor(dev, color); rgba[0] = (unsigned char) (255.0 * color[0]); rgba[1] = (unsigned char) (255.0 * color[1]); rgba[2] = (unsigned char) (255.0 * color[2]); rgba[3] = (unsigned char) (255.0); m_FiberColors->InsertTypedTuple(cell->GetPointId(j), rgba); count++; } } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::SetFiberOpacity(vtkDoubleArray* FAValArray) { for(long i=0; iGetNumberOfTuples(); i++) { double faValue = FAValArray->GetValue(i); faValue = faValue * 255.0; m_FiberColors->SetComponent(i,3, (unsigned char) faValue ); } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::ResetFiberOpacity() { for(long i=0; iGetNumberOfTuples(); i++) m_FiberColors->SetComponent(i,3, 255.0 ); m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::ColorFibersByScalarMap(mitk::Image::Pointer FAimage, bool opacity, bool normalize) { mitkPixelTypeMultiplex3( ColorFibersByScalarMap, FAimage->GetPixelType(), FAimage, opacity, normalize ); m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } template void mitk::FiberBundle::ColorFibersByScalarMap(const mitk::PixelType, mitk::Image::Pointer image, bool opacity, bool normalize) { m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * 4); m_FiberColors->SetNumberOfComponents(4); m_FiberColors->SetName("FIBER_COLORS"); mitk::ImagePixelReadAccessor readimage(image, image->GetVolumeData(0)); unsigned char rgba[4] = {0,0,0,0}; vtkPoints* pointSet = m_FiberPolyData->GetPoints(); mitk::LookupTable::Pointer mitkLookup = mitk::LookupTable::New(); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetTableRange(0.0, 0.8); lookupTable->Build(); mitkLookup->SetVtkLookupTable(lookupTable); mitkLookup->SetType(mitk::LookupTable::JET); double min = 9999999; double max = -9999999; for(long i=0; iGetNumberOfPoints(); ++i) { Point3D px; px[0] = pointSet->GetPoint(i)[0]; px[1] = pointSet->GetPoint(i)[1]; px[2] = pointSet->GetPoint(i)[2]; double pixelValue = readimage.GetPixelByWorldCoordinates(px); if (pixelValue>max) max = pixelValue; if (pixelValueGetNumberOfPoints(); ++i) { Point3D px; px[0] = pointSet->GetPoint(i)[0]; px[1] = pointSet->GetPoint(i)[1]; px[2] = pointSet->GetPoint(i)[2]; double pixelValue = readimage.GetPixelByWorldCoordinates(px); if (normalize) pixelValue = (pixelValue-min)/(max-min); else if (pixelValue>1) pixelValue = 1; double color[3]; lookupTable->GetColor(1-pixelValue, color); rgba[0] = (unsigned char) (255.0 * color[0]); rgba[1] = (unsigned char) (255.0 * color[1]); rgba[2] = (unsigned char) (255.0 * color[2]); if (opacity) rgba[3] = (unsigned char) (255.0 * pixelValue); else rgba[3] = (unsigned char) (255.0); m_FiberColors->InsertTypedTuple(i, rgba); } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::ColorFibersByFiberWeights(bool opacity, bool normalize) { m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * 4); m_FiberColors->SetNumberOfComponents(4); m_FiberColors->SetName("FIBER_COLORS"); mitk::LookupTable::Pointer mitkLookup = mitk::LookupTable::New(); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetTableRange(0.0, 0.8); lookupTable->Build(); mitkLookup->SetVtkLookupTable(lookupTable); mitkLookup->SetType(mitk::LookupTable::JET); unsigned char rgba[4] = {0,0,0,0}; unsigned int counter = 0; float max = -999999; float min = 999999; for (int i=0; iGetFiberWeight(i); if (weight>max) max = weight; if (weightGetCell(i); int numPoints = cell->GetNumberOfPoints(); double weight = this->GetFiberWeight(i); for (int j=0; j1) v = 1; double color[3]; lookupTable->GetColor(1-v, color); rgba[0] = (unsigned char) (255.0 * color[0]); rgba[1] = (unsigned char) (255.0 * color[1]); rgba[2] = (unsigned char) (255.0 * color[2]); if (opacity) rgba[3] = (unsigned char) (255.0 * v); else rgba[3] = (unsigned char) (255.0); m_FiberColors->InsertTypedTuple(counter, rgba); counter++; } } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::SetFiberColors(float r, float g, float b, float alpha) { m_FiberColors = vtkSmartPointer::New(); m_FiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * 4); m_FiberColors->SetNumberOfComponents(4); m_FiberColors->SetName("FIBER_COLORS"); unsigned char rgba[4] = {0,0,0,0}; for(long i=0; iGetNumberOfPoints(); ++i) { rgba[0] = (unsigned char) r; rgba[1] = (unsigned char) g; rgba[2] = (unsigned char) b; rgba[3] = (unsigned char) alpha; m_FiberColors->InsertTypedTuple(i, rgba); } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } void mitk::FiberBundle::GenerateFiberIds() { if (m_FiberPolyData == nullptr) return; vtkSmartPointer idFiberFilter = vtkSmartPointer::New(); idFiberFilter->SetInputData(m_FiberPolyData); idFiberFilter->CellIdsOn(); // idFiberFilter->PointIdsOn(); // point id's are not needed idFiberFilter->SetIdsArrayName(FIBER_ID_ARRAY); idFiberFilter->FieldDataOn(); idFiberFilter->Update(); m_FiberIdDataSet = idFiberFilter->GetOutput(); } -float mitk::FiberBundle::GetOverlap(ItkUcharImgType* mask, bool do_resampling) +float mitk::FiberBundle::GetOverlap(ItkUcharImgType* mask) { vtkSmartPointer PolyData = m_FiberPolyData; - mitk::FiberBundle::Pointer fibCopy = this; - if (do_resampling) - { - float minSpacing = 1; - if(mask->GetSpacing()[0]GetSpacing()[1] && mask->GetSpacing()[0]GetSpacing()[2]) - minSpacing = mask->GetSpacing()[0]; - else if (mask->GetSpacing()[1] < mask->GetSpacing()[2]) - minSpacing = mask->GetSpacing()[1]; - else - minSpacing = mask->GetSpacing()[2]; - - fibCopy = this->GetDeepCopy(); - fibCopy->ResampleLinear(minSpacing/5); - PolyData = fibCopy->GetFiberPolyData(); - } MITK_INFO << "Calculating overlap"; - int inside = 0; - int outside = 0; + auto spacing = mask->GetSpacing(); boost::progress_display disp(m_NumFibers); + double length_sum = 0; + double in_mask_length = 0; for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); - for (int j=0; jGetPoint(j); - itk::Point itkP; - itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; - itk::Index<3> idx; - mask->TransformPhysicalPointToIndex(itkP, idx); - - if ( mask->GetLargestPossibleRegion().IsInside(idx) && mask->GetPixel(idx) != 0 ) - inside++; - else - outside++; + itk::Point startVertex = GetItkPoint(points->GetPoint(j)); + itk::Index<3> startIndex; + itk::ContinuousIndex startIndexCont; + mask->TransformPhysicalPointToIndex(startVertex, startIndex); + mask->TransformPhysicalPointToContinuousIndex(startVertex, startIndexCont); + + itk::Point endVertex = GetItkPoint(points->GetPoint(j + 1)); + itk::Index<3> endIndex; + itk::ContinuousIndex endIndexCont; + mask->TransformPhysicalPointToIndex(endVertex, endIndex); + mask->TransformPhysicalPointToContinuousIndex(endVertex, endIndexCont); + + double d[3]; + for (int i=0; i<3; ++i) + d[i] = (endVertex[i]-startVertex[i])*spacing[i]; + length_sum += std::sqrt( d[0]*d[0] + d[1]*d[1] + d[2]*d[2] ); + + std::vector< std::pair< itk::Index<3>, double > > segments = mitk::imv::IntersectImage(spacing, startIndex, endIndex, startIndexCont, endIndexCont); + for (std::pair< itk::Index<3>, double > segment : segments) + { + if ( mask->GetLargestPossibleRegion().IsInside(segment.first) && mask->GetPixel(segment.first) != 0 ) + in_mask_length += segment.second; + } } } - if (inside+outside==0) - outside = 1; - return (float)inside/(inside+outside); + if (length_sum==0) + { + MITK_INFO << "Fiber length sum is zero!"; + return length_sum; + } + return in_mask_length/length_sum; } mitk::FiberBundle::Pointer mitk::FiberBundle::RemoveFibersOutside(ItkUcharImgType* mask, bool invert) { - float minSpacing = 1; - if(mask->GetSpacing()[0]GetSpacing()[1] && mask->GetSpacing()[0]GetSpacing()[2]) - minSpacing = mask->GetSpacing()[0]; - else if (mask->GetSpacing()[1] < mask->GetSpacing()[2]) - minSpacing = mask->GetSpacing()[1]; - else - minSpacing = mask->GetSpacing()[2]; - - mitk::FiberBundle::Pointer fibCopy = this->GetDeepCopy(); - fibCopy->ResampleLinear(minSpacing/10); - vtkSmartPointer PolyData =fibCopy->GetFiberPolyData(); - vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); - vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); - newFiberWeights->SetName("FIBER_WEIGHTS"); - newFiberWeights->SetNumberOfValues(m_NumFibers); + std::vector< float > fib_weights; MITK_INFO << "Cutting fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); + vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); + int newNumPoints = 0; if (numPoints>1) { - int newNumPoints = 0; for (int j=0; jGetPoint(j); - - itk::Point itkP; - itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; + itk::Point itkP = GetItkPoint(points->GetPoint(j)); itk::Index<3> idx; mask->TransformPhysicalPointToIndex(itkP, idx); - if ( mask->GetPixel(idx) != 0 && mask->GetLargestPossibleRegion().IsInside(idx) && !invert ) + bool inside = false; + if ( mask->GetLargestPossibleRegion().IsInside(idx) && mask->GetPixel(idx)!=0 ) + inside = true; + + if (inside && !invert) { - vtkIdType id = vtkNewPoints->InsertNextPoint(p); + vtkIdType id = vtkNewPoints->InsertNextPoint(itkP.GetDataPointer()); container->GetPointIds()->InsertNextId(id); newNumPoints++; } - else if ( (!mask->GetLargestPossibleRegion().IsInside(idx) || mask->GetPixel(idx) == 0) && invert ) + else if ( !inside && invert ) { - vtkIdType id = vtkNewPoints->InsertNextPoint(p); + vtkIdType id = vtkNewPoints->InsertNextPoint(itkP.GetDataPointer()); container->GetPointIds()->InsertNextId(id); newNumPoints++; } else if (newNumPoints>1) { + fib_weights.push_back(this->GetFiberWeight(i)); vtkNewCells->InsertNextCell(container); - if (newFiberWeights->GetSize()<=vtkNewCells->GetNumberOfCells()) - newFiberWeights->Resize(vtkNewCells->GetNumberOfCells()*2); - newFiberWeights->SetValue(vtkNewCells->GetNumberOfCells(), fibCopy->GetFiberWeight(i)); - + newNumPoints = 0; + container = vtkSmartPointer::New(); + } + else + { newNumPoints = 0; container = vtkSmartPointer::New(); } } if (newNumPoints>1) { + fib_weights.push_back(this->GetFiberWeight(i)); vtkNewCells->InsertNextCell(container); - if (newFiberWeights->GetSize()<=vtkNewCells->GetNumberOfCells()) - newFiberWeights->Resize(vtkNewCells->GetNumberOfCells()*2); - - newFiberWeights->SetValue(vtkNewCells->GetNumberOfCells(), fibCopy->GetFiberWeight(i)); } } } + vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); + newFiberWeights->SetName("FIBER_WEIGHTS"); + newFiberWeights->SetNumberOfValues(fib_weights.size()); + if (vtkNewCells->GetNumberOfCells()<=0) return nullptr; - newFiberWeights->Resize(vtkNewCells->GetNumberOfCells()); + + for (int i=0; iGetNumberOfValues(); i++) + newFiberWeights->SetValue(i, fib_weights.at(i)); + +// vtkSmartPointer newFiberColors = vtkSmartPointer::New(); +// newFiberColors->Allocate(m_FiberPolyData->GetNumberOfPoints() * 4); +// newFiberColors->SetNumberOfComponents(4); +// newFiberColors->SetName("FIBER_COLORS"); + +// unsigned char rgba[4] = {0,0,0,0}; +// for(long i=0; iGetNumberOfPoints(); ++i) +// { +// rgba[0] = (unsigned char) r; +// rgba[1] = (unsigned char) g; +// rgba[2] = (unsigned char) b; +// rgba[3] = (unsigned char) alpha; +// m_FiberColors->InsertTypedTuple(i, rgba); +// } vtkSmartPointer newPolyData = vtkSmartPointer::New(); newPolyData->SetPoints(vtkNewPoints); newPolyData->SetLines(vtkNewCells); mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(newPolyData); newFib->SetFiberWeights(newFiberWeights); - newFib->Compress(0.1); +// newFib->Compress(0.1); return newFib; } mitk::FiberBundle::Pointer mitk::FiberBundle::ExtractFiberSubset(DataNode* roi, DataStorage* storage) { if (roi==nullptr || !(dynamic_cast(roi->GetData()) || dynamic_cast(roi->GetData())) ) return nullptr; std::vector tmp = ExtractFiberIdSubset(roi, storage); if (tmp.size()<=0) return mitk::FiberBundle::New(); vtkSmartPointer weights = vtkSmartPointer::New(); vtkSmartPointer pTmp = GeneratePolyDataByIds(tmp, weights); mitk::FiberBundle::Pointer fib = mitk::FiberBundle::New(pTmp); fib->SetFiberWeights(weights); return fib; } std::vector mitk::FiberBundle::ExtractFiberIdSubset(DataNode *roi, DataStorage* storage) { std::vector result; if (roi==nullptr || roi->GetData()==nullptr) return result; mitk::PlanarFigureComposite::Pointer pfc = dynamic_cast(roi->GetData()); if (!pfc.IsNull()) // handle composite { DataStorage::SetOfObjects::ConstPointer children = storage->GetDerivations(roi); if (children->size()==0) return result; switch (pfc->getOperationType()) { case 0: // AND { MITK_INFO << "AND"; result = this->ExtractFiberIdSubset(children->ElementAt(0), storage); std::vector::iterator it; for (unsigned int i=1; iSize(); ++i) { std::vector inRoi = this->ExtractFiberIdSubset(children->ElementAt(i), storage); std::vector rest(std::min(result.size(),inRoi.size())); it = std::set_intersection(result.begin(), result.end(), inRoi.begin(), inRoi.end(), rest.begin() ); rest.resize( it - rest.begin() ); result = rest; } break; } case 1: // OR { MITK_INFO << "OR"; result = ExtractFiberIdSubset(children->ElementAt(0), storage); std::vector::iterator it; for (unsigned int i=1; iSize(); ++i) { it = result.end(); std::vector inRoi = ExtractFiberIdSubset(children->ElementAt(i), storage); result.insert(it, inRoi.begin(), inRoi.end()); } // remove duplicates sort(result.begin(), result.end()); it = unique(result.begin(), result.end()); result.resize( it - result.begin() ); break; } case 2: // NOT { MITK_INFO << "NOT"; for(long i=0; iGetNumFibers(); i++) result.push_back(i); std::vector::iterator it; for (unsigned int i=0; iSize(); ++i) { std::vector inRoi = ExtractFiberIdSubset(children->ElementAt(i), storage); std::vector rest(result.size()-inRoi.size()); it = std::set_difference(result.begin(), result.end(), inRoi.begin(), inRoi.end(), rest.begin() ); rest.resize( it - rest.begin() ); result = rest; } break; } } } else if ( dynamic_cast(roi->GetData()) ) // actual extraction { if ( dynamic_cast(roi->GetData()) ) { mitk::PlanarFigure::Pointer planarPoly = dynamic_cast(roi->GetData()); //create vtkPolygon using controlpoints from planarFigure polygon vtkSmartPointer polygonVtk = vtkSmartPointer::New(); for (unsigned int i=0; iGetNumberOfControlPoints(); ++i) { itk::Point p = planarPoly->GetWorldControlPoint(i); vtkIdType id = polygonVtk->GetPoints()->InsertNextPoint(p[0], p[1], p[2] ); polygonVtk->GetPointIds()->InsertNextId(id); } MITK_INFO << "Extracting with polygon"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j, p1); double p2[3] = {0,0,0}; points->GetPoint(j+1, p2); double tolerance = 0.001; // Outputs double t = 0; // Parametric coordinate of intersection (0 (corresponding to p1) to 1 (corresponding to p2)) double x[3] = {0,0,0}; // The coordinate of the intersection double pcoords[3] = {0,0,0}; int subId = 0; int iD = polygonVtk->IntersectWithLine(p1, p2, tolerance, t, x, pcoords, subId); if (iD!=0) { result.push_back(i); break; } } } } else if ( dynamic_cast(roi->GetData()) ) { mitk::PlanarFigure::Pointer planarFigure = dynamic_cast(roi->GetData()); Vector3D planeNormal = planarFigure->GetPlaneGeometry()->GetNormal(); planeNormal.Normalize(); //calculate circle radius mitk::Point3D V1w = planarFigure->GetWorldControlPoint(0); //centerPoint mitk::Point3D V2w = planarFigure->GetWorldControlPoint(1); //radiusPoint double radius = V1w.EuclideanDistanceTo(V2w); radius *= radius; MITK_INFO << "Extracting with circle"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j, p1); double p2[3] = {0,0,0}; points->GetPoint(j+1, p2); // Outputs double t = 0; // Parametric coordinate of intersection (0 (corresponding to p1) to 1 (corresponding to p2)) double x[3] = {0,0,0}; // The coordinate of the intersection int iD = vtkPlane::IntersectWithLine(p1,p2,planeNormal.GetDataPointer(),V1w.GetDataPointer(),t,x); if (iD!=0) { double dist = (x[0]-V1w[0])*(x[0]-V1w[0])+(x[1]-V1w[1])*(x[1]-V1w[1])+(x[2]-V1w[2])*(x[2]-V1w[2]); if( dist <= radius) { result.push_back(i); break; } } } } } return result; } return result; } void mitk::FiberBundle::UpdateFiberGeometry() { vtkSmartPointer cleaner = vtkSmartPointer::New(); cleaner->SetInputData(m_FiberPolyData); cleaner->PointMergingOff(); cleaner->Update(); m_FiberPolyData = cleaner->GetOutput(); m_FiberLengths.clear(); m_MeanFiberLength = 0; m_MedianFiberLength = 0; m_LengthStDev = 0; m_NumFibers = m_FiberPolyData->GetNumberOfCells(); if (m_FiberColors==nullptr || m_FiberColors->GetNumberOfTuples()!=m_FiberPolyData->GetNumberOfPoints()) this->ColorFibersByOrientation(); if (m_FiberWeights->GetNumberOfValues()!=m_NumFibers) { m_FiberWeights = vtkSmartPointer::New(); m_FiberWeights->SetName("FIBER_WEIGHTS"); m_FiberWeights->SetNumberOfValues(m_NumFibers); this->SetFiberWeights(1); } if (m_NumFibers<=0) // no fibers present; apply default geometry { m_MinFiberLength = 0; m_MaxFiberLength = 0; mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->SetImageGeometry(false); float b[] = {0, 1, 0, 1, 0, 1}; geometry->SetFloatBounds(b); SetGeometry(geometry); return; } double b[6]; m_FiberPolyData->GetBounds(b); // calculate statistics for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); int p = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); float length = 0; for (int j=0; jGetPoint(j, p1); double p2[3]; points->GetPoint(j+1, p2); float dist = std::sqrt((p1[0]-p2[0])*(p1[0]-p2[0])+(p1[1]-p2[1])*(p1[1]-p2[1])+(p1[2]-p2[2])*(p1[2]-p2[2])); length += dist; } m_FiberLengths.push_back(length); m_MeanFiberLength += length; if (i==0) { m_MinFiberLength = length; m_MaxFiberLength = length; } else { if (lengthm_MaxFiberLength) m_MaxFiberLength = length; } } m_MeanFiberLength /= m_NumFibers; std::vector< float > sortedLengths = m_FiberLengths; std::sort(sortedLengths.begin(), sortedLengths.end()); for (int i=0; i1) m_LengthStDev /= (m_NumFibers-1); else m_LengthStDev = 0; m_LengthStDev = std::sqrt(m_LengthStDev); m_MedianFiberLength = sortedLengths.at(m_NumFibers/2); mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); geometry->SetFloatBounds(b); this->SetGeometry(geometry); m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } float mitk::FiberBundle::GetFiberWeight(unsigned int fiber) const { return m_FiberWeights->GetValue(fiber); } void mitk::FiberBundle::SetFiberWeights(float newWeight) { for (int i=0; iGetNumberOfValues(); i++) m_FiberWeights->SetValue(i, newWeight); } void mitk::FiberBundle::SetFiberWeights(vtkSmartPointer weights) { if (m_NumFibers!=weights->GetNumberOfValues()) { MITK_INFO << "Weights array not equal to number of fibers! " << weights->GetNumberOfValues() << " vs " << m_NumFibers; return; } for (int i=0; iGetNumberOfValues(); i++) m_FiberWeights->SetValue(i, weights->GetValue(i)); m_FiberWeights->SetName("FIBER_WEIGHTS"); } void mitk::FiberBundle::SetFiberWeight(unsigned int fiber, float weight) { m_FiberWeights->SetValue(fiber, weight); } void mitk::FiberBundle::SetFiberColors(vtkSmartPointer fiberColors) { for(long i=0; iGetNumberOfPoints(); ++i) { unsigned char source[4] = {0,0,0,0}; fiberColors->GetTypedTuple(i, source); unsigned char target[4] = {0,0,0,0}; target[0] = source[0]; target[1] = source[1]; target[2] = source[2]; target[3] = source[3]; m_FiberColors->InsertTypedTuple(i, target); } m_UpdateTime3D.Modified(); m_UpdateTime2D.Modified(); } itk::Matrix< double, 3, 3 > mitk::FiberBundle::TransformMatrix(itk::Matrix< double, 3, 3 > m, double rx, double ry, double rz) { rx = rx*itk::Math::pi/180; ry = ry*itk::Math::pi/180; rz = rz*itk::Math::pi/180; itk::Matrix< double, 3, 3 > rotX; rotX.SetIdentity(); rotX[1][1] = cos(rx); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(rx); rotX[2][1] = -rotX[1][2]; itk::Matrix< double, 3, 3 > rotY; rotY.SetIdentity(); rotY[0][0] = cos(ry); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(ry); rotY[2][0] = -rotY[0][2]; itk::Matrix< double, 3, 3 > rotZ; rotZ.SetIdentity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; itk::Matrix< double, 3, 3 > rot = rotZ*rotY*rotX; m = rot*m; return m; } itk::Point mitk::FiberBundle::TransformPoint(vnl_vector_fixed< double, 3 > point, double rx, double ry, double rz, double tx, double ty, double tz) { rx = rx*itk::Math::pi/180; ry = ry*itk::Math::pi/180; rz = rz*itk::Math::pi/180; vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity(); rotX[1][1] = cos(rx); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(rx); rotX[2][1] = -rotX[1][2]; vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity(); rotY[0][0] = cos(ry); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(ry); rotY[2][0] = -rotY[0][2]; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; vnl_matrix_fixed< double, 3, 3 > rot = rotZ*rotY*rotX; mitk::BaseGeometry::Pointer geom = this->GetGeometry(); mitk::Point3D center = geom->GetCenter(); point[0] -= center[0]; point[1] -= center[1]; point[2] -= center[2]; point = rot*point; point[0] += center[0]+tx; point[1] += center[1]+ty; point[2] += center[2]+tz; itk::Point out; out[0] = point[0]; out[1] = point[1]; out[2] = point[2]; return out; } void mitk::FiberBundle::TransformFibers(itk::ScalableAffineTransform< mitk::ScalarType >::Pointer transform) { vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; j p = GetItkPoint(points->GetPoint(j)); p = transform->TransformPoint(p); vtkIdType id = vtkNewPoints->InsertNextPoint(p.GetDataPointer()); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::TransformFibers(double rx, double ry, double rz, double tx, double ty, double tz) { rx = rx*itk::Math::pi/180; ry = ry*itk::Math::pi/180; rz = rz*itk::Math::pi/180; vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity(); rotX[1][1] = cos(rx); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(rx); rotX[2][1] = -rotX[1][2]; vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity(); rotY[0][0] = cos(ry); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(ry); rotY[2][0] = -rotY[0][2]; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; vnl_matrix_fixed< double, 3, 3 > rot = rotZ*rotY*rotX; mitk::BaseGeometry::Pointer geom = this->GetGeometry(); mitk::Point3D center = geom->GetCenter(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vnl_vector_fixed< double, 3 > dir; dir[0] = p[0]-center[0]; dir[1] = p[1]-center[1]; dir[2] = p[2]-center[2]; dir = rot*dir; dir[0] += center[0]+tx; dir[1] += center[1]+ty; dir[2] += center[2]+tz; vtkIdType id = vtkNewPoints->InsertNextPoint(dir.data_block()); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::RotateAroundAxis(double x, double y, double z) { x = x*itk::Math::pi/180; y = y*itk::Math::pi/180; z = z*itk::Math::pi/180; vnl_matrix_fixed< double, 3, 3 > rotX; rotX.set_identity(); rotX[1][1] = cos(x); rotX[2][2] = rotX[1][1]; rotX[1][2] = -sin(x); rotX[2][1] = -rotX[1][2]; vnl_matrix_fixed< double, 3, 3 > rotY; rotY.set_identity(); rotY[0][0] = cos(y); rotY[2][2] = rotY[0][0]; rotY[0][2] = sin(y); rotY[2][0] = -rotY[0][2]; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(z); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(z); rotZ[1][0] = -rotZ[0][1]; mitk::BaseGeometry::Pointer geom = this->GetGeometry(); mitk::Point3D center = geom->GetCenter(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vnl_vector_fixed< double, 3 > dir; dir[0] = p[0]-center[0]; dir[1] = p[1]-center[1]; dir[2] = p[2]-center[2]; dir = rotZ*rotY*rotX*dir; dir[0] += center[0]; dir[1] += center[1]; dir[2] += center[2]; vtkIdType id = vtkNewPoints->InsertNextPoint(dir.data_block()); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::ScaleFibers(double x, double y, double z, bool subtractCenter) { MITK_INFO << "Scaling fibers"; boost::progress_display disp(m_NumFibers); mitk::BaseGeometry* geom = this->GetGeometry(); mitk::Point3D c = geom->GetCenter(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); if (subtractCenter) { p[0] -= c[0]; p[1] -= c[1]; p[2] -= c[2]; } p[0] *= x; p[1] *= y; p[2] *= z; if (subtractCenter) { p[0] += c[0]; p[1] += c[1]; p[2] += c[2]; } vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::TranslateFibers(double x, double y, double z) { vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); p[0] += x; p[1] += y; p[2] += z; vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::MirrorFibers(unsigned int axis) { if (axis>2) return; MITK_INFO << "Mirroring fibers"; boost::progress_display disp(m_NumFibers); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); p[axis] = -p[axis]; vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::RemoveDir(vnl_vector_fixed dir, double threshold) { dir.normalize(); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); for (int i=0; iGetNumberOfCells(); i++) { ++disp ; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); // calculate curvatures vtkSmartPointer container = vtkSmartPointer::New(); bool discard = false; for (int j=0; jGetPoint(j, p1); double p2[3]; points->GetPoint(j+1, p2); vnl_vector_fixed< double, 3 > v1; v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; if (v1.magnitude()>0.001) { v1.normalize(); if (fabs(dot_product(v1,dir))>threshold) { discard = true; break; } } } if (!discard) { for (int j=0; jGetPoint(j, p1); vtkIdType id = vtkNewPoints->InsertNextPoint(p1); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); // UpdateColorCoding(); // UpdateFiberGeometry(); } bool mitk::FiberBundle::ApplyCurvatureThreshold(float minRadius, bool deleteFibers) { if (minRadius<0) return true; vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Applying curvature threshold"; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); for (int i=0; iGetNumberOfCells(); i++) { ++disp ; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); // calculate curvatures vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j, p1); double p2[3]; points->GetPoint(j+1, p2); double p3[3]; points->GetPoint(j+2, p3); vnl_vector_fixed< float, 3 > v1, v2, v3; v1[0] = p2[0]-p1[0]; v1[1] = p2[1]-p1[1]; v1[2] = p2[2]-p1[2]; v2[0] = p3[0]-p2[0]; v2[1] = p3[1]-p2[1]; v2[2] = p3[2]-p2[2]; v3[0] = p1[0]-p3[0]; v3[1] = p1[1]-p3[1]; v3[2] = p1[2]-p3[2]; float a = v1.magnitude(); float b = v2.magnitude(); float c = v3.magnitude(); float r = a*b*c/std::sqrt((a+b+c)*(a+b-c)*(b+c-a)*(a-b+c)); // radius of triangle via Heron's formula (area of triangle) vtkIdType id = vtkNewPoints->InsertNextPoint(p1); container->GetPointIds()->InsertNextId(id); if (deleteFibers && rInsertNextCell(container); container = vtkSmartPointer::New(); } else if (j==numPoints-3) { id = vtkNewPoints->InsertNextPoint(p2); container->GetPointIds()->InsertNextId(id); id = vtkNewPoints->InsertNextPoint(p3); container->GetPointIds()->InsertNextId(id); vtkNewCells->InsertNextCell(container); } } } if (vtkNewCells->GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); return true; } bool mitk::FiberBundle::RemoveShortFibers(float lengthInMM) { MITK_INFO << "Removing short fibers"; if (lengthInMM<=0 || lengthInMMm_MaxFiberLength) // can't remove all fibers { MITK_WARN << "Process aborted. No fibers would be left!"; return false; } vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); float min = m_MaxFiberLength; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (m_FiberLengths.at(i)>=lengthInMM) { vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); if (m_FiberLengths.at(i)GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); return true; } bool mitk::FiberBundle::RemoveLongFibers(float lengthInMM) { if (lengthInMM<=0 || lengthInMM>m_MaxFiberLength) return true; if (lengthInMM vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Removing long fibers"; boost::progress_display disp(m_NumFibers); for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (m_FiberLengths.at(i)<=lengthInMM) { vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vtkIdType id = vtkNewPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } } if (vtkNewCells->GetNumberOfCells()<=0) return false; m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); return true; } void mitk::FiberBundle::ResampleSpline(float pointDistance, double tension, double continuity, double bias ) { if (pointDistance<=0) return; vtkSmartPointer vtkSmoothPoints = vtkSmartPointer::New(); //in smoothpoints the interpolated points representing a fiber are stored. //in vtkcells all polylines are stored, actually all id's of them are stored vtkSmartPointer vtkSmoothCells = vtkSmartPointer::New(); //cellcontainer for smoothed lines MITK_INFO << "Smoothing fibers"; vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); newFiberWeights->SetName("FIBER_WEIGHTS"); newFiberWeights->SetNumberOfValues(m_NumFibers); std::vector< vtkSmartPointer > resampled_streamlines; resampled_streamlines.resize(m_NumFibers); boost::progress_display disp(m_NumFibers); #pragma omp parallel for for (int i=0; i newPoints = vtkSmartPointer::New(); float length = 0; #pragma omp critical { length = m_FiberLengths.at(i); ++disp; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jInsertNextPoint(points->GetPoint(j)); } int sampling = std::ceil(length/pointDistance); vtkSmartPointer xSpline = vtkSmartPointer::New(); vtkSmartPointer ySpline = vtkSmartPointer::New(); vtkSmartPointer zSpline = vtkSmartPointer::New(); xSpline->SetDefaultBias(bias); xSpline->SetDefaultTension(tension); xSpline->SetDefaultContinuity(continuity); ySpline->SetDefaultBias(bias); ySpline->SetDefaultTension(tension); ySpline->SetDefaultContinuity(continuity); zSpline->SetDefaultBias(bias); zSpline->SetDefaultTension(tension); zSpline->SetDefaultContinuity(continuity); vtkSmartPointer spline = vtkSmartPointer::New(); spline->SetXSpline(xSpline); spline->SetYSpline(ySpline); spline->SetZSpline(zSpline); spline->SetPoints(newPoints); vtkSmartPointer functionSource = vtkSmartPointer::New(); functionSource->SetParametricFunction(spline); functionSource->SetUResolution(sampling); functionSource->SetVResolution(sampling); functionSource->SetWResolution(sampling); functionSource->Update(); vtkPolyData* outputFunction = functionSource->GetOutput(); vtkPoints* tmpSmoothPnts = outputFunction->GetPoints(); //smoothPoints of current fiber vtkSmartPointer smoothLine = vtkSmartPointer::New(); #pragma omp critical { for (int j=0; jGetNumberOfPoints(); j++) { vtkIdType id = vtkSmoothPoints->InsertNextPoint(tmpSmoothPnts->GetPoint(j)); smoothLine->GetPointIds()->InsertNextId(id); } resampled_streamlines[i] = smoothLine; } } for (auto container : resampled_streamlines) { vtkSmoothCells->InsertNextCell(container); } m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkSmoothPoints); m_FiberPolyData->SetLines(vtkSmoothCells); this->SetFiberPolyData(m_FiberPolyData, true); } void mitk::FiberBundle::ResampleSpline(float pointDistance) { ResampleSpline(pointDistance, 0, 0, 0 ); } unsigned long mitk::FiberBundle::GetNumberOfPoints() const { unsigned long points = 0; for (int i=0; iGetNumberOfCells(); i++) { vtkCell* cell = m_FiberPolyData->GetCell(i); points += cell->GetNumberOfPoints(); } return points; } void mitk::FiberBundle::Compress(float error) { vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Compressing fibers"; unsigned long numRemovedPoints = 0; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); newFiberWeights->SetName("FIBER_WEIGHTS"); newFiberWeights->SetNumberOfValues(m_NumFibers); #pragma omp parallel for for (int i=0; iGetNumberOfCells(); i++) { std::vector< vnl_vector_fixed< double, 3 > > vertices; float weight = 1; #pragma omp critical { ++disp; weight = m_FiberWeights->GetValue(i); vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j, cand); vnl_vector_fixed< double, 3 > candV; candV[0]=cand[0]; candV[1]=cand[1]; candV[2]=cand[2]; vertices.push_back(candV); } } // calculate curvatures int numPoints = vertices.size(); std::vector< int > removedPoints; removedPoints.resize(numPoints, 0); removedPoints[0]=-1; removedPoints[numPoints-1]=-1; vtkSmartPointer container = vtkSmartPointer::New(); int remCounter = 0; bool pointFound = true; while (pointFound) { pointFound = false; double minError = error; int removeIndex = -1; for (unsigned int j=0; j candV = vertices.at(j); int validP = -1; vnl_vector_fixed< double, 3 > pred; for (int k=j-1; k>=0; k--) if (removedPoints[k]<=0) { pred = vertices.at(k); validP = k; break; } int validS = -1; vnl_vector_fixed< double, 3 > succ; for (int k=j+1; k=0 && validS>=0) { double a = (candV-pred).magnitude(); double b = (candV-succ).magnitude(); double c = (pred-succ).magnitude(); double s=0.5*(a+b+c); double hc=(2.0/c)*sqrt(fabs(s*(s-a)*(s-b)*(s-c))); if (hcInsertNextPoint(vertices.at(j).data_block()); container->GetPointIds()->InsertNextId(id); } } } #pragma omp critical { newFiberWeights->SetValue(vtkNewCells->GetNumberOfCells(), weight); numRemovedPoints += remCounter; vtkNewCells->InsertNextCell(container); } } if (vtkNewCells->GetNumberOfCells()>0) { MITK_INFO << "Removed points: " << numRemovedPoints; SetFiberWeights(newFiberWeights); m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } } void mitk::FiberBundle::ResampleToNumPoints(unsigned int targetPoints) { if (targetPoints<2) mitkThrow() << "Minimum two points required for resampling!"; MITK_INFO << "Resampling fibers (number of points " << targetPoints << ")"; bool unequal_fibs = true; while (unequal_fibs) { vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); newFiberWeights->SetName("FIBER_WEIGHTS"); newFiberWeights->SetNumberOfValues(m_NumFibers); unequal_fibs = false; //#pragma omp parallel for for (int i=0; iGetNumberOfCells(); i++) { std::vector< vnl_vector_fixed< double, 3 > > vertices; float weight = 1; double seg_len = 0; //#pragma omp critical { weight = m_FiberWeights->GetValue(i); vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); if ((unsigned int)numPoints!=targetPoints) seg_len = this->GetFiberLength(i)/(targetPoints-1);; vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j, cand); vnl_vector_fixed< double, 3 > candV; candV[0]=cand[0]; candV[1]=cand[1]; candV[2]=cand[2]; vertices.push_back(candV); } } vtkSmartPointer container = vtkSmartPointer::New(); vnl_vector_fixed< double, 3 > lastV = vertices.at(0); //#pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(lastV.data_block()); container->GetPointIds()->InsertNextId(id); } for (unsigned int j=1; j vec = vertices.at(j) - lastV; double new_dist = vec.magnitude(); if (new_dist >= seg_len && seg_len>0) { vnl_vector_fixed< double, 3 > newV = lastV; if ( new_dist-seg_len <= mitk::eps ) { vec.normalize(); newV += vec * seg_len; } else { // intersection between sphere (radius 'pointDistance', center 'lastV') and line (direction 'd' and point 'p') vnl_vector_fixed< double, 3 > p = vertices.at(j-1); vnl_vector_fixed< double, 3 > d = vertices.at(j) - p; double a = d[0]*d[0] + d[1]*d[1] + d[2]*d[2]; double b = 2 * (d[0] * (p[0] - lastV[0]) + d[1] * (p[1] - lastV[1]) + d[2] * (p[2] - lastV[2])); double c = (p[0] - lastV[0])*(p[0] - lastV[0]) + (p[1] - lastV[1])*(p[1] - lastV[1]) + (p[2] - lastV[2])*(p[2] - lastV[2]) - seg_len*seg_len; double v1 =(-b + std::sqrt(b*b-4*a*c))/(2*a); double v2 =(-b - std::sqrt(b*b-4*a*c))/(2*a); if (v1>0) newV = p + d * v1; else if (v2>0) newV = p + d * v2; else MITK_INFO << "ERROR1 - linear resampling"; j--; } //#pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(newV.data_block()); container->GetPointIds()->InsertNextId(id); } lastV = newV; } else if ( (j==vertices.size()-1 && new_dist>0.0001) || seg_len==0) { //#pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(vertices.at(j).data_block()); container->GetPointIds()->InsertNextId(id); } } } //#pragma omp critical { newFiberWeights->SetValue(vtkNewCells->GetNumberOfCells(), weight); vtkNewCells->InsertNextCell(container); if (container->GetNumberOfPoints()!=targetPoints) unequal_fibs = true; } } if (vtkNewCells->GetNumberOfCells()>0) { SetFiberWeights(newFiberWeights); m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } } } void mitk::FiberBundle::ResampleLinear(double pointDistance) { vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); MITK_INFO << "Resampling fibers (linear)"; boost::progress_display disp(m_FiberPolyData->GetNumberOfCells()); vtkSmartPointer newFiberWeights = vtkSmartPointer::New(); newFiberWeights->SetName("FIBER_WEIGHTS"); newFiberWeights->SetNumberOfValues(m_NumFibers); std::vector< vtkSmartPointer > resampled_streamlines; resampled_streamlines.resize(m_FiberPolyData->GetNumberOfCells()); #pragma omp parallel for for (int i=0; iGetNumberOfCells(); i++) { std::vector< vnl_vector_fixed< double, 3 > > vertices; #pragma omp critical { ++disp; vtkCell* cell = m_FiberPolyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j, cand); vnl_vector_fixed< double, 3 > candV; candV[0]=cand[0]; candV[1]=cand[1]; candV[2]=cand[2]; vertices.push_back(candV); } } vtkSmartPointer container = vtkSmartPointer::New(); vnl_vector_fixed< double, 3 > lastV = vertices.at(0); #pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(lastV.data_block()); container->GetPointIds()->InsertNextId(id); } for (unsigned int j=1; j vec = vertices.at(j) - lastV; double new_dist = vec.magnitude(); if (new_dist >= pointDistance) { vnl_vector_fixed< double, 3 > newV = lastV; if ( new_dist-pointDistance <= mitk::eps ) { vec.normalize(); newV += vec * pointDistance; } else { // intersection between sphere (radius 'pointDistance', center 'lastV') and line (direction 'd' and point 'p') vnl_vector_fixed< double, 3 > p = vertices.at(j-1); vnl_vector_fixed< double, 3 > d = vertices.at(j) - p; double a = d[0]*d[0] + d[1]*d[1] + d[2]*d[2]; double b = 2 * (d[0] * (p[0] - lastV[0]) + d[1] * (p[1] - lastV[1]) + d[2] * (p[2] - lastV[2])); double c = (p[0] - lastV[0])*(p[0] - lastV[0]) + (p[1] - lastV[1])*(p[1] - lastV[1]) + (p[2] - lastV[2])*(p[2] - lastV[2]) - pointDistance*pointDistance; double v1 =(-b + std::sqrt(b*b-4*a*c))/(2*a); double v2 =(-b - std::sqrt(b*b-4*a*c))/(2*a); if (v1>0) newV = p + d * v1; else if (v2>0) newV = p + d * v2; else MITK_INFO << "ERROR1 - linear resampling"; j--; } #pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(newV.data_block()); container->GetPointIds()->InsertNextId(id); } lastV = newV; } else if (j==vertices.size()-1 && new_dist>0.0001) { #pragma omp critical { vtkIdType id = vtkNewPoints->InsertNextPoint(vertices.at(j).data_block()); container->GetPointIds()->InsertNextId(id); } } } #pragma omp critical { resampled_streamlines[i] = container; } } for (auto container : resampled_streamlines) { vtkNewCells->InsertNextCell(container); } if (vtkNewCells->GetNumberOfCells()>0) { m_FiberPolyData = vtkSmartPointer::New(); m_FiberPolyData->SetPoints(vtkNewPoints); m_FiberPolyData->SetLines(vtkNewCells); this->SetFiberPolyData(m_FiberPolyData, true); } } // reapply selected colorcoding in case PolyData structure has changed bool mitk::FiberBundle::Equals(mitk::FiberBundle* fib, double eps) { if (fib==nullptr) { MITK_INFO << "Reference bundle is nullptr!"; return false; } if (m_NumFibers!=fib->GetNumFibers()) { MITK_INFO << "Unequal number of fibers!"; MITK_INFO << m_NumFibers << " vs. " << fib->GetNumFibers(); return false; } for (int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); vtkCell* cell2 = fib->GetFiberPolyData()->GetCell(i); int numPoints2 = cell2->GetNumberOfPoints(); vtkPoints* points2 = cell2->GetPoints(); if (numPoints2!=numPoints) { MITK_INFO << "Unequal number of points in fiber " << i << "!"; MITK_INFO << numPoints2 << " vs. " << numPoints; return false; } for (int j=0; jGetPoint(j); double* p2 = points2->GetPoint(j); if (fabs(p1[0]-p2[0])>eps || fabs(p1[1]-p2[1])>eps || fabs(p1[2]-p2[2])>eps) { MITK_INFO << "Unequal points in fiber " << i << " at position " << j << "!"; MITK_INFO << "p1: " << p1[0] << ", " << p1[1] << ", " << p1[2]; MITK_INFO << "p2: " << p2[0] << ", " << p2[1] << ", " << p2[2]; return false; } } } return true; } void mitk::FiberBundle::PrintSelf(std::ostream &os, itk::Indent indent) const { os << this->GetNameOfClass() << ":\n"; os << indent << "Number of fibers: " << this->GetNumFibers() << std::endl; os << indent << "Min. fiber length: " << this->GetMinFiberLength() << std::endl; os << indent << "Max. fiber length: " << this->GetMaxFiberLength() << std::endl; os << indent << "Mean fiber length: " << this->GetMeanFiberLength() << std::endl; os << indent << "Median fiber length: " << this->GetMedianFiberLength() << std::endl; os << indent << "STDEV fiber length: " << this->GetLengthStDev() << std::endl; os << indent << "Number of points: " << this->GetNumberOfPoints() << std::endl; os << indent << "Extent x: " << this->GetGeometry()->GetExtentInMM(0) << "mm" << std::endl; os << indent << "Extent y: " << this->GetGeometry()->GetExtentInMM(1) << "mm" << std::endl; os << indent << "Extent z: " << this->GetGeometry()->GetExtentInMM(2) << "mm" << std::endl; os << indent << "Diagonal: " << this->GetGeometry()->GetDiagonalLength() << "mm" << std::endl; if (m_FiberWeights!=nullptr) { std::vector< float > weights; for (int i=0; iGetSize(); i++) weights.push_back(m_FiberWeights->GetValue(i)); std::sort(weights.begin(), weights.end()); os << indent << "\nFiber weight statistics" << std::endl; os << indent << "Min: " << weights.front() << std::endl; os << indent << "1% quantile: " << weights.at(weights.size()*0.01) << std::endl; os << indent << "5% quantile: " << weights.at(weights.size()*0.05) << std::endl; os << indent << "25% quantile: " << weights.at(weights.size()*0.25) << std::endl; os << indent << "Median: " << weights.at(weights.size()*0.5) << std::endl; os << indent << "75% quantile: " << weights.at(weights.size()*0.75) << std::endl; os << indent << "95% quantile: " << weights.at(weights.size()*0.95) << std::endl; os << indent << "99% quantile: " << weights.at(weights.size()*0.99) << std::endl; os << indent << "Max: " << weights.back() << std::endl; } else os << indent << "\n\nNo fiber weight array found." << std::endl; Superclass::PrintSelf(os, indent); } /* ESSENTIAL IMPLEMENTATION OF SUPERCLASS METHODS */ void mitk::FiberBundle::UpdateOutputInformation() { } void mitk::FiberBundle::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::FiberBundle::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::FiberBundle::VerifyRequestedRegion() { return true; } void mitk::FiberBundle::SetRequestedRegion(const itk::DataObject* ) { } diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h index 94caf97c92..01d7525c3c 100644 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/FiberBundle/mitkFiberBundle.h @@ -1,183 +1,183 @@ /*=================================================================== 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 _MITK_FiberBundle_H #define _MITK_FiberBundle_H //includes for MITK datastructure #include #include #include #include #include #include #include //includes storing fiberdata #include #include #include #include #include #include #include namespace mitk { /** * \brief Base Class for Fiber Bundles; */ class MITKFIBERTRACKING_EXPORT FiberBundle : public BaseData { public: typedef itk::Image ItkUcharImgType; // fiber colorcodings static const char* FIBER_ID_ARRAY; void UpdateOutputInformation() override; void SetRequestedRegionToLargestPossibleRegion() override; bool RequestedRegionIsOutsideOfTheBufferedRegion() override; bool VerifyRequestedRegion() override; void SetRequestedRegion(const itk::DataObject*) override; mitkClassMacro( FiberBundle, BaseData ) itkFactorylessNewMacro(Self) itkCloneMacro(Self) mitkNewMacro1Param(Self, vtkSmartPointer) // custom constructor // colorcoding related methods void ColorFibersByFiberWeights(bool opacity, bool normalize); void ColorFibersByCurvature(bool opacity, bool normalize); void ColorFibersByLength(bool opacity, bool normalize); void ColorFibersByScalarMap(mitk::Image::Pointer, bool opacity, bool normalize); template void ColorFibersByScalarMap(const mitk::PixelType pixelType, mitk::Image::Pointer, bool opacity, bool normalize); void ColorFibersByOrientation(); void SetFiberOpacity(vtkDoubleArray *FAValArray); void ResetFiberOpacity(); void SetFiberColors(vtkSmartPointer fiberColors); void SetFiberColors(float r, float g, float b, float alpha=255); vtkSmartPointer GetFiberColors() const { return m_FiberColors; } // fiber compression void Compress(float error = 0.0); // fiber resampling void ResampleSpline(float pointDistance=1); void ResampleSpline(float pointDistance, double tension, double continuity, double bias ); void ResampleLinear(double pointDistance=1); void ResampleToNumPoints(unsigned int targetPoints); mitk::FiberBundle::Pointer FilterByWeights(float weight_thr, bool invert=false); bool RemoveShortFibers(float lengthInMM); bool RemoveLongFibers(float lengthInMM); bool ApplyCurvatureThreshold(float minRadius, bool deleteFibers); void MirrorFibers(unsigned int axis); void RotateAroundAxis(double x, double y, double z); void TranslateFibers(double x, double y, double z); void ScaleFibers(double x, double y, double z, bool subtractCenter=true); void TransformFibers(double rx, double ry, double rz, double tx, double ty, double tz); void TransformFibers(itk::ScalableAffineTransform< mitk::ScalarType >::Pointer transform); void RemoveDir(vnl_vector_fixed dir, double threshold); itk::Point TransformPoint(vnl_vector_fixed< double, 3 > point, double rx, double ry, double rz, double tx, double ty, double tz); itk::Matrix< double, 3, 3 > TransformMatrix(itk::Matrix< double, 3, 3 > m, double rx, double ry, double rz); // add/subtract fibers FiberBundle::Pointer AddBundle(FiberBundle* fib); mitk::FiberBundle::Pointer AddBundles(std::vector< mitk::FiberBundle::Pointer > fibs); FiberBundle::Pointer SubtractBundle(FiberBundle* fib); // fiber subset extraction FiberBundle::Pointer ExtractFiberSubset(DataNode *roi, DataStorage* storage); std::vector ExtractFiberIdSubset(DataNode* roi, DataStorage* storage); FiberBundle::Pointer RemoveFibersOutside(ItkUcharImgType* mask, bool invert=false); - float GetOverlap(ItkUcharImgType* mask, bool do_resampling); + float GetOverlap(ItkUcharImgType* mask); mitk::FiberBundle::Pointer SubsampleFibers(float factor); // get/set data float GetFiberLength(int index) const { return m_FiberLengths.at(index); } vtkSmartPointer GetFiberWeights() const { return m_FiberWeights; } float GetFiberWeight(unsigned int fiber) const; void SetFiberWeights(float newWeight); void SetFiberWeight(unsigned int fiber, float weight); void SetFiberWeights(vtkSmartPointer weights); void SetFiberPolyData(vtkSmartPointer, bool updateGeometry = true); vtkSmartPointer GetFiberPolyData() const; itkGetConstMacro( NumFibers, int) //itkGetMacro( FiberSampling, int) itkGetConstMacro( MinFiberLength, float ) itkGetConstMacro( MaxFiberLength, float ) itkGetConstMacro( MeanFiberLength, float ) itkGetConstMacro( MedianFiberLength, float ) itkGetConstMacro( LengthStDev, float ) itkGetConstMacro( UpdateTime2D, itk::TimeStamp ) itkGetConstMacro( UpdateTime3D, itk::TimeStamp ) void RequestUpdate2D(){ m_UpdateTime2D.Modified(); } void RequestUpdate3D(){ m_UpdateTime3D.Modified(); } void RequestUpdate(){ m_UpdateTime2D.Modified(); m_UpdateTime3D.Modified(); } unsigned long GetNumberOfPoints() const; // copy fiber bundle mitk::FiberBundle::Pointer GetDeepCopy(); // compare fiber bundles bool Equals(FiberBundle* fib, double eps=0.01); itkSetMacro( ReferenceGeometry, mitk::BaseGeometry::Pointer ) itkGetConstMacro( ReferenceGeometry, mitk::BaseGeometry::Pointer ) vtkSmartPointer GeneratePolyDataByIds(std::vector fiberIds, vtkSmartPointer weights); protected: FiberBundle( vtkPolyData* fiberPolyData = nullptr ); ~FiberBundle() override; void GenerateFiberIds(); itk::Point GetItkPoint(double point[3]); void UpdateFiberGeometry(); void PrintSelf(std::ostream &os, itk::Indent indent) const override; private: // actual fiber container vtkSmartPointer m_FiberPolyData; // contains fiber ids vtkSmartPointer m_FiberIdDataSet; int m_NumFibers; vtkSmartPointer m_FiberColors; vtkSmartPointer m_FiberWeights; std::vector< float > m_FiberLengths; float m_MinFiberLength; float m_MaxFiberLength; float m_MeanFiberLength; float m_MedianFiberLength; float m_LengthStDev; itk::TimeStamp m_UpdateTime2D; itk::TimeStamp m_UpdateTime3D; mitk::BaseGeometry::Pointer m_ReferenceGeometry; }; } // namespace mitk #endif /* _MITK_FiberBundle_H */ diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp b/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp index 1bb35113ca..eab698d2d4 100755 --- a/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp @@ -1,156 +1,155 @@ /*=================================================================== 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 #include #include #include #include #include #include #include #include #include int mitkLocalFiberPlausibilityTest(int argc, char* argv[]) { omp_set_num_threads(1); MITK_TEST_BEGIN("mitkLocalFiberPlausibilityTest"); MITK_TEST_CONDITION_REQUIRED(argc==8,"check for input data") std::string fibFile = argv[1]; std::vector< std::string > referenceImages; referenceImages.push_back(argv[2]); referenceImages.push_back(argv[3]); std::string LDFP_ERROR_IMAGE = argv[4]; std::string LDFP_NUM_DIRECTIONS = argv[5]; std::string LDFP_VECTOR_FIELD = argv[6]; std::string LDFP_ERROR_IMAGE_IGNORE = argv[7]; float angularThreshold = 30; try { typedef itk::Image ItkUcharImgType; typedef itk::Image< itk::Vector< float, 3>, 3 > ItkDirectionImage3DType; typedef itk::VectorContainer< unsigned int, ItkDirectionImage3DType::Pointer > ItkDirectionImageContainerType; typedef itk::EvaluateDirectionImagesFilter< float > EvaluationFilterType; // load fiber bundle mitk::FiberBundle::Pointer inputTractogram = mitk::IOUtil::Load(fibFile); // load reference directions ItkDirectionImageContainerType::Pointer referenceImageContainer = ItkDirectionImageContainerType::New(); for (unsigned int i=0; i(referenceImages.at(i)); typedef mitk::ImageToItk< ItkDirectionImage3DType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(img); caster->Update(); ItkDirectionImage3DType::Pointer itkImg = caster->GetOutput(); referenceImageContainer->InsertElement(referenceImageContainer->Size(),itkImg); } catch(...){ MITK_INFO << "could not load: " << referenceImages.at(i); } } ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); ItkDirectionImage3DType::Pointer dirImg = referenceImageContainer->GetElement(0); itkMaskImage->SetSpacing( dirImg->GetSpacing() ); itkMaskImage->SetOrigin( dirImg->GetOrigin() ); itkMaskImage->SetDirection( dirImg->GetDirection() ); itkMaskImage->SetLargestPossibleRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->SetBufferedRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->SetRequestedRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->Allocate(); itkMaskImage->FillBuffer(1); // extract directions from fiber bundle itk::TractsToVectorImageFilter::Pointer fOdfFilter = itk::TractsToVectorImageFilter::New(); fOdfFilter->SetFiberBundle(inputTractogram); fOdfFilter->SetMaskImage(itkMaskImage); fOdfFilter->SetAngularThreshold(cos(angularThreshold*itk::Math::pi/180)); fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::SINGLE_VEC_NORM); fOdfFilter->SetMaxNumDirections(3); fOdfFilter->SetSizeThreshold(0.3); - fOdfFilter->SetUseWorkingCopy(false); fOdfFilter->SetNumberOfThreads(1); fOdfFilter->Update(); itk::TractsToVectorImageFilter::ItkDirectionImageType::Pointer direction_image = fOdfFilter->GetDirectionImage(); // Get directions and num directions image ItkUcharImgType::Pointer numDirImage = fOdfFilter->GetNumDirectionsImage(); mitk::Image::Pointer mitkNumDirImage = mitk::Image::New(); mitkNumDirImage->InitializeByItk( numDirImage.GetPointer() ); mitkNumDirImage->SetVolume( numDirImage->GetBufferPointer() ); // mitk::FiberBundle::Pointer testDirections = fOdfFilter->GetOutputFiberBundle(); // evaluate directions with missing directions EvaluationFilterType::Pointer evaluationFilter = EvaluationFilterType::New(); // evaluationFilter->SetImageSet(directionImageContainer); evaluationFilter->SetReferenceImageSet(referenceImageContainer); evaluationFilter->SetMaskImage(itkMaskImage); evaluationFilter->SetIgnoreMissingDirections(false); evaluationFilter->Update(); EvaluationFilterType::OutputImageType::Pointer angularErrorImage = evaluationFilter->GetOutput(0); mitk::Image::Pointer mitkAngularErrorImage = mitk::Image::New(); mitkAngularErrorImage->InitializeByItk( angularErrorImage.GetPointer() ); mitkAngularErrorImage->SetVolume( angularErrorImage->GetBufferPointer() ); // evaluate directions without missing directions evaluationFilter->SetIgnoreMissingDirections(true); evaluationFilter->Update(); EvaluationFilterType::OutputImageType::Pointer angularErrorImageIgnore = evaluationFilter->GetOutput(0); mitk::Image::Pointer mitkAngularErrorImageIgnore = mitk::Image::New(); mitkAngularErrorImageIgnore->InitializeByItk( angularErrorImageIgnore.GetPointer() ); mitkAngularErrorImageIgnore->SetVolume( angularErrorImageIgnore->GetBufferPointer() ); mitk::Image::Pointer gtAngularErrorImageIgnore = mitk::IOUtil::Load(LDFP_ERROR_IMAGE_IGNORE); mitk::Image::Pointer gtAngularErrorImage = mitk::IOUtil::Load(LDFP_ERROR_IMAGE); mitk::Image::Pointer gtNumTestDirImage = mitk::IOUtil::Load(LDFP_NUM_DIRECTIONS); MITK_ASSERT_EQUAL(gtAngularErrorImageIgnore, mitkAngularErrorImageIgnore, "Check if error images are equal (ignored missing directions)."); MITK_ASSERT_EQUAL(gtAngularErrorImage, mitkAngularErrorImage, "Check if error images are equal."); MITK_ASSERT_EQUAL(gtNumTestDirImage, mitkNumDirImage, "Check if num direction images are equal."); } catch (itk::ExceptionObject e) { MITK_INFO << e; return EXIT_FAILURE; } catch (std::exception e) { MITK_INFO << e.what(); return EXIT_FAILURE; } catch (...) { MITK_INFO << "ERROR!?!"; return EXIT_FAILURE; } MITK_TEST_END(); } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberDirectionExtraction.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberDirectionExtraction.cpp index e57b84aee0..69ec445777 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberDirectionExtraction.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberDirectionExtraction.cpp @@ -1,175 +1,174 @@ /*=================================================================== 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 "mitkCommandLineParser.h" #include #include #include #include #include #include #include /*! \brief Extract principal fiber directions from a tractogram */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Fiber Direction Extraction"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setDescription("Extract principal fiber directions from a tractogram"); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input:", "input tractogram (.fib/.trk)", us::Any(), false); parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output root", us::Any(), false); parser.addArgument("mask", "m", mitkCommandLineParser::InputFile, "Mask:", "mask image"); parser.addArgument("athresh", "a", mitkCommandLineParser::Float, "Angular threshold:", "angular threshold in degrees. closer fiber directions are regarded as one direction and clustered together.", 25, true); parser.addArgument("peakthresh", "t", mitkCommandLineParser::Float, "Peak size threshold:", "peak size threshold relative to largest peak in voxel", 0.2, true); parser.addArgument("verbose", "v", mitkCommandLineParser::Bool, "Verbose:", "output optional and intermediate calculation results"); parser.addArgument("numdirs", "d", mitkCommandLineParser::Int, "Max. num. directions:", "maximum number of fibers per voxel", 3, true); parser.addArgument("normalization", "n", mitkCommandLineParser::Int, "Normalization method:", "1=global maximum, 2=single vector, 3=voxel-wise maximum", 1); parser.addArgument("file_ending", "f", mitkCommandLineParser::String, "Image type:", ".nrrd, .nii, .nii.gz"); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string fibFile = us::any_cast(parsedArgs["input"]); std::string maskImage(""); if (parsedArgs.count("mask")) maskImage = us::any_cast(parsedArgs["mask"]); float peakThreshold = 0.2; if (parsedArgs.count("peakthresh")) peakThreshold = us::any_cast(parsedArgs["peakthresh"]); float angularThreshold = 25; if (parsedArgs.count("athresh")) angularThreshold = us::any_cast(parsedArgs["athresh"]); std::string outRoot = us::any_cast(parsedArgs["out"]); bool verbose = false; if (parsedArgs.count("verbose")) verbose = us::any_cast(parsedArgs["verbose"]); int maxNumDirs = 3; if (parsedArgs.count("numdirs")) maxNumDirs = us::any_cast(parsedArgs["numdirs"]); int normalization = 1; if (parsedArgs.count("normalization")) normalization = us::any_cast(parsedArgs["normalization"]); std::string file_ending = ".nrrd"; if (parsedArgs.count("file_ending")) file_ending = us::any_cast(parsedArgs["file_ending"]); try { typedef itk::Image ItkUcharImgType; // load fiber bundle mitk::FiberBundle::Pointer inputTractogram = mitk::IOUtil::Load(fibFile); // load/create mask image ItkUcharImgType::Pointer itkMaskImage = nullptr; if (maskImage.compare("")!=0) { std::cout << "Using mask image"; itkMaskImage = ItkUcharImgType::New(); mitk::Image::Pointer mitkMaskImage = mitk::IOUtil::Load(maskImage); mitk::CastToItkImage(mitkMaskImage, itkMaskImage); } // extract directions from fiber bundle itk::TractsToVectorImageFilter::Pointer fOdfFilter = itk::TractsToVectorImageFilter::New(); fOdfFilter->SetFiberBundle(inputTractogram); fOdfFilter->SetMaskImage(itkMaskImage); fOdfFilter->SetAngularThreshold(cos(angularThreshold*itk::Math::pi/180)); switch (normalization) { case 1: fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::GLOBAL_MAX); break; case 2: fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::SINGLE_VEC_NORM); break; case 3: fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::MAX_VEC_NORM); break; } - fOdfFilter->SetUseWorkingCopy(false); fOdfFilter->SetSizeThreshold(peakThreshold); fOdfFilter->SetMaxNumDirections(maxNumDirs); fOdfFilter->Update(); { itk::TractsToVectorImageFilter::ItkDirectionImageType::Pointer itkImg = fOdfFilter->GetDirectionImage(); typedef itk::ImageFileWriter< itk::TractsToVectorImageFilter::ItkDirectionImageType > WriterType; WriterType::Pointer writer = WriterType::New(); std::string outfilename = outRoot; outfilename.append("_DIRECTIONS"); outfilename.append(file_ending); writer->SetFileName(outfilename.c_str()); writer->SetInput(itkImg); writer->Update(); } if (verbose) { // write num direction image ItkUcharImgType::Pointer numDirImage = fOdfFilter->GetNumDirectionsImage(); typedef itk::ImageFileWriter< ItkUcharImgType > WriterType; WriterType::Pointer writer = WriterType::New(); std::string outfilename = outRoot; outfilename.append("_NUM_DIRECTIONS"); outfilename.append(file_ending); writer->SetFileName(outfilename.c_str()); writer->SetInput(numDirImage); writer->Update(); } } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FitFibersToImage.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FitFibersToImage.cpp index d8577f4050..819e709f32 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FitFibersToImage.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FitFibersToImage.cpp @@ -1,350 +1,350 @@ /*=================================================================== 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 #include #include #include #include #include #include #include #include #include typedef itksys::SystemTools ist; typedef itk::Point PointType4; typedef itk::Image< float, 4 > PeakImgType; std::vector< std::string > get_file_list(const std::string& path) { std::vector< std::string > file_list; itk::Directory::Pointer dir = itk::Directory::New(); if (dir->Load(path.c_str())) { int n = dir->GetNumberOfFiles(); for (int r = 0; r < n; r++) { const char *filename = dir->GetFile(r); std::string ext = ist::GetFilenameExtension(filename); if (ext==".fib" || ext==".trk") file_list.push_back(path + '/' + filename); } } return file_list; } /*! \brief Fits the tractogram to the input peak image by assigning a weight to each fiber (similar to https://doi.org/10.1016/j.neuroimage.2015.06.092). */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Fit Fibers To Image"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setDescription("Assigns a weight to each fiber in order to optimally explain the input peak image"); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("", "i1", mitkCommandLineParser::StringList, "Input tractograms:", "input tractograms (.fib, vtk ascii file format)", us::Any(), false); parser.addArgument("", "i2", mitkCommandLineParser::InputFile, "Input image:", "input image", us::Any(), false); parser.addArgument("", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output root", us::Any(), false); parser.addArgument("max_iter", "", mitkCommandLineParser::Int, "Max. iterations:", "maximum number of optimizer iterations", 20); parser.addArgument("bundle_based", "", mitkCommandLineParser::Bool, "Bundle based fit:", "fit one weight per input tractogram/bundle, not for each fiber", false); parser.addArgument("min_g", "", mitkCommandLineParser::Float, "Min. g:", "lower termination threshold for gradient magnitude", 1e-5); parser.addArgument("lambda", "", mitkCommandLineParser::Float, "Lambda:", "modifier for regularization", 0.1); parser.addArgument("save_res", "", mitkCommandLineParser::Bool, "Save Residuals:", "save residual images", false); parser.addArgument("save_weights", "", mitkCommandLineParser::Bool, "Save Weights:", "save fiber weights in a separate text file", false); parser.addArgument("filter_outliers", "", mitkCommandLineParser::Bool, "Filter outliers:", "perform second optimization run with an upper weight bound based on the first weight estimation (99% quantile)", false); parser.addArgument("join_tracts", "", mitkCommandLineParser::Bool, "Join output tracts:", "outout tracts are merged into a single tractogram", false); parser.addArgument("regu", "", mitkCommandLineParser::String, "Regularization:", "MSM, Variance, VoxelVariance (default), Lasso, GroupLasso, GroupVariance, NONE"); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; mitkCommandLineParser::StringContainerType fib_files = us::any_cast(parsedArgs["i1"]); std::string input_image_name = us::any_cast(parsedArgs["i2"]); std::string outRoot = us::any_cast(parsedArgs["o"]); bool single_fib = true; if (parsedArgs.count("bundle_based")) single_fib = !us::any_cast(parsedArgs["bundle_based"]); bool save_residuals = false; if (parsedArgs.count("save_res")) save_residuals = us::any_cast(parsedArgs["save_res"]); bool save_weights = false; if (parsedArgs.count("save_weights")) save_weights = us::any_cast(parsedArgs["save_weights"]); std::string regu = "VoxelVariance"; if (parsedArgs.count("regu")) regu = us::any_cast(parsedArgs["regu"]); bool join_tracts = false; if (parsedArgs.count("join_tracts")) join_tracts = us::any_cast(parsedArgs["join_tracts"]); int max_iter = 20; if (parsedArgs.count("max_iter")) max_iter = us::any_cast(parsedArgs["max_iter"]); float g_tol = 1e-5; if (parsedArgs.count("min_g")) g_tol = us::any_cast(parsedArgs["min_g"]); float lambda = 0.1; if (parsedArgs.count("lambda")) lambda = us::any_cast(parsedArgs["lambda"]); bool filter_outliers = false; if (parsedArgs.count("filter_outliers")) filter_outliers = us::any_cast(parsedArgs["filter_outliers"]); try { MITK_INFO << "Loading data"; - std::streambuf *old = cout.rdbuf(); // <-- save - std::stringstream ss; - std::cout.rdbuf (ss.rdbuf()); // <-- redirect +// std::streambuf *old = cout.rdbuf(); // <-- save +// std::stringstream ss; +// std::cout.rdbuf (ss.rdbuf()); // <-- redirect std::vector< mitk::FiberBundle::Pointer > input_tracts; mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Peak Image", "Fiberbundles"}, {}); std::vector< std::string > fib_names; for (auto item : fib_files) { if ( ist::FileIsDirectory(item) ) { for ( auto fibFile : get_file_list(item) ) { mitk::FiberBundle::Pointer inputTractogram = mitk::IOUtil::Load(fibFile); if (inputTractogram.IsNull()) continue; input_tracts.push_back(inputTractogram); fib_names.push_back(fibFile); } } else { mitk::FiberBundle::Pointer inputTractogram = mitk::IOUtil::Load(item); if (inputTractogram.IsNull()) continue; input_tracts.push_back(inputTractogram); fib_names.push_back(item); } } - std::cout.rdbuf (old); // <-- restore +// std::cout.rdbuf (old); // <-- restore itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New(); mitk::BaseData::Pointer inputData = mitk::IOUtil::Load(input_image_name, &functor)[0].GetPointer(); mitk::Image::Pointer mitk_image = dynamic_cast(inputData.GetPointer()); mitk::PeakImage::Pointer mitk_peak_image = dynamic_cast(inputData.GetPointer()); if (mitk_peak_image.IsNotNull()) { typedef mitk::ImageToItk< mitk::PeakImage::ItkPeakImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(mitk_peak_image); caster->Update(); mitk::PeakImage::ItkPeakImageType::Pointer peak_image = caster->GetOutput(); fitter->SetPeakImage(peak_image); } else if (mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(mitk_image)) { fitter->SetDiffImage(mitk::DiffusionPropertyHelper::GetItkVectorImage(mitk_image)); mitk::TensorModel<>* model = new mitk::TensorModel<>(); model->SetBvalue(1000); model->SetDiffusivity1(0.0010); model->SetDiffusivity2(0.00015); model->SetDiffusivity3(0.00015); model->SetGradientList(mitk::DiffusionPropertyHelper::GetGradientContainer(mitk_image)); fitter->SetSignalModel(model); } else if (mitk_image->GetDimension()==3) { itk::FitFibersToImageFilter::DoubleImgType::Pointer scalar_image = itk::FitFibersToImageFilter::DoubleImgType::New(); mitk::CastToItkImage(mitk_image, scalar_image); fitter->SetScalarImage(scalar_image); } else { MITK_INFO << "Input image invalid. Valid options are peak image, 3D scalar image or raw diffusion-weighted image."; return EXIT_FAILURE; } fitter->SetTractograms(input_tracts); fitter->SetFitIndividualFibers(single_fib); fitter->SetMaxIterations(max_iter); fitter->SetGradientTolerance(g_tol); fitter->SetLambda(lambda); fitter->SetFilterOutliers(filter_outliers); if (regu=="MSM") fitter->SetRegularization(VnlCostFunction::REGU::MSM); else if (regu=="Variance") fitter->SetRegularization(VnlCostFunction::REGU::VARIANCE); else if (regu=="Lasso") fitter->SetRegularization(VnlCostFunction::REGU::LASSO); else if (regu=="VoxelVariance") fitter->SetRegularization(VnlCostFunction::REGU::VOXEL_VARIANCE); else if (regu=="GroupLasso") fitter->SetRegularization(VnlCostFunction::REGU::GROUP_LASSO); else if (regu=="GroupVariance") fitter->SetRegularization(VnlCostFunction::REGU::GROUP_VARIANCE); else if (regu=="NONE") fitter->SetRegularization(VnlCostFunction::REGU::NONE); fitter->Update(); if (save_residuals && mitk_peak_image.IsNotNull()) { itk::ImageFileWriter< PeakImgType >::Pointer writer = itk::ImageFileWriter< PeakImgType >::New(); writer->SetInput(fitter->GetFittedImage()); writer->SetFileName(outRoot + "_fitted.nii.gz"); writer->Update(); writer->SetInput(fitter->GetResidualImage()); writer->SetFileName(outRoot + "_residual.nii.gz"); writer->Update(); writer->SetInput(fitter->GetOverexplainedImage()); writer->SetFileName(outRoot + "_overexplained.nii.gz"); writer->Update(); writer->SetInput(fitter->GetUnderexplainedImage()); writer->SetFileName(outRoot + "_underexplained.nii.gz"); writer->Update(); } else if (save_residuals && mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(mitk_image)) { { mitk::Image::Pointer outImage = mitk::GrabItkImageMemory( fitter->GetFittedImageDiff().GetPointer() ); mitk::DiffusionPropertyHelper::CopyProperties(mitk_image, outImage, true); mitk::DiffusionPropertyHelper propertyHelper( outImage ); propertyHelper.InitializeImage(); mitk::IOUtil::Save(outImage, "application/vnd.mitk.nii.gz", outRoot + "_fitted_image.nii.gz"); } { mitk::Image::Pointer outImage = mitk::GrabItkImageMemory( fitter->GetResidualImageDiff().GetPointer() ); mitk::DiffusionPropertyHelper::CopyProperties(mitk_image, outImage, true); mitk::DiffusionPropertyHelper propertyHelper( outImage ); propertyHelper.InitializeImage(); mitk::IOUtil::Save(outImage, "application/vnd.mitk.nii.gz", outRoot + "_residual_image.nii.gz"); } { mitk::Image::Pointer outImage = mitk::GrabItkImageMemory( fitter->GetOverexplainedImageDiff().GetPointer() ); mitk::DiffusionPropertyHelper::CopyProperties(mitk_image, outImage, true); mitk::DiffusionPropertyHelper propertyHelper( outImage ); propertyHelper.InitializeImage(); mitk::IOUtil::Save(outImage, "application/vnd.mitk.nii.gz", outRoot + "_overexplained_image.nii.gz"); } { mitk::Image::Pointer outImage = mitk::GrabItkImageMemory( fitter->GetUnderexplainedImageDiff().GetPointer() ); mitk::DiffusionPropertyHelper::CopyProperties(mitk_image, outImage, true); mitk::DiffusionPropertyHelper propertyHelper( outImage ); propertyHelper.InitializeImage(); mitk::IOUtil::Save(outImage, "application/vnd.mitk.nii.gz", outRoot + "_underexplained_image.nii.gz"); } } else if (save_residuals) { itk::ImageFileWriter< itk::FitFibersToImageFilter::DoubleImgType >::Pointer writer = itk::ImageFileWriter< itk::FitFibersToImageFilter::DoubleImgType >::New(); writer->SetInput(fitter->GetFittedImageScalar()); writer->SetFileName(outRoot + "_fitted_image.nii.gz"); writer->Update(); writer->SetInput(fitter->GetResidualImageScalar()); writer->SetFileName(outRoot + "_residual_image.nii.gz"); writer->Update(); writer->SetInput(fitter->GetOverexplainedImageScalar()); writer->SetFileName(outRoot + "_overexplained_image.nii.gz"); writer->Update(); writer->SetInput(fitter->GetUnderexplainedImageScalar()); writer->SetFileName(outRoot + "_underexplained_image.nii.gz"); writer->Update(); } std::vector< mitk::FiberBundle::Pointer > output_tracts = fitter->GetTractograms(); if (!join_tracts) { for (unsigned int bundle=0; bundleGetNumFibers(); ++f) logfile << output_tracts.at(bundle)->GetFiberWeight(f) << "\n"; logfile.close(); } } } else { mitk::FiberBundle::Pointer out = mitk::FiberBundle::New(); out = out->AddBundles(output_tracts); out->ColorFibersByFiberWeights(false, true); mitk::IOUtil::Save(out, outRoot + "_fitted.fib"); if (save_weights) { ofstream logfile; logfile.open (outRoot + "_weights.txt"); for (int f=0; fGetNumFibers(); ++f) logfile << out->GetFiberWeight(f) << "\n"; logfile.close(); } } } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/GetOverlappingTracts.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/GetOverlappingTracts.cpp index 9fe96b6b7e..5a46d38d55 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/GetOverlappingTracts.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/GetOverlappingTracts.cpp @@ -1,173 +1,171 @@ /*=================================================================== 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 "mitkCommandLineParser.h" #include #include #include #include #include #include #include #include #include #define _USE_MATH_DEFINES #include typedef itksys::SystemTools ist; typedef itk::Image ItkFloatImgType; /*! \brief Extract fibers from a tractogram using binary image ROIs */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Get Overlapping Tracts"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setContributor("MIC"); parser.setDescription("Find tracts that overlap with the reference masks or tracts"); parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", mitkCommandLineParser::StringList, "Input:", "input tractograms (.fib/.trk/.tck/.dcm)", us::Any(), false); parser.addArgument("reference", "r", mitkCommandLineParser::StringList, "Reference:", "reference tractograms or mask images", us::Any(), false); parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output Folder:", "move input tracts that do/don't overlap here", us::Any(), false); parser.addArgument("overlap_fraction", "", mitkCommandLineParser::Float, "Overlap fraction:", "", 0.9); parser.addArgument("use_any_overlap", "", mitkCommandLineParser::Bool, "Use any overlap:", "Don't find maximum overlap but use first overlap larger threshold"); parser.addArgument("dont_save_tracts", "", mitkCommandLineParser::Bool, "Don't save tracts:", "if true, only text files documenting the overlaps are saved and no tract files are copied"); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; mitkCommandLineParser::StringContainerType input = us::any_cast(parsedArgs["input"]); mitkCommandLineParser::StringContainerType reference = us::any_cast(parsedArgs["reference"]); std::string out_folder = us::any_cast(parsedArgs["out"]); bool use_any_overlap = false; if (parsedArgs.count("use_any_overlap")) use_any_overlap = us::any_cast(parsedArgs["use_any_overlap"]); bool dont_save_tracts = false; if (parsedArgs.count("dont_save_tracts")) dont_save_tracts = us::any_cast(parsedArgs["dont_save_tracts"]); float overlap_threshold = 0.9; if (parsedArgs.count("overlap_fraction")) overlap_threshold = us::any_cast(parsedArgs["overlap_fraction"]); try { itk::TractDensityImageFilter< ItkFloatImgType >::Pointer filter = itk::TractDensityImageFilter< ItkFloatImgType >::New(); - filter->SetDoFiberResampling(true); filter->SetUpsamplingFactor(0.25); filter->SetBinaryOutput(true); MITK_INFO << "Loading references"; std::vector< ItkFloatImgType::Pointer > masks; for (auto f : reference) { MITK_INFO << f; std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect mitk::FiberBundle::Pointer fib = mitk::IOUtil::Load(f); if (fib.IsNotNull()) { filter->SetFiberBundle(fib); filter->Update(); masks.push_back(filter->GetOutput()); } else { mitk::Image::Pointer m = mitk::IOUtil::Load(f); ItkFloatImgType::Pointer itkImage = ItkFloatImgType::New(); CastToItkImage(m, itkImage); masks.push_back(itkImage); } std::cout.rdbuf (old); // <-- restore } MITK_INFO << "Finding overlaps"; ofstream logfile; logfile.open (out_folder + "Overlaps.txt"); ofstream logfile2; logfile2.open (out_folder + "AllOverlaps.txt"); boost::progress_display disp(input.size()); for (auto f : input) { ++disp; std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect bool is_overlapping = false; mitk::FiberBundle::Pointer fib = mitk::IOUtil::Load(f); - fib->ResampleLinear(2); float overlap = 0; float max_overlap = 0; std::string max_ref = "-"; int i = 0; std::string overlap_string = ist::GetFilenameWithoutExtension(f); for (auto m : masks) { - overlap = fib->GetOverlap(m, false); + overlap = fib->GetOverlap(m); if (overlap>max_overlap) { max_overlap = overlap; max_ref = ist::GetFilenameWithoutExtension(reference.at(i)); } if (use_any_overlap && overlap>=overlap_threshold) break; overlap_string += " " + ist::GetFilenameWithoutExtension(reference.at(i)) + " " + boost::lexical_cast(overlap); ++i; } if (overlap>=overlap_threshold) is_overlapping = true; logfile << ist::GetFilenameWithoutExtension(f) << " - " << max_ref << ": " << boost::lexical_cast(max_overlap) << "\n"; logfile2 << overlap_string << "\n"; if (!dont_save_tracts && is_overlapping) ist::CopyAFile(f, out_folder + ist::GetFilenameName(f)); std::cout.rdbuf (old); // <-- restore } logfile.close(); logfile2.close(); } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensity.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensity.cpp index ead6ac999d..e9c1b20d15 100644 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensity.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensity.cpp @@ -1,215 +1,213 @@ /*=================================================================== 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 #include #include #include #include #include "mitkCommandLineParser.h" #include #include #include #include #include mitk::FiberBundle::Pointer LoadFib(std::string filename) { std::vector fibInfile = mitk::IOUtil::Load(filename); if( fibInfile.empty() ) std::cout << "File " << filename << " could not be read!"; mitk::BaseData::Pointer baseData = fibInfile.at(0); return dynamic_cast(baseData.GetPointer()); } /*! \brief Modify input tractogram: fiber resampling, compression, pruning and transformation. */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Tract Density"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setDescription("Generate tract density image, fiber envelope or fiber endpoints image."); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", mitkCommandLineParser::String, "Input:", "input fiber bundle (.fib)", us::Any(), false); parser.addArgument("output", "o", mitkCommandLineParser::String, "Output:", "output image", us::Any(), false); parser.addArgument("binary", "", mitkCommandLineParser::Bool, "Binary output:", "calculate binary tract envelope", us::Any()); parser.addArgument("normalize", "", mitkCommandLineParser::Bool, "Normalized output:", "normalize output to 0-1", us::Any()); parser.addArgument("endpoints", "", mitkCommandLineParser::Bool, "Output endpoints image:", "calculate image of fiber endpoints instead of mask", us::Any()); parser.addArgument("reference_image", "", mitkCommandLineParser::String, "Reference image:", "output image will have geometry of this reference image", us::Any()); parser.addArgument("upsampling", "", mitkCommandLineParser::Float, "Upsampling:", "upsampling", 1.0); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; bool binary = false; if (parsedArgs.count("binary")) binary = us::any_cast(parsedArgs["binary"]); bool endpoints = false; if (parsedArgs.count("endpoints")) endpoints = us::any_cast(parsedArgs["endpoints"]); bool normalize = false; if (parsedArgs.count("normalize")) normalize = us::any_cast(parsedArgs["normalize"]); float upsampling = 1.0; if (parsedArgs.count("upsampling")) upsampling = us::any_cast(parsedArgs["upsampling"]); MITK_INFO << "Upsampling: " << upsampling; std::string reference_image = ""; if (parsedArgs.count("reference_image")) reference_image = us::any_cast(parsedArgs["reference_image"]); std::string inFileName = us::any_cast(parsedArgs["input"]); std::string outFileName = us::any_cast(parsedArgs["output"]); try { mitk::FiberBundle::Pointer fib = LoadFib(inFileName); mitk::Image::Pointer ref_img; if (!reference_image.empty()) ref_img = mitk::IOUtil::Load(reference_image); if (endpoints) { typedef unsigned int OutPixType; typedef itk::Image OutImageType; typedef itk::TractsToFiberEndingsImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(upsampling); if (ref_img.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(ref_img, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); mitk::IOUtil::Save(img, outFileName ); } else if (binary) { typedef unsigned char OutPixType; typedef itk::Image OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetOutputAbsoluteValues(!normalize); - generator->SetWorkOnFiberCopy(false); generator->SetUpsamplingFactor(upsampling); if (ref_img.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(ref_img, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); mitk::IOUtil::Save(img, outFileName ); } else { typedef float OutPixType; typedef itk::Image OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetOutputAbsoluteValues(!normalize); - generator->SetWorkOnFiberCopy(false); generator->SetUpsamplingFactor(upsampling); if (ref_img.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(ref_img, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); mitk::IOUtil::Save(img, outFileName ); } } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensityFilter.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensityFilter.cpp index 1f789fe9ce..5fe1a73974 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensityFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensityFilter.cpp @@ -1,111 +1,110 @@ /*=================================================================== 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 "mitkCommandLineParser.h" #include #include #include #include #include #include #include #include #include #define _USE_MATH_DEFINES #include typedef itksys::SystemTools ist; typedef itk::Image ItkFloatImgType; /*! \brief Extract fibers from a tractogram using binary image ROIs */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Filter Outliers by Tract Density"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", mitkCommandLineParser::String, "Input:", "input tractogram (.fib/.trk/.tck/.dcm)", us::Any(), false); parser.addArgument("out", "o", mitkCommandLineParser::String, "Output:", "output tractogram", us::Any(), false); parser.addArgument("threshold", "", mitkCommandLineParser::Float, "Threshold:", "positive means ROI image value threshold", 0.05); parser.addArgument("overlap", "", mitkCommandLineParser::Float, "Overlap:", "positive means ROI image value threshold", 0.5); parser.addArgument("min_fibers", "", mitkCommandLineParser::Int, "Min. num. fibers:", "discard positive tracts with less fibers", 0); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string inFib = us::any_cast(parsedArgs["input"]); std::string outFib = us::any_cast(parsedArgs["out"]); int min_fibers = 0; if (parsedArgs.count("min_fibers")) min_fibers = us::any_cast(parsedArgs["min_fibers"]); float overlap = 0.5; if (parsedArgs.count("overlap")) overlap = us::any_cast(parsedArgs["overlap"]); float threshold = 0.05; if (parsedArgs.count("threshold")) threshold = us::any_cast(parsedArgs["threshold"]); try { mitk::FiberBundle::Pointer inputTractogram = mitk::IOUtil::Load(inFib); itk::TractDensityImageFilter< ItkFloatImgType >::Pointer generator = itk::TractDensityImageFilter< ItkFloatImgType >::New(); generator->SetFiberBundle(inputTractogram); generator->SetBinaryOutput(false); generator->SetOutputAbsoluteValues(false); - generator->SetWorkOnFiberCopy(true); generator->Update(); itk::FiberExtractionFilter::Pointer extractor = itk::FiberExtractionFilter::New(); extractor->SetRoiImages({generator->GetOutput()}); extractor->SetInputFiberBundle(inputTractogram); extractor->SetOverlapFraction(overlap); extractor->SetInterpolate(true); extractor->SetThreshold(threshold); extractor->SetNoNegatives(true); extractor->Update(); if (extractor->GetPositives().at(0)->GetNumFibers()>=min_fibers) mitk::IOUtil::Save(extractor->GetPositives().at(0), outFib); } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/Fiberfox/FiberfoxOptimization.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/Fiberfox/FiberfoxOptimization.cpp index 070cf357b2..b6c9959895 100644 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/Fiberfox/FiberfoxOptimization.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/Fiberfox/FiberfoxOptimization.cpp @@ -1,831 +1,837 @@ /*=================================================================== 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 #include #include "mitkCommandLineParser.h" #include #include #include #include #include #include #include #include #include #include #include #include using namespace mitk; double CalcErrorSignal(const std::vector& histo_mod, itk::VectorImage< short, 3 >* reference, itk::VectorImage< short, 3 >* simulation, itk::Image< unsigned char,3 >::Pointer mask, itk::Image< double,3 >::Pointer fa) { typedef itk::Image< double, 3 > DoubleImageType; typedef itk::VectorImage< short, 3 > DwiImageType; if (fa.IsNotNull()) { itk::ImageRegionIterator< DwiImageType > it1(reference, reference->GetLargestPossibleRegion()); itk::ImageRegionIterator< DwiImageType > it2(simulation, simulation->GetLargestPossibleRegion()); itk::ImageRegionConstIterator< DoubleImageType > it3(fa, fa->GetLargestPossibleRegion()); unsigned int count = 0; double error = 0; while(!it1.IsAtEnd()) { if (mask.IsNull() || (mask.IsNotNull() && mask->GetLargestPossibleRegion().IsInside(it1.GetIndex()) && mask->GetPixel(it1.GetIndex())>0) ) { double fa = it3.Get(); if (fa>0) { double mod = 1.0; for (int i=histo_mod.size()-1; i>=0; --i) if (fa >= (double)i/histo_mod.size()) { mod = histo_mod.at(i); break; } for (unsigned int i=0; iGetVectorLength(); ++i) { if (it1.Get()[i]>0) { double diff = (double)it2.Get()[i]/it1.Get()[i] - 1.0; error += std::pow(mod, 4) * fabs(diff); count++; } } } } ++it1; ++it2; ++it3; } return error/count; } else { itk::ImageRegionIterator< DwiImageType > it1(reference, reference->GetLargestPossibleRegion()); itk::ImageRegionIterator< DwiImageType > it2(simulation, simulation->GetLargestPossibleRegion()); unsigned int count = 0; double error = 0; while(!it1.IsAtEnd()) { if (mask.IsNull() || (mask.IsNotNull() && mask->GetLargestPossibleRegion().IsInside(it1.GetIndex()) && mask->GetPixel(it1.GetIndex())>0) ) { for (unsigned int i=0; iGetVectorLength(); ++i) { if (it1.Get()[i]>0) { double diff = (double)it2.Get()[i]/it1.Get()[i] - 1.0; error += fabs(diff); count++; } } } ++it1; ++it2; } return error/count; } return -1; } double CalcErrorFA(const std::vector& histo_mod, mitk::Image::Pointer dwi1, itk::VectorImage< short, 3 >* dwi2, itk::Image< unsigned char,3 >::Pointer mask, itk::Image< double,3 >::Pointer fa1, itk::Image< double,3 >::Pointer md1, bool b0_contrast) { typedef itk::TensorDerivedMeasurementsFilter MeasurementsType; typedef itk::Image< double, 3 > DoubleImageType; typedef itk::VectorImage< short, 3 > DwiType; DwiType::Pointer dwi1_itk = mitk::DiffusionPropertyHelper::GetItkVectorImage(dwi1); typedef itk::DiffusionTensor3DReconstructionImageFilter TensorReconstructionImageFilterType; DoubleImageType::Pointer fa2; { mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer gradientContainerCopy = mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::New(); for(auto it = mitk::DiffusionPropertyHelper::GetGradientContainer(dwi1)->Begin(); it != mitk::DiffusionPropertyHelper::GetGradientContainer(dwi1)->End(); it++) gradientContainerCopy->push_back(it.Value()); TensorReconstructionImageFilterType::Pointer tensorReconstructionFilter = TensorReconstructionImageFilterType::New(); tensorReconstructionFilter->SetBValue( mitk::DiffusionPropertyHelper::GetReferenceBValue(dwi1) ); tensorReconstructionFilter->SetGradientImage(gradientContainerCopy, dwi2 ); tensorReconstructionFilter->Update(); MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput( tensorReconstructionFilter->GetOutput() ); measurementsCalculator->SetMeasure(MeasurementsType::FA); measurementsCalculator->Update(); fa2 = measurementsCalculator->GetOutput(); } DoubleImageType::Pointer md2; if (md1.IsNotNull()) { typedef itk::AdcImageFilter< short, double > AdcFilterType; AdcFilterType::Pointer filter = AdcFilterType::New(); filter->SetInput( dwi2 ); filter->SetGradientDirections( mitk::DiffusionPropertyHelper::GetGradientContainer(dwi1) ); filter->SetB_value( mitk::DiffusionPropertyHelper::GetReferenceBValue(dwi1) ); filter->SetFitSignal(false); filter->Update(); md2 = filter->GetOutput(); } itk::ImageRegionConstIterator< DoubleImageType > it1(fa1, fa1->GetLargestPossibleRegion()); itk::ImageRegionConstIterator< DoubleImageType > it2(fa2, fa2->GetLargestPossibleRegion()); itk::ImageRegionConstIterator< itk::VectorImage< short, 3 > > it_diff1(dwi1_itk, dwi1_itk->GetLargestPossibleRegion()); itk::ImageRegionConstIterator< itk::VectorImage< short, 3 > > it_diff2(dwi2, dwi2->GetLargestPossibleRegion()); unsigned int count = 0; double error = 0; if (md1.IsNotNull() && md2.IsNotNull()) { itk::ImageRegionConstIterator< DoubleImageType > it3(md1, md1->GetLargestPossibleRegion()); itk::ImageRegionConstIterator< DoubleImageType > it4(md2, md2->GetLargestPossibleRegion()); while(!it1.IsAtEnd()) { if (mask.IsNull() || (mask.IsNotNull() && mask->GetLargestPossibleRegion().IsInside(it1.GetIndex()) && mask->GetPixel(it1.GetIndex())>0) ) { double fa = it1.Get(); if (fa>0 && it3.Get()>0) { double mod = 1.0; for (int i=histo_mod.size()-1; i>=0; --i) if (fa >= (double)i/histo_mod.size()) { mod = histo_mod.at(i); break; } double fa_diff = std::fabs(it2.Get()/fa - 1.0); double md_diff = std::fabs(it4.Get()/it3.Get() - 1.0); - error += std::pow(mod, 4) * (fa_diff + md_diff); + error += mod * (fa_diff + md_diff); count += 2; if (b0_contrast && it_diff1.Get()[0]>0) { double b0_diff = (double)it_diff2.Get()[0]/it_diff1.Get()[0] - 1.0; - error += std::pow(mod, 4) * std::fabs(b0_diff); + error += std::fabs(b0_diff); ++count; } } } ++it1; ++it2; ++it3; ++it4; ++it_diff1; ++it_diff2; } } else { unsigned int count = 0; double error = 0; while(!it1.IsAtEnd()) { if (mask.IsNull() || (mask.IsNotNull() && mask->GetLargestPossibleRegion().IsInside(it1.GetIndex()) && mask->GetPixel(it1.GetIndex())>0) ) { double fa = it1.Get(); if (fa>0) { double mod = 1.0; for (int i=histo_mod.size()-1; i>=0; --i) if (fa >= (double)i/histo_mod.size()) { mod = histo_mod.at(i); break; } double fa_diff = fabs(it2.Get()/fa - 1.0); - error += std::pow(mod, 4) * fa_diff; + error += mod * fa_diff; ++count; if (b0_contrast && it_diff1.Get()[0]>0) { double b0_diff = (double)it_diff2.Get()[0]/it_diff1.Get()[0] - 1.0; - error += std::pow(mod, 4) * std::fabs(b0_diff); + error += std::fabs(b0_diff); ++count; } } } ++it1; ++it2; ++it_diff1; ++it_diff2; } } return error/count; } FiberfoxParameters MakeProposalScale(FiberfoxParameters old_params, double temperature) { FiberfoxParameters new_params(old_params); std::random_device r; std::default_random_engine randgen(r()); std::normal_distribution normal_dist(0, new_params.m_SignalGen.m_SignalScale*0.1*temperature); double add = 0; while (add == 0) add = normal_dist(randgen); new_params.m_SignalGen.m_SignalScale += add; MITK_INFO << "Proposal Signal Scale: " << new_params.m_SignalGen.m_SignalScale << " (" << add << ")"; return new_params; } FiberfoxParameters MakeProposalRelaxation(FiberfoxParameters old_params, double temperature) { FiberfoxParameters new_params(old_params); std::random_device r; std::default_random_engine randgen(r()); std::uniform_int_distribution uint1(0, 3); int prop = uint1(randgen); switch(prop) { case 0: { int model_index = rand()%new_params.m_NonFiberModelList.size(); double t2 = new_params.m_NonFiberModelList[model_index]->GetT2(); std::normal_distribution normal_dist(0, t2*0.1*temperature); double add = 0; while (add == 0) add = normal_dist(randgen); if ( (t2+add)*1.5 > new_params.m_NonFiberModelList[model_index]->GetT1() ) add = -add; t2 += add; new_params.m_NonFiberModelList[model_index]->SetT2(t2); MITK_INFO << "Proposal T2 (Non-Fiber " << model_index << "): " << t2 << " (" << add << ")"; break; } case 1: { int model_index = rand()%new_params.m_FiberModelList.size(); double t2 = new_params.m_FiberModelList[model_index]->GetT2(); std::normal_distribution normal_dist(0, t2*0.1*temperature); double add = 0; while (add == 0) add = normal_dist(randgen); if ( (t2+add)*1.5 > new_params.m_FiberModelList[model_index]->GetT1() ) add = -add; t2 += add; new_params.m_FiberModelList[model_index]->SetT2(t2); MITK_INFO << "Proposal T2 (Fiber " << model_index << "): " << t2 << " (" << add << ")"; break; } case 2: { int model_index = rand()%new_params.m_NonFiberModelList.size(); double t1 = new_params.m_NonFiberModelList[model_index]->GetT1(); std::normal_distribution normal_dist(0, t1*0.1*temperature); double add = 0; while (add == 0) add = normal_dist(randgen); if ( t1+add < new_params.m_NonFiberModelList[model_index]->GetT2() * 1.5 ) add = -add; t1 += add; new_params.m_NonFiberModelList[model_index]->SetT1(t1); MITK_INFO << "Proposal T1 (Non-Fiber " << model_index << "): " << t1 << " (" << add << ")"; break; } case 3: { int model_index = rand()%new_params.m_FiberModelList.size(); double t1 = new_params.m_FiberModelList[model_index]->GetT1(); std::normal_distribution normal_dist(0, t1*0.1*temperature); double add = 0; while (add == 0) add = normal_dist(randgen); if ( t1+add < new_params.m_FiberModelList[model_index]->GetT2() * 1.5 ) add = -add; t1 += add; new_params.m_FiberModelList[model_index]->SetT1(t1); MITK_INFO << "Proposal T1 (Fiber " << model_index << "): " << t1 << " (" << add << ")"; break; } } return new_params; } double UpdateDiffusivity(double d, double temperature) { std::random_device r; std::default_random_engine randgen(r()); std::normal_distribution normal_dist(0, d*0.1*temperature); double add = 0; while (add == 0) add = normal_dist(randgen); if (d+add > 0.0025) d -= add; else if ( d+add < 0.0 ) d -= add; else d += add; return d; } void ProposeDiffusivities(mitk::DiffusionSignalModel<>* signalModel, double temperature) { if (dynamic_cast*>(signalModel)) { mitk::StickModel<>* m = dynamic_cast*>(signalModel); double new_d = UpdateDiffusivity(m->GetDiffusivity(), temperature); MITK_INFO << "d: " << new_d << " (" << new_d-m->GetDiffusivity() << ")"; m->SetDiffusivity(new_d); } else if (dynamic_cast*>(signalModel)) { mitk::TensorModel<>* m = dynamic_cast*>(signalModel); double new_d1 = UpdateDiffusivity(m->GetDiffusivity1(), temperature); double new_d2 = UpdateDiffusivity(m->GetDiffusivity2(), temperature); while (new_d1GetDiffusivity2(), temperature); MITK_INFO << "d1: " << new_d1 << " (" << new_d1-m->GetDiffusivity1() << ")"; MITK_INFO << "d2: " << new_d2 << " (" << new_d2-m->GetDiffusivity2() << ")"; m->SetDiffusivity1(new_d1); m->SetDiffusivity2(new_d2); m->SetDiffusivity3(new_d2); } else if (dynamic_cast*>(signalModel)) { mitk::BallModel<>* m = dynamic_cast*>(signalModel); double new_d = UpdateDiffusivity(m->GetDiffusivity(), temperature); MITK_INFO << "d: " << new_d << " (" << new_d-m->GetDiffusivity() << ")"; m->SetDiffusivity(new_d); } else if (dynamic_cast*>(signalModel)) { mitk::AstroStickModel<>* m = dynamic_cast*>(signalModel); double new_d = UpdateDiffusivity(m->GetDiffusivity(), temperature); MITK_INFO << "d: " << new_d << " (" << new_d-m->GetDiffusivity() << ")"; m->SetDiffusivity(new_d); } } FiberfoxParameters MakeProposalDiff(FiberfoxParameters old_params, double temperature) { FiberfoxParameters new_params(old_params); std::random_device r; std::default_random_engine randgen(r()); std::uniform_int_distribution uint1(0, new_params.m_NonFiberModelList.size() + new_params.m_FiberModelList.size() - 1); unsigned int prop = uint1(randgen); if (prop::Pointer > frac, double temperature) { FiberfoxParameters new_params(old_params); MITK_INFO << "Proposal Volume"; std::random_device r; std::default_random_engine randgen(r()); { std::normal_distribution normal_dist(0, old_tdi_thr*0.1*temperature); new_tdi_thr = old_tdi_thr + normal_dist(randgen); while (new_tdi_thr<=0.01) + { new_tdi_thr = old_tdi_thr + normal_dist(randgen); + } } { std::normal_distribution normal_dist(0, old_sqrt*0.1*temperature); new_sqrt = old_sqrt + normal_dist(randgen); while (new_sqrt<=0.01) + { new_sqrt = old_sqrt + normal_dist(randgen); + } } itk::TdiToVolumeFractionFilter< double >::Pointer fraction_generator = itk::TdiToVolumeFractionFilter< double >::New(); fraction_generator->SetTdiThreshold(new_tdi_thr); fraction_generator->SetSqrt(new_sqrt); fraction_generator->SetInput(0, frac.at(0)); fraction_generator->SetInput(1, frac.at(1)); fraction_generator->SetInput(2, frac.at(2)); fraction_generator->SetInput(3, frac.at(3)); fraction_generator->SetInput(4, frac.at(4)); fraction_generator->Update(); new_params.m_FiberModelList[0]->SetVolumeFractionImage(fraction_generator->GetOutput(0)); new_params.m_FiberModelList[1]->SetVolumeFractionImage(fraction_generator->GetOutput(1)); new_params.m_NonFiberModelList[0]->SetVolumeFractionImage(fraction_generator->GetOutput(2)); new_params.m_NonFiberModelList[1]->SetVolumeFractionImage(fraction_generator->GetOutput(3)); MITK_INFO << "TDI Threshold: " << new_tdi_thr << " (" << new_tdi_thr-old_tdi_thr << ")"; MITK_INFO << "SQRT: " << new_sqrt << " (" << new_sqrt-old_sqrt << ")"; return new_params; } /*! * \brief Command line interface to optimize Fiberfox parameters. */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("FiberfoxOptimization"); parser.setCategory("Optimize Fiberfox Parameters"); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.beginGroup("1. Mandatory Input:"); parser.addArgument("parameters", "p", mitkCommandLineParser::InputFile, "Parameter File:", "fiberfox parameter file (.ffp)", us::Any(), false); parser.addArgument("tracts", "t", mitkCommandLineParser::String, "Input Tractogram:", "Input tractogram.", us::Any(), false); parser.addArgument("out_folder", "o", mitkCommandLineParser::String, "Output Folder:", "", us::Any(), false); parser.addArgument("dmri", "d", mitkCommandLineParser::String, "Target image:", "Target dMRI to approximate.", us::Any(), false); parser.addArgument("mask", "", mitkCommandLineParser::InputFile, "Mask image:", "Error is only calculated inside the mask image", false); parser.endGroup(); parser.beginGroup("2. Parameters to optimize:"); parser.addArgument("no_diff", "", mitkCommandLineParser::Bool, "Don't optimize diffusivities:", "Don't optimize diffusivities"); parser.addArgument("no_relax", "", mitkCommandLineParser::Bool, "Don't optimize relaxation times:", "Don't optimize relaxation times"); parser.addArgument("no_scale", "", mitkCommandLineParser::Bool, "Don't optimize signal scale:", "Don't optimize global signal scale"); parser.endGroup(); parser.beginGroup("3. Error measure:"); parser.addArgument("fa_error", "", mitkCommandLineParser::Bool, "Optimize FA", "Optimize FA instead of raw signal. Requires FA image."); parser.addArgument("fa_image", "", mitkCommandLineParser::InputFile, "FA image:", "Weight error by FA histogram. Always necessary with option fa_error!"); parser.addArgument("md_image", "", mitkCommandLineParser::InputFile, "MD image:", "Optimize MD in conjunction with FA (recommended when optimizing FA)."); parser.endGroup(); parser.beginGroup("4. Optimization of volume fraction maps:"); parser.addArgument("tdi", "", mitkCommandLineParser::InputFile, "TDI:", "tract density image"); parser.addArgument("wm", "", mitkCommandLineParser::InputFile, "WM:", "white matter volume fraction image"); parser.addArgument("gm", "", mitkCommandLineParser::InputFile, "GM:", "gray matter volume fraction image"); parser.addArgument("dgm", "", mitkCommandLineParser::InputFile, "DGM:", "subcortical gray matter volume fraction image"); parser.addArgument("csf", "", mitkCommandLineParser::InputFile, "CSF:", "CSF volume fraction image"); parser.addArgument("tdi_threshold", "", mitkCommandLineParser::Float, "", "", 0.75); parser.addArgument("sqrt", "", mitkCommandLineParser::Float, "", "", 1.0); parser.endGroup(); parser.beginGroup("5. General parameters:"); parser.addArgument("iterations", "", mitkCommandLineParser::Int, "Iterations:", "Number of optimizations steps", 1000); parser.addArgument("start_temp", "", mitkCommandLineParser::Float, "Start temperature:", "Higher temperature means larger parameter change proposals", 1.0); parser.addArgument("end_temp", "", mitkCommandLineParser::Float, "End temperature:", "Higher temperature means larger parameter change proposals", 0.1); parser.endGroup(); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string paramName = us::any_cast(parsedArgs["parameters"]); std::string out_folder = us::any_cast(parsedArgs["out_folder"]); std::string tract_file = us::any_cast(parsedArgs["tracts"]); MITK_INFO << "Loading target dMRI and parameters"; FiberfoxParameters parameters; parameters.LoadParameters(paramName); typedef itk::VectorImage< short, 3 > ItkDwiType; mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Diffusion Weighted Images", "Fiberbundles"}, {}); auto dwi = mitk::IOUtil::Load(us::any_cast(parsedArgs["dmri"]), &functor); ItkDwiType::Pointer reference = mitk::DiffusionPropertyHelper::GetItkVectorImage(dwi); parameters.m_SignalGen.m_ImageRegion = reference->GetLargestPossibleRegion(); parameters.m_SignalGen.m_ImageSpacing = reference->GetSpacing(); parameters.m_SignalGen.m_ImageOrigin = reference->GetOrigin(); parameters.m_SignalGen.m_ImageDirection = reference->GetDirection(); parameters.SetBvalue(static_cast(dwi->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue()); parameters.SetGradienDirections(static_cast( dwi->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer()); auto tracts = mitk::IOUtil::Load(tract_file, &functor); int iterations=1000; if (parsedArgs.count("iterations")) iterations = us::any_cast(parsedArgs["iterations"]); float start_temp=1.0; if (parsedArgs.count("start_temp")) start_temp = us::any_cast(parsedArgs["start_temp"]); float end_temp=0.1; if (parsedArgs.count("end_temp")) end_temp = us::any_cast(parsedArgs["end_temp"]); float tdi_threshold=0.75; if (parsedArgs.count("tdi_threshold")) tdi_threshold = us::any_cast(parsedArgs["tdi_threshold"]); float sqrt=1.0; if (parsedArgs.count("sqrt")) sqrt = us::any_cast(parsedArgs["sqrt"]); bool fa_error=false; if (parsedArgs.count("fa_error")) fa_error = true; std::string fa_file = ""; if (parsedArgs.count("fa_image")) fa_file = us::any_cast(parsedArgs["fa_image"]); std::string md_file = ""; if (parsedArgs.count("md_image")) md_file = us::any_cast(parsedArgs["md_image"]); std::vector< int > possible_proposals; if (!parsedArgs.count("no_diff")) { MITK_INFO << "Optimizing diffusivities"; possible_proposals.push_back(0); } if (!parsedArgs.count("no_relax")) { MITK_INFO << "Optimizing relaxation constants"; possible_proposals.push_back(1); } if (!parsedArgs.count("no_scale")) { MITK_INFO << "Optimizing global signal scale"; possible_proposals.push_back(2); } - if (possible_proposals.empty()) - { - MITK_INFO << "Incompatible options. Nothing to optimize."; - return EXIT_FAILURE; - } itk::ImageFileReader< itk::Image< unsigned char, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< unsigned char, 3 > >::New(); reader->SetFileName( us::any_cast(parsedArgs["mask"]) ); reader->Update(); itk::Image< unsigned char,3 >::Pointer mask = reader->GetOutput(); std::vector< itk::Image< double, 3 >::Pointer > fracs; if ( parsedArgs.count("tdi")>0 && parsedArgs.count("wm")>0 && parsedArgs.count("gm")>0 && parsedArgs.count("dgm")>0 && parsedArgs.count("csf")>0 ) { MITK_INFO << "Optimizing volume fractions"; { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( us::any_cast(parsedArgs["tdi"]) ); reader->Update(); fracs.push_back(reader->GetOutput()); } { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( us::any_cast(parsedArgs["wm"]) ); reader->Update(); fracs.push_back(reader->GetOutput()); } { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( us::any_cast(parsedArgs["gm"]) ); reader->Update(); fracs.push_back(reader->GetOutput()); } { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( us::any_cast(parsedArgs["dgm"]) ); reader->Update(); fracs.push_back(reader->GetOutput()); } { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( us::any_cast(parsedArgs["csf"]) ); reader->Update(); fracs.push_back(reader->GetOutput()); } MITK_INFO << "Initial sqrt: " << sqrt; MITK_INFO << "Initial TDI threshold: " << tdi_threshold; possible_proposals.push_back(3); } std::vector< double > histogram_modifiers; itk::Image< double,3 >::Pointer fa_image = nullptr; if (fa_file.compare("")!=0) { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( fa_file ); reader->Update(); fa_image = reader->GetOutput(); - int binsPerDimension = 20; + int binsPerDimension = 10; using ImageToHistogramFilterType = itk::Statistics::MaskedImageToHistogramFilter< itk::Image< double,3 >, itk::Image< unsigned char,3 > >; ImageToHistogramFilterType::HistogramType::MeasurementVectorType lowerBound(binsPerDimension); lowerBound.Fill(0.0); ImageToHistogramFilterType::HistogramType::MeasurementVectorType upperBound(binsPerDimension); upperBound.Fill(1.0); ImageToHistogramFilterType::HistogramType::SizeType size(1); size.Fill(binsPerDimension); ImageToHistogramFilterType::Pointer imageToHistogramFilter = ImageToHistogramFilterType::New(); imageToHistogramFilter->SetInput( fa_image ); imageToHistogramFilter->SetHistogramBinMinimum( lowerBound ); imageToHistogramFilter->SetHistogramBinMaximum( upperBound ); imageToHistogramFilter->SetHistogramSize( size ); imageToHistogramFilter->SetMaskImage(mask); imageToHistogramFilter->SetMaskValue(1); imageToHistogramFilter->Update(); ImageToHistogramFilterType::HistogramType* histogram = imageToHistogramFilter->GetOutput(); unsigned int max = 0; for(unsigned int i = 0; i < histogram->GetSize()[0]; ++i) { if (histogram->GetFrequency(i)>max) max = histogram->GetFrequency(i); } MITK_INFO << "FA histogram modifiers:"; for(unsigned int i = 0; i < histogram->GetSize()[0]; ++i) { - histogram_modifiers.push_back((double)max/histogram->GetFrequency(i)); - MITK_INFO << std::pow(histogram_modifiers.back(), 4); + histogram_modifiers.push_back(1.0 - (double)histogram->GetFrequency(i)/(double)max); + MITK_INFO << histogram_modifiers.back(); } if (fa_error) MITK_INFO << "Using FA error measure."; } itk::Image< double,3 >::Pointer md_image = nullptr; if (md_file.compare("")!=0) { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( md_file ); reader->Update(); md_image = reader->GetOutput(); if (fa_error) MITK_INFO << "Using MD error measure."; } if (fa_error && fa_image.IsNull()) { MITK_INFO << "Incompatible options. Need FA image to calculate FA error."; return EXIT_FAILURE; } + if (possible_proposals.empty()) + { + MITK_INFO << "Incompatible options. Nothing to optimize."; + return EXIT_FAILURE; + } + itk::TractsToDWIImageFilter< short >::Pointer tractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New(); tractsToDwiFilter->SetFiberBundle(tracts); tractsToDwiFilter->SetParameters(parameters); tractsToDwiFilter->Update(); ItkDwiType::Pointer sim = tractsToDwiFilter->GetOutput(); { mitk::Image::Pointer image = mitk::GrabItkImageMemory( tractsToDwiFilter->GetOutput() ); image->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( parameters.m_SignalGen.GetGradientDirections() ) ); image->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( parameters.m_SignalGen.GetBvalue() ) ); mitk::DiffusionPropertyHelper propertyHelper( image ); propertyHelper.InitializeImage(); mitk::IOUtil::Save(image, out_folder + "/initial.dwi"); } double old_tdi_thr = tdi_threshold; double old_sqrt = sqrt; - double new_tdi_thr; - double new_sqrt; + double new_tdi_thr = old_tdi_thr; + double new_sqrt = old_sqrt; MITK_INFO << "\n\n"; MITK_INFO << "Iterations: " << iterations; MITK_INFO << "start_temp: " << start_temp; MITK_INFO << "end_temp: " << end_temp; double alpha = log(end_temp/start_temp); int accepted = 0; double last_error = 9999999; if (fa_error) { MITK_INFO << "Calculating FA error"; last_error = CalcErrorFA(histogram_modifiers, dwi, sim, mask, fa_image, md_image, true); } else { MITK_INFO << "Calculating raw-image error"; last_error = CalcErrorSignal(histogram_modifiers, reference, sim, mask, fa_image); } MITK_INFO << "Initial E = " << last_error; MITK_INFO << "\n\n**************************************************************************************"; std::random_device r; std::default_random_engine randgen(r()); std::uniform_int_distribution uint1(0, possible_proposals.size()-1); for (int i=0; i::Pointer tractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New(); tractsToDwiFilter->SetFiberBundle(dynamic_cast(tracts.GetPointer())); tractsToDwiFilter->SetParameters(proposal); tractsToDwiFilter->Update(); ItkDwiType::Pointer sim = tractsToDwiFilter->GetOutput(); std::cout.rdbuf (old); // <-- restore double new_error = 9999999; if (fa_error && fa_image.IsNotNull()) new_error = CalcErrorFA(histogram_modifiers, dwi, sim, mask, fa_image, md_image, true); else new_error = CalcErrorSignal(histogram_modifiers, reference, sim, mask, fa_image); MITK_INFO << "E = " << new_error << "(" << new_error-last_error << ")"; if (last_errorGetOutput() ); image->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( parameters.m_SignalGen.GetGradientDirections() ) ); image->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( parameters.m_SignalGen.GetBvalue() ) ); mitk::DiffusionPropertyHelper propertyHelper( image ); propertyHelper.InitializeImage(); mitk::IOUtil::Save(image, out_folder + "/optimized.dwi"); proposal.SaveParameters(out_folder + "/optimized.ffp"); std::cout.rdbuf (old); // <-- restore accepted++; old_tdi_thr = new_tdi_thr; old_sqrt = new_sqrt; MITK_INFO << "Accepted (acc. rate " << (float)accepted/(i+1) << ")"; parameters = FiberfoxParameters(proposal); last_error = new_error; } MITK_INFO << "\n\n\n"; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorConstrainedPlausibility.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorConstrainedPlausibility.cpp index 42338774b9..0a616ad8bf 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorConstrainedPlausibility.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorConstrainedPlausibility.cpp @@ -1,575 +1,558 @@ /*=================================================================== 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 #include #include #include #include #include #include #include #include #include typedef itksys::SystemTools ist; typedef itk::Point PointType4; typedef itk::Image< float, 4 > PeakImgType; typedef itk::Image< unsigned char, 3 > ItkUcharImageType; std::vector< mitk::FiberBundle::Pointer > CombineTractograms(std::vector< mitk::FiberBundle::Pointer > reference, std::vector< mitk::FiberBundle::Pointer > candidates, int skip=-1) { std::vector< mitk::FiberBundle::Pointer > fib; for (auto f : reference) fib.push_back(f); int c = 0; for (auto f : candidates) { if (c!=skip) fib.push_back(f); ++c; } return fib; } std::vector< std::string > get_file_list(const std::string& path, std::vector< std::string > extensions={".fib", ".trk"}) { std::vector< std::string > file_list; itk::Directory::Pointer dir = itk::Directory::New(); if (dir->Load(path.c_str())) { int n = dir->GetNumberOfFiles(); for (int r = 0; r < n; r++) { const char *filename = dir->GetFile(r); std::string ext = ist::GetFilenameExtension(filename); for (auto e : extensions) { if (ext==e) { file_list.push_back(path + '/' + filename); break; } } } } return file_list; } /*! \brief Score input candidate tracts using ACP analysis */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Anchor Constrained Plausibility"); parser.setCategory("Fiber Tracking Evaluation"); parser.setDescription("Score input candidate tracts using ACP analysis"); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("", "a", mitkCommandLineParser::InputFile, "Anchor tractogram:", "anchor tracts in one tractogram file", us::Any(), false); parser.addArgument("", "p", mitkCommandLineParser::InputFile, "Input peaks:", "input peak image", us::Any(), false); parser.addArgument("", "c", mitkCommandLineParser::InputDirectory, "Candidates folder:", "folder containing candidate tracts", us::Any(), false); parser.addArgument("", "o", mitkCommandLineParser::OutputDirectory, "Output folder:", "output folder", us::Any(), false); parser.addArgument("anchor_masks", "", mitkCommandLineParser::StringList, "Reference Masks:", "reference tract masks for accuracy evaluation"); parser.addArgument("mask", "", mitkCommandLineParser::InputFile, "Mask image:", "scoring is only performed inside the mask image"); parser.addArgument("greedy_add", "", mitkCommandLineParser::Bool, "Greedy:", "if enabled, the candidate tracts are not jointly fitted to the residual image but one after the other employing a greedy scheme", false); parser.addArgument("lambda", "", mitkCommandLineParser::Float, "Lambda:", "modifier for regularization", 0.1); parser.addArgument("filter_outliers", "", mitkCommandLineParser::Bool, "Filter outliers:", "perform second optimization run with an upper weight bound based on the first weight estimation (99% quantile)", false); parser.addArgument("regu", "", mitkCommandLineParser::String, "Regularization:", "MSM, Variance, VoxelVariance, Lasso, GroupLasso, GroupVariance, NONE (default)"); parser.addArgument("use_num_streamlines", "", mitkCommandLineParser::Bool, "Use number of streamlines as score:", "Don't fit candidates, simply use number of streamlines per candidate as score", false); parser.addArgument("use_weights", "", mitkCommandLineParser::Bool, "Use input weights as score:", "Don't fit candidates, simply use first input streamline weight per candidate as score", false); parser.addArgument("filter_zero_weights", "", mitkCommandLineParser::Bool, "Filter zero-weights", "Remove streamlines with weight 0 from candidates", false); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string anchors_file = us::any_cast(parsedArgs["a"]); std::string peak_file_name = us::any_cast(parsedArgs["p"]); std::string candidate_tract_folder = us::any_cast(parsedArgs["c"]); std::string out_folder = us::any_cast(parsedArgs["o"]); bool greedy_add = false; if (parsedArgs.count("greedy_add")) greedy_add = us::any_cast(parsedArgs["greedy_add"]); float lambda = 0.1; if (parsedArgs.count("lambda")) lambda = us::any_cast(parsedArgs["lambda"]); bool filter_outliers = false; if (parsedArgs.count("filter_outliers")) filter_outliers = us::any_cast(parsedArgs["filter_outliers"]); bool filter_zero_weights = false; if (parsedArgs.count("filter_zero_weights")) filter_zero_weights = us::any_cast(parsedArgs["filter_zero_weights"]); std::string mask_file = ""; if (parsedArgs.count("mask")) mask_file = us::any_cast(parsedArgs["mask"]); mitkCommandLineParser::StringContainerType anchor_mask_files_folders; if (parsedArgs.count("anchor_masks")) anchor_mask_files_folders = us::any_cast(parsedArgs["anchor_masks"]); std::string regu = "NONE"; if (parsedArgs.count("regu")) regu = us::any_cast(parsedArgs["regu"]); bool use_weights = false; if (parsedArgs.count("use_weights")) use_weights = us::any_cast(parsedArgs["use_weights"]); bool use_num_streamlines = false; if (parsedArgs.count("use_num_streamlines")) use_num_streamlines = us::any_cast(parsedArgs["use_num_streamlines"]); try { itk::TimeProbe clock; clock.Start(); if (!ist::PathExists(out_folder)) { MITK_INFO << "Creating output directory"; ist::MakeDirectory(out_folder); } MITK_INFO << "Loading data"; std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect ofstream logfile; logfile.open (out_folder + "log.txt"); itk::ImageFileWriter< PeakImgType >::Pointer peak_image_writer = itk::ImageFileWriter< PeakImgType >::New(); mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Peak Image", "Fiberbundles"}, {}); mitk::Image::Pointer inputImage = dynamic_cast(mitk::IOUtil::Load(peak_file_name, &functor)[0].GetPointer()); - float minSpacing = 1; - if(inputImage->GetGeometry()->GetSpacing()[0]GetGeometry()->GetSpacing()[1] && inputImage->GetGeometry()->GetSpacing()[0]GetGeometry()->GetSpacing()[2]) - minSpacing = inputImage->GetGeometry()->GetSpacing()[0]; - else if (inputImage->GetGeometry()->GetSpacing()[1] < inputImage->GetGeometry()->GetSpacing()[2]) - minSpacing = inputImage->GetGeometry()->GetSpacing()[1]; - else - minSpacing = inputImage->GetGeometry()->GetSpacing()[2]; - // Load mask file. Fit is only performed inside the mask itk::FitFibersToImageFilter::UcharImgType::Pointer mask = nullptr; if (mask_file.compare("")!=0) { mitk::Image::Pointer mitk_mask = mitk::IOUtil::Load(mask_file); mitk::CastToItkImage(mitk_mask, mask); } // Load masks covering the true positives for evaluation purposes std::vector< itk::FitFibersToImageFilter::UcharImgType::Pointer > reference_masks; std::vector< std::string > anchor_mask_files; for (auto filename : anchor_mask_files_folders) { if (itksys::SystemTools::PathExists(filename)) { auto list = get_file_list(filename, {".nrrd",".nii.gz",".nii"}); for (auto f : list) { MITK_INFO << f; itk::FitFibersToImageFilter::UcharImgType::Pointer ref_mask = nullptr; mitk::Image::Pointer ref_mitk_mask = mitk::IOUtil::Load(f); mitk::CastToItkImage(ref_mitk_mask, ref_mask); reference_masks.push_back(ref_mask); anchor_mask_files.push_back(f); } } else if (itksys::SystemTools::FileExists(filename)) { anchor_mask_files.push_back(filename); itk::FitFibersToImageFilter::UcharImgType::Pointer ref_mask = nullptr; mitk::Image::Pointer ref_mitk_mask = mitk::IOUtil::Load(filename); mitk::CastToItkImage(ref_mitk_mask, ref_mask); reference_masks.push_back(ref_mask); } } // Load peak image typedef mitk::ImageToItk< PeakImgType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(inputImage); caster->Update(); PeakImgType::Pointer peak_image = caster->GetOutput(); // Load all candidate tracts std::vector< std::string > candidate_tract_files = get_file_list(candidate_tract_folder); std::vector< mitk::FiberBundle::Pointer > input_candidates; for (std::string f : candidate_tract_files) { mitk::FiberBundle::Pointer fib = mitk::IOUtil::Load(f); if (fib.IsNull()) continue; if (fib->GetNumFibers()<=0) continue; - fib->ResampleLinear(minSpacing/10.0); input_candidates.push_back(fib); } std::cout.rdbuf (old); // <-- restore MITK_INFO << "Loaded " << candidate_tract_files.size() << " candidate tracts."; MITK_INFO << "Loaded " << reference_masks.size() << " reference masks."; double rmse = 0.0; int iteration = 0; std::string name = "NOANCHOR"; // Load reference tractogram consisting of all known tracts std::vector< mitk::FiberBundle::Pointer > input_reference; mitk::FiberBundle::Pointer anchor_tractogram = mitk::IOUtil::Load(anchors_file); if ( !(anchor_tractogram.IsNull() || anchor_tractogram->GetNumFibers()==0) ) { - std::streambuf *old = cout.rdbuf(); // <-- save - std::stringstream ss; - std::cout.rdbuf (ss.rdbuf()); // <-- redirect - anchor_tractogram->ResampleLinear(minSpacing/10.0); - std::cout.rdbuf (old); // <-- restore input_reference.push_back(anchor_tractogram); // Fit known tracts to peak image to obtain underexplained image MITK_INFO << "Fit anchor tracts"; itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New(); fitter->SetTractograms(input_reference); fitter->SetLambda(lambda); fitter->SetFilterOutliers(filter_outliers); fitter->SetPeakImage(peak_image); fitter->SetVerbose(true); - fitter->SetResampleFibers(false); fitter->SetMaskImage(mask); fitter->SetRegularization(VnlCostFunction::REGU::NONE); fitter->Update(); rmse = fitter->GetRMSE(); vnl_vector rms_diff = fitter->GetRmsDiffPerBundle(); logfile << "RMS_DIFF: " << setprecision(5) << rms_diff[0] << " " << name << " RMSE: " << rmse << "\n"; name = ist::GetFilenameWithoutExtension(anchors_file); mitk::FiberBundle::Pointer anchor_tracts = fitter->GetTractograms().at(0); anchor_tracts->SetFiberColors(255,255,255); mitk::IOUtil::Save(anchor_tracts, out_folder + boost::lexical_cast((int)(100000*rms_diff[0])) + "_" + name + ".fib"); peak_image = fitter->GetUnderexplainedImage(); peak_image_writer->SetInput(peak_image); peak_image_writer->SetFileName(out_folder + "Residual_" + name + ".nii.gz"); peak_image_writer->Update(); } if (use_weights || use_num_streamlines) { MITK_INFO << "Using tract weights as scores"; int c = 0; for (auto fib : input_candidates) { int mod = 1; double score = 0; if (use_weights) { score = fib->GetFiberWeight(0); mod = 100000; } else if (use_num_streamlines) score = fib->GetNumFibers(); fib->ColorFibersByOrientation(); std::string bundle_name = ist::GetFilenameWithoutExtension(candidate_tract_files.at(c)); std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect mitk::IOUtil::Save(fib, out_folder + boost::lexical_cast((int)(mod*score)) + "_" + bundle_name + ".fib"); float best_overlap = 0; int best_overlap_index = -1; int m_idx = 0; for (auto ref_mask : reference_masks) { - float overlap = fib->GetOverlap(ref_mask, false); + float overlap = fib->GetOverlap(ref_mask); if (overlap>best_overlap) { best_overlap = overlap; best_overlap_index = m_idx; } ++m_idx; } unsigned int num_voxels = 0; { itk::TractDensityImageFilter< ItkUcharImageType >::Pointer masks_filter = itk::TractDensityImageFilter< ItkUcharImageType >::New(); masks_filter->SetInputImage(mask); masks_filter->SetBinaryOutput(true); masks_filter->SetFiberBundle(fib); masks_filter->SetUseImageGeometry(true); masks_filter->Update(); num_voxels = masks_filter->GetNumCoveredVoxels(); } double weight_sum = 0; for (int i=0; iGetNumFibers(); i++) weight_sum += fib->GetFiberWeight(i); std::cout.rdbuf (old); // <-- restore logfile << "RMS_DIFF: " << setprecision(5) << score << " " << bundle_name << " " << num_voxels << " " << fib->GetNumFibers() << " " << weight_sum << "\n"; if (best_overlap_index>=0) logfile << "Best_overlap: " << setprecision(5) << best_overlap << " " << ist::GetFilenameWithoutExtension(anchor_mask_files.at(best_overlap_index)) << "\n"; else logfile << "No_overlap\n"; ++c; } } else if (!greedy_add) { MITK_INFO << "Fit candidate tracts"; itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New(); fitter->SetLambda(lambda); fitter->SetFilterOutliers(filter_outliers); fitter->SetVerbose(true); fitter->SetPeakImage(peak_image); - fitter->SetResampleFibers(false); fitter->SetMaskImage(mask); fitter->SetTractograms(input_candidates); fitter->SetFitIndividualFibers(true); if (regu=="MSM") fitter->SetRegularization(VnlCostFunction::REGU::MSM); else if (regu=="Variance") fitter->SetRegularization(VnlCostFunction::REGU::VARIANCE); else if (regu=="Lasso") fitter->SetRegularization(VnlCostFunction::REGU::LASSO); else if (regu=="VoxelVariance") fitter->SetRegularization(VnlCostFunction::REGU::VOXEL_VARIANCE); else if (regu=="GroupLasso") fitter->SetRegularization(VnlCostFunction::REGU::GROUP_LASSO); else if (regu=="GroupVariance") fitter->SetRegularization(VnlCostFunction::REGU::GROUP_VARIANCE); else if (regu=="NONE") fitter->SetRegularization(VnlCostFunction::REGU::NONE); fitter->Update(); vnl_vector rms_diff = fitter->GetRmsDiffPerBundle(); // vnl_vector log_rms_diff = rms_diff-rms_diff.min_value() + 1; // log_rms_diff = log_rms_diff.apply(std::log); // log_rms_diff /= log_rms_diff.max_value(); int c = 0; for (auto fib : input_candidates) { // fib->SetFiberWeights( log_rms_diff[c] ); // fib->ColorFibersByOrientation(); std::string bundle_name = ist::GetFilenameWithoutExtension(candidate_tract_files.at(c)); std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect if (filter_zero_weights) fib = fib->FilterByWeights(0); mitk::IOUtil::Save(fib, out_folder + boost::lexical_cast((int)(100000*rms_diff[c])) + "_" + bundle_name + ".fib"); float best_overlap = 0; int best_overlap_index = -1; int m_idx = 0; for (auto ref_mask : reference_masks) { - float overlap = fib->GetOverlap(ref_mask, false); + float overlap = fib->GetOverlap(ref_mask); if (overlap>best_overlap) { best_overlap = overlap; best_overlap_index = m_idx; } ++m_idx; } unsigned int num_voxels = 0; { itk::TractDensityImageFilter< ItkUcharImageType >::Pointer masks_filter = itk::TractDensityImageFilter< ItkUcharImageType >::New(); masks_filter->SetInputImage(mask); masks_filter->SetBinaryOutput(true); masks_filter->SetFiberBundle(fib); masks_filter->SetUseImageGeometry(true); masks_filter->Update(); num_voxels = masks_filter->GetNumCoveredVoxels(); } double weight_sum = 0; for (int i=0; iGetNumFibers(); i++) weight_sum += fib->GetFiberWeight(i); std::cout.rdbuf (old); // <-- restore logfile << "RMS_DIFF: " << setprecision(5) << rms_diff[c] << " " << bundle_name << " " << num_voxels << " " << fib->GetNumFibers() << " " << weight_sum << "\n"; if (best_overlap_index>=0) logfile << "Best_overlap: " << setprecision(5) << best_overlap << " " << ist::GetFilenameWithoutExtension(anchor_mask_files.at(best_overlap_index)) << "\n"; else logfile << "No_overlap\n"; ++c; } mitk::FiberBundle::Pointer out_fib = mitk::FiberBundle::New(); out_fib = out_fib->AddBundles(input_candidates); out_fib->ColorFibersByFiberWeights(false, true); mitk::IOUtil::Save(out_fib, out_folder + "AllCandidates.fib"); peak_image = fitter->GetUnderexplainedImage(); peak_image_writer->SetInput(peak_image); peak_image_writer->SetFileName(out_folder + "Residual_AllCandidates.nii.gz"); peak_image_writer->Update(); } else { MITK_INFO << "RMSE: " << setprecision(5) << rmse; // fitter->SetPeakImage(peak_image); // Iteratively add candidate bundles in a greedy manner while (!input_candidates.empty()) { double next_rmse = rmse; double num_peaks = 0; mitk::FiberBundle::Pointer best_candidate = nullptr; PeakImgType::Pointer best_candidate_peak_image = nullptr; for (int i=0; i<(int)input_candidates.size(); ++i) { // WHY NECESSARY AGAIN?? itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New(); fitter->SetLambda(lambda); fitter->SetFilterOutliers(filter_outliers); fitter->SetVerbose(false); fitter->SetPeakImage(peak_image); - fitter->SetResampleFibers(false); fitter->SetMaskImage(mask); // ****************************** fitter->SetTractograms({input_candidates.at(i)}); std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect fitter->Update(); std::cout.rdbuf (old); // <-- restore double candidate_rmse = fitter->GetRMSE(); if (candidate_rmseGetNumCoveredDirections(); best_candidate = fitter->GetTractograms().at(0); best_candidate_peak_image = fitter->GetUnderexplainedImage(); } } if (best_candidate.IsNull()) break; // fitter->SetPeakImage(peak_image); peak_image = best_candidate_peak_image; int i=0; std::vector< mitk::FiberBundle::Pointer > remaining_candidates; std::vector< std::string > remaining_candidate_files; for (auto fib : input_candidates) { if (fib!=best_candidate) { remaining_candidates.push_back(fib); remaining_candidate_files.push_back(candidate_tract_files.at(i)); } else name = ist::GetFilenameWithoutExtension(candidate_tract_files.at(i)); ++i; } input_candidates = remaining_candidates; candidate_tract_files = remaining_candidate_files; iteration++; std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect // Save winning candidate if (filter_zero_weights) best_candidate = best_candidate->FilterByWeights(0); mitk::IOUtil::Save(best_candidate, out_folder + boost::lexical_cast(iteration) + "_" + name + ".fib"); peak_image_writer->SetInput(peak_image); peak_image_writer->SetFileName(out_folder + boost::lexical_cast(iteration) + "_" + name + ".nrrd"); peak_image_writer->Update(); // Calculate best overlap with reference masks for evaluation purposes float best_overlap = 0; int best_overlap_index = -1; i = 0; for (auto ref_mask : reference_masks) { - float overlap = best_candidate->GetOverlap(ref_mask, false); + float overlap = best_candidate->GetOverlap(ref_mask); if (overlap>best_overlap) { best_overlap = overlap; best_overlap_index = i; } ++i; } std::cout.rdbuf (old); // <-- restore logfile << "RMSE: " << setprecision(5) << rmse << " " << name << " " << num_peaks << "\n"; if (best_overlap_index>=0) logfile << "Best_overlap: " << setprecision(5) << best_overlap << " " << ist::GetFilenameWithoutExtension(anchor_mask_files.at(best_overlap_index)) << "\n"; else logfile << "No_overlap\n"; } } clock.Stop(); int h = clock.GetTotal()/3600; int m = ((int)clock.GetTotal()%3600)/60; int s = (int)clock.GetTotal()%60; MITK_INFO << "Plausibility estimation took " << h << "h, " << m << "m and " << s << "s"; logfile.close(); } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/RenderWindowManager/files.cmake b/Modules/RenderWindowManager/files.cmake index 5e95f08b7a..8d8bb99f84 100644 --- a/Modules/RenderWindowManager/files.cmake +++ b/Modules/RenderWindowManager/files.cmake @@ -1,19 +1,11 @@ set(H_FILES - include/QmitkRenderWindowDataModel.h - include/mitkRenderWindowLayerController.h - include/mitkRenderWindowViewDirectionController.h - include/mitkRenderWindowLayerUtilities.h + include/mitkRenderWindowViewDirectionController.h + include/mitkRenderWindowLayerUtilities.h ) set(CPP_FILES - QmitkRenderWindowDataModel.cpp - - mitkRenderWindowLayerController.cpp - mitkRenderWindowViewDirectionController.cpp - mitkRenderWindowLayerUtilities.cpp -) - -set(MOC_H_FILES - include/QmitkRenderWindowDataModel.h + mitkRenderWindowLayerController.cpp + mitkRenderWindowViewDirectionController.cpp + mitkRenderWindowLayerUtilities.cpp ) diff --git a/Modules/RenderWindowManager/include/QmitkRenderWindowDataModel.h b/Modules/RenderWindowManager/include/QmitkRenderWindowDataModel.h deleted file mode 100644 index b96a518bc2..0000000000 --- a/Modules/RenderWindowManager/include/QmitkRenderWindowDataModel.h +++ /dev/null @@ -1,69 +0,0 @@ -/*=================================================================== - -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 QMITKRENDERWINDOWDATAMODEL_H -#define QMITKRENDERWINDOWDATAMODEL_H - -// render window manager module -#include "MitkRenderWindowManagerExports.h" -#include "mitkRenderWindowLayerUtilities.h" - -//mitk core -#include -#include - -// qt -#include - -/* -* @brief This class extends the 'QAbstractTableModel' to meet the specific requirements of the QmitkRenderWindowDataModel. -*/ -class MITKRENDERWINDOWMANAGER_EXPORT QmitkRenderWindowDataModel : public QAbstractTableModel -{ - Q_OBJECT - -public: - - QmitkRenderWindowDataModel(QObject* parent = nullptr); - ~QmitkRenderWindowDataModel() override; - - ////////////////////////////////////////////////////////////////////////// - /// overridden functions from QAbstractItemModel - ////////////////////////////////////////////////////////////////////////// - Qt::ItemFlags flags(const QModelIndex &index) const override; - QVariant data(const QModelIndex &index, int role) const override; - QVariant headerData(int section, Qt::Orientation orientation, int role) const override; - int rowCount(const QModelIndex &parent = QModelIndex()) const override; - int columnCount(const QModelIndex &parent = QModelIndex()) const override; - bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; - ////////////////////////////////////////////////////////////////////////// - /// end override - ///////////////////////////////////////////////////////////////////////// - - void SetDataStorage(mitk::DataStorage::Pointer dataStorage); - void SetCurrentRenderer(std::string rendererName); - mitk::BaseRenderer* GetCurrentRenderer() const { return m_BaseRenderer.GetPointer(); } - void DataChanged(const mitk::DataNode* dataNode); - -private: - - mitk::DataStorage::Pointer m_DataStorage; - mitk::BaseRenderer::Pointer m_BaseRenderer; - RenderWindowLayerUtilities::LayerStack m_TempLayerStack; - -}; - -#endif // QMITKRENDERWINDOWDATAMODEL_H diff --git a/Modules/RenderWindowManager/src/QmitkRenderWindowDataModel.cpp b/Modules/RenderWindowManager/src/QmitkRenderWindowDataModel.cpp deleted file mode 100644 index a8888f8042..0000000000 --- a/Modules/RenderWindowManager/src/QmitkRenderWindowDataModel.cpp +++ /dev/null @@ -1,208 +0,0 @@ -/*=================================================================== - -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. - -===================================================================*/ - -// render window manager UI module -#include "QmitkRenderWindowDataModel.h" - -#include "QmitkCustomVariants.h" - -QmitkRenderWindowDataModel::QmitkRenderWindowDataModel(QObject* parent /*= nullptr*/) - : QAbstractTableModel(parent) -{ - // nothing here -} - -QmitkRenderWindowDataModel::~QmitkRenderWindowDataModel() -{ - if (m_DataStorage.IsNotNull()) - { - m_DataStorage->ChangedNodeEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkRenderWindowDataModel::DataChanged)); - m_DataStorage->RemoveNodeEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkRenderWindowDataModel::DataChanged)); - } -} - -int QmitkRenderWindowDataModel::rowCount(const QModelIndex &parent /*= QModelIndex()*/) const -{ - if (parent.isValid()) - { - return 0; - } - - return static_cast(m_TempLayerStack.size()); -} - -int QmitkRenderWindowDataModel::columnCount(const QModelIndex &parent /*= QModelIndex()*/) const -{ - if (parent.isValid()) - { - return 0; - } - - return 2; -} - -QVariant QmitkRenderWindowDataModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - { - return QVariant(); - } - - if ((index.row()) < static_cast(m_TempLayerStack.size())) - { - RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIt = m_TempLayerStack.begin(); - std::advance(layerStackIt, index.row()); - mitk::DataNode* dataNode = layerStackIt->second; - if (Qt::CheckStateRole == role && 0 == index.column()) - { - bool visibility = false; - dataNode->GetVisibility(visibility, m_BaseRenderer); - if (visibility) - { - return Qt::Checked; - } - else - { - return Qt::Unchecked; - } - } - else if (Qt::DisplayRole == role && 1 == index.column()) - { - return QVariant(QString::fromStdString(dataNode->GetName())); - } - else if (Qt::ToolTipRole == role) - { - if (0 == index.column()) - { - return QVariant("Show/hide data node."); - } - else if (1 == index.column()) - { - return QVariant("Name of the data node."); - } - } - else if (Qt::UserRole == role) - { - // user role always returns a reference to the data node, - // which can be used to modify the data node in the data storage - return QVariant::fromValue(dataNode); - } - } - return QVariant(); -} - -Qt::ItemFlags QmitkRenderWindowDataModel::flags(const QModelIndex &index) const -{ - Qt::ItemFlags flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; - if (0 == index.column()) - { - flags |= Qt::ItemIsUserCheckable; - } - - return flags; -} - -QVariant QmitkRenderWindowDataModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (Qt::Horizontal == orientation && Qt::DisplayRole == role) - { - if (0 == section) - { - return QVariant("Visibility"); - } - else if (1 == section) - { - return QVariant("Data node"); - } - } - return QVariant(); -} - -bool QmitkRenderWindowDataModel::setData(const QModelIndex &index, const QVariant &value, int role /*= Qt::EditRole*/) -{ - if (!index.isValid()) - { - return false; - } - - if ((index.row()) < static_cast(m_TempLayerStack.size())) - { - RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIt = m_TempLayerStack.begin(); - std::advance(layerStackIt, index.row()); - mitk::DataNode* dataNode = layerStackIt->second; - if (Qt::CheckStateRole == role) - { - Qt::CheckState newCheckState = static_cast(value.toInt()); - - if (Qt::PartiallyChecked == newCheckState || Qt::Checked == newCheckState) - { - dataNode->SetVisibility(true, m_BaseRenderer); - } - else - { - dataNode->SetVisibility(false, m_BaseRenderer); - } - emit dataChanged(index, index); - mitk::RenderingManager::GetInstance()->RequestUpdate(m_BaseRenderer->GetRenderWindow()); - return true; - } - } - return false; -} - -void QmitkRenderWindowDataModel::SetDataStorage(mitk::DataStorage::Pointer dataStorage) -{ - if (m_DataStorage != dataStorage) - { - // given data storage is a new data storage - if (m_DataStorage.IsNotNull()) - { - // remove listener from old data storage - m_DataStorage->ChangedNodeEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkRenderWindowDataModel::DataChanged)); - m_DataStorage->RemoveNodeEvent.RemoveListener(mitk::MessageDelegate1(this, &QmitkRenderWindowDataModel::DataChanged)); - } - // set the new data storage - m_DataStorage = dataStorage; - // register new data storage listener - if (m_DataStorage.IsNotNull()) - { - m_DataStorage->ChangedNodeEvent.AddListener(mitk::MessageDelegate1(this, &QmitkRenderWindowDataModel::DataChanged)); - m_DataStorage->RemoveNodeEvent.AddListener(mitk::MessageDelegate1(this, &QmitkRenderWindowDataModel::DataChanged)); - } - DataChanged(nullptr); - } -} - -void QmitkRenderWindowDataModel::SetCurrentRenderer(std::string renderWindowName) -{ - m_BaseRenderer = mitk::BaseRenderer::GetByName(renderWindowName); - if (m_DataStorage.IsNotNull()) - { - DataChanged(nullptr); - } -} - -void QmitkRenderWindowDataModel::DataChanged(const mitk::DataNode* /*dataNode*/) -{ - if (m_BaseRenderer.IsNotNull()) - { - // update the model, so that the table will be filled with the nodes information of the new data storage - beginResetModel(); - // get the current layer stack of the given base renderer - m_TempLayerStack = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage, m_BaseRenderer, true); - endResetModel(); - } -} diff --git a/Modules/RenderWindowManagerUI/files.cmake b/Modules/RenderWindowManagerUI/files.cmake index a998c3cf7f..a350cab98c 100644 --- a/Modules/RenderWindowManagerUI/files.cmake +++ b/Modules/RenderWindowManagerUI/files.cmake @@ -1,15 +1,18 @@ set(H_FILES include/QmitkRenderWindowManipulatorWidget.h + include/QmitkDataStorageLayerStackModel.h ) set(CPP_FILES QmitkRenderWindowManipulatorWidget.cpp + QmitkDataStorageLayerStackModel.cpp ) set(MOC_H_FILES include/QmitkRenderWindowManipulatorWidget.h + include/QmitkDataStorageLayerStackModel.h ) set(UI_FILES src/QmitkRenderWindowManipulatorWidget.ui ) \ No newline at end of file diff --git a/Modules/RenderWindowManagerUI/include/QmitkDataStorageLayerStackModel.h b/Modules/RenderWindowManagerUI/include/QmitkDataStorageLayerStackModel.h new file mode 100644 index 0000000000..d106d23db8 --- /dev/null +++ b/Modules/RenderWindowManagerUI/include/QmitkDataStorageLayerStackModel.h @@ -0,0 +1,93 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 QMITKDATASTORAGELAYERSTACKMODEL_H +#define QMITKDATASTORAGELAYERSTACKMODEL_H + +// render window manager UI module +#include "MitkRenderWindowManagerUIExports.h" + +// render window manager module +#include "mitkRenderWindowLayerUtilities.h" + +// qt widgets module +#include + +/** +* @brief The 'QmitkDataStorageLayerStackModel' is a customized table model, derived from the 'QmitkAbstractDataStorageModel'. +* It provides functions to accept a data storage and a node predicate in order to customize the model data nodes. +* Furthermore it overrides the functions of 'QAbstractItemModel' to create a customized qt table model. +* This model can be used in conjunction with a 'QmitkDataStorageSelectionConnector'. +*/ +class MITKRENDERWINDOWMANAGERUI_EXPORT QmitkDataStorageLayerStackModel : public QmitkAbstractDataStorageModel +{ + Q_OBJECT + +public: + + QmitkDataStorageLayerStackModel(QObject* parent = nullptr); + + // override from 'QmitkAbstractDataStorageModel' + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void DataStorageChanged() override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodePredicateChanged() override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeAdded(const mitk::DataNode* node) override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeChanged(const mitk::DataNode* node) override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeRemoved(const mitk::DataNode* node) override; + + void SetCurrentRenderer(const std::string& rendererName); + + mitk::BaseRenderer* GetCurrentRenderer() const; + + ////////////////////////////////////////////////////////////////////////// + /// overridden functions from QAbstractItemModel + ////////////////////////////////////////////////////////////////////////// + QModelIndex index(int row, int column, const QModelIndex& parent) const; + QModelIndex parent(const QModelIndex& child) const; + Qt::ItemFlags flags(const QModelIndex& index) const override; + QVariant headerData(int section, Qt::Orientation orientation, int role) const override; + int rowCount(const QModelIndex& parent = QModelIndex()) const override; + int columnCount(const QModelIndex& parent = QModelIndex()) const override; + QVariant data(const QModelIndex& index, int role) const override; + bool setData(const QModelIndex& index, const QVariant& value, int role = Qt::EditRole) override; + ////////////////////////////////////////////////////////////////////////// + /// end override + ///////////////////////////////////////////////////////////////////////// + +private: + + void UpdateModelData(); + + mitk::WeakPointer m_BaseRenderer; + RenderWindowLayerUtilities::LayerStack m_TempLayerStack; + +}; + +#endif // QMITKDATASTORAGELAYERSTACKMODEL_H diff --git a/Modules/RenderWindowManagerUI/include/QmitkRenderWindowManipulatorWidget.h b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowManipulatorWidget.h index e08edafbce..c863b88052 100644 --- a/Modules/RenderWindowManagerUI/include/QmitkRenderWindowManipulatorWidget.h +++ b/Modules/RenderWindowManagerUI/include/QmitkRenderWindowManipulatorWidget.h @@ -1,108 +1,114 @@ /*=================================================================== 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 QMITKRENDERWINDOWMANIPULATORWIDGET_H #define QMITKRENDERWINDOWMANIPULATORWIDGET_H // render window manager UI module #include "MitkRenderWindowManagerUIExports.h" #include "ui_QmitkRenderWindowManipulatorWidget.h" +#include // render window manager module #include #include -#include // qt #include /** * The QmitkRenderWindowManipulatorWidget offers a GUI to manipulate the base renderer / render windows of the MITK workbench. * The widgets supports adding a layer to an active render window, moving layers up and down, removing layers, * resetting layers (hiding them) or removing all layers at once. * * In order to use this widget, a (e.g.) plugin has to set the controlled renderer, which will be forwarded to * a render window layer controller and a render window view direction controller. * The plugin also has to provide a Q_SLOT that is connected to the 'AddLayerButtonClicked'-Q_SIGNAL of this widget. * This allows for a customized add-layer functionality. */ class MITKRENDERWINDOWMANAGERUI_EXPORT QmitkRenderWindowManipulatorWidget : public QWidget { Q_OBJECT public: QmitkRenderWindowManipulatorWidget(mitk::DataStorage::Pointer dataStorage, QWidget* parent = nullptr); /** + * @brief Get the table view that displays the layer stack inside this widget + */ + QTableView* GetLayerStackTableView(); + /** * @brief Set the controlled base renderer. */ void SetControlledRenderer(RenderWindowLayerUtilities::RendererVector controlledRenderer); /** * @brief Set the currently selected render window * * @param renderWindowId the text inside the combo box */ void SetActiveRenderWindow(const QString &renderWindowId); /** * @brief Use the RenderWindowLayerController to insert the given data node into the currently active render window. * The new node is placed on top of all existing layer nodes in that render window. * * @param dataNode The data node that should be inserted. */ void AddLayer(mitk::DataNode* dataNode); /** * @brief Use the RenderWindowLayerController to insert the given data node into all controlled render windows. * The new node is placed on top of all existing layer nodes in the render window. * * @param dataNode The data node that should be inserted. */ void AddLayerToAllRenderer(mitk::DataNode* dataNode); /** * @brief Use the RenderWindowLayerController to hide the given data node in the currently active render window. * * @param dataNode The data node that should be hid. */ void HideDataNodeInAllRenderer(const mitk::DataNode* dataNode); Q_SIGNALS: + void AddLayerButtonClicked(); private Q_SLOTS: void RemoveLayer(); void SetAsBaseLayer(); void MoveLayer(const QString &direction); void ResetRenderer(); void ClearRenderer(); void ChangeViewDirection(const QString &viewDirection); private: void Init(); void SetUpConnections(); Ui::QmitkRenderWindowManipulatorWidget m_Controls; mitk::DataStorage::Pointer m_DataStorage; - std::unique_ptr m_RenderWindowDataModel; std::unique_ptr m_RenderWindowLayerController; std::unique_ptr m_RenderWindowViewDirectionController; + + QmitkDataStorageLayerStackModel* m_StorageModel; }; #endif // QMITKRENDERWINDOWMANIPULATORWIDGET_H diff --git a/Modules/RenderWindowManagerUI/src/QmitkDataStorageLayerStackModel.cpp b/Modules/RenderWindowManagerUI/src/QmitkDataStorageLayerStackModel.cpp new file mode 100644 index 0000000000..e4f627fffc --- /dev/null +++ b/Modules/RenderWindowManagerUI/src/QmitkDataStorageLayerStackModel.cpp @@ -0,0 +1,238 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +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 + +// qt widgets module +#include "QmitkCustomVariants.h" +#include "QmitkEnums.h" + +QmitkDataStorageLayerStackModel::QmitkDataStorageLayerStackModel(QObject* parent/* = nullptr*/) + : QmitkAbstractDataStorageModel(parent) +{ + // nothing here +} + +void QmitkDataStorageLayerStackModel::DataStorageChanged() +{ + UpdateModelData(); +} + +void QmitkDataStorageLayerStackModel::NodePredicateChanged() +{ + UpdateModelData(); +} + +void QmitkDataStorageLayerStackModel::NodeAdded(const mitk::DataNode* /*node*/) +{ + // nothing here; layers (nodes) are only added after button click +} + +void QmitkDataStorageLayerStackModel::NodeChanged(const mitk::DataNode* /*node*/) +{ + UpdateModelData(); +} + +void QmitkDataStorageLayerStackModel::NodeRemoved(const mitk::DataNode* /*node*/) +{ + UpdateModelData(); +} + +void QmitkDataStorageLayerStackModel::SetCurrentRenderer(const std::string& renderWindowName) +{ + if (!m_DataStorage.IsExpired()) + { + m_BaseRenderer = mitk::BaseRenderer::GetByName(renderWindowName); + UpdateModelData(); + } +} + +mitk::BaseRenderer* QmitkDataStorageLayerStackModel::GetCurrentRenderer() const +{ + return m_BaseRenderer.Lock(); +} + +QModelIndex QmitkDataStorageLayerStackModel::index(int row, int column, const QModelIndex& parent) const +{ + bool hasIndex = this->hasIndex(row, column, parent); + if (hasIndex) + { + return this->createIndex(row, column); + } + + return QModelIndex(); +} + +QModelIndex QmitkDataStorageLayerStackModel::parent(const QModelIndex& /*child*/) const +{ + return QModelIndex(); +} + +Qt::ItemFlags QmitkDataStorageLayerStackModel::flags(const QModelIndex& index) const +{ + Qt::ItemFlags flags = Qt::NoItemFlags; + if (index.isValid() && index.model() == this) + { + flags = Qt::ItemIsEnabled | Qt::ItemIsSelectable; + if (0 == index.column()) + { + flags |= Qt::ItemIsUserCheckable; + } + } + + return flags; +} + +QVariant QmitkDataStorageLayerStackModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (Qt::Horizontal == orientation && Qt::DisplayRole == role) + { + if (0 == section) + { + return QVariant("Visibility"); + } + else if (1 == section) + { + return QVariant("Data node"); + } + } + return QVariant(); +} + +int QmitkDataStorageLayerStackModel::rowCount(const QModelIndex& parent/* = QModelIndex()*/) const +{ + if (parent.isValid()) + { + return 0; + } + + return static_cast(m_TempLayerStack.size()); +} + +int QmitkDataStorageLayerStackModel::columnCount(const QModelIndex& parent/* = QModelIndex()*/) const +{ + if (parent.isValid()) + { + return 0; + } + + return 2; +} + +QVariant QmitkDataStorageLayerStackModel::data(const QModelIndex& index, int role) const +{ + if (!index.isValid() || index.model() != this) + { + return QVariant(); + } + + if ((index.row()) < 0 || index.row() >= static_cast(m_TempLayerStack.size())) + { + return QVariant(); + } + + RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIt = m_TempLayerStack.begin(); + std::advance(layerStackIt, index.row()); + mitk::DataNode* dataNode = layerStackIt->second; + if (Qt::CheckStateRole == role && 0 == index.column()) + { + bool visibility = false; + dataNode->GetVisibility(visibility, m_BaseRenderer.Lock()); + if (visibility) + { + return Qt::Checked; + } + else + { + return Qt::Unchecked; + } + } + else if (Qt::DisplayRole == role && 1 == index.column()) + { + return QVariant(QString::fromStdString(dataNode->GetName())); + } + else if (Qt::ToolTipRole == role) + { + if (0 == index.column()) + { + return QVariant("Show/hide data node."); + } + else if (1 == index.column()) + { + return QVariant("Name of the data node."); + } + } + else if (QmitkDataNodeRole == role) + { + return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); + } + else if (QmitkDataNodeRawPointerRole == role) + { + return QVariant::fromValue(dataNode); + } + + return QVariant(); +} + +bool QmitkDataStorageLayerStackModel::setData(const QModelIndex &index, const QVariant &value, int role /*= Qt::EditRole*/) +{ + if (!index.isValid() || index.model() != this) + { + return false; + } + + if ((index.row()) < 0 || index.row() >= static_cast(m_TempLayerStack.size())) + { + return false; + } + + if (!m_BaseRenderer.IsExpired()) + { + auto baseRenderer = m_BaseRenderer.Lock(); + + RenderWindowLayerUtilities::LayerStack::const_iterator layerStackIt = m_TempLayerStack.begin(); + std::advance(layerStackIt, index.row()); + mitk::DataNode* dataNode = layerStackIt->second; + if (Qt::CheckStateRole == role) + { + Qt::CheckState newCheckState = static_cast(value.toInt()); + + if (Qt::PartiallyChecked == newCheckState || Qt::Checked == newCheckState) + { + dataNode->SetVisibility(true, baseRenderer); + } + else + { + dataNode->SetVisibility(false, baseRenderer); + } + emit dataChanged(index, index); + mitk::RenderingManager::GetInstance()->RequestUpdate(baseRenderer->GetRenderWindow()); + return true; + } + } + + return false; +} + +void QmitkDataStorageLayerStackModel::UpdateModelData() +{ + // update the model, so that the table will be filled with the nodes according to the current + // data storage and base renderer + beginResetModel(); + // get the current layer stack of the given base renderer + m_TempLayerStack = RenderWindowLayerUtilities::GetLayerStack(m_DataStorage.Lock(), m_BaseRenderer.Lock(), true); + endResetModel(); +} diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.cpp b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.cpp index c8ecd4bee7..cb8ad4eb8e 100644 --- a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.cpp +++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.cpp @@ -1,216 +1,272 @@ /*=================================================================== 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. ===================================================================*/ // render window manager UI module #include "QmitkRenderWindowManipulatorWidget.h" +// qt widgets module #include "QmitkCustomVariants.h" +#include "QmitkEnums.h" // mitk core #include // qt #include QmitkRenderWindowManipulatorWidget::QmitkRenderWindowManipulatorWidget(mitk::DataStorage::Pointer dataStorage, QWidget* parent /*=nullptr*/) : QWidget(parent) , m_DataStorage(dataStorage) + , m_StorageModel(nullptr) { Init(); } void QmitkRenderWindowManipulatorWidget::Init() { - // create GUI from the Qt Designer's .ui file m_Controls.setupUi(this); // initialize the render window layer controller and the render window view direction controller // and set the controller renderer (in constructor) and the data storage m_RenderWindowLayerController = std::make_unique(); m_RenderWindowViewDirectionController = std::make_unique(); m_RenderWindowLayerController->SetDataStorage(m_DataStorage); m_RenderWindowViewDirectionController->SetDataStorage(m_DataStorage); - // create a new model - m_RenderWindowDataModel = std::make_unique(this); - m_RenderWindowDataModel->SetDataStorage(m_DataStorage); + m_Controls.layerStackTableView->setEditTriggers(QAbstractItemView::NoEditTriggers); + m_Controls.layerStackTableView->horizontalHeader()->setStretchLastSection(true); + m_Controls.layerStackTableView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.layerStackTableView->setSelectionMode(QAbstractItemView::SingleSelection); - m_Controls.renderWindowTableView->setModel(m_RenderWindowDataModel.get()); - m_Controls.renderWindowTableView->setEditTriggers(QAbstractItemView::NoEditTriggers); - m_Controls.renderWindowTableView->horizontalHeader()->setStretchLastSection(true); - m_Controls.renderWindowTableView->setSelectionBehavior(QAbstractItemView::SelectRows); - m_Controls.renderWindowTableView->setSelectionMode(QAbstractItemView::SingleSelection); + m_StorageModel = new QmitkDataStorageLayerStackModel(this); + m_StorageModel->SetDataStorage(m_DataStorage); + + m_Controls.layerStackTableView->setModel(m_StorageModel); SetUpConnections(); } void QmitkRenderWindowManipulatorWidget::SetUpConnections() { // signal to signal connection connect(m_Controls.pushButtonAddLayer, SIGNAL(clicked()), this, SIGNAL(AddLayerButtonClicked())); connect(m_Controls.pushButtonRemoveLayer, SIGNAL(clicked()), this, SLOT(RemoveLayer())); connect(m_Controls.pushButtonSetAsBaseLayer, SIGNAL(clicked()), this, SLOT(SetAsBaseLayer())); QSignalMapper* udSignalMapper = new QSignalMapper(this); udSignalMapper->setMapping(m_Controls.pushButtonMoveUp, QString("up")); udSignalMapper->setMapping(m_Controls.pushButtonMoveDown, QString("down")); connect(udSignalMapper, SIGNAL(mapped(const QString&)), this, SLOT(MoveLayer(const QString&))); connect(m_Controls.pushButtonMoveUp, SIGNAL(clicked()), udSignalMapper, SLOT(map())); connect(m_Controls.pushButtonMoveDown, SIGNAL(clicked()), udSignalMapper, SLOT(map())); connect(m_Controls.pushButtonResetRenderer, SIGNAL(clicked()), this, SLOT(ResetRenderer())); connect(m_Controls.pushButtonClearRenderer, SIGNAL(clicked()), this, SLOT(ClearRenderer())); QSignalMapper* changeViewDirectionSignalMapper = new QSignalMapper(this); changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonAxial, QString("axial")); changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonCoronal, QString("coronal")); changeViewDirectionSignalMapper->setMapping(m_Controls.radioButtonSagittal, QString("sagittal")); connect(changeViewDirectionSignalMapper, SIGNAL(mapped(const QString&)), this, SLOT(ChangeViewDirection(const QString&))); connect(m_Controls.radioButtonAxial, SIGNAL(clicked()), changeViewDirectionSignalMapper, SLOT(map())); connect(m_Controls.radioButtonCoronal, SIGNAL(clicked()), changeViewDirectionSignalMapper, SLOT(map())); connect(m_Controls.radioButtonSagittal, SIGNAL(clicked()), changeViewDirectionSignalMapper, SLOT(map())); } +QTableView* QmitkRenderWindowManipulatorWidget::GetLayerStackTableView() +{ + return m_Controls.layerStackTableView; +} + void QmitkRenderWindowManipulatorWidget::SetControlledRenderer(RenderWindowLayerUtilities::RendererVector controlledRenderer) { m_RenderWindowLayerController->SetControlledRenderer(controlledRenderer); m_RenderWindowViewDirectionController->SetControlledRenderer(controlledRenderer); } void QmitkRenderWindowManipulatorWidget::SetActiveRenderWindow(const QString &renderWindowId) { + if (nullptr == m_StorageModel) + { + return; + } + std::string currentRendererName = renderWindowId.toStdString(); - m_RenderWindowDataModel->SetCurrentRenderer(currentRendererName); + m_StorageModel->SetCurrentRenderer(currentRendererName); mitk::BaseRenderer* selectedRenderer = mitk::BaseRenderer::GetByName(currentRendererName); if (nullptr == selectedRenderer) { return; } mitk::SliceNavigationController::ViewDirection viewDirection = selectedRenderer->GetSliceNavigationController()->GetDefaultViewDirection(); switch (viewDirection) { case mitk::SliceNavigationController::Axial: m_Controls.radioButtonAxial->setChecked(true); break; case mitk::SliceNavigationController::Frontal: m_Controls.radioButtonCoronal->setChecked(true); break; case mitk::SliceNavigationController::Sagittal: m_Controls.radioButtonSagittal->setChecked(true); break; default: break; } } void QmitkRenderWindowManipulatorWidget::AddLayer(mitk::DataNode* dataNode) { - m_RenderWindowLayerController->InsertLayerNode(dataNode, -1, m_RenderWindowDataModel->GetCurrentRenderer()); + if (nullptr == m_StorageModel) + { + return; + } + + m_RenderWindowLayerController->InsertLayerNode(dataNode, -1, m_StorageModel->GetCurrentRenderer()); } void QmitkRenderWindowManipulatorWidget::AddLayerToAllRenderer(mitk::DataNode* dataNode) { m_RenderWindowLayerController->InsertLayerNode(dataNode, -1, nullptr); } void QmitkRenderWindowManipulatorWidget::HideDataNodeInAllRenderer(const mitk::DataNode* dataNode) { m_RenderWindowLayerController->HideDataNodeInAllRenderer(dataNode); } void QmitkRenderWindowManipulatorWidget::RemoveLayer() { - QModelIndex selectedIndex = m_Controls.renderWindowTableView->currentIndex(); + if (nullptr == m_StorageModel) + { + return; + } + + QModelIndex selectedIndex = m_Controls.layerStackTableView->currentIndex(); if (selectedIndex.isValid()) { - QVariant qvariantDataNode = m_RenderWindowDataModel->data(selectedIndex, Qt::UserRole); + QVariant qvariantDataNode = m_StorageModel->data(selectedIndex, QmitkDataNodeRawPointerRole); if (qvariantDataNode.canConvert()) { mitk::DataNode* dataNode = qvariantDataNode.value(); - m_RenderWindowLayerController->RemoveLayerNode(dataNode, m_RenderWindowDataModel->GetCurrentRenderer()); - m_Controls.renderWindowTableView->clearSelection(); + m_RenderWindowLayerController->RemoveLayerNode(dataNode, m_StorageModel->GetCurrentRenderer()); + m_Controls.layerStackTableView->clearSelection(); } } } void QmitkRenderWindowManipulatorWidget::SetAsBaseLayer() { - QModelIndex selectedIndex = m_Controls.renderWindowTableView->currentIndex(); + if (nullptr == m_StorageModel) + { + return; + } + + QModelIndex selectedIndex = m_Controls.layerStackTableView->currentIndex(); if (selectedIndex.isValid()) { - QVariant qvariantDataNode = m_RenderWindowDataModel->data(selectedIndex, Qt::UserRole); + QVariant qvariantDataNode = m_StorageModel->data(selectedIndex, QmitkDataNodeRawPointerRole); if (qvariantDataNode.canConvert()) { mitk::DataNode* dataNode = qvariantDataNode.value(); - m_RenderWindowLayerController->SetBaseDataNode(dataNode, m_RenderWindowDataModel->GetCurrentRenderer()); - m_Controls.renderWindowTableView->clearSelection(); + m_RenderWindowLayerController->SetBaseDataNode(dataNode, m_StorageModel->GetCurrentRenderer()); + m_Controls.layerStackTableView->clearSelection(); } } } void QmitkRenderWindowManipulatorWidget::MoveLayer(const QString &direction) { - QModelIndex selectedIndex = m_Controls.renderWindowTableView->currentIndex(); + if (nullptr == m_StorageModel) + { + return; + } + + QModelIndex selectedIndex = m_Controls.layerStackTableView->currentIndex(); if (selectedIndex.isValid()) { - QVariant qvariantDataNode = m_RenderWindowDataModel->data(selectedIndex, Qt::UserRole); + QVariant qvariantDataNode = m_StorageModel->data(selectedIndex, QmitkDataNodeRawPointerRole); if (qvariantDataNode.canConvert()) { mitk::DataNode* dataNode = qvariantDataNode.value(); - const mitk::BaseRenderer* selectedRenderer = m_RenderWindowDataModel->GetCurrentRenderer(); + const mitk::BaseRenderer* selectedRenderer = m_StorageModel->GetCurrentRenderer(); bool success = false; if ("up" == direction) { success = m_RenderWindowLayerController->MoveNodeUp(dataNode, selectedRenderer); if (success) { // node has been successfully moved up - m_Controls.renderWindowTableView->selectRow(selectedIndex.row() - 1); + QTableView* tableView = dynamic_cast(m_Controls.layerStackTableView); + if (nullptr != tableView) + { + tableView->selectRow(selectedIndex.row() - 1); + } } } else { success = m_RenderWindowLayerController->MoveNodeDown(dataNode, selectedRenderer); if (success) { // node has been successfully moved down - m_Controls.renderWindowTableView->selectRow(selectedIndex.row() + 1); + QTableView* tableView = dynamic_cast(m_Controls.layerStackTableView); + if (nullptr != tableView) + { + tableView->selectRow(selectedIndex.row() + 1); + } } } } } } void QmitkRenderWindowManipulatorWidget::ResetRenderer() { - m_RenderWindowLayerController->ResetRenderer(true, m_RenderWindowDataModel->GetCurrentRenderer()); - m_Controls.renderWindowTableView->clearSelection(); + if (nullptr == m_StorageModel) + { + return; + } + + m_RenderWindowLayerController->ResetRenderer(true, m_StorageModel->GetCurrentRenderer()); + m_Controls.layerStackTableView->clearSelection(); } void QmitkRenderWindowManipulatorWidget::ClearRenderer() { - m_RenderWindowLayerController->ResetRenderer(false, m_RenderWindowDataModel->GetCurrentRenderer()); - m_Controls.renderWindowTableView->clearSelection(); + if (nullptr == m_StorageModel) + { + return; + } + + m_RenderWindowLayerController->ResetRenderer(false, m_StorageModel->GetCurrentRenderer()); + m_Controls.layerStackTableView->clearSelection(); } void QmitkRenderWindowManipulatorWidget::ChangeViewDirection(const QString &viewDirection) { - m_RenderWindowViewDirectionController->SetViewDirectionOfRenderer(viewDirection.toStdString(), m_RenderWindowDataModel->GetCurrentRenderer()); + if (nullptr == m_StorageModel) + { + return; + + } + + m_RenderWindowViewDirectionController->SetViewDirectionOfRenderer(viewDirection.toStdString(), m_StorageModel->GetCurrentRenderer()); } diff --git a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.ui b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.ui index 01e6a1b05f..b0db32738a 100644 --- a/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.ui +++ b/Modules/RenderWindowManagerUI/src/QmitkRenderWindowManipulatorWidget.ui @@ -1,120 +1,120 @@ QmitkRenderWindowManipulatorWidget 0 0 308 246 0 0 0 0 Render window manager Render window overview - + Add Layer Remove layer Set as base layer Move up Move down Reset render window Clear render window Axial true Coronal Sagittal diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsDataViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsDataViewControls.ui index e7196a043c..30c38e39f9 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsDataViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsDataViewControls.ui @@ -1,299 +1,278 @@ QmitkConnectomicsDataViewControls 0 0 286 639 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 Input Data 6 6 6 6 QLabel { color: rgb(255, 0, 0) } Select a parcellation and a tractogram! Image 1: - Image 2: - Network Creation Options 6 6 6 6 Create a network from a parcellation and a fiber image Networkify Create Correlation Matrix true Synthetic Network Options 6 6 6 6 Parameter 2 false 3 999.899999999999977 Parameter 1 false 9999 Create Synthetic Networks 0 0 Anatomical labeling 6 6 6 6 Qt::Vertical 20 40 QmitkFreeSurferParcellationWidget QWidget
QmitkFreeSurferParcellationWidget.h
1
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsNetworkOperationsViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsNetworkOperationsViewControls.ui index 50883169d6..f82c28053d 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsNetworkOperationsViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsNetworkOperationsViewControls.ui @@ -1,306 +1,285 @@ QmitkConnectomicsNetworkOperationsViewControls 0 0 283 639 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 Data 6 6 6 6 QLabel { color: rgb(255, 0, 0) } Select a network or a parcellation! Image 1: - Convert the selected image to RGBA format Turn Into RGBA Image Assign FreeSurfer Colors Divide in Modules Connectivity Matrix Image Options 6 6 6 6 Create Connectivity Matrix Image Rescale Binary Prune Options 6 6 6 6 Prune Network Target Density 1.000000000000000 0.010000000000000 Target Threshold Threshold weight Threshold Below Density Random Removal Threshold Qt::Vertical 20 40 \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsStatisticsViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsStatisticsViewControls.ui index 1610d78f61..fccdcfe848 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsStatisticsViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkConnectomicsStatisticsViewControls.ui @@ -1,317 +1,296 @@ QmitkConnectomicsStatisticsViewControls 0 0 557 1218 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 Input Data 6 6 6 6 Network: Network Statistics 6 6 6 6 true 0 0 true Informational Balloons. 6 6 6 6 false PointingHandCursor Qt::RightToLeft true false false -1 12 QComboBox::InsertAlphabetically 0 0 MS Shell Dlg 2 8 IBeamCursor false true Histograms 6 6 6 6 0 0 50 150 50 150 50 150 Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkNetworkHistogramCanvas QWidget
internal/QmitkNetworkHistogramCanvas.h
1
networkBalloonsNodeLabelsComboBox currentIndexChanged(int) networkBalloonsNodeLabelsComboBox setCurrentIndex(int) 360 409 360 409
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkRandomParcellationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkRandomParcellationViewControls.ui index 0078a5b273..0e6a66e144 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkRandomParcellationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/QmitkRandomParcellationViewControls.ui @@ -1,343 +1,322 @@ QmitkRandomParcellationViewControls true 0 0 327 591 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 QLabel { color: rgb(255, 0, 0) } Please select an image! true Nodes false 6 6 6 6 true Choose the number of nodes: 2 5000 true Merging 6 6 6 6 Merging on false QFrame::NoFrame QFrame::Raised 0 0 0 0 According to the number of parcels false QFrame::StyledPanel QFrame::Raised 0 0 0 Number of Parcels: 1 5000 According to the size of parcels false QFrame::StyledPanel QFrame::Raised 0 0 0 Size of the smallest parcel: 2 100000 Just merge small parcels false Do image processing Select random nodes Qt::Vertical 20 40 Counting 6 6 6 6 Number of voxels with value 1: Number of nodes: \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.denoising/src/internal/QmitkDenoisingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.denoising/src/internal/QmitkDenoisingViewControls.ui index 7f732f0e06..f803e29af7 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.denoising/src/internal/QmitkDenoisingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.denoising/src/internal/QmitkDenoisingViewControls.ui @@ -1,375 +1,354 @@ QmitkDenoisingViewControls 0 0 351 734 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 9 9 9 9 25 QFrame::NoFrame QFrame::Raised 0 0 0 0 Input Image: Total-variation Discrete Gaussian Non-local means Filter: Parameters 6 6 6 6 Lambda: 4 0.000000000000000 1.000000000000000 0.100000000000000 0.100000000000000 Iterations: 1 999 1 Parameters 6 6 6 6 Sampling Radius: 1 999 10 1 999 4 1 999 4 Num. Patches: 1 50 1 Iterations: Patch Size: Parameters 6 6 6 6 4 1.000000000000000 99999.000000000000000 0.100000000000000 1.000000000000000 Variance: Start Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxViewControls.ui index 9228e80e1e..b6a77c5b76 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFiberfoxViewControls.ui @@ -1,3608 +1,3687 @@ - + QmitkFiberfoxViewControls 0 0 463 875 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { - border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; -} - -QGroupBox { - background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; -} + + + + Load Parameters - :/QmitkDiffusionImaging/general_icons/upload.ico -:/QmitkDiffusionImaging/general_icons/upload.ico + :/QmitkDiffusionImaging/general_icons/upload.ico:/QmitkDiffusionImaging/general_icons/upload.ico + + + Save Parameters - :/QmitkDiffusionImaging/general_icons/download.ico -:/QmitkDiffusionImaging/general_icons/download.ico + :/QmitkDiffusionImaging/general_icons/download.ico:/QmitkDiffusionImaging/general_icons/download.ico - + + + 75 + true + + + + + + + + + 0 + 0 + 431 + 2692 + + Signal Generation 25 QFrame::NoFrame QFrame::Raised 0 0 0 0 true <html><head/><body><p>Start DWI generation from selected fiber bundle.</p><p>If no fiber bundle but an existing diffusion weighted image is selected, the enabled artifacts are added to this image.</p><p>If neither a fiber bundle nor a diffusion weighted image is selected, a grayscale image containing a simple gradient is generated.</p></body></html> + + + Start Simulation - :/QmitkDiffusionImaging/general_icons/right.ico -:/QmitkDiffusionImaging/general_icons/right.ico + :/QmitkDiffusionImaging/general_icons/right.ico:/QmitkDiffusionImaging/general_icons/right.ico + + QGroupBox { + background-color: transparent; +} + Input Data 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 - ... <html><head/><body><p>Select a binary image to define the area of signal generation. Outside of the mask image only noise will be actively generated.</p></body></html> QComboBox::AdjustToMinimumContentsLength - + - + - + Fiber Bundle: false - + - + - + Save path: false - + - + - + Tissue Mask: false <html><head/><body><p>Select a fiber bundle to generate the white matter signal from. You can either use the fiber definition tab to manually define an input fiber bundle or you can also use any existing bundle, e.g. yielded by a tractography algorithm.</p></body></html> QComboBox::AdjustToMinimumContentsLength - + - + - + Template Image: false <html><head/><body><p>The parameters for the simulation (e.g. spacing, size, diffuison-weighted gradients, b-value) are adopted from this image.</p></body></html> QComboBox::AdjustToMinimumContentsLength true Stop current simulation. + + + Abort Simulation - :/QmitkDiffusionImaging/general_icons/abort.ico -:/QmitkDiffusionImaging/general_icons/abort.ico + :/QmitkDiffusionImaging/general_icons/abort.ico:/QmitkDiffusionImaging/general_icons/abort.ico Courier 7 true + + QGroupBox { + background-color: transparent; +} + Extra-axonal Compartments 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 Volume Fraction: - + Select signal model for extra-axonal compartment. Ball Model Astrosticks Model Dot Model Prototype Signal - + - + - + - + Qt::Horizontal QFrame::NoFrame QFrame::Raised 0 0 0 0 Volume Fraction: Optional! If no volume fraction map for this compartment is set, the corresponding volume fractions are calculated from the input fibers. - + - + - + Select signal model for extra-axonal compartment. -- Ball Model Astrosticks Model Dot Model Prototype Signal - + + + QGroupBox { + background-color: transparent; +} + Intra-axonal Compartment 6 6 6 6 - + - + - + Select signal model for intra-axonal compartment. Stick Model Zeppelin Model Tensor Model Prototype Signal - + QFrame::NoFrame QFrame::Raised 0 0 0 0 Volume Fraction: Optional! If no volume fraction map for this compartment is set, the corresponding volume fractions are calculated from the input fibers. + + QGroupBox { + background-color: transparent; +} + Image Settings 6 6 6 6 Advanced Options QFrame::NoFrame QFrame::Raised 0 0 0 0 6 Gradient Directions: Number of gradient directions distributed over the half sphere. 0 10000 1 30 - + - + - + - <html><head/><body><p>b-Value<span style=" font-style:italic;"> [s/mm</span><span style=" font-style:italic; vertical-align:super;">2</span><span style=" font-style:italic;">]</span>:</p></body></html> + <html><head/><body><p>b-Value<span style=" font-style:italic;"> [s/mm</span><span style=" font-style:italic; vertical-align:super;">2</span><span style=" font-style:italic;">]</span>:</p></body></html> false b-value in s/mm² 0 10000 100 1000 color: rgb(255, 0, 0); Using geometry of selected image! color: rgb(255, 0, 0); Using gradients of selected DWI! QFrame::NoFrame QFrame::Raised 0 0 0 0 6 - + - + - + <html><head/><body><p>Number of Channels:</p></body></html> false TR in milliseconds 1 999999999 1 4000 Output one image per compartment containing the corresponding volume fractions per voxel. Reverse Phase Encoding Direction false Signal Scale: Dwell time (time to read one line in k-space) in ms. 100.000000000000000 0.100000000000000 1.000000000000000 TE in milliseconds 1 999999999 1 100 Fiber Radius: - + - + - + Partial Fourier: false Disable partial volume. Treat voxel content as fiber-only if at least one fiber is present. Disable Partial Volume Effects false - + - + - + <html><head/><body><p>Coil Sensitivity:</p></body></html> false Partial fourier factor (0.5-1) 3 0.500000000000000 1.000000000000000 0.100000000000000 1.000000000000000 Output phase image and volume fraction maps. Output Additional Images false Relaxation time due to magnetic field inhomogeneities (T2', in milliseconds). 1 10000 1 50 - + - + - + - <html><head/><body><p>Repetition Time <span style=" font-style:italic;">TR</span>: </p></body></html> + <html><head/><body><p>Repetition Time <span style=" font-style:italic;">TR</span>: </p></body></html> false Constant Linear Exponential - + - + - + Dwell Time: false - + - + - + - <html><head/><body><p><span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> Relaxation: </p></body></html> + <html><head/><body><p><span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> Relaxation: </p></body></html> false - <html><head/><body><p><span style=" font-style:italic;">TE</span>, <span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> and <span style=" font-style:italic;">T2</span> will have no effect if unchecked.</p></body></html> + <html><head/><body><p><span style=" font-style:italic;">TE</span>, <span style=" font-style:italic;">T</span><span style=" font-style:italic; vertical-align:sub;">inhom</span> and <span style=" font-style:italic;">T2</span> will have no effect if unchecked.</p></body></html> Simulate Signal Relaxation true - + - + - + - <html><head/><body><p>Echo Time <span style=" font-style:italic;">TE</span>: </p></body></html> + <html><head/><body><p>Echo Time <span style=" font-style:italic;">TE</span>: </p></body></html> false TE in milliseconds 1 10000 1 100 Number of coil elements used for the acquisiton. 1 128 1 1 Acquisition Type: Single Shot EPI Spin Echo Fiber radius used to calculate volume fractions (in µm). Set to 0 for automatic radius estimation. 9999.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 3 0.100000000000000 50.000000000000000 0.100000000000000 2.000000000000000 Image Spacing: 3 0.100000000000000 50.000000000000000 0.100000000000000 2.000000000000000 3 0.100000000000000 50.000000000000000 0.100000000000000 2.000000000000000 Image Dimensions: Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 1000 1 20 Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 1000 1 20 Fiber sampling factor which determines the accuracy of the calculated fiber and non-fiber volume fractions. 1 1000 1 3 + + QGroupBox { + background-color: transparent; +} + Inter-axonal Compartment 6 6 6 6 Select signal model for intra-axonal compartment. -- Stick Model Zeppelin Model Tensor Model - + - + - + - + QFrame::NoFrame QFrame::Raised 0 0 0 0 Volume Fraction: Optional! If no volume fraction map for this compartment is set, the corresponding volume fractions are calculated from the input fibers. + + QGroupBox { + background-color: transparent; +} + Noise and other Artifacts 6 6 6 6 Add Distortions false Add Spikes false true QFrame::NoFrame QFrame::Raised QFormLayout::AllNonFixedFieldsGrow 6 0 0 0 0 - + - + - + Gradient: false Eddy current induced magnetic field gradient (in mT/m). 4 1000.000000000000000 0.001000000000000 0.010000000000000 Add Motion Artifacts false Qt::Horizontal true QFrame::NoFrame QFrame::Raised 6 0 0 0 0 - + - + - + K-Space Line Offset: false A larger offset increases the inensity of the ghost image. 3 1.000000000000000 0.010000000000000 0.250000000000000 Add Noise false QFrame::NoFrame QFrame::Raised 0 0 0 0 Num. Spikes: The number of randomly occurring signal spikes. 1 Spike amplitude relative to the largest signal amplitude of the corresponding k-space slice. 0.100000000000000 0.100000000000000 Scale: true QFrame::NoFrame QFrame::Raised 0 6 0 0 6 Toggle between random movement and linear movement. Randomize motion true + + QGroupBox { + background-color: transparent; +} + Rotation 6 9 6 6 - + - + - + Degree: false - + - + - + x false - + - + - + Axis: false Maximum rotation around x-axis. 1 -360.000000000000000 360.000000000000000 1.000000000000000 0.000000000000000 Maximum rotation around z-axis. 1 -360.000000000000000 360.000000000000000 1.000000000000000 15.000000000000000 - + - + - + y false - + - + - + z false Maximum rotation around y-axis. 1 -360.000000000000000 360.000000000000000 1.000000000000000 0.000000000000000 + + QGroupBox { + background-color: transparent; +} + Translation 6 6 6 - + - + - + Distance: false - + - + - + x false - + - + - + y false - + - + - + Axis: false - + - + - + z false Maximum translation along x-axis. 1 -1000.000000000000000 1000.000000000000000 1.000000000000000 0.000000000000000 Maximum translation along y-axis. 1 -1000.000000000000000 1000.000000000000000 1.000000000000000 0.000000000000000 Maximum translation along z-axis. 1 -1000.000000000000000 1000.000000000000000 1.000000000000000 0.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 Motion volumes: - Type in the volume indices that should be affected by motion (e.g. "0 3 7" whithout quotation marks). Leave blank for motion in all volumes. Type in "random" to randomly select volumes for motion. A list of negative numbers (e.g. -1 -2 -3) excludes volumes (e.g. 1 2 3) selects all remaining volumes. + Type in the volume indices that should be affected by motion (e.g. "0 3 7" whithout quotation marks). Leave blank for motion in all volumes. Type in "random" to randomly select volumes for motion. A list of negative numbers (e.g. -1 -2 -3) excludes volumes (e.g. 1 2 3) selects all remaining volumes. random Add ringing artifacts occuring at strong edges in the image. Add Gibbs Ringing false Qt::Horizontal Qt::Horizontal Qt::Horizontal Qt::Horizontal Add N/2 Ghosts false Add Aliasing false Qt::Horizontal Qt::Horizontal - + Add Eddy Current Effects false true QFrame::NoFrame QFrame::Raised 6 0 0 0 0 - + - + - + Shrink FOV (%): false Shrink FOV by this percentage. 1 0.000000000000000 90.000000000000000 0.100000000000000 25.000000000000000 true QFrame::NoFrame QFrame::Raised 6 0 0 0 0 - + - + - + Frequency Map: false Select image specifying the frequency inhomogeneities (in Hz). QFrame::NoFrame QFrame::Raised 0 0 0 0 Variance: Variance of selected noise distribution. 10 0.000000000000000 999999999.000000000000000 0.001000000000000 50.000000000000000 Distribution: Noise distribution Complex Gaussian Rician - + + + + 0 + 0 + 431 + 979 + + Fiber Definition 25 Qt::Vertical 20 40 color: rgb(255, 0, 0); - Please select an image or an existing fiber bundle to draw the fiber fiducials. If you can't provide a suitable image, generate one using the "Signal Generation" tab. + Please select an image or an existing fiber bundle to draw the fiber fiducials. If you can't provide a suitable image, generate one using the "Signal Generation" tab. Qt::AutoText Qt::AlignJustify|Qt::AlignVCenter true + + QGroupBox { + background-color: transparent; +} + Fiducial Options 6 6 6 6 All fiducials are treated as circles with the same radius as the first fiducial. Use Constant Fiducial Radius false false Align selected fiducials with voxel grid. Shifts selected fiducials to nearest voxel center. + + QCommandLinkButton:disabled { + border: none; +} + Align With Grid - :/QmitkDiffusionImaging/general_icons/right.ico -:/QmitkDiffusionImaging/general_icons/right.ico + :/QmitkDiffusionImaging/general_icons/right.ico:/QmitkDiffusionImaging/general_icons/right.ico + + QGroupBox { + background-color: transparent; +} + Operations 6 6 6 6 false + + QCommandLinkButton:disabled { + border: none; +} + Join Bundles - :/QmitkDiffusionImaging/general_icons/plus.ico -:/QmitkDiffusionImaging/general_icons/plus.ico + :/QmitkDiffusionImaging/general_icons/plus.ico:/QmitkDiffusionImaging/general_icons/plus.ico QFrame::NoFrame QFrame::Raised 0 0 0 0 - + - + - + Y false Rotation angle (in degree) around x-axis. 3 -360.000000000000000 360.000000000000000 0.100000000000000 - + - + - + Axis: false Rotation angle (in degree) around y-axis. 3 -360.000000000000000 360.000000000000000 0.100000000000000 - + - + - + Translation: false Translation (in mm) in direction of the z-axis. 3 -1000.000000000000000 1000.000000000000000 0.100000000000000 Translation (in mm) in direction of the y-axis. 3 -1000.000000000000000 1000.000000000000000 0.100000000000000 - + - + - + X false - + - + - + Rotation: false - + - + - + Z false Rotation angle (in degree) around z-axis. 3 -360.000000000000000 360.000000000000000 0.100000000000000 Translation (in mm) in direction of the x-axis. 3 -1000.000000000000000 1000.000000000000000 0.100000000000000 - + - + - + Scaling: false Scaling factor for selected fiber bundle along the x-axis. 0.010000000000000 10.000000000000000 0.010000000000000 1.000000000000000 Scaling factor for selected fiber bundle along the y-axis. 0.010000000000000 10.000000000000000 0.010000000000000 1.000000000000000 Scaling factor for selected fiber bundle along the z-axis. 0.010000000000000 10.000000000000000 0.010000000000000 1.000000000000000 false + + QCommandLinkButton:disabled { + border: none; +} + Copy Bundles - :/QmitkDiffusionImaging/general_icons/copy2.ico -:/QmitkDiffusionImaging/general_icons/copy2.ico + :/QmitkDiffusionImaging/general_icons/copy2.ico:/QmitkDiffusionImaging/general_icons/copy2.ico false + + QCommandLinkButton:disabled { + border: none; +} + Transform Selection - :/QmitkDiffusionImaging/general_icons/refresh.ico -:/QmitkDiffusionImaging/general_icons/refresh.ico + :/QmitkDiffusionImaging/general_icons/refresh.ico:/QmitkDiffusionImaging/general_icons/refresh.ico If checked, the fiducials belonging to the modified bundle are also modified. Include Fiducials true + + QGroupBox { + background-color: transparent; +} + Fiber Options 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 - + - + - + Tension: false - + - + - + Fiber Sampling: false - + 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 - + - + - + Bias: false - + - + - + Continuity: false 3 -1.000000000000000 1.000000000000000 0.100000000000000 0.000000000000000 Distance of fiber sampling points (in mm) 1 0.100000000000000 0.100000000000000 1.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 6 - + - + - + #Fibers: false Specify number of fibers to generate for the selected bundle. 1 1000000 100 100 false + + QCommandLinkButton:disabled { + border: none; +} + Generate Fibers - :/QmitkDiffusionImaging/general_icons/right.ico -:/QmitkDiffusionImaging/general_icons/right.ico + :/QmitkDiffusionImaging/general_icons/right.ico:/QmitkDiffusionImaging/general_icons/right.ico QFrame::NoFrame QFrame::Raised 0 0 0 0 Select fiber distribution inside of the fiducials. Uniform Gaussian - + - + - + Fiber Distribution: false Variance of the gaussian 3 0.001000000000000 10.000000000000000 0.010000000000000 0.100000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 - Disable to only generate fibers if "Generate Fibers" button is pressed. + Disable to only generate fibers if "Generate Fibers" button is pressed. Real Time Fibers true - Disable to only generate fibers if "Generate Fibers" button is pressed. + Disable to only generate fibers if "Generate Fibers" button is pressed. Advanced Options false QFrame::NoFrame QFrame::Raised 0 0 0 0 false 30 30 Draw elliptical fiducial. - + - :/QmitkDiffusionImaging/circle.png -:/QmitkDiffusionImaging/circle.png + :/QmitkDiffusionImaging/circle.png:/QmitkDiffusionImaging/circle.png 32 32 false true false 30 30 Flip fiber waypoints of selcted fiducial around one axis. - + - :/QmitkDiffusionImaging/general_icons/refresh.ico -:/QmitkDiffusionImaging/general_icons/refresh.ico + :/QmitkDiffusionImaging/general_icons/refresh.ico:/QmitkDiffusionImaging/general_icons/refresh.ico 32 32 false true Qt::Horizontal 40 20 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
QmitkTensorModelParametersWidget QWidget
QmitkTensorModelParametersWidget.h
1
QmitkStickModelParametersWidget QWidget
QmitkStickModelParametersWidget.h
1
QmitkZeppelinModelParametersWidget QWidget
QmitkZeppelinModelParametersWidget.h
1
QmitkBallModelParametersWidget QWidget
QmitkBallModelParametersWidget.h
1
QmitkAstrosticksModelParametersWidget QWidget
QmitkAstrosticksModelParametersWidget.h
1
QmitkDotModelParametersWidget QWidget
QmitkDotModelParametersWidget.h
1
QmitkPrototypeSignalParametersWidget QWidget
QmitkPrototypeSignalParametersWidget.h
1
m_CircleButton m_FlipButton m_RealTimeFibers m_AdvancedOptionsBox m_DistributionBox m_VarianceBox m_FiberDensityBox m_FiberSamplingBox m_TensionBox m_ContinuityBox m_BiasBox m_GenerateFibersButton m_ConstantRadiusBox m_AlignOnGrid m_XrotBox m_YrotBox m_ZrotBox m_XtransBox m_YtransBox m_ZtransBox m_XscaleBox m_YscaleBox m_ZscaleBox m_TransformBundlesButton m_CopyBundlesButton m_JoinBundlesButton m_IncludeFiducials m_FiberBundleComboBox m_MaskComboBox m_TemplateComboBox m_SavePathEdit m_OutputPathButton m_SizeX m_SizeY m_SizeZ m_SpacingX m_SpacingY m_SpacingZ m_NumGradientsBox m_BvalueBox m_AdvancedOptionsBox_2 m_SignalScaleBox m_TEbox m_TRbox m_LineReadoutTimeBox m_PartialFourier m_T2starBox m_FiberRadius m_ReversePhaseBox m_RelaxationBox m_EnforcePureFiberVoxelsBox m_VolumeFractionsBox m_Compartment1Box m_Comp1VolumeFraction m_Compartment2Box m_Comp2VolumeFraction m_Compartment3Box m_Comp3VolumeFraction m_Compartment4Box m_Comp4VolumeFraction m_AddNoise m_NoiseDistributionBox m_NoiseLevel m_AddSpikes m_SpikeNumBox m_SpikeScaleBox m_AddGhosts m_kOffsetBox m_AddAliasing m_WrapBox m_AddDistortions m_FrequencyMapBox m_AddMotion m_RandomMotion m_MaxRotationBoxX m_MaxRotationBoxY m_MaxRotationBoxZ m_MaxTranslationBoxX m_MaxTranslationBoxY m_MaxTranslationBoxZ m_AddEddy m_EddyGradientStrength m_AddGibbsRinging m_SaveParametersButton m_LoadParametersButton toolBox - + - -
\ No newline at end of file + + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFieldmapGeneratorViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFieldmapGeneratorViewControls.ui index 58600b9fab..4f15c732be 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFieldmapGeneratorViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/QmitkFieldmapGeneratorViewControls.ui @@ -1,407 +1,386 @@ QmitkFieldmapGeneratorViewControls 0 0 358 536 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 9 9 9 9 25 QFrame::NoFrame QFrame::Raised 0 0 0 0 Place Field Source QFrame::NoFrame QFrame::Raised 0 0 0 0 World Coordinates: - Index: - Generate Fieldmap Please Select Reference Image 6 6 6 6 Add Gradient 6 6 6 6 Gradient x: z: 4 -1000.000000000000000 1000.000000000000000 4 -1000.000000000000000 1000.000000000000000 y: 4 -1000.000000000000000 1000.000000000000000 Offset 4 -1000.000000000000000 1000.000000000000000 4 -1000.000000000000000 1000.000000000000000 4 -1000.000000000000000 1000.000000000000000 Qt::Vertical QSizePolicy::Expanding 20 220 Edit Selected Source 6 6 6 6 Name: Height: Variance: - 999999.000000000000000 999999.000000000000000 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberClusteringViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberClusteringViewControls.ui index 83c5746932..22d11ae3eb 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberClusteringViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberClusteringViewControls.ui @@ -1,545 +1,524 @@ QmitkFiberClusteringViewControls 0 0 474 683 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 Qt::Vertical 20 40 Metrics 6 6 6 6 Weighting factor for metric values. 1 999.000000000000000 1.000000000000000 Euclidean true Weighting factor for metric values. 1 999.000000000000000 1.000000000000000 Euclidean STDEV Weighting factor for metric values. 1 999.000000000000000 1.000000000000000 Euclidean Maximum Weighting factor for metric values. 1 999.000000000000000 1.000000000000000 Weighting factor for metric values. 1 999.000000000000000 1.000000000000000 Inner Angles Weighting factor for metric values. 1 999.000000000000000 1.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 6 Distance is based on the selected parcellation. Anatomical Distance is based on the selected parcellation. Weighting factor for metric values. 1 999.000000000000000 30.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 Distance is based on the scalar map values along the tract. Scalar Map Distance is based on the scalar map values along the tract. Streamline Length Input Data 6 6 6 6 Input Centroids: If set, the input tractogram is clustered around the input centroids and no new clusters are created. false 0 0 200 16777215 11 Start Tractogram: Parameters Only output clusters with ate least the specified number of fibers. 1 9999999 50 Only output the N largest clusters. Zero means no limit. 99999999 10 Min. Fibers per Cluster: Max. Clusters: Fiber Points: Merge duplicate clusters withthe specified distance threshold. If threshold is < 0, the threshold is set to half of the specified cluster size. -1.000000000000000 99999.000000000000000 0.000000000000000 Cluster Size: Cluster size in mm. 1 9999999 20 Fibers are resampled to the desired number of points for clustering. Smaller is faster but less accurate. 2 9999999 12 Merge Duplicate Clusters: Output Centroids: QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberFitViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberFitViewControls.ui index 1712aaae56..521636a52e 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberFitViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberFitViewControls.ui @@ -1,245 +1,224 @@ QmitkFiberFitViewControls 0 0 484 574 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } QFrame::NoFrame QFrame::Raised 0 0 0 0 6 false Output Residuals: Weight for regularization. 999999.000000000000000 0.100000000000000 0.100000000000000 Tractogram: false 0 0 200 16777215 11 Start λ: Image: false Suppress Outliers: Regularization: Voxel-wise Variance Variance Mean Squared Magnitude Lasso None Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui index e155a9b83e..8a38651dfc 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberProcessingViewControls.ui @@ -1,1620 +1,1603 @@ - + QmitkFiberProcessingViewControls 0 0 385 684 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 9 9 9 9 + + + 75 + true + + 0 5 0 0 353 441 Fiber Extraction Extract a fiber subset from the selected fiber bundle using manually placed planar figures as waypoints or binary regions of interest. false 0 0 200 16777215 11 Extract fibers passing through selected ROI or composite ROI. Select ROI and fiber bundle to execute. Extract Qt::Vertical 20 40 QFrame::NoFrame QFrame::Raised 0 0 0 0 6 Interactive Extraction 0 0 200 0 16777215 60 QFrame::NoFrame QFrame::Raised 0 0 0 0 30 30 Draw circular ROI. Select reference fiber bundle to execute. - + - :/QmitkDiffusionImaging/circle.png -:/QmitkDiffusionImaging/circle.png + :/QmitkDiffusionImaging/circle.png:/QmitkDiffusionImaging/circle.png 32 32 false true Qt::Horizontal 40 20 30 30 Draw polygonal ROI. Select reference fiber bundle to execute. - + - :/QmitkDiffusionImaging/polygon.png -:/QmitkDiffusionImaging/polygon.png + :/QmitkDiffusionImaging/polygon.png:/QmitkDiffusionImaging/polygon.png 32 32 true true 0 0 200 0 16777215 60 QFrame::NoFrame QFrame::Raised 0 0 0 0 false 60 16777215 Create NOT composition from selected ROI. NOT false 60 16777215 Create OR composition with selected ROIs. OR Qt::Horizontal 40 20 false 60 16777215 Create AND composition with selected ROIs. AND false 0 0 16777215 16777215 11 Generate a binary image containing all selected ROIs. Select at least one ROI (planar figure) and a reference fiber bundle or image. Generate ROI Image 0 0 Extract using planar figures Extract using ROI image QFrame::NoFrame QFrame::Raised 0 0 0 0 Min. overlap: Extract fibers: Both ends true - Minimum overlap of streamlines and ROI in terms of streamline length. Zero means that one streamline point inside the ROI is enough to be considered as "overlapping". + Minimum overlap of streamlines and ROI in terms of streamline length. Zero means that one streamline point inside the ROI is enough to be considered as "overlapping". 3 1.000000000000000 0.100000000000000 0 0 Ending in ROI Not ending in ROI Passing ROI Not passing ROI Interpolate ROI true Threshold: Threshold on ROI image for positions to be considered as positive. 3 9999.000000000000000 0.100000000000000 0.500000000000000 0 0 367 408 Fiber Removal Remove fibers that satisfy certain criteria from the selected bundle. QFrame::NoFrame QFrame::Raised 0 0 0 0 If unchecked, the fiber exceeding the threshold will be split in two instead of removed. Remove Fiber false QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Max. Angular Deviation: Qt::Horizontal 40 20 Maximum angular deviation in degree 180.000000000000000 0.100000000000000 30.000000000000000 Distance: Distance in mm 1 999.000000000000000 1.000000000000000 10.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 X: Y: - + - + Z: - + Angle: Angular deviation threshold in degree 1 90.000000000000000 1.000000000000000 25.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 Qt::Horizontal 40 20 Minimum fiber length in mm 0 999999999 20 Max. Length: Min. Length: Maximum fiber length in mm 0 999999999 300 false 0 0 200 16777215 11 - + Remove Qt::Vertical 20 40 0 0 Remove fibers in direction Remove fibers by length Remove fibers by curvature Remove fiber parts outside mask Remove fiber parts inside mask Remove fibers by weight QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Weight threshold: Only fibers with weight larger than this threshold are kept. 5 99999.000000000000000 0.100000000000000 0 0 367 408 Bundle Modification Modify the selected bundle with operations such as fiber resampling, FA coloring, etc. QFrame::NoFrame QFrame::Raised 0 0 0 0 0 6 Error threshold in mm: 999999999.000000000000000 0.100000000000000 0.100000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 6 Sagittal Coronal Axial Select direction: QFrame::NoFrame QFrame::Raised 0 0 0 0 0 6 If checked, the image values are not only used to color the fibers but are also used as opaxity values. Values as opacity false - + Scalar map: The values used to color the fibers are min-max normalized. If not checked, the values should be between 0 and 1. Normalize values true 0 0 Resample fibers (spline) Resample fibers (linear) Compress fibers Color fibers by scalar map (e.g. FA) Mirror fibers Weight bundle Color fibers by curvature Color fibers by fiber weights Color fibers by length QFrame::NoFrame QFrame::Raised 0 0 0 0 0 6 0.010000000000000 999999999.000000000000000 0.100000000000000 1.000000000000000 Point distance in mm: Qt::Vertical 20 40 false 0 0 200 16777215 11 - + Execute QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Weight: 7 999999999.000000000000000 0.100000000000000 1.000000000000000 0 0 367 - 172 + 168 Bundle Operations Join, subtract or copy bundles. false 0 0 200 16777215 11 Returns all fibers contained in bundle X that are not contained in bundle Y (not commutative!). Select at least two fiber bundles to execute. Substract Qt::Vertical 20 40 false 0 0 200 16777215 11 Merge selected fiber bundles. Select at least two fiber bundles to execute. Join false 0 0 200 16777215 11 Merge selected fiber bundles. Select at least two fiber bundles to execute. Copy Please Select Input Data 6 6 6 6 - <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> + <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> true - <html><head/><body><p><span style=" color:#969696;">needed for extraction</span></p></body></html> + <html><head/><body><p><span style=" color:#969696;">needed for extraction</span></p></body></html> true Input DTI Fiber Bundle: Binary seed ROI. If not specified, the whole image area is seeded. ROI: Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
- - + + - -
\ No newline at end of file + + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp index aca647f8fe..336ebe38cd 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp @@ -1,441 +1,440 @@ /*=================================================================== 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 "QmitkFiberQuantificationView.h" // Qt #include // MITK #include #include #include #include #include #include #include #include // ITK #include #include #include #include #include const std::string QmitkFiberQuantificationView::VIEW_ID = "org.mitk.views.fiberquantification"; using namespace mitk; QmitkFiberQuantificationView::QmitkFiberQuantificationView() : QmitkAbstractView() , m_Controls( 0 ) , m_UpsamplingFactor(5) , m_Visible(false) { } // Destructor QmitkFiberQuantificationView::~QmitkFiberQuantificationView() { } void QmitkFiberQuantificationView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkFiberQuantificationViewControls; m_Controls->setupUi( parent ); connect( m_Controls->m_ProcessFiberBundleButton, SIGNAL(clicked()), this, SLOT(ProcessSelectedBundles()) ); connect( m_Controls->m_ExtractFiberPeaks, SIGNAL(clicked()), this, SLOT(CalculateFiberDirections()) ); m_Controls->m_TractBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isFib = mitk::TNodePredicateDataType::New(); m_Controls->m_TractBox->SetPredicate( isFib ); m_Controls->m_ImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_ImageBox->SetZeroEntryText("--"); mitk::TNodePredicateDataType::Pointer isImagePredicate = mitk::TNodePredicateDataType::New(); mitk::NodePredicateDimension::Pointer is3D = mitk::NodePredicateDimension::New(3); m_Controls->m_ImageBox->SetPredicate( mitk::NodePredicateAnd::New(isImagePredicate, is3D) ); connect( (QObject*)(m_Controls->m_TractBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); connect( (QObject*)(m_Controls->m_ImageBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); } } void QmitkFiberQuantificationView::Activated() { } void QmitkFiberQuantificationView::Deactivated() { } void QmitkFiberQuantificationView::Visible() { m_Visible = true; } void QmitkFiberQuantificationView::Hidden() { m_Visible = false; } void QmitkFiberQuantificationView::SetFocus() { m_Controls->m_ProcessFiberBundleButton->setFocus(); } void QmitkFiberQuantificationView::CalculateFiberDirections() { typedef itk::Image ItkUcharImgType; // load fiber bundle mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(m_SelectedFB.back()->GetData()); itk::TractsToVectorImageFilter::Pointer fOdfFilter = itk::TractsToVectorImageFilter::New(); if (m_SelectedImage.IsNotNull()) { ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); mitk::CastToItkImage(m_SelectedImage, itkMaskImage); fOdfFilter->SetMaskImage(itkMaskImage); } // extract directions from fiber bundle fOdfFilter->SetFiberBundle(inputTractogram); fOdfFilter->SetAngularThreshold(cos(m_Controls->m_AngularThreshold->value()*itk::Math::pi/180)); switch (m_Controls->m_FiberDirNormBox->currentIndex()) { case 0: fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::GLOBAL_MAX); break; case 1: fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::SINGLE_VEC_NORM); break; case 2: fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::MAX_VEC_NORM); break; } - fOdfFilter->SetUseWorkingCopy(true); fOdfFilter->SetSizeThreshold(m_Controls->m_PeakThreshold->value()); fOdfFilter->SetMaxNumDirections(m_Controls->m_MaxNumDirections->value()); fOdfFilter->Update(); QString name = m_SelectedFB.back()->GetName().c_str(); if (m_Controls->m_NumDirectionsBox->isChecked()) { mitk::Image::Pointer mitkImage = mitk::Image::New(); mitkImage->InitializeByItk( fOdfFilter->GetNumDirectionsImage().GetPointer() ); mitkImage->SetVolume( fOdfFilter->GetNumDirectionsImage()->GetBufferPointer() ); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(mitkImage); node->SetName((name+"_NUM_DIRECTIONS").toStdString().c_str()); GetDataStorage()->Add(node, m_SelectedFB.back()); } Image::Pointer mitkImage = dynamic_cast(PeakImage::New().GetPointer()); mitk::CastToMitkImage(fOdfFilter->GetDirectionImage(), mitkImage); mitkImage->SetVolume(fOdfFilter->GetDirectionImage()->GetBufferPointer()); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(mitkImage); node->SetName( (name+"_DIRECTIONS").toStdString().c_str()); GetDataStorage()->Add(node, m_SelectedFB.back()); } void QmitkFiberQuantificationView::UpdateGui() { m_SelectedFB.clear(); if (m_Controls->m_TractBox->GetSelectedNode().IsNotNull()) m_SelectedFB.push_back(m_Controls->m_TractBox->GetSelectedNode()); m_SelectedImage = nullptr; if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) m_SelectedImage = dynamic_cast(m_Controls->m_ImageBox->GetSelectedNode()->GetData()); m_Controls->m_ProcessFiberBundleButton->setEnabled(!m_SelectedFB.empty()); m_Controls->m_ExtractFiberPeaks->setEnabled(!m_SelectedFB.empty()); } void QmitkFiberQuantificationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& ) { UpdateGui(); } void QmitkFiberQuantificationView::ProcessSelectedBundles() { if ( m_SelectedFB.empty() ){ QMessageBox::information( nullptr, "Warning", "No fibe bundle selected!"); MITK_WARN("QmitkFiberQuantificationView") << "no fibe bundle selected"; return; } int generationMethod = m_Controls->m_GenerationBox->currentIndex(); for( unsigned int i=0; i(node->GetData())) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); QString name(node->GetName().c_str()); DataNode::Pointer newNode = nullptr; switch(generationMethod){ case 0: newNode = GenerateTractDensityImage(fib, false, true); name += "_TDI"; break; case 1: newNode = GenerateTractDensityImage(fib, false, false); name += "_TDI"; break; case 2: newNode = GenerateTractDensityImage(fib, true, false); name += "_envelope"; break; case 3: newNode = GenerateColorHeatmap(fib); break; case 4: newNode = GenerateFiberEndingsImage(fib); name += "_fiber_endings"; break; case 5: newNode = GenerateFiberEndingsPointSet(fib); name += "_fiber_endings"; break; } if (newNode.IsNotNull()) { newNode->SetName(name.toStdString()); GetDataStorage()->Add(newNode); } } } } // generate pointset displaying the fiber endings mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateFiberEndingsPointSet(mitk::FiberBundle::Pointer fib) { mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); vtkSmartPointer fiberPolyData = fib->GetFiberPolyData(); int count = 0; int numFibers = fib->GetNumFibers(); for( int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (numPoints>0) { double* point = points->GetPoint(0); itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; pointSet->InsertPoint(count, itkPoint); count++; } if (numPoints>2) { double* point = points->GetPoint(numPoints-1); itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; pointSet->InsertPoint(count, itkPoint); count++; } } mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( pointSet ); return node; } // generate image displaying the fiber endings mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateFiberEndingsImage(mitk::FiberBundle::Pointer fib) { typedef unsigned int OutPixType; typedef itk::Image OutImageType; typedef itk::TractsToFiberEndingsImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image OutImageType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } // generate rgba heatmap from fiber bundle mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateColorHeatmap(mitk::FiberBundle::Pointer fib) { typedef itk::RGBAPixel OutPixType; typedef itk::Image OutImageType; typedef itk::TractsToRgbaImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { itk::Image::Pointer itkImage = itk::Image::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } // generate tract density image from fiber bundle mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateTractDensityImage(mitk::FiberBundle::Pointer fib, bool binary, bool absolute) { mitk::DataNode::Pointer node = mitk::DataNode::New(); if (binary) { typedef unsigned char OutPixType; typedef itk::Image OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetOutputAbsoluteValues(absolute); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); if (m_SelectedImage.IsNotNull()) { mitk::LabelSetImage::Pointer multilabelImage = mitk::LabelSetImage::New(); multilabelImage->InitializeByLabeledImage(img); mitk::Label::Pointer label = multilabelImage->GetActiveLabel(); label->SetName("Tractogram"); // label->SetColor(color); label->SetValue(1); // multilabelImage->GetActiveLabelSet()->AddLabel(label); multilabelImage->GetActiveLabelSet()->SetActiveLabel(1); PropertyList::Pointer dicomSegPropertyList = mitk::DICOMSegmentationPropertyHandler::GetDICOMSegmentationProperties(m_SelectedImage->GetPropertyList()); multilabelImage->GetPropertyList()->ConcatenatePropertyList(dicomSegPropertyList); mitk::DICOMSegmentationPropertyHandler::GetDICOMSegmentProperties(multilabelImage->GetActiveLabel(multilabelImage->GetActiveLayer())); // init data node node->SetData(multilabelImage); } else { // init data node node->SetData(img); } } else { typedef float OutPixType; typedef itk::Image OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetOutputAbsoluteValues(absolute); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } //generator->SetDoFiberResampling(false); generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node node->SetData(img); } return node; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui index bd45e43f55..a2cd04430c 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationViewControls.ui @@ -1,441 +1,420 @@ QmitkFiberQuantificationViewControls 0 0 365 581 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 Fiber-derived images 6 6 6 6 false 0 0 200 16777215 11 Perform selected operation on all selected fiber bundles. Generate Image 0 0 Upsampling factor 1 0.100000000000000 10.000000000000000 0.100000000000000 1.000000000000000 0 0 Tract Density Image (TDI) Normalized TDI Binary Envelope Fiber Bundle Image Fiber Endings Image Fiber Endings Pointset Principal Fiber Directions 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 Fiber directions with an angle smaller than the defined threshold are clustered. 2 0.000000000000000 90.000000000000000 1.000000000000000 30.000000000000000 0 0 <html><head/><body><p>Directions shorter than the defined threshold are discarded.</p></body></html> 3 1.000000000000000 0.100000000000000 0.300000000000000 Angular Threshold: Max. Peaks: Size Threshold: 0 0 Maximum number of fiber directions per voxel. 100 3 Normalization: 0 0 0 Global maximum Single vector Voxel-wise maximum 0 0 Image containing the number of distinct fiber clusters per voxel. Output #Directions per Voxel false false Generate Directions Input Data 6 6 6 6 Tractogram: Reference Image: Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryViewControls.ui index fe454057d0..22b1a6a4e1 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryViewControls.ui @@ -1,157 +1,136 @@ QmitkTractometryViewControls 0 0 484 574 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } QFrame::NoFrame QFrame::Raised 0 0 0 0 6 Input Image: 3 99999 100 Sampling Points: Qt::Vertical 20 40 0 100 Show STDEV true QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkChartWidget QWidget
QmitkChartWidget.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMViewControls.ui index b83e5d07d1..3d114861ae 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/QmitkIVIMViewControls.ui @@ -1,1208 +1,1187 @@ QmitkIVIMViewControls 0 0 423 1563 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 9 9 9 9 9 Intra Voxel Incoherent Motion Estimation 6 9 6 6 Input Data 6 6 6 6 Optional ROI image ROI: DWI to analyze Raw DWI: QFrame::NoFrame QFrame::Raised 0 0 0 0 warning display Qt::RichText true 0 0 16 16 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 16 16 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 16 16 QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::StyledPanel QFrame::Raised 0 0 0 0 0 0 0 IVIM Parameters 9 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 80 16777215 D* 100 60 Qt::Horizontal 51 16777215 200 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter QFrame::NoFrame QFrame::Raised 0 0 0 0 0 80 16777215 neglect b< 250 34 Qt::Horizontal 51 16777215 46.5 Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter QFrame::NoFrame QFrame::Raised 0 0 0 0 0 80 16777215 #iterations 100 10 Qt::Horizontal 30 16777215 TextLabel Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter QFrame::NoFrame QFrame::Raised 0 0 0 0 0 80 16777215 lambda 1000 10 Qt::Horizontal 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 0 30 16777215 TextLabel Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 15 16777215 Calculate threshold from histogram * QFrame::NoFrame QFrame::Plain 0 0 0 0 0 80 16777215 neglect Si< 100 0 Qt::Horizontal 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 0 30 16777215 TextLabel Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter 15 16777215 Calculate threshold from histogram * QFrame::NoFrame QFrame::Raised 0 0 0 0 80 0 Output Images f true D false D* false true 0 0 0 400 Choose Method 2 3 Param. Fit Fit D & f with fixed D* value Fit D & f (high b), then fit D* Linearly fit D & f (high b), then fit D* Regularized Kurtosis QFrame::StyledPanel QFrame::Raised 2 2 2 2 2 Smoothing sigma Select Fit Type Omit b=0 Measurement 80 0 Output Images Force the fitting of K to remain within the given boundaries Boundaries for K Select if the data is fitted directly (straight) or the logarithmic equation is used Straight Fit Logarithmic Fit 2 QLayout::SetMaximumSize D false K true Signa for gaussian smoothing applied prior to map computation 0.000000000000000 5.000000000000000 0.100000000000000 On 0 0 0 400 Generate Output Images QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Datapoints to Clipboard Parameters to Clipboard QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
QmitkIVIMWidget QWidget
QmitkIVIMWidget.h
1
QmitkKurtosisWidget QWidget
QmitkKurtosisWidget.h
1
ctkRangeWidget QWidget
ctkRangeWidget.h
1
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionViewControls.ui index dc363b8334..80d9d455b5 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.odfpeaks/src/internal/QmitkOdfMaximaExtractionViewControls.ui @@ -1,497 +1,476 @@ QmitkOdfMaximaExtractionViewControls 0 0 397 848 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 QFrame::NoFrame QFrame::Raised 0 0 0 0 true Generate ODF image and MITK compatible SH coefficient from other toolkits. Start SH Coefficient Import true Extract ODF peaks using finite differences on the densely sampled ODF surface. Start Peak Extraction Please Select Input Data 6 6 6 6 Select a tensor image or a SH coefficient image (generate using Q-Ball reconstruction view). ShCoeff/DTI: Mask Image: Additional Output QFormLayout::AllNonFixedFieldsGrow 6 6 6 6 Output unsigned char image containing the number of directions per voxel. #Peaks per Voxel false Parameters 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 6 Vector Normalization: <html><head/><body><p>The vector fields are always coorected for image spacing and using the lagest eigenvalue in case of the tensor peak extraction. This is done for visualizytion purposes. The output direction images are not affected.</p></body></html> 1 No Normalization MAX Normalize Single Vec Normalization true QFrame::NoFrame QFrame::Raised 0 0 0 0 6 true Max. Peaks: Relative Threshold: true Peak threshold relative to the largest peak per voxel. 3 0.000000000000000 1.000000000000000 0.100000000000000 0.500000000000000 true Absolute peak threshold (only used for the finite differences method). The value is additionally scaled by 1/GFA. 3 0.000000000000000 1.000000000000000 0.010000000000000 0.030000000000000 true Maximum number of peaks to extract. 1 1000 3 Clustering Angle: Cluster close directions. Define "close" here. 90 30 Absolute Threshold: Angular Threshold: Discard smaller peaks in the defined angle around the maximum peaks that were too far away to be clustered. 0 90 0 Qt::Vertical 20 259 Spherical Harmonic Convention 6 6 6 6 Define SH coefficient convention (depends on toolkit) 0 MITK/MRtrix FSL QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisViewControls.ui index baec9ccaa4..418ffce5e5 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.partialvolume/src/internal/QmitkPartialVolumeAnalysisViewControls.ui @@ -1,879 +1,858 @@ QmitkPartialVolumeAnalysisViewControls true 0 0 360 565 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 0 9 3 9 3 Data 0 0 Tensor/Scalar Image: 0 0 Mask Image: <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> Parameters QFrame::NoFrame QFrame::Raised 0 QFrame::NoFrame QFrame::Raised 0 0 false QFrame::NoFrame QFrame::Raised 0 30 30 Draw circular ROI :/QmitkDiffusionImaging/circle.png :/QmitkDiffusionImaging/circle.png 32 32 true true 30 30 Draw quadratic ROI :/QmitkDiffusionImaging/rectangle.png :/QmitkDiffusionImaging/rectangle.png 32 32 true true 30 30 Draw polygonal ROI :/QmitkDiffusionImaging/polygon.png :/QmitkDiffusionImaging/polygon.png 32 32 true true Qt::Horizontal 40 20 true QFrame::NoFrame QFrame::Raised QFormLayout::AllNonFixedFieldsGrow 0 Upsampling QFrame::NoFrame QFrame::Raised 0 1 50 1 25 Qt::Horizontal 50 0 2.5 Similar angles QFrame::NoFrame 0 90 0 Qt::Horizontal QSlider::NoTicks 50 0 90° QFrame::NoFrame QFrame::Raised 0 0 display histogram true 0 0 QFrame::NoFrame QFrame::Raised 0 QFrame::NoFrame QFrame::Raised 0 20 20 true true Green Partial Volume Partial Volume Partial Volume Partial Volume PV Red true All Export clustering result as float image. ... :/org.mitk.gui.qt.diffusionimaging/resources/arrow.png :/org.mitk.gui.qt.diffusionimaging/resources/arrow.png QFrame::NoFrame 0 Opacity 10 5 Qt::Horizontal QSlider::TicksBelow Qt::Vertical QSizePolicy::Fixed 20 10 The computed class values (median, variance of the gaussians) are automatically copied to clipboard. Qt::AutoText true Qt::Vertical QSizePolicy::Fixed 20 10 Histogram to Clipboard Advanced Qt::Vertical QSizePolicy::Preferred 10 1 QFrame::NoFrame QFrame::Raised QFormLayout::AllNonFixedFieldsGrow 0 Blurring QFrame::NoFrame QFrame::Raised 0 200 1 0 Qt::Horizontal 50 0 0.0 # Bins QFrame::NoFrame 0 1 100 10 Qt::Horizontal QSlider::NoTicks 50 0 50 quantiles QFrame::StyledPanel QFrame::Raised 0 1.000000000000000 0.010000000000000 0.250000000000000 1.000000000000000 0.010000000000000 0.750000000000000 Estimate circle from binary image "Thick" PFs Qt::Vertical 20 40 QmitkPartialVolumeAnalysisWidget QWidget
QmitkPartialVolumeAnalysisWidget.h
1
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingViewControls.ui index 6120fc9c5f..ffff3e46a9 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.preprocessing/src/internal/QmitkPreprocessingViewControls.ui @@ -1,1759 +1,1738 @@ QmitkPreprocessingViewControls 0 0 503 813 0 0 false QmitkPreprocessingViewControls true - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 Please Select Input Data 6 6 6 6 Image: QComboBox::AdjustToMinimumContentsLength 0 Gradients 25 Qt::Vertical 20 40 0 0 Qt::ScrollBarAsNeeded Qt::ScrollBarAlwaysOff true 100 true false true b-Value Number of gradients QFrame::NoFrame QFrame::Raised 0 0 0 0 6 <html><head/><body><p>Define the sampling frame the b-Values are rounded with.</p></body></html> Sampling frame: false <html><head/><body><p>Round b-values to nearest multiple of this value (click &quot;Round b-value&quot; to create new image with these values).</p></body></html> QAbstractSpinBox::CorrectToNearestValue 1 10000 10 false Sometimes the gradient directions are not located on one half sphere. Mirror gradients to half sphere false Generate pointset displaying the gradient vectors (applied measurement frame). Show gradients false Generate pointset displaying the gradient vectors (applied measurement frame). Flip gradients false Retain only the specified number of gradient directions and according image volumes. The retained directions are spread equally over the half sphere using an iterative energy repulsion strategy. Reduce number of gradients QFrame::NoFrame QFrame::Plain 0 0 0 0 0 x y z false Round b-values false By default, the image matrix is applied to the image gradients. This button removes this additional rotation. Clear rotation of gradients Remove or extract gradient volumes 6 6 6 6 6 6 false Remove gradient volume false Extract gradient volume Image Values 25 Qt::Vertical 20 40 QFrame::NoFrame QFrame::Raised 0 0 0 0 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. 6 2.000000000000000 0.000100000000000 0.001000000000000 Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Accumulates the information that was acquired with multiple repetitions for one gradient. Vectors do not have to be precisely equal in order to be merged, if a "Merge radius" > 0 is configured. Merge radius false Merges selected DWIs of same dimension. If several b-values are present, the resulting image will contain multiple b-shells. Merge selected DWIs false Normalizes the diffusion-weighted image values across all weighted volumes to the given mean and standard deviation. Normalize image values QFrame::NoFrame QFrame::Raised 0 0 0 0 0 false Target b-value 100000 500 Select projection method. QComboBox::AdjustToMinimumContentsLength ADC Average AKC Bi-Exponential false Multiple acquistions of one gradient direction can be averaged. Due to rounding errors, similar gradients often differ in the last decimal positions. The Merge radius allows to average them by taking all directions within a certain radius into account. Average repetitions false Project image values onto one b-shell. Project onto shell QFrame::NoFrame QFrame::Raised 0 0 0 0 0 true New stdev 100000 100 500 Select binary mask image. The mask is used to calculate the old mean and standard deviation. QComboBox::AdjustToMinimumContentsLength true New mean value 100000 100 1000 false Merges selected DWIs of same dimension. If several b-values are present, the resulting image will contain multiple b-shells. Flip axis QFrame::NoFrame QFrame::Raised 0 0 0 0 Y Qt::Horizontal 40 20 X Z Axis: QComboBox::AdjustToMinimumContentsLength Resample image 6 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0.010000000000000 2.000000000000000 0.010000000000000 2.000000000000000 0.010000000000000 2.000000000000000 Sampling factor New image spacing New image size QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Interpolator: Nearest neighbour Linear B-spline Windowed sinc false Resample image QFrame::NoFrame QFrame::Raised 0 0 0 0 0 1 10000 1 10000 1 10000 Crop Image 6 6 6 6 6 x: y: z: Crop Image Header 25 Voxel size 6 6 6 6 4 0.000000000000000 99.989999999999995 4 4 false Apply new header information Direction matrix 6 6 6 6 false 0 0 0 0 IBeamCursor true Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff true false false true true 0 false true true New Row New Row New Row New Column New Column New Column Qt::Horizontal 40 20 0 0 Measurment frame 6 6 6 6 false 0 0 0 0 IBeamCursor true Qt::ScrollBarAlwaysOff Qt::ScrollBarAlwaysOff true false false true true 0 false true true New Row New Row New Row New Column New Column New Column Qt::Horizontal 40 20 Qt::Vertical 20 40 Origin 6 6 6 6 4 -999999999.000000000000000 999999999.000000000000000 4 -99999999.000000000000000 999999999.000000000000000 4 -999999999.000000000000000 999999999.000000000000000 Align origins 6 6 6 6 QComboBox::AdjustToMinimumContentsLength Align to Other false If multiple baseline acquisitions are present, the default behaviour is to output an averaged image. Estimate binary brain mask Maximum number of iterations. 10000 10000 Qt::Vertical 20 40 false If multiple baseline acquisitions are present, the default behaviour is to output an averaged image. Extract baseline image Create a 3D+t data set containing all b0 images as timesteps Disable averaging QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
m_SelctedImageComboBox tabWidget m_B_ValueMap_TableWidget m_CreateLengthCorrectedDwi m_B_ValueMap_Rounder_SpinBox m_FlipGradientsButton m_FlipGradBoxX m_FlipGradBoxY m_FlipGradBoxZ m_ShowGradientsButton m_MirrorGradientToHalfSphereButton m_ReduceGradientsButton m_ClearRotationButton m_RemoveGradientButton m_RemoveGradientBox m_ExtractGradientButton m_ExtractGradientBox m_ButtonAverageGradients m_Blur m_ProjectSignalButton m_targetBValueSpinBox m_ProjectionMethodBox m_NormalizeImageValuesButton m_NewMean m_NewStdev m_NormalizationMaskBox m_FlipAxis m_FlipX m_FlipY m_FlipZ m_MergeDwisButton m_MergeDwiBox m_ResampleTypeBox m_ResampleDoubleX m_ResampleDoubleY m_ResampleDoubleZ m_ResampleIntX m_ResampleIntY m_ResampleIntZ m_InterpolatorBox m_ResampleImageButton m_XstartBox m_XendBox m_YstartBox m_YendBox m_ZstartBox m_ZendBox m_CropImageButton m_ModifyHeader m_HeaderOriginX m_HeaderOriginY m_HeaderOriginZ m_HeaderSpacingX m_HeaderSpacingY m_HeaderSpacingZ m_DirectionMatrixTable m_MeasurementFrameTable m_ButtonExtractB0 m_CheckExtractAll m_ExtractBrainMask m_BrainMaskIterationsBox
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionViewControls.ui index 3671293c44..6c6eadc387 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.python/src/internal/QmitkBrainExtractionViewControls.ui @@ -1,118 +1,97 @@ QmitkBrainExtractionViewControls 0 0 435 744 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } false Start Brain Extraction Qt::Vertical 20 40 QFrame::NoFrame QFrame::Raised 0 0 0 0 Input Image: QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationViewControls.ui index 6002ee62c4..7c58ae24d6 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationViewControls.ui @@ -1,451 +1,430 @@ QmitkDiffusionQuantificationViewControls 0 0 343 888 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 Input Data 6 6 6 6 Image Scale Image Values: 9999999.000000000000000 1.000000000000000 Raw diffusion-weighted image 6 6 6 6 false ADC false MD false Ball-Stick false Multi-Tensor Fit ODF image 6 6 6 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 Generalized GFA QFrame::NoFrame QFrame::Raised 0 0 0 0 true k true true p true false GFA QFrame::NoFrame QFrame::Raised 0 0 0 0 Min. angle Max. angle false Curvature Tensor image 6 6 6 6 false FA (Fractional Anisotropy) false RA (Relative Anisotropy) false AD (Axial Diffusivity) false RD (Radial Diffusivity) false MD (Mean Diffusivity) false 1-(λ2+λ3)/(2*λ1) Qt::Vertical QSizePolicy::Expanding 20 220 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsViewControls.ui index bad0fc4932..f25a1adb7b 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkODFDetailsViewControls.ui @@ -1,280 +1,259 @@ QmitkODFDetailsViewControls 0 0 351 734 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 6 9 9 9 9 Please Select Input Data 6 6 6 6 DTI/ODF: <html><head/><body><p><span style=" color:#ff0000;">mandatory</span></p></body></html> true Overview 6 6 6 6 0 0 0 0 true 0 0 200 200 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 ODF Values 6 6 6 6 true 0 0 0 200 Qt::Vertical QSizePolicy::Expanding 20 220 QmitkODFDetailsWidget QWidget
QmitkODFDetailsWidget.h
1
QmitkODFRenderWidget QWidget
QmitkODFRenderWidget.h
1
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkQBallReconstructionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkQBallReconstructionViewControls.ui index bb4d30e9be..f73ef39cc5 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkQBallReconstructionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkQBallReconstructionViewControls.ui @@ -1,450 +1,429 @@ QmitkQBallReconstructionViewControls 0 0 372 844 0 0 true QmitkQBallReconstructionViewControls - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 Parameters 6 6 6 6 2 Numerical Standard Solid Angle Constraint Solid Angle ADC-Profile only Raw Signal only Multi-Shell TextLabel QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 true Regularization Parameter Lambda: false Regularization factor 3 1.000000000000000 0.001000000000000 0.006000000000000 true SH-Order: false true -1 true B0 Threshold false 10000 Output SH-Coefficient Image false false Start Reconstruction Input Data 6 6 6 6 Input for Q-Ball reconstruction. Raw DWI: true Qt::LeftToRight false Multi-Shell Reconstruction 6 6 6 6 Qt::Vertical 20 0 Convert SH to sampled ODF image 6 6 6 6 false Convert QFrame::NoFrame QFrame::Raised 0 0 0 0 Input for Q-Ball reconstruction. SH Image: QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkTensorReconstructionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkTensorReconstructionViewControls.ui index a7512461be..1650d5269f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkTensorReconstructionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkTensorReconstructionViewControls.ui @@ -1,778 +1,757 @@ QmitkTensorReconstructionViewControls 0 0 368 1019 0 0 true QmitkTensorReconstructionViewControls - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 ODF Image from Tensors 6 6 6 6 false Calculate ODF value as tensor value in the according direction Start QFrame::NoFrame QFrame::Raised 0 0 0 0 Tensor Image: Diffusion-weighted Image from Tensors 6 6 6 6 false Estimates the original diffusion weighted image based on a reconstructed tensor image. Estimate DWI based on Tensor Image QFrame::NoFrame QFrame::Raised QFormLayout::AllNonFixedFieldsGrow 6 6 0 0 0 0 how fuzzy the confidence boundary should be. By default, confidence boundary is perfectly sharp (float); default: "0" how fuzzy the confidence boundary should be. By default, confidence boundary is perfectly sharp (float); default: "0" how fuzzy the confidence boundary should be. By default, confidence boundary is perfectly sharp (float); default: "0" B-Value false #Gradient Directions 3 12 42 92 162 252 362 492 642 812 1002 10000 100 1000 QFrame::NoFrame QFrame::Raised 0 0 0 0 Tensor Image: Calculate Residuals false false 6 6 6 6 6 false percentages of error 0 Per volume 200 300 Per slice outliers per slice QFrame::NoFrame QFrame::Raised 0 0 0 0 300 400 QFrame::NoFrame QFrame::Raised 0 0 0 0 20 255 Volume: .., Slice:.. false Calculate the residual from a dti and a dwi image Start QFrame::NoFrame QFrame::Raised 0 0 0 0 Diffusion-weighted Image: Tensor Image: Qt::Vertical 20 40 Tensor Reconstruction 6 6 6 6 Advanced Settings false false Select raw DWI! Start Reconstruction QFrame::StyledPanel QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 B0 Threshold false 10000 Only influences WLS reconstruction Ignore voxels with negative eigenvalues 0 ITK Linear Least Squares With correction for negative eigenvalues QFrame::NoFrame QFrame::Raised 0 0 0 0 Diffusion-weighted Image: QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkResidualAnalysisWidget QWidget
QmitkResidualAnalysisWidget.h
1
QmitkResidualViewWidget QGraphicsView
QmitkResidualViewWidget.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionViewControls.ui index c73acb1a3a..e919050341 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkHeadMotionCorrectionViewControls.ui @@ -1,118 +1,97 @@ QmitkHeadMotionCorrectionViewControls 0 0 435 744 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } false Start DWI registration/Head Motion Correction Start Head Motion Correction Qt::Vertical 20 40 QFrame::NoFrame QFrame::Raised 0 0 0 0 Input Image: QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationViewControls.ui index 1073648dd4..005a0cec60 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkSimpleRegistrationViewControls.ui @@ -1,309 +1,288 @@ QmitkSimpleRegistrationViewControls 0 0 435 744 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 25 Qt::Vertical 20 40 Image Registration 6 6 6 6 false Start Registration QFrame::NoFrame QFrame::Raised 0 0 0 0 Rigid Affine Registration Type: Output Registration Object: QFrame::NoFrame QFrame::Raised 0 0 0 0 Moving Image: false Select dMRI volume used to calculate transformation. false Select dMRI volume used to calculate transformation. Fixed Image: QFrame::NoFrame QFrame::Raised 0 0 0 0 false Start Tractography Registration Tractography Registration 6 6 6 6 Registration Object: Tractogram: QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationViewControls.ui index 3edd0a05a2..cfcacb84f6 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationViewControls.ui @@ -1,158 +1,137 @@ QmitkTbssSkeletonizationViewControls 0 0 431 811 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 0 0 0 80 QFrame::StyledPanel QFrame::Raised false Mean: false Patient Data: false Tubular Structure Mask: false Skeletonize false Skeletonize and Project false Output binary mask true false Output distance map true \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTractbasedSpatialStatisticsViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTractbasedSpatialStatisticsViewControls.ui index fc056a2cfa..2fe7b197fa 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTractbasedSpatialStatisticsViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTractbasedSpatialStatisticsViewControls.ui @@ -1,495 +1,474 @@ QmitkTractbasedSpatialStatisticsViewControls 0 0 265 811 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 0 0 FSL import Subject Data false false QFrame::NoFrame QFrame::Raised 0 QFrame::NoFrame QFrame::Raised Group information QAbstractItemView::SelectRows 0 0 110 100 QFrame::NoFrame QFrame::Raised 0 0 Add group entry. After that give the group a name and the correct number Add 0 0 Remove selected entries Remove false 0 0 Import a 4D image containing group data after group information has been set Import data 0 0 QFrame::StyledPanel QFrame::Raised 0 0 Measure Measurement in the to be imported 4D image FA 0 0 Tract-specific analysis true To create a roi first load a tbss meta image into the datamanager 0 ROIs 0 0 Points on Roi 100 100 0 100 Use this widget to create points on the ROI by shift-leftclick on the right positions on the skeleton. Then click Create Roi. The Roi that will be created will pass through the points in the order of occurence in this list false 0 0 No suitable tbss meta image selected yet. The meta image needs to contain a mean FA skeleton and a skeleton mask Create ROI 0 0 Points on the ROI 0 0 Name Give a name to the region of interest roiname 0 0 Structure info On what anatomical structure lies the ROI? Structure 0 0 current selection mean FA skeleton: Qt::Horizontal 253 20 Measuring 16777215 50 false #segments false 100 25 false Average false Cut To plot, load a tbss image with subject information and a region of interest corresponding to the study and select them both Copy to clipboard QmitkPointListWidget QWidget
QmitkPointListWidget.h
QmitkTbssRoiAnalysisWidget QWidget
QmitkTbssRoiAnalysisWidget.h
1
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkGibbsTrackingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkGibbsTrackingViewControls.ui index ea598ceab8..4822482046 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkGibbsTrackingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkGibbsTrackingViewControls.ui @@ -1,1199 +1,1178 @@ QmitkGibbsTrackingViewControls 0 0 463 1011 0 0 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } QFormLayout::AllNonFixedFieldsGrow QFrame::NoFrame QFrame::Plain 0 0 0 0 0 6 false No ODF/tensor image selected. Qt::LeftToRight Start Tractography :/QtWidgetsExt/play.xpm :/QtWidgetsExt/play.xpm false Qt::LeftToRight Stop Tractography :/QtWidgetsExt/stop.xpm :/QtWidgetsExt/stop.xpm Parameters 6 6 6 6 Output File: Advanced Settings true Activate continuous visualization of intermediate results. Visualize Tractography true QFrame::NoFrame QFrame::Plain 0 0 0 0 0 0 Select output file name and folder. ... N/A true Visualize intermediate result. :/QmitkDiffusionImaging/Refresh_48.png :/QmitkDiffusionImaging/Refresh_48.png true Iterations: 1e9 true QFrame::StyledPanel QFrame::Raised 0 0 0 0 6 Particle Width: 0 Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 0.1 Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Particle Weight: 1 99 1 10 Qt::Horizontal QSlider::NoTicks Start Temperature: automatic estimation from gfa map and ODF data. 0 1000 1 0 Qt::Horizontal true QSlider::NoTicks IE Bias < 0 < EE Bias -50 50 1 Qt::Horizontal QSlider::NoTicks 0.001 Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Curvature Threshold: Balance In/Ex Energy: 45° Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter auto = 0.5 * min. spacing; sigma 100 1 Qt::Horizontal QSlider::NoTicks Particle Length: auto Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter Min. Fiber Length: Only fibers longer than specified are accepted. 500 1 20 Qt::Horizontal QSlider::NoTicks Allow only fiber curvature values smaller than the selected threshold. 180 1 45 Qt::Horizontal QSlider::NoTicks End Temperature: 20mm Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter auto Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 1 100 1 10 Qt::Horizontal false false QSlider::NoTicks auto Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter auto = 1.5 * min. spacing; l 100 1 Qt::Horizontal QSlider::NoTicks Random Seed auto Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter auto = 1.5 * min. spacing; l -1 100 1 -1 Qt::Horizontal QSlider::NoTicks QFrame::NoFrame QFrame::Plain 0 0 0 0 0 6 true Save current parameters as xml (.gtp) Qt::LeftToRight Save Parameters :/QmitkDiffusionImaging/general_icons/download.ico :/QmitkDiffusionImaging/general_icons/download.ico true Load parameters from xml file (.gtp) Qt::LeftToRight Load Parameters :/QmitkDiffusionImaging/general_icons/upload.ico :/QmitkDiffusionImaging/general_icons/upload.ico Qt::Vertical QSizePolicy::Expanding 0 0 0 0 Input Data 6 6 6 6 0 0 ODF/Tensor Image: Mask Image: 0 0 0 0 0 0 Monitor 6 6 6 6 6 Progress: - Will only be updated if tracking is visualized Will only be updated if tracking is visualized Accepted Fibers: Connections: Particles: Proposal Acceptance Rate: Tracking Time: Will only be updated if tracking is visualized - - - - - QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkMLBTViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkMLBTViewControls.ui index cc06db5811..eea4153d87 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkMLBTViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkMLBTViewControls.ui @@ -1,465 +1,444 @@ QmitkMLBTViewControls 0 0 476 548 Form - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Remove training data pair ... :/org_mitk_icons/icons/tango/scalable/actions/list-remove.svg :/org_mitk_icons/icons/tango/scalable/actions/list-remove.svg Add additional training data pair ... :/org_mitk_icons/icons/tango/scalable/actions/list-add.svg :/org_mitk_icons/icons/tango/scalable/actions/list-add.svg <html><head/><body><p><span style=" font-weight:600; color:#ff0000;">It is recommended to use the command line application 'RfTraining' instead of this graphical user interface for the training process. Additional feature images are not supported here.</span></p><p><span style=" font-weight:600; color:#ff0000;">The GUI is intended for testing using small examples.</span></p></body></html> Qt::RichText Qt::AlignCenter true 5 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 6 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Input DWI: Qt::AlignCenter Reference Tractogram: Qt::AlignCenter Mask: Qt::AlignCenter WM: Qt::AlignCenter QFrame::NoFrame QFrame::Raised 0 0 0 0 Fraction of samples used to train each tree. 3 1.000000000000000 0.100000000000000 0.700000000000000 Num. Trees: Sample Fraction: Max. Depth: Fiber sampling in mm. Determines the number of white-matter samples (-1 = auto). 3 -1.000000000000000 999.000000000000000 0.100000000000000 -1.000000000000000 Number of tress in the final random forest. 1 999999999 30 Non-WM Sampling Points: Fiber Sampling: Maximum tree depth. 1 999999999 25 Number of sampling points outside of the white-matter (-1 = automatic estimation). -1 999999999 -1 Num. previous directions: Number of previous fiber directions used as features. 0 50 1 dMRI Features: Spherical Harmonics Coefficients Raw Data Start Training. This can take up to a couple of hours. Start Training Qt::Vertical 20 40 \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingViewControls.ui index 32fc1145d5..0ea54e5f85 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingViewControls.ui @@ -1,1590 +1,1575 @@ - + QmitkStreamlineTrackingViewControls 0 0 453 859 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 3 3 0 40 QFrame::NoFrame QFrame::Raised 0 15 0 0 6 15 true 0 0 true QFrame::NoFrame QFrame::Raised 0 0 0 0 Input Image. ODF, tensor and peak images are currently supported. Input Image: Input Image. ODF, tensor, peak, and, in case of ML tractography, raw diffusion-weighted images are currently supported. - <html><head/><body><p><span style=" color:#ff0000;">select image in data-manager</span></p></body></html> + <html><head/><body><p><span style=" color:#ff0000;">select image in data-manager</span></p></body></html> true - + Tractography Forest: Random forest for machine learning based tractography. QComboBox::AdjustToMinimumContentsLength - true Stop tractography and return all fibers reconstructed until now. Stop Tractography false Start Tractography 0 0 0 0 + + + 75 + true + + 0 0 0 421 262 Seeding Specify how, where and how many tractography seed points are placed. QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Number of seed points equally distributed around selected position. 1 9999999 50 - + Radius: Seedpoints are equally distributed within a sphere centered at the selected position with the specified radius (in mm). 2 50.000000000000000 0.100000000000000 2.000000000000000 - + Num. Seeds: true When checked, parameter changes cause instant retracking while in interactive mode. Update on Parameter Change true QFrame::NoFrame QFrame::Raised 0 0 0 0 Try each seed N times until a valid streamline is obtained (only for probabilistic tractography). Minimum fiber length (in mm) 1 999 10 - + Trials Per Seed: - + Max. Num. Fibers: Tractography is stopped after the desired number of fibers is reached, even before all seed points are processed (-1 means no limit). -1 999999999 -1 QFrame::NoFrame QFrame::Raised 0 0 0 0 Number of seed points placed in each voxel. 1 9999999 - + Seeds per Voxel: Seed points are only placed inside the regions defined in the seed image. If no seed image is selected, the whole image is seeded. QComboBox::AdjustToMinimumContentsLength - - + Seed Image: true Dynamically pick a seed location by click into image. Enable Interactive Tractography Qt::Vertical 20 40 0 0 435 224 ROI Constraints Specify various ROI and mask images to constrain the tractography process. - + Mask Image: Fibers that enter a region defined in this image will stop immediately. QComboBox::AdjustToMinimumContentsLength - Select which fibers should be accepted or rejected based on the location of their endpoints. QComboBox::AdjustToMinimumContentsLength No Constraints on EP locations Both EPs in Target Image Both EPs in Target Image But Different Label One EP in Seed Image and One EP in Target Image At Least One EP in Target Image Exactly One EP in Target Image No EP in Target Image - + Endpoint Constraints: - + Stop ROI Image: The target image is used for the endpoint constraint strategy defined above. QComboBox::AdjustToMinimumContentsLength - - + Exclusion ROI Image: Fibers that leave the regions defined in this image will stop immediately. QComboBox::AdjustToMinimumContentsLength - - + Target ROI Image: Fibers that enter a region defined in this image will be discarded. QComboBox::AdjustToMinimumContentsLength - Qt::Vertical 20 40 0 0 421 351 Tractography Parameters Specify the behavior of the tractography at each streamline integration step (step size, deterministic/probabilistic, ...). Qt::Vertical 20 40 f=1 + g=0 means FACT (depending on the chosen interpolation). f=0 and g=1 means TEND (disable interpolation for this mode!). 2 1.000000000000000 0.100000000000000 0.000000000000000 Toggle between deterministic and probabilistic tractography. Some modes might not be available for all types of tractography. Deterministic Probabilistic - + Cutoff: - + FA/GFA Image: - + Mode: - + Angular Threshold: Step size (in voxels) 2 0.010000000000000 10.000000000000000 0.100000000000000 0.500000000000000 Maximum allowed angular SDTEV over 4 voxel lengths. Default: no loop check. - + -1 180 -1 If an image is selected, the stopping criterion is not calculated from the input image but instead the selected image is used. QComboBox::AdjustToMinimumContentsLength - - + Step Size: Additional threshold on the ODF magnitude. This is useful in case of CSD fODF tractography. For fODFs a good default value is 0.1, for normalized dODFs, e.g. Q-ball ODFs, this threshold should be very low (0.00025) or 0. 5 1.000000000000000 0.100000000000000 0.000250000000000 f=1 + g=0 means FACT (depending on the chosen interpolation). f=0 and g=1 means TEND (disable interpolation for this mode!). 2 1.000000000000000 0.100000000000000 1.000000000000000 If you are using dODF images as input, it is advisable to sharpen the ODFs (min-max normalize and raise to the power of 4). This is not necessary for CSD fODFs, since they are naturally much sharper. - + f parameter of tensor tractography. f=1 + g=0 means FACT (depending on the chosen interpolation). f=0 and g=1 means TEND (disable interpolation for this mode!). f: - + Min. Tract Length: Threshold on peak magnitude, FA, GFA, ... 5 1.000000000000000 0.100000000000000 0.100000000000000 - + ODF Cutoff: Minimum tract length in mm. Shorter fibers are discarded. Minimum fiber length (in mm) 1 999.000000000000000 1.000000000000000 20.000000000000000 - + Loop Check: Angular threshold between two steps (in degree). Default: 90° * step_size -1 90 1 -1 - + g: - + Sharpen ODFs: 0 0 435 224 Tractography Prior Restrict to Prior: Weight: Peak Image: Weighting factor between prior and data. 1.000000000000000 0.100000000000000 0.500000000000000 Restrict tractography to regions where the prior is valid. - + true - + Qt::Vertical 20 40 New Directions from Prior: If unchecked, the prior cannot create directions where there are none in the data. - + true 0 0 435 224 Neighborhood Sampling Specify if and how information about the current streamline neighborhood should be used. Only neighborhood samples in front of the current streamline position are considered. Use Only Frontal Samples false If checked, the majority of sampling points has to place a stop-vote for the streamline to terminate. If not checked, all sampling positions have to vote for a streamline termination. Use Stop-Votes false QFrame::NoFrame QFrame::Raised 0 0 0 0 - + Num. Samples: Number of neighborhood samples that are used to determine the next fiber progression direction. 50 - + Sampling Distance: Sampling distance (in voxels) 2 10.000000000000000 0.100000000000000 0.250000000000000 Qt::Vertical 20 40 0 0 435 224 Data Handling Specify interpolation and direction flips. QFrame::NoFrame QFrame::Raised 0 0 0 0 Trilinearly interpolate the input image used for tractography. Interpolate Tractography Data true Trilinearly interpolate the ROI images used to constrain the tractography. Interpolate ROI Images true QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Internally flips progression directions. This might be necessary depending on the input data. x Internally flips progression directions. This might be necessary depending on the input data. y Internally flips progression directions. This might be necessary depending on the input data. z - + Flip directions: Qt::Vertical 20 40 0 0 435 224 Output and Postprocessing Specify the tractography output (streamlines or probability maps) and postprocessing steps. QFrame::NoFrame QFrame::Raised 0 0 0 0 Compress fibers using the specified error constraint. Compress Fibers true Qt::StrongFocus Lossy fiber compression. Recommended for large tractograms. Maximum error in mm. 3 10.000000000000000 0.010000000000000 0.100000000000000 Output map with voxel-wise visitation counts instead of streamlines. Output Probability Map false Qt::Vertical 20 40 - + QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
- - -
\ No newline at end of file + + + diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui index 9d779a6a02..ee1c8be363 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkControlVisualizationPropertiesViewControls.ui @@ -1,1030 +1,1009 @@ QmitkControlVisualizationPropertiesViewControls 0 0 567 619 0 100 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Multislice Projection MIP QToolButton::MenuButtonPopup Qt::NoArrow QFrame::NoFrame QFrame::Plain 0 0 0 0 Toggle visibility of ODF glyphs (axial) :/QmitkDiffusionImaging/glyphsoff_T.png :/QmitkDiffusionImaging/glyphson_T.png :/QmitkDiffusionImaging/glyphsoff_T.png true false Toggle visibility of ODF glyphs (sagittal) :/QmitkDiffusionImaging/glyphsoff_S.png :/QmitkDiffusionImaging/glyphson_S.png :/QmitkDiffusionImaging/glyphsoff_S.png true false Toggle visibility of ODF glyphs (coronal) :/QmitkDiffusionImaging/glyphsoff_C.png :/QmitkDiffusionImaging/glyphson_C.png :/QmitkDiffusionImaging/glyphsoff_C.png true false #Glyphs 9999 Qt::Horizontal 20 20 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Plain 0 0 0 0 ODF normalization false Min-Max Max None ODF Normalization: ODF normalization false ODF Value Principal Direction Color ODFs/Tensors by: QFrame::NoFrame QFrame::Plain 0 0 0 0 ODF Scale: false None FA/GFA * Additional scaling factor 3 999999999.000000000000000 0.100000000000000 1.000000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 Reset to Default Coloring :/QmitkDiffusionImaging/color64.gif :/QmitkDiffusionImaging/color64.gif Reset to Default Coloring :/QmitkDiffusionImaging/reset.png :/QmitkDiffusionImaging/reset.png Position Crosshair by 3D-Click :/QmitkDiffusionImaging/crosshair.png :/QmitkDiffusionImaging/crosshair.png true false 2D Fiberfading on/off Qt::Horizontal 40 20 QFrame::NoFrame QFrame::Raised 0 0 0 0 2D Clipping 100 10 10 10 Qt::Horizontal 90 0 10000 16777215 Range QFrame::NoFrame QFrame::Raised 0 0 0 0 Tube Radius 3 0.100000000000000 Ribbon Width 3 0.100000000000000 50 false false <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> <p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" color:#ff0000;">One or more slices are rotated. ODF Visualisation is not possible in rotated planes. Use 'Reinit' on the image node to reset. </span></p></body></html> Qt::AutoText true QFrame::NoFrame QFrame::Raised 0 0 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 y z x 0 0 Flip Peaks QFrame::NoFrame QFrame::Raised 0 0 0 0 Reset to Default Coloring :/QmitkDiffusionImaging/reset.png :/QmitkDiffusionImaging/reset.png Reset to Default Coloring :/QmitkDiffusionImaging/color64.gif :/QmitkDiffusionImaging/color64.gif Qt::Horizontal 40 20 Line Width 1 1.000000000000000 0.100000000000000 1.000000000000000 3D Clipping 6 6 6 6 0 Coronal Axial No clipping true Sagittal Flipp Clipping Direction Enable 3D Rendering Qt::Vertical 20 40 QmitkDataStorageComboBox.h \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDicomTractogramTagEditorViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDicomTractogramTagEditorViewControls.ui index 5c160ad17e..e31cb7a178 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDicomTractogramTagEditorViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDicomTractogramTagEditorViewControls.ui @@ -1,186 +1,165 @@ QmitkDicomTractogramTagEditorViewControls 0 0 397 366 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 3 3 0 QFrame::NoFrame QFrame::Raised 0 0 0 9 Tractogram: Seed points are only placed inside the mask image. If no seed mask is selected, the whole image is seeded. QComboBox::AdjustToMinimumContentsLength - Tractography DICOM Tags 6 6 6 6 0 QFrame::NoFrame Qt::ScrollBarAlwaysOff QAbstractScrollArea::AdjustToContents Qt::Vertical QSizePolicy::Expanding 20 220 Copies the DICOM properties of the tractogram selected in this view to the one selected in the datamanager. Copy Properties From Image QmitkDataStorageComboBoxWithSelectNone QComboBox
QmitkDataStorageComboBoxWithSelectNone.h
\ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportViewControls.ui index 336dc2fbac..fbe4a816f8 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/QmitkDiffusionDicomImportViewControls.ui @@ -1,401 +1,380 @@ QmitkDiffusionDicomImportControls 0 0 374 603 0 0 true QmitkDiffusionDicomImport - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 16777215 70 QFrame::NoFrame QFrame::Plain 0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'Ubuntu'; font-size:11pt; font-weight:400; font-style:normal;"> <table border="0" style="-qt-table-type: root; margin-top:4px; margin-bottom:4px; margin-left:4px; margin-right:4px;"> <tr> <td style="border: none;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">Each input folder must only contain DICOM-images that can be combined into one vector-valued 3D output volume. Different patients must be loaded from different input-folders. The folders must not contain other acquisitions (e.g. T1,T2,localizer).</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans'; font-size:10pt;"><br /></p> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-family:'Sans'; font-size:10pt;">In case many imports are performed at once, it is recommended to set the the optional output folder argument. This prevents the images from being kept in memory.</span></p> <p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-family:'Sans'; font-size:10pt;"><br /></p></td></tr></table></body></html> 0 0 QFrame::NoFrame QFrame::Raised 0 0 0 0 0 Add Input Folders Remove Clear 0 0 0 70 QFrame::Box QFrame::Plain 1 0 Qt::ScrollBarAsNeeded Qt::ScrollBarAlwaysOn QListView::Adjust true QFrame::StyledPanel QFrame::Raised Recursive 8 QLayout::SetNoConstraint Set Prefix Reset Multiple acquistions of one gradient direction can be averaged. Due to rounding errors, similar gradients often differ in the last decimal positions. The Merge radius allows to average them anyway by taking into account all directions within a certain radius. QFrame::NoFrame QFrame::Raised 0 0 0 0 Merge duplicate gradients: false 4 2.000000000000000 0.000100000000000 0.001000000000000 QFrame::NoFrame QFrame::Raised 0 0 0 0 40 25 30 16777215 Files are automaticall saved to disc. If the files can not be written, they are added to the data manager. Set ... optional out-folder ... false true 50 25 30 16777215 Clear Override existing files Split Mosaic Import DICOM as *.dwi Qt::Vertical 20 40 \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/QmitkDiffusionImagingAppWorkbenchAdvisor.cpp b/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/QmitkDiffusionImagingAppWorkbenchAdvisor.cpp index 417146690b..c1fa703c99 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/QmitkDiffusionImagingAppWorkbenchAdvisor.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/QmitkDiffusionImagingAppWorkbenchAdvisor.cpp @@ -1,99 +1,99 @@ /*=================================================================== 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 "QmitkDiffusionImagingAppWorkbenchAdvisor.h" #include "internal/QmitkDiffusionApplicationPlugin.h" #include #include #include #include #include #include #include #include const QString QmitkDiffusionImagingAppWorkbenchAdvisor::WELCOME_PERSPECTIVE_ID = "org.mitk.diffusionimagingapp.perspectives.welcome"; class QmitkDiffusionImagingAppWorkbenchWindowAdvisor : public QmitkExtWorkbenchWindowAdvisor { public: QmitkDiffusionImagingAppWorkbenchWindowAdvisor(berry::WorkbenchAdvisor* wbAdvisor, berry::IWorkbenchWindowConfigurer::Pointer configurer) : QmitkExtWorkbenchWindowAdvisor(wbAdvisor, configurer) { } void PostWindowOpen() override { QmitkExtWorkbenchWindowAdvisor::PostWindowOpen(); berry::IWorkbenchWindowConfigurer::Pointer configurer = GetWindowConfigurer(); - configurer->GetWindow()->GetWorkbench()->GetIntroManager()->ShowIntro(configurer->GetWindow(), false); +// configurer->GetWindow()->GetWorkbench()->GetIntroManager()->ShowIntro(configurer->GetWindow(), false); } }; void QmitkDiffusionImagingAppWorkbenchAdvisor::Initialize(berry::IWorkbenchConfigurer::Pointer configurer) { berry::QtWorkbenchAdvisor::Initialize(configurer); configurer->SetSaveAndRestore(true); } berry::WorkbenchWindowAdvisor* QmitkDiffusionImagingAppWorkbenchAdvisor::CreateWorkbenchWindowAdvisor( berry::IWorkbenchWindowConfigurer::Pointer configurer) { QList perspExcludeList; perspExcludeList.push_back( "org.blueberry.uitest.util.EmptyPerspective" ); perspExcludeList.push_back( "org.blueberry.uitest.util.EmptyPerspective2" ); perspExcludeList.push_back("org.blueberry.perspectives.help"); QList viewExcludeList; viewExcludeList.push_back( "org.mitk.views.controlvisualizationpropertiesview" ); viewExcludeList.push_back( "org.mitk.views.modules" ); //QRect rec = QApplication::desktop()->screenGeometry(); //configurer->SetInitialSize(QPoint(rec.width(),rec.height())); QmitkDiffusionImagingAppWorkbenchWindowAdvisor* advisor = new QmitkDiffusionImagingAppWorkbenchWindowAdvisor(this, configurer); advisor->ShowViewMenuItem(true); advisor->ShowNewWindowMenuItem(true); advisor->ShowClosePerspectiveMenuItem(true); advisor->SetPerspectiveExcludeList(perspExcludeList); advisor->SetViewExcludeList(viewExcludeList); advisor->ShowViewToolbar(false); advisor->ShowPerspectiveToolbar(true); advisor->ShowVersionInfo(false); advisor->ShowMitkVersionInfo(false); advisor->ShowMemoryIndicator(false); advisor->SetProductName("MITK Diffusion"); advisor->SetWindowIcon(":/org.mitk.gui.qt.diffusionimagingapp/app-icon.png"); return advisor; } QString QmitkDiffusionImagingAppWorkbenchAdvisor::GetInitialWindowPerspectiveId() { return WELCOME_PERSPECTIVE_ID; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/QmitkWelcomeScreenViewControls.ui b/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/QmitkWelcomeScreenViewControls.ui index e567f646f8..c8e0f4f8ad 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/QmitkWelcomeScreenViewControls.ui +++ b/Plugins/org.mitk.gui.qt.diffusionimagingapp/src/internal/QmitkWelcomeScreenViewControls.ui @@ -1,64 +1,43 @@ QmitkWelcomeScreenViewControls 0 0 458 398 0 0 QmitkTemplate - QCommandLinkButton { - font-weight: lighter; -} - -QCommandLinkButton:disabled { + QCommandLinkButton:disabled { border: none; - font-weight: lighter; -} - -QToolBox::tab { - font-weight: bold; -} - -QToolBox::tab:hover { - font-weight: bold; -} - -QToolBox::tab:selected { - font-weight: bold; } QGroupBox { background-color: transparent; -} - -QGroupBox, QGroupBox:disabled { - background-color: transparent; } 0 \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.cpp b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.cpp index d7228f1e18..49301d03dd 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.cpp +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.cpp @@ -1,1011 +1,1042 @@ /*=================================================================== 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 "PAImageProcessing.h" // Qt #include #include #include #include //mitk image #include #include "mitkPhotoacousticFilterService.h" #include "mitkCastToFloatImageFilter.h" #include "mitkBeamformingFilter.h" //other #include #include #include const std::string PAImageProcessing::VIEW_ID = "org.mitk.views.paimageprocessing"; PAImageProcessing::PAImageProcessing() : m_ResampleSpacing(0), m_UseLogfilter(false), m_FilterBank(mitk::PhotoacousticFilterService::New()) { qRegisterMetaType(); qRegisterMetaType(); } void PAImageProcessing::SetFocus() { m_Controls.buttonApplyBModeFilter->setFocus(); } void PAImageProcessing::CreateQtPartControl(QWidget *parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); connect(m_Controls.buttonApplyBModeFilter, SIGNAL(clicked()), this, SLOT(StartBmodeThread())); connect(m_Controls.DoResampling, SIGNAL(clicked()), this, SLOT(UseResampling())); connect(m_Controls.Logfilter, SIGNAL(clicked()), this, SLOT(UseLogfilter())); connect(m_Controls.ResamplingValue, SIGNAL(valueChanged(double)), this, SLOT(SetResampling())); connect(m_Controls.buttonApplyBeamforming, SIGNAL(clicked()), this, SLOT(StartBeamformingThread())); connect(m_Controls.buttonApplyCropFilter, SIGNAL(clicked()), this, SLOT(StartCropThread())); connect(m_Controls.buttonApplyBandpass, SIGNAL(clicked()), this, SLOT(StartBandpassThread())); connect(m_Controls.UseImageSpacing, SIGNAL(clicked()), this, SLOT(UseImageSpacing())); connect(m_Controls.ScanDepth, SIGNAL(valueChanged(double)), this, SLOT(UpdateImageInfo())); connect(m_Controls.SpeedOfSound, SIGNAL(valueChanged(double)), this, SLOT(UpdateImageInfo())); connect(m_Controls.SpeedOfSound, SIGNAL(valueChanged(double)), this, SLOT(ChangedSOSBeamforming())); connect(m_Controls.BPSpeedOfSound, SIGNAL(valueChanged(double)), this, SLOT(ChangedSOSBandpass())); connect(m_Controls.Samples, SIGNAL(valueChanged(int)), this, SLOT(UpdateImageInfo())); connect(m_Controls.UseImageSpacing, SIGNAL(clicked()), this, SLOT(UpdateImageInfo())); connect(m_Controls.boundLow, SIGNAL(valueChanged(int)), this, SLOT(LowerSliceBoundChanged())); connect(m_Controls.boundHigh, SIGNAL(valueChanged(int)), this, SLOT(UpperSliceBoundChanged())); connect(m_Controls.Partial, SIGNAL(clicked()), this, SLOT(SliceBoundsEnabled())); connect(m_Controls.BatchProcessing, SIGNAL(clicked()), this, SLOT(BatchProcessing())); connect(m_Controls.StepBeamforming, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); connect(m_Controls.StepCropping, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); connect(m_Controls.StepBandpass, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); connect(m_Controls.StepBMode, SIGNAL(clicked()), this, SLOT(UpdateSaveBoxes())); + connect(m_Controls.UseSignalDelay, SIGNAL(clicked()), this, SLOT(UseSignalDelay())); UpdateSaveBoxes(); + UseSignalDelay(); m_Controls.DoResampling->setChecked(false); m_Controls.ResamplingValue->setEnabled(false); m_Controls.progressBar->setMinimum(0); m_Controls.progressBar->setMaximum(100); m_Controls.progressBar->setVisible(false); m_Controls.UseImageSpacing->setToolTip("Image spacing of y-Axis must be in us, x-Axis in mm."); m_Controls.UseImageSpacing->setToolTipDuration(5000); m_Controls.ProgressInfo->setVisible(false); - m_Controls.UseBP->hide(); m_Controls.UseGPUBmode->hide(); #ifndef PHOTOACOUSTICS_USE_GPU m_Controls.UseGPUBf->setEnabled(false); m_Controls.UseGPUBf->setChecked(false); m_Controls.UseGPUBmode->setEnabled(false); m_Controls.UseGPUBmode->setChecked(false); #endif UseImageSpacing(); } +void PAImageProcessing::UseSignalDelay() +{ + if (m_Controls.UseSignalDelay->isChecked()) + { + m_Controls.SignalDelay->setEnabled(true); + } + else + { + m_Controls.SignalDelay->setEnabled(false); + } +} + void PAImageProcessing::ChangedSOSBandpass() { m_Controls.SpeedOfSound->setValue(m_Controls.BPSpeedOfSound->value()); } void PAImageProcessing::ChangedSOSBeamforming() { m_Controls.BPSpeedOfSound->setValue(m_Controls.SpeedOfSound->value()); } std::vector splitpath( const std::string& str , const std::set delimiters) { std::vector result; char const* pch = str.c_str(); char const* start = pch; for (; *pch; ++pch) { if (delimiters.find(*pch) != delimiters.end()) { if (start != pch) { std::string str(start, pch); result.push_back(str); } else { result.push_back(""); } start = pch + 1; } } result.push_back(start); return result; } void PAImageProcessing::UpdateSaveBoxes() { if (m_Controls.StepBeamforming->isChecked()) m_Controls.SaveBeamforming->setEnabled(true); else m_Controls.SaveBeamforming->setEnabled(false); if (m_Controls.StepCropping->isChecked()) m_Controls.SaveCropping->setEnabled(true); else m_Controls.SaveCropping->setEnabled(false); if (m_Controls.StepBandpass->isChecked()) m_Controls.SaveBandpass->setEnabled(true); else m_Controls.SaveBandpass->setEnabled(false); if (m_Controls.StepBMode->isChecked()) m_Controls.SaveBMode->setEnabled(true); else m_Controls.SaveBMode->setEnabled(false); } void PAImageProcessing::BatchProcessing() { QFileDialog LoadDialog(nullptr, "Select Files to be processed"); LoadDialog.setFileMode(QFileDialog::FileMode::ExistingFiles); LoadDialog.setNameFilter(tr("Images (*.nrrd)")); LoadDialog.setViewMode(QFileDialog::Detail); QStringList fileNames; if (LoadDialog.exec()) fileNames = LoadDialog.selectedFiles(); QString saveDir = QFileDialog::getExistingDirectory(nullptr, tr("Select Directory To Save To"), "", QFileDialog::ShowDirsOnly | QFileDialog::DontResolveSymlinks); DisableControls(); std::set delims{ '/' }; bool doSteps[] = { m_Controls.StepBeamforming->isChecked(), m_Controls.StepCropping->isChecked() , m_Controls.StepBandpass->isChecked(), m_Controls.StepBMode->isChecked() }; bool saveSteps[] = { m_Controls.SaveBeamforming->isChecked(), m_Controls.SaveCropping->isChecked() , m_Controls.SaveBandpass->isChecked(), m_Controls.SaveBMode->isChecked() }; for (int fileNumber = 0; fileNumber < fileNames.size(); ++fileNumber) { m_Controls.progressBar->setValue(0); m_Controls.progressBar->setVisible(true); m_Controls.ProgressInfo->setVisible(true); m_Controls.ProgressInfo->setText("loading file"); QString filename = fileNames.at(fileNumber); auto split = splitpath(filename.toStdString(), delims); std::string imageName = split.at(split.size() - 1); // remove ".nrrd" imageName = imageName.substr(0, imageName.size() - 5); mitk::Image::Pointer image = mitk::IOUtil::Load(filename.toStdString().c_str()); auto BFconfig = CreateBeamformingSettings(image); // Beamforming if (doSteps[0]) { std::function progressHandle = [this](int progress, std::string progressInfo) { this->UpdateProgress(progress, progressInfo); }; m_Controls.progressBar->setValue(100); image = m_FilterBank->ApplyBeamforming(image, BFconfig, progressHandle); if (saveSteps[0]) { std::string saveFileName = saveDir.toStdString() + "/" + imageName + " beamformed" + ".nrrd"; mitk::IOUtil::Save(image, saveFileName); } } // Cropping if (doSteps[1]) { m_Controls.ProgressInfo->setText("cropping image"); image = m_FilterBank->ApplyCropping(image, m_Controls.CutoffAbove->value(), m_Controls.CutoffBelow->value(), 0, 0, 0, 0); if (saveSteps[1]) { std::string saveFileName = saveDir.toStdString() + "/" + imageName + " cropped" + ".nrrd"; mitk::IOUtil::Save(image, saveFileName); } } // Bandpass if (doSteps[2]) { m_Controls.ProgressInfo->setText("applying bandpass"); float recordTime = image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / 1000 / m_Controls.BPSpeedOfSound->value(); // add a safeguard so the program does not chrash when applying a Bandpass that reaches out of the bounds of the image float maxFrequency = 1 / (recordTime / image->GetDimension(1)) * image->GetDimension(1) / 2 / 2 / 1000; float BPHighPass = 1000000 * m_Controls.BPhigh->value(); // [Hz] float BPLowPass = maxFrequency - 1000000 * m_Controls.BPlow->value(); // [Hz] - if (BPLowPass > maxFrequency && m_Controls.UseBP->isChecked()) + if (BPLowPass > maxFrequency) { QMessageBox Msgbox; Msgbox.setText("LowPass too low, disabled it."); Msgbox.exec(); BPLowPass = 0; } - if (BPLowPass < 0 && m_Controls.UseBP->isChecked()) + if (BPLowPass < 0) { QMessageBox Msgbox; Msgbox.setText("LowPass too high, disabled it."); Msgbox.exec(); BPLowPass = 0; } - if (BPHighPass > maxFrequency && m_Controls.UseBP->isChecked()) + if (BPHighPass > maxFrequency) { QMessageBox Msgbox; Msgbox.setText("HighPass too high, disabled it."); Msgbox.exec(); BPHighPass = 0; } if (BPHighPass > maxFrequency - BPLowPass) { QMessageBox Msgbox; Msgbox.setText("HighPass higher than LowPass, disabled both."); Msgbox.exec(); BPHighPass = 0; BPLowPass = 0; } image = m_FilterBank->ApplyBandpassFilter(image, BPHighPass, BPLowPass, m_Controls.BPFalloffHigh->value(), m_Controls.BPFalloffLow->value()); if (saveSteps[2]) { std::string saveFileName = saveDir.toStdString() + "/" + imageName + " bandpassed" + ".nrrd"; mitk::IOUtil::Save(image, saveFileName); } } // Bmode if (doSteps[3]) { m_Controls.ProgressInfo->setText("applying bmode filter"); if (m_Controls.BModeMethod->currentText() == "Absolute Filter") image = m_FilterBank->ApplyBmodeFilter(image, mitk::PhotoacousticFilterService::BModeMethod::Abs, m_UseLogfilter); else if (m_Controls.BModeMethod->currentText() == "Envelope Detection") image = m_FilterBank->ApplyBmodeFilter(image, mitk::PhotoacousticFilterService::BModeMethod::EnvelopeDetection, m_UseLogfilter); double desiredSpacing[2]{ image->GetGeometry()->GetSpacing()[0], m_ResampleSpacing }; image = m_FilterBank->ApplyResampling(image, desiredSpacing); if (saveSteps[3]) { std::string saveFileName = saveDir.toStdString() + "/" + imageName + " bmode" + ".nrrd"; mitk::IOUtil::Save(image, saveFileName); } } m_Controls.progressBar->setVisible(false); } EnableControls(); } void PAImageProcessing::StartBeamformingThread() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::DataNode::Pointer 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; } 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) { auto BFconfig = CreateBeamformingSettings(image); std::stringstream message; std::string name; message << "Performing beamforming for image "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; m_OldNodeName = name; } else m_OldNodeName = " "; message << "."; MITK_INFO << message.str(); m_Controls.progressBar->setValue(0); m_Controls.progressBar->setVisible(true); m_Controls.ProgressInfo->setVisible(true); m_Controls.ProgressInfo->setText("started"); DisableControls(); BeamformingThread *thread = new BeamformingThread(); connect(thread, &BeamformingThread::result, this, &PAImageProcessing::HandleResults); connect(thread, &BeamformingThread::updateProgress, this, &PAImageProcessing::UpdateProgress); connect(thread, &BeamformingThread::finished, thread, &QObject::deleteLater); thread->setConfig(BFconfig); + + if (m_Controls.UseSignalDelay->isChecked()) + thread->setSignalDelay(m_Controls.SignalDelay->value()); + thread->setInputImage(image); thread->setFilterBank(m_FilterBank); MITK_INFO << "Started new thread for Beamforming"; thread->start(); } } } void PAImageProcessing::HandleResults(mitk::Image::Pointer image, std::string nameExtension) { MITK_INFO << "Handling results..."; auto newNode = mitk::DataNode::New(); newNode->SetData(image); newNode->SetName(m_OldNodeName + nameExtension); // update level window for the current dynamic range mitk::LevelWindow levelWindow; newNode->GetLevelWindow(levelWindow); levelWindow.SetAuto(image, true, true); newNode->SetLevelWindow(levelWindow); // add new node to data storage this->GetDataStorage()->Add(newNode); // disable progress bar m_Controls.progressBar->setVisible(false); m_Controls.ProgressInfo->setVisible(false); EnableControls(); // update rendering mitk::RenderingManager::GetInstance()->InitializeViews(image->GetGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); MITK_INFO << "Handling results...[Done]"; } void PAImageProcessing::StartBmodeThread() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::DataNode::Pointer 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; } 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 << "'"; m_OldNodeName = name; } else m_OldNodeName = " "; message << "."; MITK_INFO << message.str(); DisableControls(); BmodeThread *thread = new BmodeThread(); connect(thread, &BmodeThread::result, this, &PAImageProcessing::HandleResults); connect(thread, &BmodeThread::finished, thread, &QObject::deleteLater); bool useGPU = m_Controls.UseGPUBmode->isChecked(); if (m_Controls.BModeMethod->currentText() == "Absolute Filter") thread->setConfig(m_UseLogfilter, m_ResampleSpacing, mitk::PhotoacousticFilterService::BModeMethod::Abs, useGPU); else if (m_Controls.BModeMethod->currentText() == "Envelope Detection") thread->setConfig(m_UseLogfilter, m_ResampleSpacing, mitk::PhotoacousticFilterService::BModeMethod::EnvelopeDetection, useGPU); thread->setInputImage(image); thread->setFilterBank(m_FilterBank); MITK_INFO << "Started new thread for Image Processing"; thread->start(); } } } void PAImageProcessing::StartCropThread() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::DataNode::Pointer 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 cropping."); return; } 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 cropping for image "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; m_OldNodeName = name; } else m_OldNodeName = " "; message << "."; MITK_INFO << message.str(); DisableControls(); CropThread *thread = new CropThread(); connect(thread, &CropThread::result, this, &PAImageProcessing::HandleResults); connect(thread, &CropThread::finished, thread, &QObject::deleteLater); if(m_Controls.Partial->isChecked()) thread->setConfig(m_Controls.CutoffAbove->value(), m_Controls.CutoffBelow->value(), m_Controls.boundLow->value(), m_Controls.boundHigh->value()); else thread->setConfig(m_Controls.CutoffAbove->value(), m_Controls.CutoffBelow->value(), 0, image->GetDimension(2) - 1); thread->setInputImage(image); thread->setFilterBank(m_FilterBank); MITK_INFO << "Started new thread for Image Cropping"; thread->start(); } } } void PAImageProcessing::StartBandpassThread() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataStorage::Pointer storage = this->GetDataStorage(); mitk::DataNode::Pointer node = nodes.front(); if (!node) { // Nothing selected. Inform the user and return QMessageBox::information(NULL, "Template", "Please load and select an image before applying a bandpass filter."); return; } 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 Bandpass filter on image "; if (node->GetName(name)) { // a property called "name" was found for this DataNode message << "'" << name << "'"; m_OldNodeName = name; } else m_OldNodeName = " "; message << "."; MITK_INFO << message.str(); DisableControls(); BandpassThread *thread = new BandpassThread(); connect(thread, &BandpassThread::result, this, &PAImageProcessing::HandleResults); connect(thread, &BandpassThread::finished, thread, &QObject::deleteLater); float BPHighPass = 1000000.0f * m_Controls.BPhigh->value(); // [Now in Hz] float BPLowPass = 1000000.0f * m_Controls.BPlow->value(); // [Now in Hz] thread->setConfig(BPHighPass, BPLowPass, m_Controls.BPFalloffLow->value(), m_Controls.BPFalloffHigh->value(), 0); thread->setInputImage(image); thread->setFilterBank(m_FilterBank); MITK_INFO << "Started new thread for Bandpass filter"; thread->start(); } } } void PAImageProcessing::SliceBoundsEnabled() { if (!m_Controls.Partial->isChecked()) { m_Controls.boundLow->setEnabled(false); m_Controls.boundHigh->setEnabled(false); return; } else { m_Controls.boundLow->setEnabled(true); m_Controls.boundHigh->setEnabled(true); } } void PAImageProcessing::UpperSliceBoundChanged() { if (m_Controls.boundLow->value() > m_Controls.boundHigh->value()) { m_Controls.boundLow->setValue(m_Controls.boundHigh->value()); } } void PAImageProcessing::LowerSliceBoundChanged() { if (m_Controls.boundLow->value() > m_Controls.boundHigh->value()) { m_Controls.boundHigh->setValue(m_Controls.boundLow->value()); } } void PAImageProcessing::UpdateProgress(int progress, std::string progressInfo) { if (progress < 100) m_Controls.progressBar->setValue(progress); else m_Controls.progressBar->setValue(100); m_Controls.ProgressInfo->setText(progressInfo.c_str()); qApp->processEvents(); } void PAImageProcessing::PAMessageBox(std::string message) { if (0 != message.compare("noMessage")) { QMessageBox msgBox; msgBox.setText(message.c_str()); msgBox.exec(); } } void PAImageProcessing::UpdateImageInfo() { QList nodes = this->GetDataManagerSelection(); if (nodes.empty()) return; mitk::DataNode::Pointer node = nodes.front(); if (!node) { // Nothing selected return; } 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) { // beamforming configs if (m_Controls.UseImageSpacing->isChecked()) { m_Controls.ElementCount->setValue(image->GetDimension(0)); m_Controls.Pitch->setValue(image->GetGeometry()->GetSpacing()[0]); } m_Controls.boundLow->setMaximum(image->GetDimension(2) - 1); m_Controls.boundHigh->setMaximum(image->GetDimension(2) - 1); float speedOfSound = m_Controls.SpeedOfSound->value(); // [m/s] std::stringstream frequency; float timeSpacing; if (m_Controls.UseImageSpacing->isChecked()) { timeSpacing = image->GetGeometry()->GetSpacing()[1] / 1000000.0f; MITK_INFO << "Calculated Scan Depth of " << (image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / 1000000) * speedOfSound * 100 / 2 << "cm"; } else { timeSpacing = (2 * m_Controls.ScanDepth->value() / 1000 / speedOfSound) / image->GetDimension(1); } float maxFrequency = (1 / timeSpacing) * image->GetDimension(1) / 2 / 2 / 1000; frequency << maxFrequency / 1000000; //[MHz] frequency << "MHz"; m_Controls.BPhigh->setMaximum(maxFrequency / 1000000); m_Controls.BPlow->setMaximum(maxFrequency / 1000000); frequency << " is the maximal allowed frequency for the selected image."; m_Controls.BPhigh->setToolTip(frequency.str().c_str()); m_Controls.BPlow->setToolTip(frequency.str().c_str()); m_Controls.BPhigh->setToolTipDuration(5000); m_Controls.BPlow->setToolTipDuration(5000); } } } void PAImageProcessing::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())) { m_Controls.labelWarning->setVisible(false); m_Controls.buttonApplyBModeFilter->setEnabled(true); m_Controls.labelWarning2->setVisible(false); m_Controls.buttonApplyCropFilter->setEnabled(true); m_Controls.labelWarning3->setVisible(false); m_Controls.buttonApplyBandpass->setEnabled(true); m_Controls.labelWarning4->setVisible(false); m_Controls.buttonApplyBeamforming->setEnabled(true); UpdateImageInfo(); return; } } m_Controls.labelWarning->setVisible(true); m_Controls.buttonApplyBModeFilter->setEnabled(false); m_Controls.labelWarning2->setVisible(true); m_Controls.buttonApplyCropFilter->setEnabled(false); m_Controls.labelWarning3->setVisible(true); m_Controls.buttonApplyBandpass->setEnabled(false); m_Controls.labelWarning4->setVisible(true); m_Controls.buttonApplyBeamforming->setEnabled(false); } void PAImageProcessing::UseResampling() { if (m_Controls.DoResampling->isChecked()) { m_Controls.ResamplingValue->setEnabled(true); m_ResampleSpacing = m_Controls.ResamplingValue->value(); } else { m_Controls.ResamplingValue->setEnabled(false); m_ResampleSpacing = 0; } } void PAImageProcessing::UseLogfilter() { m_UseLogfilter = m_Controls.Logfilter->isChecked(); } void PAImageProcessing::SetResampling() { m_ResampleSpacing = m_Controls.ResamplingValue->value(); } mitk::BeamformingSettings::Pointer PAImageProcessing::CreateBeamformingSettings(mitk::Image::Pointer image) { mitk::BeamformingSettings::BeamformingAlgorithm algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DAS; if ("DAS" == m_Controls.BFAlgorithm->currentText()) algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DAS; else if ("DMAS" == m_Controls.BFAlgorithm->currentText()) algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::DMAS; else if ("sDMAS" == m_Controls.BFAlgorithm->currentText()) algorithm = mitk::BeamformingSettings::BeamformingAlgorithm::sDMAS; mitk::BeamformingSettings::DelayCalc delay = mitk::BeamformingSettings::DelayCalc::Spherical; mitk::BeamformingSettings::Apodization apod = mitk::BeamformingSettings::Apodization::Box; if ("Von Hann" == m_Controls.Apodization->currentText()) { apod = mitk::BeamformingSettings::Apodization::Hann; } else if ("Hamming" == m_Controls.Apodization->currentText()) { apod = mitk::BeamformingSettings::Apodization::Hamm; } else if ("Box" == m_Controls.Apodization->currentText()) { apod = mitk::BeamformingSettings::Apodization::Box; } float pitchInMeters = m_Controls.Pitch->value() / 1000; // [m] float speedOfSound = m_Controls.SpeedOfSound->value(); // [m/s] unsigned int samplesPerLine = m_Controls.Samples->value(); unsigned int reconstructionLines = m_Controls.Lines->value(); unsigned int apodizatonArraySize = m_Controls.Lines->value(); float angle = m_Controls.Angle->value(); // [deg] bool useGPU = m_Controls.UseGPUBf->isChecked(); float timeSpacing; if (m_Controls.UseImageSpacing->isChecked()) { timeSpacing = image->GetGeometry()->GetSpacing()[1] / 1000000.0f; MITK_INFO << "Calculated Scan Depth of " << (image->GetDimension(1)*image->GetGeometry()->GetSpacing()[1] / 1000000) * speedOfSound * 100 / 2 << "cm"; } else { timeSpacing = (2 * m_Controls.ScanDepth->value() / 1000 / speedOfSound) / image->GetDimension(1); } bool isPAImage = true; if ("US Image" == m_Controls.ImageType->currentText()) { isPAImage = false; } else if ("PA Image" == m_Controls.ImageType->currentText()) { isPAImage = true; } float reconstructionDepth = m_Controls.ReconstructionDepth->value() / 1000.f; // [m] return mitk::BeamformingSettings::New(pitchInMeters, speedOfSound, timeSpacing, angle, isPAImage, samplesPerLine, reconstructionLines, image->GetDimensions(), reconstructionDepth, useGPU, 16, delay, apod, apodizatonArraySize, algorithm); } void PAImageProcessing::EnableControls() { m_Controls.BatchProcessing->setEnabled(true); m_Controls.StepBeamforming->setEnabled(true); m_Controls.StepBandpass->setEnabled(true); m_Controls.StepCropping->setEnabled(true); m_Controls.StepBMode->setEnabled(true); UpdateSaveBoxes(); m_Controls.DoResampling->setEnabled(true); UseResampling(); m_Controls.Logfilter->setEnabled(true); m_Controls.BModeMethod->setEnabled(true); m_Controls.buttonApplyBModeFilter->setEnabled(true); m_Controls.CutoffAbove->setEnabled(true); m_Controls.CutoffBelow->setEnabled(true); m_Controls.buttonApplyCropFilter->setEnabled(true); m_Controls.BPSpeedOfSound->setEnabled(true); m_Controls.buttonApplyBandpass->setEnabled(true); m_Controls.Partial->setEnabled(true); m_Controls.boundHigh->setEnabled(true); m_Controls.boundLow->setEnabled(true); m_Controls.BFAlgorithm->setEnabled(true); m_Controls.ReconstructionDepth->setEnabled(true); m_Controls.ImageType->setEnabled(true); m_Controls.Apodization->setEnabled(true); - m_Controls.UseBP->setEnabled(true); #ifdef PHOTOACOUSTICS_USE_GPU m_Controls.UseGPUBf->setEnabled(true); m_Controls.UseGPUBmode->setEnabled(true); #endif m_Controls.BPhigh->setEnabled(true); m_Controls.BPlow->setEnabled(true); m_Controls.BPFalloffLow->setEnabled(true); m_Controls.BPFalloffHigh->setEnabled(true); m_Controls.UseImageSpacing->setEnabled(true); UseImageSpacing(); m_Controls.Pitch->setEnabled(true); m_Controls.ElementCount->setEnabled(true); m_Controls.SpeedOfSound->setEnabled(true); m_Controls.Samples->setEnabled(true); m_Controls.Lines->setEnabled(true); m_Controls.Angle->setEnabled(true); m_Controls.buttonApplyBeamforming->setEnabled(true); + m_Controls.UseSignalDelay->setEnabled(true); + m_Controls.SignalDelay->setEnabled(true); } void PAImageProcessing::DisableControls() { m_Controls.BatchProcessing->setEnabled(false); m_Controls.StepBeamforming->setEnabled(false); m_Controls.StepBandpass->setEnabled(false); m_Controls.StepCropping->setEnabled(false); m_Controls.StepBMode->setEnabled(false); m_Controls.SaveBeamforming->setEnabled(false); m_Controls.SaveBandpass->setEnabled(false); m_Controls.SaveCropping->setEnabled(false); m_Controls.SaveBMode->setEnabled(false); m_Controls.DoResampling->setEnabled(false); m_Controls.ResamplingValue->setEnabled(false); m_Controls.Logfilter->setEnabled(false); m_Controls.BModeMethod->setEnabled(false); m_Controls.buttonApplyBModeFilter->setEnabled(false); m_Controls.CutoffAbove->setEnabled(false); m_Controls.CutoffBelow->setEnabled(false); m_Controls.buttonApplyCropFilter->setEnabled(false); m_Controls.BPSpeedOfSound->setEnabled(false); m_Controls.buttonApplyBandpass->setEnabled(false); m_Controls.Partial->setEnabled(false); m_Controls.boundHigh->setEnabled(false); m_Controls.boundLow->setEnabled(false); m_Controls.BFAlgorithm->setEnabled(false); m_Controls.ReconstructionDepth->setEnabled(false); m_Controls.ImageType->setEnabled(false); m_Controls.Apodization->setEnabled(false); - m_Controls.UseBP->setEnabled(false); #ifdef PHOTOACOUSTICS_USE_GPU m_Controls.UseGPUBf->setEnabled(false); m_Controls.UseGPUBmode->setEnabled(false); #endif m_Controls.BPhigh->setEnabled(false); m_Controls.BPlow->setEnabled(false); m_Controls.BPFalloffLow->setEnabled(false); m_Controls.BPFalloffHigh->setEnabled(false); m_Controls.UseImageSpacing->setEnabled(false); m_Controls.ScanDepth->setEnabled(false); m_Controls.Pitch->setEnabled(false); m_Controls.ElementCount->setEnabled(false); m_Controls.SpeedOfSound->setEnabled(false); m_Controls.Samples->setEnabled(false); m_Controls.Lines->setEnabled(false); m_Controls.Angle->setEnabled(false); m_Controls.buttonApplyBeamforming->setEnabled(false); + m_Controls.UseSignalDelay->setEnabled(false); + m_Controls.SignalDelay->setEnabled(false); } void PAImageProcessing::UseImageSpacing() { if (m_Controls.UseImageSpacing->isChecked()) { m_Controls.ScanDepth->setDisabled(true); } else { m_Controls.ScanDepth->setEnabled(true); } } #include void BeamformingThread::run() { - mitk::Image::Pointer resultImage = mitk::Image::New(); - mitk::Image::Pointer resultImageBuffer; + mitk::Image::Pointer preprocessedImage = m_InputImage; + if (m_SignalDelay != 0) + { + int cropPixels = std::round(m_SignalDelay / m_BFconfig->GetTimeSpacing() / 1000000); + MITK_INFO << cropPixels; + preprocessedImage = m_FilterBank->ApplyCropping(m_InputImage, cropPixels, 0, 0, 0, 0, m_InputImage->GetDimension(2) - 1); + } + + mitk::Image::Pointer resultImage; std::function progressHandle = [this](int progress, std::string progressInfo) { emit updateProgress(progress, progressInfo); }; - resultImageBuffer = m_FilterBank->ApplyBeamforming(m_InputImage, m_BFconfig, progressHandle); - emit result(resultImageBuffer, "_bf"); + resultImage = m_FilterBank->ApplyBeamforming(preprocessedImage, m_BFconfig, progressHandle); + emit result(resultImage, "_bf"); } void BeamformingThread::setConfig(mitk::BeamformingSettings::Pointer BFconfig) { m_BFconfig = BFconfig; } +void BeamformingThread::setSignalDelay(float delay) +{ + m_SignalDelay = delay; +} + void BeamformingThread::setInputImage(mitk::Image::Pointer image) { m_InputImage = image; } void BmodeThread::run() { mitk::Image::Pointer resultImage = m_FilterBank->ApplyBmodeFilter(m_InputImage, m_Method, m_UseLogfilter); if (m_ResampleSpacing != 0) { double desiredSpacing[2]{ m_InputImage->GetGeometry()->GetSpacing()[0], m_ResampleSpacing }; resultImage = m_FilterBank->ApplyResampling(resultImage, desiredSpacing); } emit result(resultImage, "_bmode"); } void BmodeThread::setConfig(bool useLogfilter, double resampleSpacing, mitk::PhotoacousticFilterService::BModeMethod method, bool useGPU) { m_UseLogfilter = useLogfilter; m_ResampleSpacing = resampleSpacing; m_Method = method; m_UseGPU = useGPU; } void BmodeThread::setInputImage(mitk::Image::Pointer image) { m_InputImage = image; } void CropThread::run() { mitk::Image::Pointer resultImage; resultImage = m_FilterBank->ApplyCropping(m_InputImage, m_CutAbove, m_CutBelow, 0, 0, m_CutSliceFirst, (m_InputImage->GetDimension(2) - 1) - m_CutSliceLast); emit result(resultImage, "_cropped"); } void CropThread::setConfig(unsigned int CutAbove, unsigned int CutBelow, unsigned int CutSliceFirst, unsigned int CutSliceLast) { m_CutAbove = CutAbove; m_CutBelow = CutBelow; m_CutSliceLast = CutSliceLast; m_CutSliceFirst = CutSliceFirst; } void CropThread::setInputImage(mitk::Image::Pointer image) { m_InputImage = image; } void BandpassThread::run() { mitk::Image::Pointer resultImage = m_FilterBank->ApplyBandpassFilter(m_InputImage, m_BPHighPass, m_BPLowPass, m_TukeyAlphaHighPass, m_TukeyAlphaLowPass); emit result(resultImage, "_bandpassed"); } void BandpassThread::setConfig(float BPHighPass, float BPLowPass, float TukeyAlphaHighPass, float TukeyAlphaLowPass, float recordTime) { m_BPHighPass = BPHighPass; m_BPLowPass = BPLowPass; m_TukeyAlphaHighPass = TukeyAlphaHighPass; m_TukeyAlphaLowPass = TukeyAlphaLowPass; m_RecordTime = recordTime; } void BandpassThread::setInputImage(mitk::Image::Pointer image) { m_InputImage = image; } diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h index c111aa71df..1b90f0d277 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessing.h @@ -1,237 +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. ===================================================================*/ #ifndef PAImageProcessing_h #define PAImageProcessing_h #include #include #include #include #include "ui_PAImageProcessingControls.h" #include "mitkBeamformingFilter.h" #include "mitkBeamformingSettings.h" Q_DECLARE_METATYPE(mitk::Image::Pointer) Q_DECLARE_METATYPE(std::string) /*! * \brief Plugin implementing an interface for the Photoacoustic Algorithms Module * * Beamforming, Image processing as B-Mode filtering, cropping, resampling, as well as batch processing can be performed using this plugin. */ class PAImageProcessing : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) Q_OBJECT public: static const std::string VIEW_ID; PAImageProcessing(); protected slots: void UpperSliceBoundChanged(); void LowerSliceBoundChanged(); void SliceBoundsEnabled(); void UseResampling(); void UseLogfilter(); void SetResampling(); void UseImageSpacing(); void UpdateImageInfo(); + void UseSignalDelay(); /** \brief Beamforming is being performed in a separate thread to keep the workbench from freezing. */ void StartBeamformingThread(); /** \brief B-mode filtering is being performed in a separate thread to keep the workbench from freezing. */ void StartBmodeThread(); /** \brief Cropping is being performed in a separate thread to keep the workbench from freezing. */ void StartCropThread(); /** \brief Method called when the bandpass thread finishes; * it adds the image to a new data node and registers it to the worbench's data storage */ void HandleResults(mitk::Image::Pointer image, std::string nameExtension); /** \brief Bandpassing is being performed in a separate thread to keep the workbench from freezing. */ void StartBandpassThread(); void UpdateProgress(int progress, std::string progressInfo); void PAMessageBox(std::string message); void BatchProcessing(); void UpdateSaveBoxes(); void ChangedSOSBandpass(); void ChangedSOSBeamforming(); protected: virtual void CreateQtPartControl(QWidget *parent) override; virtual void SetFocus() override; /** \brief called by QmitkFunctionality when DataManager's selection has changed. * On a change some parameters are internally updated to calculate bounds for GUI elements as the slice selector for beamforming or * the bandpass filter settings. */ virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer source, const QList& nodes) override; /** \brief Instance of the GUI controls */ Ui::PAImageProcessingControls m_Controls; float m_ResampleSpacing; bool m_UseLogfilter; std::string m_OldNodeName; /** \brief Method for updating the BFconfig by using a selected image and the GUI configuration. */ mitk::BeamformingSettings::Pointer CreateBeamformingSettings(mitk::Image::Pointer image); void EnableControls(); void DisableControls(); /** \brief Class through which the filters are called. */ mitk::PhotoacousticFilterService::Pointer m_FilterBank; }; class BeamformingThread : public QThread { Q_OBJECT void run() Q_DECL_OVERRIDE; signals: void result(mitk::Image::Pointer, std::string nameExtension); void updateProgress(int, std::string); void message(std::string); public: + BeamformingThread() : m_SignalDelay(0) {} + void setConfig(mitk::BeamformingSettings::Pointer BFconfig); + void setSignalDelay(float delay); void setInputImage(mitk::Image::Pointer image); void setFilterBank(mitk::PhotoacousticFilterService::Pointer filterBank) { m_FilterBank = filterBank; } protected: mitk::BeamformingSettings::Pointer m_BFconfig; mitk::Image::Pointer m_InputImage; int m_Cutoff; + float m_SignalDelay; // [us] mitk::PhotoacousticFilterService::Pointer m_FilterBank; }; class BmodeThread : public QThread { Q_OBJECT void run() Q_DECL_OVERRIDE; signals: void result(mitk::Image::Pointer, std::string nameExtension); public: enum BModeMethod { ShapeDetection, Abs }; void setConfig(bool useLogfilter, double resampleSpacing, mitk::PhotoacousticFilterService::BModeMethod method, bool useGPU); void setInputImage(mitk::Image::Pointer image); void setFilterBank(mitk::PhotoacousticFilterService::Pointer filterBank) { m_FilterBank = filterBank; } protected: mitk::Image::Pointer m_InputImage; mitk::PhotoacousticFilterService::BModeMethod m_Method; bool m_UseLogfilter; double m_ResampleSpacing; bool m_UseGPU; mitk::PhotoacousticFilterService::Pointer m_FilterBank; }; class CropThread : public QThread { Q_OBJECT void run() Q_DECL_OVERRIDE; signals: void result(mitk::Image::Pointer, std::string nameExtension); public: void setConfig(unsigned int CutAbove, unsigned int CutBelow, unsigned int CutSliceFirst, unsigned int CutSliceLast); void setInputImage(mitk::Image::Pointer image); void setFilterBank(mitk::PhotoacousticFilterService::Pointer filterBank) { m_FilterBank = filterBank; } protected: mitk::Image::Pointer m_InputImage; unsigned int m_CutAbove; unsigned int m_CutBelow; unsigned int m_CutSliceLast; unsigned int m_CutSliceFirst; mitk::PhotoacousticFilterService::Pointer m_FilterBank; }; class BandpassThread : public QThread { Q_OBJECT void run() Q_DECL_OVERRIDE; signals: void result(mitk::Image::Pointer, std::string nameExtension); public: void setConfig(float BPHighPass, float BPLowPass, float TukeyAlphaHighPass, float TukeyAlphaLowPass, float recordTime); void setInputImage(mitk::Image::Pointer image); void setFilterBank(mitk::PhotoacousticFilterService::Pointer filterBank) { m_FilterBank = filterBank; } protected: mitk::Image::Pointer m_InputImage; float m_BPHighPass; float m_BPLowPass; float m_TukeyAlphaHighPass; float m_TukeyAlphaLowPass; float m_RecordTime; mitk::PhotoacousticFilterService::Pointer m_FilterBank; }; #endif // PAImageProcessing_h diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui index d4b2d03e51..5901dcb238 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/PAImageProcessingControls.ui @@ -1,998 +1,1011 @@ PAImageProcessingControls 0 0 385 1278 0 0 QmitkTemplate <html><head/><body><p><span style=" font-weight:600;">Batch Processing</span></p></body></html> Start Batch Processing Bandpass true Crop true Save false Save false Save true Beamform true BMode true Save true <html><head/><body><p><span style=" font-weight:600;">B-mode Filter Settings</span></p></body></html> Absolute Filter Absolute Filter Envelope Detection Do Resampling true 0 0 13 0 11 3 0.010000000000000 1.000000000000000 0.010000000000000 0.150000000000000 [mm] Resampled Depth Spacing Logarithmic Compression Use GPU QLabel { color: rgb(255, 0, 0) } <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600;">Please select an image!</span></p></body></html> 0 0 Do image processing Apply B-mode Filter Qt::Horizontal <html><head/><body><p><span style=" font-weight:600;">Bandpass Filter Settings</span></p></body></html> QLayout::SetDefaultConstraint 0 0 0 3 0.010000000000000 200.000000000000000 0.100000000000000 1.000000000000000 [MHz] f High Pass [MHz] f Low Pass 0 0 3 200.000000000000000 0.100000000000000 1 200.000000000000000 3000.000000000000000 5.000000000000000 1540.000000000000000 [m/s] Speed of Sound 1.000000000000000 0.100000000000000 0.500000000000000 Tukey Window α High Pass 2 1.000000000000000 0.100000000000000 0.000000000000000 Tukey Window α Low Pass <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600; color:#ff0000;">Please select an image!</span></p></body></html> Apply Bandpass Qt::Horizontal <html><head/><body><p><span style=" font-weight:600;">Crop Filter Settings</span></p></body></html> 99999 300 Cut Top Cut Bottom 99999 5 800 false 99999 Maximal beamformed slice max false 99999 10 minimal beamformed slice min select slices <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600; color:#ff0000;">Please select an image!</span></p></body></html> Apply Crop Filer Qt::Horizontal <html><head/><body><p><span style=" font-weight:600;">Beamforming Filter Settings</span></p></body></html> 5 2 - + 0 0 1 200.000000000000000 3000.000000000000000 5.000000000000000 1540.000000000000000 - + Auto Get Depth true - + Apply Beamforming - + Beamforming Method - + [mm] Scan Depth - + 0 0 3 0.010000000000000 9.000000000000000 0.050000000000000 0.300000000000000 - + Transducer Elements - + 0 0 4 300.000000000000000 0.100000000000000 50.000000000000000 - + [mm] Transducer Pitch - + 0 0 64 1024 128 128 - + 0 0 256 16384 256 2048 - + 0 0 64 2048 128 256 - + Samples - + Reconstruction Lines - + true 0 0 100 0 0 0 DAS DMAS sDMAS 0 0 PA Image US Image Image Type 0 0 Von Hann Hamming Box Apodization - + [m/s] Speed of Sound - + Compute On GPU true - - - - true - - - Auto Use Bandpass - - - 0 0 1 1.000000000000000 180.000000000000000 27.000000000000000 [°] Element Angle - + <html><head/><body><p align="center"><span style=" font-size:10pt; font-weight:600; color:#ff0000;">Please select an image!</span></p></body></html> - + [mm] Reconstruction Depth - + 4 300.000000000000000 0.100000000000000 10.000000000000000 + + + + 0.100000000000000 + + + 1.000000000000000 + + + + + + + <html><head/><body><p>Some setups' hardware produces signal delays that need to be cropped out of the image before performing beamforming. To do this, select this box.</p></body></html> + + + Consider Hardware Delay [µs] + + + false + + + Qt::Vertical 20 40 diff --git a/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.cpp b/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.cpp index 1307b4045e..99ef6fcaf9 100644 --- a/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.cpp +++ b/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.cpp @@ -1,114 +1,156 @@ /*=================================================================== 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. ===================================================================*/ // render window manager plugin #include "QmitkRenderWindowManagerView.h" // blueberry #include #include // mitk core #include #include +// org.mitk.gui.qt.common +#include + const std::string QmitkRenderWindowManagerView::VIEW_ID = "org.mitk.views.renderwindowmanager"; void QmitkRenderWindowManagerView::SetFocus() { // nothing here } void QmitkRenderWindowManagerView::CreateQtPartControl(QWidget* parent) { + m_Parent = parent; // create GUI widgets m_Controls.setupUi(parent); // add custom render window manager UI widget to the 'renderWindowManagerTab' m_RenderWindowManipulatorWidget = new QmitkRenderWindowManipulatorWidget(GetDataStorage(), parent); m_RenderWindowManipulatorWidget->setObjectName(QStringLiteral("m_RenderWindowManipulatorWidget")); m_Controls.verticalLayout->addWidget(m_RenderWindowManipulatorWidget); SetControlledRenderer(); for (const auto& renderer : m_ControlledRenderer) { m_Controls.comboBoxRenderWindowSelection->addItem(renderer->GetName()); } + SetUpConnections(); + OnRenderWindowSelectionChanged(m_Controls.comboBoxRenderWindowSelection->itemText(0)); +} +void QmitkRenderWindowManagerView::SetUpConnections() +{ connect(m_Controls.comboBoxRenderWindowSelection, SIGNAL(currentIndexChanged(const QString&)), this, SLOT(OnRenderWindowSelectionChanged(const QString&))); connect(m_RenderWindowManipulatorWidget, SIGNAL(AddLayerButtonClicked()), this, SLOT(OnAddLayerButtonClicked())); + + m_ModelViewSelectionConnector = std::make_unique(); + try + { + m_ModelViewSelectionConnector->SetView(m_RenderWindowManipulatorWidget->GetLayerStackTableView()); + } + catch (mitk::Exception& e) + { + mitkReThrow(e) << "Cannot connect the model-view pair signals and slots."; + } + m_SelectionServiceConnector = std::make_unique(); } void QmitkRenderWindowManagerView::SetControlledRenderer() { const mitk::RenderingManager::RenderWindowVector allRegisteredRenderWindows = mitk::RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); mitk::BaseRenderer* baseRenderer = nullptr; for (const auto &renderWindow : allRegisteredRenderWindows) { baseRenderer = mitk::BaseRenderer::GetInstance(renderWindow); if (nullptr != baseRenderer) { m_ControlledRenderer.push_back(baseRenderer); } } m_RenderWindowManipulatorWidget->SetControlledRenderer(m_ControlledRenderer); } void QmitkRenderWindowManagerView::OnRenderWindowSelectionChanged(const QString &renderWindowId) { m_RenderWindowManipulatorWidget->SetActiveRenderWindow(renderWindowId); } void QmitkRenderWindowManagerView::OnAddLayerButtonClicked() { - QList nodes = GetDataManagerSelection(); - for (mitk::DataNode* dataNode : nodes) + QmitkNodeSelectionDialog* dialog = new QmitkNodeSelectionDialog(m_Parent, "Select nodes to add to the render window", ""); + dialog->SetDataStorage(GetDataStorage()); + dialog->SetSelectOnlyVisibleNodes(true); + dialog->SetSelectionMode(QAbstractItemView::MultiSelection); + + if (QDialog::Accepted == dialog->exec()) { - if (nullptr != dataNode) + auto nodes = dialog->GetSelectedNodes(); + for (mitk::DataNode* dataNode : nodes) { - m_RenderWindowManipulatorWidget->AddLayer(dataNode); - - // get child nodes of the current node - mitk::DataStorage::SetOfObjects::ConstPointer derivedNodes = GetDataStorage()->GetDerivations(dataNode, nullptr, false); - for (mitk::DataStorage::SetOfObjects::ConstIterator it = derivedNodes->Begin(); it != derivedNodes->End(); ++it) + if (nullptr != dataNode) { - m_RenderWindowManipulatorWidget->AddLayer(it->Value()); + m_RenderWindowManipulatorWidget->AddLayer(dataNode); + + // get child nodes of the current node + mitk::DataStorage::SetOfObjects::ConstPointer derivedNodes = GetDataStorage()->GetDerivations(dataNode, nullptr, false); + for (mitk::DataStorage::SetOfObjects::ConstIterator it = derivedNodes->Begin(); it != derivedNodes->End(); ++it) + { + m_RenderWindowManipulatorWidget->AddLayer(it->Value()); + } } } } + + delete dialog; +} + +void QmitkRenderWindowManagerView::SetSelectionProvider() +{ + m_SelectionProvider = QmitkDataNodeSelectionProvider::Pointer(new QmitkDataNodeSelectionProvider); + m_SelectionProvider->SetItemSelectionModel(m_RenderWindowManipulatorWidget->GetLayerStackTableView()->selectionModel()); + GetSite()->SetSelectionProvider(berry::ISelectionProvider::Pointer(m_SelectionProvider)); + + // This function is called during the creation of the GUI. It is overridden in this class to create a custom selection provider. + // This view is used as a selection provider (not used as a selection listener) + m_SelectionServiceConnector->SetAsSelectionProvider(m_SelectionProvider.GetPointer()); + connect(m_ModelViewSelectionConnector.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector.get(), SLOT(ChangeServiceSelection(QList))); } void QmitkRenderWindowManagerView::NodeAdded(const mitk::DataNode* node) { bool global = false; node->GetBoolProperty("globalObject_RWM", global); if (global) { // initially insert new point set node into the node list of all render windows // the node object of a new point set won't be visible due to its "helper object" property set to true m_RenderWindowManipulatorWidget->AddLayerToAllRenderer(const_cast(node)); } else { // initially set new node as invisible in all render windows // this way, each single renderer overwrites the common renderer and the node is invisible // until it is inserted into the node list of a render windows m_RenderWindowManipulatorWidget->HideDataNodeInAllRenderer(node); } } diff --git a/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.h b/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.h index ba9743fb77..3d3968f752 100644 --- a/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.h +++ b/Plugins/org.mitk.gui.qt.renderwindowmanager/src/internal/QmitkRenderWindowManagerView.h @@ -1,82 +1,93 @@ /*=================================================================== 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 QMITKRENDERWINDOWMANAGERVIEW_H #define QMITKRENDERWINDOWMANAGERVIEW_H // render window manager plugin #include "ui_QmitkRenderWindowManagerControls.h" // render window manager UI module #include // blueberry #include -// qt +// mitk gui qt common plugin #include +#include "QmitkModelViewSelectionConnector.h" +#include "QmitkSelectionServiceConnector.h" /** * @brief RenderWindowManager */ class QmitkRenderWindowManagerView : public QmitkAbstractView { Q_OBJECT public: static const std::string VIEW_ID; protected: virtual void SetFocus() override; virtual void CreateQtPartControl(QWidget* parent) override; private Q_SLOTS: /** * @brief Called when the user changes the render window selection in the combo box. * * @param renderWindowId The text inside the combo box. */ void OnRenderWindowSelectionChanged(const QString &renderWindowId); /** * @brief Called when the 'AddLayer'-button of he render window manipulator widget has been pushed. */ void OnAddLayerButtonClicked(); private: + void SetUpConnections(); void SetControlledRenderer(); + /** + * @brief see QmitkAbstractView + */ + void SetSelectionProvider() override; /** * @brief Reacts to a node that has been added to the data storage. * 1. Insert new node into the node list of all render windows, if it is an "globalObject_RWM"-node. * or else * 2. Set data node invisible in all render windows, as soon as the node is added to the data storage. */ void NodeAdded(const mitk::DataNode* node) override; // the Qt parent of our GUI QWidget* m_Parent; Ui::QmitkRenderWindowManagerControls m_Controls; QmitkRenderWindowManipulatorWidget* m_RenderWindowManipulatorWidget; + std::unique_ptr m_ModelViewSelectionConnector; + std::unique_ptr m_SelectionServiceConnector; + QmitkDataNodeSelectionProvider::Pointer m_SelectionProvider; + RenderWindowLayerUtilities::RendererVector m_ControlledRenderer; }; #endif // QMITKRENDERWINDOWMANAGERVIEW_H