diff --git a/CMake/mitkFunctionCreateModule.cmake b/CMake/mitkFunctionCreateModule.cmake index 3aeba861c4..0934298042 100644 --- a/CMake/mitkFunctionCreateModule.cmake +++ b/CMake/mitkFunctionCreateModule.cmake @@ -1,656 +1,656 @@ ################################################################## # # mitk_create_module # #! Creates a module for the automatic module dependency system within MITK. #! #! Example: #! #! \code #! mitk_create_module( #! DEPENDS PUBLIC MitkCore #! PACKAGE_DEPENDS #! PRIVATE Qt5|Xml+Networking #! PUBLIC ITK|Watershed #! \endcode #! #! The parameter specifies the name of the module which is used #! to create a logical target name. The parameter is optional in case the #! MITK_MODULE_NAME_DEFAULTS_TO_DIRECTORY_NAME variable evaluates to TRUE. The #! module name will then be derived from the directory name in which this #! function is called. #! #! If set, the following variables will be used to validate the module name: #! #! MITK_MODULE_NAME_REGEX_MATCH The module name must match this regular expression. #! MITK_MODULE_NAME_REGEX_NOT_MATCH The module name must not match this regular expression. #! #! If the MITK_MODULE_NAME_PREFIX variable is set, the module name will be prefixed #! with its contents. #! #! A modules source files are specified in a separate CMake file usually #! called files.cmake, located in the module root directory. The #! mitk_create_module() macro evaluates the following CMake variables #! from the files.cmake file: #! #! - CPP_FILES A list of .cpp files #! - H_FILES A list of .h files without a corresponding .cpp file #! - TXX_FILES A list of .txx files #! - RESOURCE_FILES A list of files (resources) which are embedded into the module #! - MOC_H_FILES A list of Qt header files which should be processed by the MOC #! - UI_FILES A list of .ui Qt UI files #! - QRC_FILES A list of .qrc Qt resource files #! - DOX_FILES A list of .dox Doxygen files #! #! List of variables available after the function is called: #! - MODULE_NAME #! - MODULE_TARGET #! - MODULE_IS_ENABLED #! - MODULE_SUBPROJECTS #! #! \sa mitk_create_executable #! #! Parameters (all optional): #! #! \param The module name (also used as target name) #! \param FILES_CMAKE File name of a CMake file setting source list variables #! (defaults to files.cmake) #! \param VERSION Module version number, e.g. "1.2.0" #! \param AUTOLOAD_WITH A module target name identifying the module which will #! trigger the automatic loading of this module #! \param DEPRECATED_SINCE Marks this modules as deprecated since #! \param DESCRIPTION A description for this module #! #! Multi-value Parameters (all optional): #! #! \param SUBPROJECTS List of CDash labels #! \param INCLUDE_DIRS Include directories for this module: #! \verbatim #! [[PUBLIC|PRIVATE|INTERFACE] ...]... #! \endverbatim #! The default scope for include directories is PUBLIC. #! \param DEPENDS List of module dependencies: #! \verbatim #! [[PUBLIC|PRIVATE|INTERFACE] ...]... #! \endverbatim #! The default scope for module dependencies is PUBLIC. #! \param PACKAGE_DEPENDS List of public packages dependencies (e.g. Qt, VTK, etc.). #! Package dependencies have the following syntax: #! \verbatim #! [PUBLIC|PRIVATE|INTERFACE] PACKAGE[|COMPONENT1[+COMPONENT2]...] #! \endverbatim #! The default scope for package dependencies is PRIVATE. #! \param ADDITIONAL_LIBS List of additional private libraries linked to this module. #! The folder containing the library will be added to the global list of library search paths. #! \param CPP_FILES List of source files for this module. If the list is non-empty, #! the module does not need to provide a files.cmake file or FILES_CMAKE argument. #! \param H_FILES List of public header files for this module. It is recommended to use #! a files.cmake file instead. #! #! Options (optional) #! #! \param FORCE_STATIC Force building this module as a static library #! \param GCC_DEFAULT_VISIBILITY Do not use gcc visibility flags - all #! symbols will be exported #! \param NO_INIT Do not create CppMicroServices initialization code #! \param NO_FEATURE_INFO Do not create a feature info by calling add_feature_info() #! \param WARNINGS_NO_ERRORS Do not treat compiler warnings as errors # ################################################################## function(mitk_create_module) set(_macro_params VERSION # module version number, e.g. "1.2.0" EXPORT_DEFINE # export macro name for public symbols of this module (DEPRECATED) AUTOLOAD_WITH # a module target name identifying the module which will trigger the # automatic loading of this module FILES_CMAKE # file name of a CMake file setting source list variables # (defaults to files.cmake) DEPRECATED_SINCE # marks this modules as deprecated DESCRIPTION # a description for this module ) set(_macro_multiparams SUBPROJECTS # list of CDash labels INCLUDE_DIRS # include directories: [PUBLIC|PRIVATE|INTERFACE] INTERNAL_INCLUDE_DIRS # include dirs internal to this module (DEPRECATED) DEPENDS # list of modules this module depends on: [PUBLIC|PRIVATE|INTERFACE] DEPENDS_INTERNAL # list of modules this module internally depends on (DEPRECATED) PACKAGE_DEPENDS # list of "packages this module depends on (e.g. Qt, VTK, etc.): [PUBLIC|PRIVATE|INTERFACE] TARGET_DEPENDS # list of CMake targets this module should depend on ADDITIONAL_LIBS # list of addidtional private libraries linked to this module. CPP_FILES # list of cpp files H_FILES # list of header files: [PUBLIC|PRIVATE] ) set(_macro_options FORCE_STATIC # force building this module as a static library HEADERS_ONLY # this module is a headers-only library GCC_DEFAULT_VISIBILITY # do not use gcc visibility flags - all symbols will be exported NO_DEFAULT_INCLUDE_DIRS # do not add default include directories like "include" or "." NO_INIT # do not create CppMicroServices initialization code NO_FEATURE_INFO # do not create a feature info by calling add_feature_info() WARNINGS_NO_ERRORS # do not treat compiler warnings as errors EXECUTABLE # create an executable; do not use directly, use mitk_create_executable() instead C_MODULE # compile all source files as C sources CXX_MODULE # compile all source files as C++ sources ) cmake_parse_arguments(MODULE "${_macro_options}" "${_macro_params}" "${_macro_multiparams}" ${ARGN}) set(MODULE_NAME ${MODULE_UNPARSED_ARGUMENTS}) # ----------------------------------------------------------------- # Sanity checks if(NOT MODULE_NAME) if(MITK_MODULE_NAME_DEFAULTS_TO_DIRECTORY_NAME) get_filename_component(MODULE_NAME ${CMAKE_CURRENT_SOURCE_DIR} NAME) else() message(SEND_ERROR "The module name must not be empty") endif() endif() set(_deprecated_args INTERNAL_INCLUDE_DIRS DEPENDS_INTERNAL EXPORT_DEFINE TARGET_DEPENDS HEADERS_ONLY) foreach(_deprecated_arg ${_deprecated_args}) if(MODULE_${_deprecated_arg}) message(WARNING "The ${_deprecated_arg} argument is deprecated") endif() endforeach() set(_module_type module) set(_Module_type Module) if(MODULE_EXECUTABLE) set(_module_type executable) set(_Module_type Executable) endif() if(MITK_MODULE_NAME_REGEX_MATCH) if(NOT ${MODULE_NAME} MATCHES ${MITK_MODULE_NAME_REGEX_MATCH}) message(SEND_ERROR "The ${_module_type} name \"${MODULE_NAME}\" does not match the regular expression \"${MITK_MODULE_NAME_REGEX_MATCH}\".") endif() endif() if(MITK_MODULE_NAME_REGEX_NOT_MATCH) if(${MODULE_NAME} MATCHES ${MITK_MODULE_NAME_REGEX_NOT_MATCH}) message(SEND_ERROR "The ${_module_type} name \"${MODULE_NAME}\" must not match the regular expression \"${MITK_MODULE_NAME_REGEX_NOT_MATCH}\".") endif() endif() if(MITK_MODULE_NAME_PREFIX AND NOT MODULE_NAME MATCHES "^${MITK_MODULE_NAME_PREFIX}.*$") set(MODULE_NAME "${MITK_MODULE_NAME_PREFIX}${MODULE_NAME}") endif() if(NOT MODULE_FILES_CMAKE) set(MODULE_FILES_CMAKE files.cmake) endif() if(NOT IS_ABSOLUTE ${MODULE_FILES_CMAKE}) set(MODULE_FILES_CMAKE ${CMAKE_CURRENT_SOURCE_DIR}/${MODULE_FILES_CMAKE}) endif() if(NOT MODULE_SUBPROJECTS) if(MITK_DEFAULT_SUBPROJECTS) set(MODULE_SUBPROJECTS ${MITK_DEFAULT_SUBPROJECTS}) - else() + elseif(TARGET MITK-Modules) set(MODULE_SUBPROJECTS MITK-Modules) endif() endif() # check if the subprojects exist as targets if(MODULE_SUBPROJECTS) foreach(subproject ${MODULE_SUBPROJECTS}) if(NOT TARGET ${subproject}) message(SEND_ERROR "The subproject ${subproject} does not have a corresponding target") endif() endforeach() endif() # ----------------------------------------------------------------- # Check if module should be build set(MODULE_TARGET ${MODULE_NAME}) # assume worst case set(MODULE_IS_ENABLED 0) # first we check if we have an explicit module build list if(MITK_MODULES_TO_BUILD) list(FIND MITK_MODULES_TO_BUILD ${MODULE_NAME} _MOD_INDEX) if(_MOD_INDEX EQUAL -1) set(MODULE_IS_EXCLUDED 1) endif() endif() if(NOT MODULE_IS_EXCLUDED) # first of all we check for the dependencies _mitk_parse_package_args(${MODULE_PACKAGE_DEPENDS}) mitk_check_module_dependencies(MODULES ${MODULE_DEPENDS} PACKAGES ${PACKAGE_NAMES} MISSING_DEPENDENCIES_VAR _MISSING_DEP PACKAGE_DEPENDENCIES_VAR PACKAGE_NAMES) if(_MISSING_DEP) if(MODULE_NO_FEATURE_INFO) message("${_Module_type} ${MODULE_NAME} won't be built, missing dependency: ${_MISSING_DEP}") endif() set(MODULE_IS_ENABLED 0) else() set(MODULE_IS_ENABLED 1) # now check for every package if it is enabled. This overlaps a bit with # MITK_CHECK_MODULE ... foreach(_package ${PACKAGE_NAMES}) if((DEFINED MITK_USE_${_package}) AND NOT (MITK_USE_${_package})) message("${_Module_type} ${MODULE_NAME} won't be built. Turn on MITK_USE_${_package} if you want to use it.") set(MODULE_IS_ENABLED 0) break() endif() endforeach() endif() endif() # ----------------------------------------------------------------- # Start creating the module if(MODULE_IS_ENABLED) # clear variables defined in files.cmake set(RESOURCE_FILES ) set(CPP_FILES ) set(H_FILES ) set(TXX_FILES ) set(DOX_FILES ) set(UI_FILES ) set(MOC_H_FILES ) set(QRC_FILES ) # clear other variables set(Q${KITNAME}_GENERATED_CPP ) set(Q${KITNAME}_GENERATED_MOC_CPP ) set(Q${KITNAME}_GENERATED_QRC_CPP ) set(Q${KITNAME}_GENERATED_UI_CPP ) # check and set-up auto-loading if(MODULE_AUTOLOAD_WITH) if(NOT TARGET "${MODULE_AUTOLOAD_WITH}") message(SEND_ERROR "The module target \"${MODULE_AUTOLOAD_WITH}\" specified as the auto-loading module for \"${MODULE_NAME}\" does not exist") endif() endif() set(_module_autoload_meta_target "${CMAKE_PROJECT_NAME}-autoload") # create a meta-target if it does not already exist if(NOT TARGET ${_module_autoload_meta_target}) add_custom_target(${_module_autoload_meta_target}) endif() if(NOT MODULE_EXPORT_DEFINE) set(MODULE_EXPORT_DEFINE ${MODULE_NAME}_EXPORT) endif() if(MITK_GENERATE_MODULE_DOT) message("MODULEDOTNAME ${MODULE_NAME}") foreach(dep ${MODULE_DEPENDS}) message("MODULEDOT \"${MODULE_NAME}\" -> \"${dep}\" ; ") endforeach(dep) endif(MITK_GENERATE_MODULE_DOT) if (EXISTS ${MODULE_FILES_CMAKE}) include(${MODULE_FILES_CMAKE}) endif() if(MODULE_CPP_FILES) list(APPEND CPP_FILES ${MODULE_CPP_FILES}) endif() if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src") # Preprend the "src" directory to the cpp file list set(_cpp_files ${CPP_FILES}) set(CPP_FILES ) foreach(_cpp_file ${_cpp_files}) list(APPEND CPP_FILES "src/${_cpp_file}") endforeach() endif() if(CPP_FILES OR RESOURCE_FILES OR UI_FILES OR MOC_H_FILES OR QRC_FILES) set(MODULE_HEADERS_ONLY 0) if(MODULE_C_MODULE) set_source_files_properties(${CPP_FILES} PROPERTIES LANGUAGE C) elseif(MODULE_CXX_MODULE) set_source_files_properties(${CPP_FILES} PROPERTIES LANGUAGE CXX) endif() else() set(MODULE_HEADERS_ONLY 1) if(MODULE_AUTOLOAD_WITH) message(SEND_ERROR "A headers only module cannot be auto-loaded") endif() endif() set(module_c_flags ) set(module_c_flags_debug ) set(module_c_flags_release ) set(module_cxx_flags ) set(module_cxx_flags_debug ) set(module_cxx_flags_release ) if(MODULE_GCC_DEFAULT_VISIBILITY OR NOT CMAKE_COMPILER_IS_GNUCXX) # We only support hidden visibility for gcc for now. Clang still has troubles with # correctly marking template declarations and explicit template instantiations as exported. # See http://comments.gmane.org/gmane.comp.compilers.clang.scm/50028 # and http://llvm.org/bugs/show_bug.cgi?id=10113 set(CMAKE_CXX_VISIBILITY_PRESET default) set(CMAKE_VISIBILITY_INLINES_HIDDEN 0) else() set(CMAKE_CXX_VISIBILITY_PRESET hidden) set(CMAKE_VISIBILITY_INLINES_HIDDEN 1) endif() if(NOT MODULE_WARNINGS_NO_ERRORS) if(MSVC_VERSION) mitkFunctionCheckCAndCXXCompilerFlags("/WX" module_c_flags module_cxx_flags) else() mitkFunctionCheckCAndCXXCompilerFlags(-Werror module_c_flags module_cxx_flags) # The flag "c++0x-static-nonintegral-init" has been renamed in newer Clang # versions to "static-member-init", see # http://clang-developers.42468.n3.nabble.com/Wc-0x-static-nonintegral-init-gone-td3999651.html # # Also, older Clang and seemingly all gcc versions do not warn if unknown # "-no-*" flags are used, so CMake will happily append any -Wno-* flag to the # command line. This may get confusing if unrelated compiler errors happen and # the error output then additionally contains errors about unknown flags (which # is not the case if there were no compile errors). # # So instead of using -Wno-* we use -Wno-error=*, which will be properly rejected by # the compiler and if applicable, prints the specific warning as a real warning and # not as an error (although -Werror was given). mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=c++0x-static-nonintegral-init" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=static-member-init" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=unknown-warning" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=gnu" module_c_flags module_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=inconsistent-missing-override" module_c_flags module_cxx_flags) endif() endif() if(MODULE_FORCE_STATIC) set(_STATIC STATIC) else() set(_STATIC ) endif(MODULE_FORCE_STATIC) if(NOT MODULE_HEADERS_ONLY) if(NOT MODULE_NO_INIT OR RESOURCE_FILES) find_package(CppMicroServices QUIET NO_MODULE REQUIRED) endif() if(NOT MODULE_NO_INIT) usFunctionGenerateModuleInit(CPP_FILES) endif() set(binary_res_files ) set(source_res_files ) if(RESOURCE_FILES) if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/resource") set(res_dir resource) elseif(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/Resources") set(res_dir Resources) else() message(SEND_ERROR "Resources specified but ${CMAKE_CURRENT_SOURCE_DIR}/resource directory not found.") endif() foreach(res_file ${RESOURCE_FILES}) if(EXISTS ${CMAKE_CURRENT_BINARY_DIR}/${res_dir}/${res_file}) list(APPEND binary_res_files "${res_file}") else() list(APPEND source_res_files "${res_file}") endif() endforeach() # Add a source level dependencies on resource files usFunctionGetResourceSource(TARGET ${MODULE_TARGET} OUT CPP_FILES) endif() endif() if(MITK_USE_Qt5) if(UI_FILES) qt5_wrap_ui(Q${KITNAME}_GENERATED_UI_CPP ${UI_FILES}) endif() if(MOC_H_FILES) qt5_wrap_cpp(Q${KITNAME}_GENERATED_MOC_CPP ${MOC_H_FILES} OPTIONS -DBOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) endif() if(QRC_FILES) qt5_add_resources(Q${KITNAME}_GENERATED_QRC_CPP ${QRC_FILES}) endif() endif() set(Q${KITNAME}_GENERATED_CPP ${Q${KITNAME}_GENERATED_CPP} ${Q${KITNAME}_GENERATED_UI_CPP} ${Q${KITNAME}_GENERATED_MOC_CPP} ${Q${KITNAME}_GENERATED_QRC_CPP}) mitkFunctionOrganizeSources( SOURCE ${CPP_FILES} HEADER ${H_FILES} TXX ${TXX_FILES} DOC ${DOX_FILES} UI ${UI_FILES} QRC ${QRC_FILES} MOC ${Q${KITNAME}_GENERATED_MOC_CPP} GEN_QRC ${Q${KITNAME}_GENERATED_QRC_CPP} GEN_UI ${Q${KITNAME}_GENERATED_UI_CPP} ) set(coverage_sources ${CPP_FILES} ${H_FILES} ${GLOBBED__H_FILES} ${CORRESPONDING__H_FILES} ${TXX_FILES} ${TOOL_CPPS} ${TOOL_GUI_CPPS}) if(MODULE_SUBPROJECTS) set_property(SOURCE ${coverage_sources} APPEND PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) endif() # --------------------------------------------------------------- # Create the actual module target if(MODULE_HEADERS_ONLY) add_library(${MODULE_TARGET} INTERFACE) else() if(MODULE_EXECUTABLE) add_executable(${MODULE_TARGET} ${MODULE_CPP_FILES} ${coverage_sources} ${CPP_FILES_GENERATED} ${Q${KITNAME}_GENERATED_CPP} ${DOX_FILES} ${UI_FILES} ${QRC_FILES}) set(_us_module_name main) else() add_library(${MODULE_TARGET} ${_STATIC} ${coverage_sources} ${CPP_FILES_GENERATED} ${Q${KITNAME}_GENERATED_CPP} ${DOX_FILES} ${UI_FILES} ${QRC_FILES}) set(_us_module_name ${MODULE_TARGET}) endif() # Apply properties to the module target. target_compile_definitions(${MODULE_TARGET} PRIVATE US_MODULE_NAME=${_us_module_name}) if(MODULE_C_MODULE) if(module_c_flags) string(REPLACE " " ";" module_c_flags "${module_c_flags}") target_compile_options(${MODULE_TARGET} PRIVATE ${module_c_flags}) endif() if(module_c_flags_debug) string(REPLACE " " ";" module_c_flags_debug "${module_c_flags_debug}") target_compile_options(${MODULE_TARGET} PRIVATE $<$:${module_c_flags_debug}>) endif() if(module_c_flags_release) string(REPLACE " " ";" module_c_flags_release "${module_c_flags_release}") target_compile_options(${MODULE_TARGET} PRIVATE $<$:${module_c_flags_release}>) endif() else() if(module_cxx_flags) string(REPLACE " " ";" module_cxx_flags "${module_cxx_flags}") target_compile_options(${MODULE_TARGET} PRIVATE ${module_cxx_flags}) endif() if(module_cxx_flags_debug) string(REPLACE " " ";" module_cxx_flags_debug "${module_cxx_flags_debug}") target_compile_options(${MODULE_TARGET} PRIVATE $<$:${module_cxx_flags_debug}>) endif() if(module_cxx_flags_release) string(REPLACE " " ";" module_cxx_flags_release "${module_cxx_flags_release}") target_compile_options(${MODULE_TARGET} PRIVATE $<$:${module_cxx_flags_release}>) endif() endif() set_property(TARGET ${MODULE_TARGET} PROPERTY US_MODULE_NAME ${_us_module_name}) if(MINGW) target_link_libraries(${MODULE_TARGET} ssp) # add stack smash protection lib endif() # Add additional library search directories to a global property which # can be evaluated by other CMake macros, e.g. our install scripts. if(MODULE_ADDITIONAL_LIBS) target_link_libraries(${MODULE_TARGET} PRIVATE ${MODULE_ADDITIONAL_LIBS}) get_property(_mitk_additional_library_search_paths GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS) foreach(_lib_filepath ${MODULE_ADDITIONAL_LIBS}) get_filename_component(_search_path "${_lib_filepath}" PATH) if(_search_path) list(APPEND _mitk_additional_library_search_paths "${_search_path}") endif() endforeach() if(_mitk_additional_library_search_paths) list(REMOVE_DUPLICATES _mitk_additional_library_search_paths) set_property(GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS ${_mitk_additional_library_search_paths}) endif() endif() # add the target name to a global property which is used in the top-level # CMakeLists.txt file to export the target set_property(GLOBAL APPEND PROPERTY MITK_MODULE_TARGETS ${MODULE_TARGET}) if(MODULE_AUTOLOAD_WITH) # for auto-loaded modules, adapt the output directory add_dependencies(${_module_autoload_meta_target} ${MODULE_TARGET}) if(WIN32) set(_module_output_prop RUNTIME_OUTPUT_DIRECTORY) else() set(_module_output_prop LIBRARY_OUTPUT_DIRECTORY) endif() set(_module_output_dir ${CMAKE_${_module_output_prop}}/${MODULE_AUTOLOAD_WITH}) get_target_property(_module_is_imported ${MODULE_AUTOLOAD_WITH} IMPORTED) if(NOT _module_is_imported) # if the auto-loading module is not imported, get its location # and put the auto-load module relative to it. get_target_property(_module_output_dir ${MODULE_AUTOLOAD_WITH} ${_module_output_prop}) set_target_properties(${MODULE_TARGET} PROPERTIES ${_module_output_prop} ${_module_output_dir}/${MODULE_AUTOLOAD_WITH}) else() set_target_properties(${MODULE_TARGET} PROPERTIES ${_module_output_prop} ${CMAKE_${_module_output_prop}}/${MODULE_AUTOLOAD_WITH}) endif() set_target_properties(${MODULE_TARGET} PROPERTIES MITK_AUTOLOAD_DIRECTORY ${MODULE_AUTOLOAD_WITH}) # add the auto-load module name as a property set_property(TARGET ${MODULE_AUTOLOAD_WITH} APPEND PROPERTY MITK_AUTOLOAD_TARGETS ${MODULE_TARGET}) endif() if(binary_res_files) usFunctionAddResources(TARGET ${MODULE_TARGET} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/${res_dir} FILES ${binary_res_files}) endif() if(source_res_files) usFunctionAddResources(TARGET ${MODULE_TARGET} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/${res_dir} FILES ${source_res_files}) endif() if(binary_res_files OR source_res_files) usFunctionEmbedResources(TARGET ${MODULE_TARGET}) endif() if(MODULE_DEPRECATED_SINCE) set_property(TARGET ${MODULE_TARGET} PROPERTY MITK_MODULE_DEPRECATED_SINCE ${MODULE_DEPRECATED_SINCE}) endif() # create export macros if (NOT MODULE_EXECUTABLE) set(_export_macro_name ) if(MITK_LEGACY_EXPORT_MACRO_NAME) set(_export_macro_names EXPORT_MACRO_NAME ${MODULE_EXPORT_DEFINE} NO_EXPORT_MACRO_NAME ${MODULE_NAME}_NO_EXPORT DEPRECATED_MACRO_NAME ${MODULE_NAME}_DEPRECATED NO_DEPRECATED_MACRO_NAME ${MODULE_NAME}_NO_DEPRECATED ) endif() generate_export_header(${MODULE_NAME} ${_export_macro_names} EXPORT_FILE_NAME ${MODULE_NAME}Exports.h ) endif() target_include_directories(${MODULE_TARGET} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}) endif() # --------------------------------------------------------------- # Properties for both header-only and compiled modules if(MODULE_HEADERS_ONLY) set(_module_property_type INTERFACE) else() set(_module_property_type PUBLIC) endif() if(MODULE_TARGET_DEPENDS) add_dependencies(${MODULE_TARGET} ${MODULE_TARGET_DEPENDS}) endif() if(MODULE_SUBPROJECTS AND NOT MODULE_HEADERS_ONLY) set_property(TARGET ${MODULE_TARGET} PROPERTY LABELS ${MODULE_SUBPROJECTS} MITK) foreach(subproject ${MODULE_SUBPROJECTS}) add_dependencies(${subproject} ${MODULE_TARGET}) endforeach() endif() set(DEPENDS "${MODULE_DEPENDS}") if(NOT MODULE_NO_INIT AND NOT MODULE_HEADERS_ONLY) # Add a CppMicroServices dependency implicitly, since it is # needed for the generated "module initialization" code. set(DEPENDS "CppMicroServices;${DEPENDS}") endif() if(DEPENDS OR MODULE_PACKAGE_DEPENDS) mitk_use_modules(TARGET ${MODULE_TARGET} MODULES ${DEPENDS} PACKAGES ${MODULE_PACKAGE_DEPENDS} ) endif() if(NOT MODULE_C_MODULE) target_compile_features(${MODULE_TARGET} ${_module_property_type} ${MITK_CXX_FEATURES}) endif() # add include directories if(MODULE_INTERNAL_INCLUDE_DIRS) target_include_directories(${MODULE_TARGET} PRIVATE ${MODULE_INTERNAL_INCLUDE_DIRS}) endif() if(NOT MODULE_NO_DEFAULT_INCLUDE_DIRS) if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/include) target_include_directories(${MODULE_TARGET} ${_module_property_type} include) else() target_include_directories(${MODULE_TARGET} ${_module_property_type} .) endif() if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/src) target_include_directories(${MODULE_TARGET} PRIVATE src) endif() endif() target_include_directories(${MODULE_TARGET} ${_module_property_type} ${MODULE_INCLUDE_DIRS}) endif() # ----------------------------------------------------------------- # Record missing dependency information if(_MISSING_DEP) if(MODULE_DESCRIPTION) set(MODULE_DESCRIPTION "${MODULE_DESCRIPTION} (missing dependencies: ${_MISSING_DEP})") else() set(MODULE_DESCRIPTION "(missing dependencies: ${_MISSING_DEP})") endif() endif() if(NOT MODULE_NO_FEATURE_INFO) add_feature_info(${MODULE_NAME} MODULE_IS_ENABLED "${MODULE_DESCRIPTION}") endif() set(MODULE_NAME ${MODULE_NAME} PARENT_SCOPE) set(MODULE_TARGET ${MODULE_TARGET} PARENT_SCOPE) set(MODULE_IS_ENABLED ${MODULE_IS_ENABLED} PARENT_SCOPE) set(MODULE_SUBPROJECTS ${MODULE_SUBPROJECTS} PARENT_SCOPE) endfunction() diff --git a/CMake/mitkFunctionCreatePlugin.cmake b/CMake/mitkFunctionCreatePlugin.cmake index 0cd1499508..acbc2bc297 100644 --- a/CMake/mitkFunctionCreatePlugin.cmake +++ b/CMake/mitkFunctionCreatePlugin.cmake @@ -1,343 +1,343 @@ #! \brief Creates a MITK CTK plugin. #! #! This function should be called from the plugins CMakeLists.txt file. #! The target name is available after the macro call as ${PLUGIN_TARGET} #! to add additional libraries in your CMakeLists.txt. Include paths and link #! libraries are set depending on the value of the Required-Plugins header #! in your manifest_headers.cmake file. #! #! This function internally calls ctkMacroBuildPlugin() and adds support #! for Qt Help files and installers. #! #! Options: #! \param TEST_PLUGIN Mark this plug-in as a testing plug-in. #! \param NO_INSTALL Don't install this plug-in. #! #! Parameters: #! #! \param EXPORT_DIRECTIVE (required) The export directive to use in the generated #! _Exports.h file. #! #! Multi-value parameters (all optional): #! #! \param EXPORTED_INCLUDE_SUFFIXES A list of sub-directories which should #! be added to the current source directory. The resulting directories #! will be available in the set of include directories of depending plug-ins. #! \param MODULE_DEPENDS (optional) A list of Modules this plug-in depends on. #! \param PACKAGE_DEPENDS (optional) A list of external packages this plug-in depends on. #! \param DOXYGEN_TAGFILES (optional) Which external tag files should be available for the plugin documentation #! \param MOC_OPTIONS (optional) Additional options to pass to the Qt MOC compiler #! \param WARNINGS_NO_ERRORS (optional) Do not handle compiler warnings as errors function(mitk_create_plugin) # options set(arg_options TEST_PLUGIN # Mark this plug-in as a testing plug-in NO_INSTALL # Don't install this plug-in NO_QHP_TRANSFORM WARNINGS_NO_ERRORS ) # single value arguments set(arg_single EXPORT_DIRECTIVE # (required) TODO: could be generated via CMake as it is done for MITK modules already ) # multiple value arguments set(arg_multiple EXPORTED_INCLUDE_SUFFIXES # (optional) additional public include directories MODULE_DEPENDS # (optional) PACKAGE_DEPENDS DOXYGEN_TAGFILES MOC_OPTIONS SUBPROJECTS ) cmake_parse_arguments(_PLUGIN "${arg_options}" "${arg_single}" "${arg_multiple}" ${ARGN}) if(_PLUGIN_TEST_PLUGIN) set(_PLUGIN_NO_INSTALL 1) set(is_test_plugin "TEST_PLUGIN") else() set(is_test_plugin) endif() set(_PLUGIN_MOC_OPTIONS "-DBOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION -DBOOST_TT_HAS_OPERATOR_HPP_INCLUDED ${_PLUGIN_MOC_OPTIONS}") set(PLUGIN_TARGET ${PROJECT_NAME}) mitk_check_module_dependencies(MODULES ${_PLUGIN_MODULE_DEPENDS} PACKAGES ${_PLUGIN_PACKAGE_DEPENDS} MISSING_DEPENDENCIES_VAR _missing_deps MODULE_DEPENDENCIES_VAR _module_deps PACKAGE_DEPENDENCIES_VAR _package_deps) if(_missing_deps) if(NOT MITK_BUILD_ALL_PLUGINS) message(SEND_ERROR "${PROJECT_NAME} is missing requirements and won't be built. Missing: ${_missing_deps}") else() message(STATUS "${PROJECT_NAME} is missing requirements and won't be built. Missing: ${_missing_deps}") endif() return() endif() # -------------- All dependencies are resolved ------------------ message(STATUS "Creating CTK plugin ${PROJECT_NAME}") include(files.cmake) set(_PLUGIN_CPP_FILES ${CPP_FILES}) set(_PLUGIN_MOC_H_FILES ${MOC_H_FILES}) set(_PLUGIN_UI_FILES ${UI_FILES}) set(_PLUGIN_CACHED_RESOURCE_FILES ${CACHED_RESOURCE_FILES}) set(_PLUGIN_TRANSLATION_FILES ${TRANSLATION_FILES}) set(_PLUGIN_QRC_FILES ${QRC_FILES}) set(_PLUGIN_H_FILES ${H_FILES}) set(_PLUGIN_TXX_FILES ${TXX_FILES}) set(_PLUGIN_DOX_FILES ${DOX_FILES}) set(_PLUGIN_CMAKE_FILES ${CMAKE_FILES} files.cmake) set(_PLUGIN_FILE_DEPENDENCIES ${FILE_DEPENDENCIES}) if(CTK_PLUGINS_OUTPUT_DIR) set(_output_dir "${CTK_PLUGINS_OUTPUT_DIR}") else() set(_output_dir "") endif() # Compute the plugin dependencies ctkFunctionGetTargetLibraries(_PLUGIN_target_libraries "") #------------------------------------------------------------# #------------------ Qt Help support -------------------------# set(PLUGIN_GENERATED_QCH_FILES ) if(BLUEBERRY_USE_QT_HELP AND EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/documentation/UserManual") set(PLUGIN_DOXYGEN_INPUT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/documentation/UserManual") set(PLUGIN_DOXYGEN_OUTPUT_DIR "${CMAKE_CURRENT_BINARY_DIR}/documentation/UserManual") # Create a list of Doxygen tag files from the plug-in dependencies set(PLUGIN_DOXYGEN_TAGFILES) foreach(_dep_target ${_PLUGIN_target_libraries}) string(REPLACE _ . _dep ${_dep_target}) get_target_property(_is_imported ${_dep_target} IMPORTED) if(_is_imported) get_target_property(_import_loc_debug ${_dep_target} IMPORTED_LOCATION_DEBUG) get_target_property(_import_loc_release ${_dep_target} IMPORTED_LOCATION_RELEASE) # There is not necessarily a debug and release build if(_import_loc_release) set(_import_loc ${_import_loc_release}) else() set(_import_loc ${_import_loc_debug}) endif() get_filename_component(_target_filename "${_import_loc}" NAME) # on windows there might be a Debug or Release subdirectory string(REGEX REPLACE "/bin/plugins/(Debug/|Release/)?${_target_filename}" "/Plugins/${_dep}/documentation/UserManual" plugin_tag_dir "${_import_loc}" ) else() set(plugin_tag_dir "${CMAKE_BINARY_DIR}/Plugins/${_dep}/documentation/UserManual") endif() set(_tag_file "${plugin_tag_dir}/${_dep_target}.tag") if(EXISTS ${_tag_file}) set(PLUGIN_DOXYGEN_TAGFILES "${PLUGIN_DOXYGEN_TAGFILES} \"${_tag_file}=qthelp://${_dep}/bundle/\"") endif() endforeach() if(_PLUGIN_DOXYGEN_TAGFILES) set(PLUGIN_DOXYGEN_TAGFILES "${PLUGIN_DOXYGEN_TAGFILES} ${_PLUGIN_DOXYGEN_TAGFILES}") endif() #message("PLUGIN_DOXYGEN_TAGFILES: ${PLUGIN_DOXYGEN_TAGFILES}") if(_PLUGIN_NO_QHP_TRANSFORM) set(_use_qhp_xsl 0) else() set(_use_qhp_xsl 1) endif() _FUNCTION_CREATE_CTK_QT_COMPRESSED_HELP(PLUGIN_GENERATED_QCH_FILES ${_use_qhp_xsl}) list(APPEND _PLUGIN_CACHED_RESOURCE_FILES ${PLUGIN_GENERATED_QCH_FILES}) endif() #------------------------------------------------------------# #------------------ Create Plug-in --------------------------# mitkFunctionOrganizeSources( SOURCE ${_PLUGIN_CPP_FILES} HEADER ${_PLUGIN_H_FILES} TXX ${_PLUGIN_TXX_FILES} DOC ${_PLUGIN_DOX_FILES} UI ${_PLUGIN_UI_FILES} QRC ${_PLUGIN_QRC_FILES} ${_PLUGIN_CACHED_RESOURCE_FILES} META ${_PLUGIN_META_FILES} MOC ${MY_MOC_CPP} GEN_UI ${MY_UI_CPP} GEN_QRC ${MY_QRC_SRCS} ) ctkMacroBuildPlugin( NAME ${PLUGIN_TARGET} EXPORT_DIRECTIVE ${_PLUGIN_EXPORT_DIRECTIVE} SRCS ${_PLUGIN_CPP_FILES} ${_PLUGIN_H_FILES} ${CORRESPONDING__H_FILES} ${GLOBBED__H_FILES} MOC_SRCS ${_PLUGIN_MOC_H_FILES} MOC_OPTIONS ${_PLUGIN_MOC_OPTIONS} UI_FORMS ${_PLUGIN_UI_FILES} EXPORTED_INCLUDE_SUFFIXES ${_PLUGIN_EXPORTED_INCLUDE_SUFFIXES} RESOURCES ${_PLUGIN_QRC_FILES} TARGET_LIBRARIES ${_PLUGIN_target_libraries} CACHED_RESOURCEFILES ${_PLUGIN_CACHED_RESOURCE_FILES} TRANSLATIONS ${_PLUGIN_TRANSLATION_FILES} OUTPUT_DIR ${_output_dir} NO_INSTALL # we install the plug-in ourselves ${is_test_plugin} ) mitk_use_modules(TARGET ${PLUGIN_TARGET} MODULES ${_PLUGIN_MODULE_DEPENDS} PACKAGES ${_PLUGIN_PACKAGE_DEPENDS} ) set_property(TARGET ${PLUGIN_TARGET} APPEND PROPERTY COMPILE_DEFINITIONS US_MODULE_NAME=${PLUGIN_TARGET}) set_property(TARGET ${PLUGIN_TARGET} PROPERTY US_MODULE_NAME ${PLUGIN_TARGET}) set(plugin_c_flags) set(plugin_cxx_flags) if(NOT _PLUGIN_WARNINGS_NO_ERRORS) if(MSVC_VERSION) mitkFunctionCheckCAndCXXCompilerFlags("/WX" plugin_c_flags plugin_cxx_flags) else() mitkFunctionCheckCAndCXXCompilerFlags(-Werror plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=c++0x-static-nonintegral-init" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=static-member-init" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=unknown-warning" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=gnu" plugin_c_flags plugin_cxx_flags) mitkFunctionCheckCAndCXXCompilerFlags("-Wno-error=inconsistent-missing-override" plugin_c_flags plugin_cxx_flags) endif() endif() if(plugin_c_flags) string(REPLACE " " ";" plugin_c_flags "${plugin_c_flags}") target_compile_options(${PLUGIN_TARGET} PRIVATE ${plugin_c_flags}) endif() if(plugin_cxx_flags) string(REPLACE " " ";" plugin_cxx_flags "${plugin_cxx_flags}") target_compile_options(${PLUGIN_TARGET} PRIVATE ${plugin_cxx_flags}) endif() if(NOT MY_SUBPROJECTS) if(MITK_DEFAULT_SUBPROJECTS) set(MY_SUBPROJECTS ${MITK_DEFAULT_SUBPROJECTS}) - else() + elseif(TARGET MITK-Plugins) set(MY_SUBPROJECTS MITK-Plugins) endif() endif() if(MY_SUBPROJECTS) set_property(TARGET ${PLUGIN_TARGET} PROPERTY LABELS ${MY_SUBPROJECTS}) foreach(subproject ${MY_SUBPROJECTS}) add_dependencies(${subproject} ${PLUGIN_TARGET}) endforeach() endif() if(_PLUGIN_TEST_PLUGIN) find_package(CppUnit REQUIRED) target_include_directories(${PLUGIN_TARGET} PRIVATE ${CppUnit_INCLUDE_DIRS}) target_link_libraries(${PLUGIN_TARGET} PRIVATE ${CppUnit_LIBRARIES}) endif() if(mbilog_FOUND) target_link_libraries(${PLUGIN_TARGET} PRIVATE mbilog) endif() set(_PLUGIN_META_FILES "${CMAKE_CURRENT_SOURCE_DIR}/manifest_headers.cmake") if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/plugin.xml") list(APPEND _PLUGIN_META_FILES "${CMAKE_CURRENT_SOURCE_DIR}/plugin.xml") endif() set(PLUGIN_TARGET ${PLUGIN_TARGET} PARENT_SCOPE) #------------------------------------------------------------# #------------------ Installer support -----------------------# if(NOT _PLUGIN_NO_INSTALL) set(install_directories "") if(NOT MACOSX_BUNDLE_NAMES) set(install_directories bin/plugins) else(NOT MACOSX_BUNDLE_NAMES) foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND install_directories ${bundle_name}.app/Contents/MacOS/plugins) endforeach(bundle_name) endif(NOT MACOSX_BUNDLE_NAMES) foreach(install_subdir ${install_directories}) mitkFunctionInstallCTKPlugin(TARGETS ${PLUGIN_TARGET} DESTINATION ${install_subdir}) endforeach() set(_autoload_targets ) foreach(_dependency ${_module_deps}) get_target_property(_dep_autoloads ${_dependency} MITK_AUTOLOAD_TARGETS) if (_dep_autoloads) list(APPEND _autoload_targets ${_dep_autoloads}) endif() endforeach() # The MITK_AUTOLOAD_TARGETS property is used in the mitkFunctionInstallAutoLoadModules # macro which expects a list of plug-in targets. if (_autoload_targets) list(REMOVE_DUPLICATES _autoload_targets) set_target_properties(${PLUGIN_TARGET} PROPERTIES MITK_AUTOLOAD_TARGETS "${_autoload_targets}") endif() endif() endfunction() function(_FUNCTION_CREATE_CTK_QT_COMPRESSED_HELP qch_file use_xsl) set(_manifest_path "${CMAKE_CURRENT_SOURCE_DIR}/manifest_headers.cmake") if(NOT EXISTS ${_manifest_path}) message(FATAL_ERROR "${_manifest_path} not found") endif() include(${_manifest_path}) string(REPLACE "_" "." Plugin-SymbolicName "${PLUGIN_TARGET}") configure_file(${MITK_SOURCE_DIR}/Documentation/doxygen_plugin_manual.conf.in ${PLUGIN_DOXYGEN_OUTPUT_DIR}/doxygen.conf ) set(_qhp_xsl_file "${MITK_SOURCE_DIR}/Documentation/qhp_toc.xsl") set(_generated_qhp_file "${PLUGIN_DOXYGEN_OUTPUT_DIR}/html/index.qhp") set(_transformed_qhp_file "${PLUGIN_DOXYGEN_OUTPUT_DIR}/html/${PLUGIN_TARGET}.qhp") set(${qch_file} "${CMAKE_CURRENT_BINARY_DIR}/resources/${PLUGIN_TARGET}.qch") set(_xsl_command ) if(use_xsl) set(_xsl_command COMMAND ${QT_XMLPATTERNS_EXECUTABLE} ${_qhp_xsl_file} ${_generated_qhp_file} -output ${_transformed_qhp_file}) endif() file(GLOB _file_dependencies "${PLUGIN_DOXYGEN_INPUT_DIR}/*") add_custom_command(OUTPUT ${${qch_file}} # Generate a Qt help project (index.qhp) with doxygen COMMAND ${DOXYGEN_EXECUTABLE} ${PLUGIN_DOXYGEN_OUTPUT_DIR}/doxygen.conf # Use a XSL transformation to get rid of the top-level entry ${_xsl_command} # Generate the final Qt compressed help file (.qch) COMMAND ${QT_HELPGENERATOR_EXECUTABLE} ${_transformed_qhp_file} -o ${${qch_file}} DEPENDS ${PLUGIN_DOXYGEN_OUTPUT_DIR}/doxygen.conf ${_file_dependencies} ) #set_source_files_properties(${qch_file} PROPERTIES GENERATED 1) set(${qch_file} ${${qch_file}} PARENT_SCOPE) endfunction() function(MACRO_CREATE_MITK_CTK_PLUGIN) message(SEND_ERROR "The function MACRO_CREATE_MITK_CTK_PLUGIN was renamed to mitk_create_plugin in MITK 2015.05.") endfunction() diff --git a/CMakeExternals/OpenCV.cmake b/CMakeExternals/OpenCV.cmake index c1bbfd676b..b784310523 100644 --- a/CMakeExternals/OpenCV.cmake +++ b/CMakeExternals/OpenCV.cmake @@ -1,103 +1,103 @@ #----------------------------------------------------------------------------- # OpenCV #----------------------------------------------------------------------------- if(MITK_USE_OpenCV) # Sanity checks if(DEFINED OpenCV_DIR AND NOT EXISTS ${OpenCV_DIR}) message(FATAL_ERROR "OpenCV_DIR variable is defined but corresponds to non-existing directory") endif() set(proj OpenCV) set(proj_DEPENDENCIES) set(OpenCV_DEPENDS ${proj}) if(NOT DEFINED OpenCV_DIR) set(additional_cmake_args -DBUILD_opencv_java:BOOL=OFF -DBUILD_opencv_ts:BOOL=OFF -DBUILD_PERF_TESTS:BOOL=OFF ) if(MITK_USE_Python) if(NOT MITK_USE_SYSTEM_PYTHON) list(APPEND proj_DEPENDENCIES Python Numpy) # export python home set(ENV{PYTHONHOME} "${Python_DIR}") set(CV_PACKAGE_PATH -DPYTHON_PACKAGES_PATH:PATH=${MITK_PYTHON_SITE_DIR}) else() set(CV_PACKAGE_PATH -DPYTHON_PACKAGES_PATH:PATH=${ep_prefix}/lib/python${PYTHON_VERSION_MAJOR}.${PYTHON_VERSION_MINOR}/site-packages) endif() list(APPEND additional_cmake_args -DBUILD_opencv_python:BOOL=ON -DBUILD_NEW_PYTHON_SUPPORT:BOOL=ON -DPYTHON_DEBUG_LIBRARY:FILEPATH=${PYTHON_DEBUG_LIBRARY} -DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE} -DPYTHON_INCLUDE_DIR:PATH=${PYTHON_INCLUDE_DIR} -DPYTHON_INCLUDE_DIR2:PATH=${PYTHON_INCLUDE_DIR2} -DPYTHON_LIBRARY:FILEPATH=${PYTHON_LIBRARY} ${CV_PACKAGE_PATH} #-DPYTHON_LIBRARIES=${PYTHON_LIBRARY} #-DPYTHON_DEBUG_LIBRARIES=${PYTHON_DEBUG_LIBRARIES} ) else() list(APPEND additional_cmake_args -DBUILD_opencv_python:BOOL=OFF -DBUILD_NEW_PYTHON_SUPPORT:BOOL=OFF ) endif() # 12-05-02, muellerm, added QT usage by OpenCV if QT is used in MITK # 12-09-11, muellerm, removed automatic usage again, since this will struggle with the MITK Qt application object if(MITK_USE_Qt5) list(APPEND additional_cmake_args -DWITH_QT:BOOL=OFF -DWITH_QT_OPENGL:BOOL=OFF -DQT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE} ) endif() if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() - set(opencv_url ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/opencv-2.4.13.2.tar.gz) - set(opencv_url_md5 80a4a3bee0e98898bbbc68986ca73655) + set(opencv_url ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/opencv-2.4.13.5.tar.gz) + set(opencv_url_md5 6cbe56ffb9ab1424fc2f5e78f46c82a8) ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} URL ${opencv_url} URL_MD5 ${opencv_url_md5} # Related bug: http://bugs.mitk.org/show_bug.cgi?id=5912 PATCH_COMMAND ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/OpenCV.patch CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} -DBUILD_TESTS:BOOL=OFF -DBUILD_DOCS:BOOL=OFF -DBUILD_EXAMPLES:BOOL=OFF -DBUILD_DOXYGEN_DOCS:BOOL=OFF -DWITH_CUDA:BOOL=OFF ${additional_cmake_args} CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) set(OpenCV_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeExternals/OpenCV.patch b/CMakeExternals/OpenCV.patch index 371019db71..c2f5733d0d 100644 --- a/CMakeExternals/OpenCV.patch +++ b/CMakeExternals/OpenCV.patch @@ -1,31 +1,53 @@ ---- OpenCV-2.4.11/cmake/OpenCVModule.cmake 2015-02-25 13:10:31.000000000 +0100 -+++ opencv/cmake/OpenCVModule.cmake 2015-03-06 13:05:45.000000000 +0100 -@@ -521,7 +521,7 @@ +--- a/cmake/OpenCVModule.cmake ++++ b/cmake/OpenCVModule.cmake +@@ -525,7 +525,7 @@ ocv_include_directories(${OPENCL_INCLUDE_DIRS}) add_custom_command( OUTPUT "${CMAKE_CURRENT_BINARY_DIR}/opencl_kernels.cpp" "${CMAKE_CURRENT_BINARY_DIR}/opencl_kernels.hpp" - COMMAND ${CMAKE_COMMAND} -DCL_DIR="${CMAKE_CURRENT_SOURCE_DIR}/src/opencl" -DOUTPUT="${CMAKE_CURRENT_BINARY_DIR}/opencl_kernels.cpp" -P "${OpenCV_SOURCE_DIR}/cmake/cl2cpp.cmake" + COMMAND ${CMAKE_COMMAND} -DCL_DIR=${CMAKE_CURRENT_SOURCE_DIR}/src/opencl -DOUTPUT=${CMAKE_CURRENT_BINARY_DIR}/opencl_kernels.cpp -P ${OpenCV_SOURCE_DIR}/cmake/cl2cpp.cmake DEPENDS ${cl_kernels} "${OpenCV_SOURCE_DIR}/cmake/cl2cpp.cmake") source_group("OpenCL" FILES ${cl_kernels} "${CMAKE_CURRENT_BINARY_DIR}/opencl_kernels.cpp" "${CMAKE_CURRENT_BINARY_DIR}/opencl_kernels.hpp") list(APPEND lib_srcs ${cl_kernels} "${CMAKE_CURRENT_BINARY_DIR}/opencl_kernels.cpp" "${CMAKE_CURRENT_BINARY_DIR}/opencl_kernels.hpp") ---- OpenCV-2.4.11/cmake/templates/OpenCVConfig.cmake.in 2015-02-25 13:10:31.000000000 +0100 -+++ opencv/cmake/templates/OpenCVConfig.cmake.in 2015-03-06 13:08:56.000000000 +0100 +--- a/cmake/templates/OpenCVConfig.cmake.in ++++ b/cmake/templates/OpenCVConfig.cmake.in @@ -120,7 +120,7 @@ # Provide the include directories to the caller set(OpenCV_INCLUDE_DIRS @OpenCV_INCLUDE_DIRS_CONFIGCMAKE@) -include_directories(${OpenCV_INCLUDE_DIRS}) +# include_directories(${OpenCV_INCLUDE_DIRS}) # ====================================================== # Link directories to add to the user project: @@ -153,7 +153,7 @@ # ============================================================== SET(OpenCV2_INCLUDE_DIRS @OpenCV2_INCLUDE_DIRS_CONFIGCMAKE@) if(OpenCV2_INCLUDE_DIRS) - include_directories(${OpenCV2_INCLUDE_DIRS}) + # include_directories(${OpenCV2_INCLUDE_DIRS}) list(APPEND OpenCV_INCLUDE_DIRS ${OpenCV2_INCLUDE_DIRS}) set(OpenCV_ADD_DEBUG_RELEASE @OpenCV_ADD_DEBUG_RELEASE_CONFIGCMAKE@) +--- a/cmake/OpenCVConfig.cmake ++++ b/cmake/OpenCVConfig.cmake +@@ -81,7 +81,7 @@ + set(OpenCV_RUNTIME vc12) + elseif(MSVC_VERSION EQUAL 1900) + set(OpenCV_RUNTIME vc14) +- elseif(MSVC_VERSION EQUAL 1910 OR MSVC_VERSION EQUAL 1911) ++ elseif(MSVC_VERSION MATCHES "^191[0-9]$") + set(OpenCV_RUNTIME vc15) + endif() + elseif(MINGW) +--- a/cmake/OpenCVDetectCXXCompiler.cmake ++++ b/cmake/OpenCVDetectCXXCompiler.cmake +@@ -100,7 +100,7 @@ + set(OpenCV_RUNTIME vc12) + elseif(MSVC_VERSION EQUAL 1900) + set(OpenCV_RUNTIME vc14) +- elseif(MSVC_VERSION EQUAL 1910 OR MSVC_VERSION EQUAL 1911) ++ elseif(MSVC_VERSION MATCHES "^191[0-9]$") + set(OpenCV_RUNTIME vc15) + endif() + elseif(MINGW) diff --git a/Modules/Core/src/Rendering/mitkAnnotationUtils.cpp b/Modules/Core/src/Rendering/mitkAnnotationUtils.cpp index f47ae70eae..a053943a52 100644 --- a/Modules/Core/src/Rendering/mitkAnnotationUtils.cpp +++ b/Modules/Core/src/Rendering/mitkAnnotationUtils.cpp @@ -1,126 +1,128 @@ /*=================================================================== 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 "mitkAnnotationUtils.h" #include "mitkAnnotation.h" #include "vtkCallbackCommand.h" #include "vtkCommand.h" #include namespace mitk { AnnotationUtils::AnnotationUtils() {} AnnotationUtils::~AnnotationUtils() {} AbstractAnnotationRenderer *AnnotationUtils::GetAnnotationRenderer(const std::string &arTypeID, const std::string &rendererID) { // get the context us::ModuleContext *context = us::GetModuleContext(); // specify a filter that defines the requested type std::string filter = "(&(" + AbstractAnnotationRenderer::US_PROPKEY_ID + "=" + arTypeID + ")(" + AbstractAnnotationRenderer::US_PROPKEY_RENDERER_ID + "=" + rendererID + "))"; // find the fitting service std::vector serviceReferences = context->GetServiceReferences(AbstractAnnotationRenderer::US_INTERFACE_NAME, filter); // check if a service reference was found. It is also possible that several // services were found. This is not checked here, just the first one is taken. AbstractAnnotationRenderer *ar = nullptr; if (serviceReferences.size()) { ar = context->GetService(serviceReferences.front()); } // no service reference was found or found service reference has no valid source return ar; } void AnnotationUtils::RegisterAnnotationRenderer(AbstractAnnotationRenderer *annotationRenderer) { static AnnotationRendererServices AnnotationRendererServices; // Define ServiceProps us::ServiceProperties props; props[AbstractAnnotationRenderer::US_PROPKEY_RENDERER_ID] = annotationRenderer->GetRendererID(); props[AbstractAnnotationRenderer::US_PROPKEY_ID] = annotationRenderer->GetID(); us::GetModuleContext()->RegisterService(annotationRenderer, props); AnnotationRendererServices.push_back(std::unique_ptr(annotationRenderer)); } void AnnotationUtils::UpdateAnnotationRenderer(const std::string &rendererID) { for (AbstractAnnotationRenderer *annotationRenderer : GetAnnotationRenderer(rendererID)) { annotationRenderer->Update(); } } void AnnotationUtils::BaseRendererChanged(BaseRenderer *renderer) { for (AbstractAnnotationRenderer *annotationRenderer : GetAnnotationRenderer(renderer->GetName())) { annotationRenderer->CurrentBaseRendererChanged(); } vtkCallbackCommand *renderCallbackCommand = vtkCallbackCommand::New(); renderCallbackCommand->SetCallback(AnnotationUtils::RenderWindowCallback); renderer->GetRenderWindow()->AddObserver(vtkCommand::ModifiedEvent, renderCallbackCommand); renderCallbackCommand->Delete(); } void AnnotationUtils::RenderWindowCallback(vtkObject *caller, unsigned long, void *, void *) { auto *renderWindow = dynamic_cast(caller); if (!renderWindow) return; BaseRenderer *renderer = BaseRenderer::GetInstance(renderWindow); - for (AbstractAnnotationRenderer *annotationRenderer : GetAnnotationRenderer(renderer->GetName())) + + if (nullptr != renderer) { - annotationRenderer->OnRenderWindowModified(); + for (AbstractAnnotationRenderer *annotationRenderer : GetAnnotationRenderer(renderer->GetName())) + annotationRenderer->OnRenderWindowModified(); } } Annotation *AnnotationUtils::GetAnnotation(const std::string &AnnotationID) { std::string ldapFilter = "(" + Annotation::US_PROPKEY_ID + "=" + AnnotationID + ")"; us::ModuleContext *context = us::GetModuleContext(); std::vector> annotations = context->GetServiceReferences(ldapFilter); Annotation *annotation = nullptr; if (!annotations.empty()) { annotation = us::GetModuleContext()->GetService(annotations.front()); } return annotation; } std::vector AnnotationUtils::GetAnnotationRenderer(const std::string &rendererID) { us::ModuleContext *context = us::GetModuleContext(); // specify a filter that defines the requested type std::string filter = "(&(" + AbstractAnnotationRenderer::US_PROPKEY_ID + "=*)(" + AbstractAnnotationRenderer::US_PROPKEY_RENDERER_ID + "=" + rendererID + "))"; // find the fitting service std::vector serviceReferences = context->GetServiceReferences(AbstractAnnotationRenderer::US_INTERFACE_NAME, filter); std::vector arList; for (us::ServiceReferenceU service : serviceReferences) { arList.push_back(context->GetService(service)); } return arList; } } diff --git a/Modules/Core/src/Rendering/mitkRenderWindowBase.cpp b/Modules/Core/src/Rendering/mitkRenderWindowBase.cpp index 7e8e746096..d30ea1f15b 100644 --- a/Modules/Core/src/Rendering/mitkRenderWindowBase.cpp +++ b/Modules/Core/src/Rendering/mitkRenderWindowBase.cpp @@ -1,120 +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. ===================================================================*/ #include "mitkRenderWindowBase.h" #include "mitkRenderingManager.h" #include "mitkVtkLayerController.h" #include "vtkRenderer.h" #include "mitkAnnotationUtils.h" mitk::RenderWindowBase::RenderWindowBase() : m_RenderProp(nullptr), m_InResize(false) { } /* * "Member functions, including virtual functions (10.3), can be called during construction or destruction (12.6.2). When a * virtual function is called directly or indirectly from a constructor (including from the mem-initializer for a data member) or from * a destructor, and the object to which the call applies is the object under construction or destruction, the function called is * the one defined in the constructor or destructor's own class or in one of its bases, but not a function overriding it in a class * derived from the constructor or destructor's class, or overriding it in one of the other base classes of the most derived object[..]" * or short: within constructors and destructors classes are not polymorph. */ void mitk::RenderWindowBase::Initialize(mitk::RenderingManager *renderingManager, const char *name, mitk::BaseRenderer::RenderingMode::Type renderingMode) { if (renderingManager == nullptr) { renderingManager = mitk::RenderingManager::GetInstance(); } if (m_Renderer.IsNull()) { m_Renderer = mitk::VtkPropRenderer::New(name, GetVtkRenderWindow(), renderingManager, renderingMode); } m_Renderer->InitRenderer(this->GetVtkRenderWindow()); mitk::BaseRenderer::AddInstance(GetVtkRenderWindow(), m_Renderer); renderingManager->AddRenderWindow(GetVtkRenderWindow()); // Add previously created overlays to new BaseRenderer mitk::AnnotationUtils::BaseRendererChanged(m_Renderer); m_RenderProp = vtkMitkRenderProp::New(); m_RenderProp->SetPropRenderer(m_Renderer); m_Renderer->GetVtkRenderer()->AddViewProp(m_RenderProp); if ((this->GetVtkRenderWindow()->GetSize()[0] > 10) && (this->GetVtkRenderWindow()->GetSize()[1] > 10)) m_Renderer->InitSize(this->GetVtkRenderWindow()->GetSize()[0], this->GetVtkRenderWindow()->GetSize()[1]); m_InResize = false; } bool mitk::RenderWindowBase::HandleEvent(InteractionEvent *interactionEvent) { return m_Renderer->GetDispatcher()->ProcessEvent(interactionEvent); } void mitk::RenderWindowBase::Destroy() { m_Renderer->GetRenderingManager()->RemoveRenderWindow(GetVtkRenderWindow()); m_Renderer->GetVtkRenderer()->RemoveViewProp(m_RenderProp); m_RenderProp->Delete(); + BaseRenderer::RemoveInstance(this->GetVtkRenderWindow()); } mitk::RenderWindowBase::~RenderWindowBase() { } mitk::SliceNavigationController *mitk::RenderWindowBase::GetSliceNavigationController() { return mitk::BaseRenderer::GetInstance(this->GetVtkRenderWindow())->GetSliceNavigationController(); } mitk::CameraRotationController *mitk::RenderWindowBase::GetCameraRotationController() { return mitk::BaseRenderer::GetInstance(this->GetVtkRenderWindow())->GetCameraRotationController(); } mitk::BaseController *mitk::RenderWindowBase::GetController() { mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(GetVtkRenderWindow()); switch (renderer->GetMapperID()) { case mitk::BaseRenderer::Standard2D: return GetSliceNavigationController(); case mitk::BaseRenderer::Standard3D: return GetCameraRotationController(); default: return GetSliceNavigationController(); } } mitk::VtkPropRenderer *mitk::RenderWindowBase::GetRenderer() { return m_Renderer; } diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/itkConnectomicsNetworkToConnectivityMatrixImageFilter.cpp b/Modules/DiffusionImaging/Connectomics/Algorithms/itkConnectomicsNetworkToConnectivityMatrixImageFilter.cpp index 33e6285f00..405bf202eb 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/itkConnectomicsNetworkToConnectivityMatrixImageFilter.cpp +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/itkConnectomicsNetworkToConnectivityMatrixImageFilter.cpp @@ -1,186 +1,186 @@ /*=================================================================== 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 ITK_ConnectomicsNetworkToConnectivityMatrixImageFilter_CPP #define ITK_ConnectomicsNetworkToConnectivityMatrixImageFilter_CPP #include #include itk::ConnectomicsNetworkToConnectivityMatrixImageFilter::ConnectomicsNetworkToConnectivityMatrixImageFilter() : m_BinaryConnectivity(false) , m_RescaleConnectivity(false) , m_InputNetwork(nullptr) { } itk::ConnectomicsNetworkToConnectivityMatrixImageFilter::~ConnectomicsNetworkToConnectivityMatrixImageFilter() { } void itk::ConnectomicsNetworkToConnectivityMatrixImageFilter::GenerateData() { this->AllocateOutputs(); OutputImageType::Pointer output = this->GetOutput(); if(m_InputNetwork.IsNull()) { MITK_ERROR << "Failed to generate data, no valid network was set."; return; } typedef mitk::ConnectomicsNetwork::NetworkType NetworkType; typedef boost::graph_traits< NetworkType >::vertex_descriptor DescriptorType; typedef boost::graph_traits< NetworkType >::vertex_iterator IteratorType; // prepare connectivity matrix for data - std::vector< std::vector< int > > connectivityMatrix; + std::vector< std::vector< double > > connectivityMatrix; int numberOfVertices = m_InputNetwork->GetNumberOfVertices(); connectivityMatrix.resize( numberOfVertices ); for( int index(0); index < numberOfVertices; index++ ) { connectivityMatrix[ index ].resize( numberOfVertices ); } // Create LabelToIndex translation std::map< std::string, DescriptorType > labelToIndexMap; NetworkType boostGraph = *(m_InputNetwork->GetBoostGraph()); // translate index to label IteratorType iterator, end; boost::tie(iterator, end) = boost::vertices( boostGraph ); for ( ; iterator != end; ++iterator) { labelToIndexMap.insert( std::pair< std::string, DescriptorType >( boostGraph[ *iterator ].label, *iterator ) ); } std::vector< std::string > indexToLabel; // translate index to label indexToLabel.resize( numberOfVertices ); boost::tie(iterator, end) = boost::vertices( boostGraph ); for ( ; iterator != end; ++iterator) { indexToLabel[ *iterator ] = boostGraph[ *iterator ].label; } //translate label to position std::vector< std::string > positionToLabelVector; positionToLabelVector = indexToLabel; std::sort ( positionToLabelVector.begin(), positionToLabelVector.end() ); for( int outerLoop( 0 ); outerLoop < numberOfVertices; outerLoop++ ) { DescriptorType fromVertexDescriptor = labelToIndexMap.find( positionToLabelVector[ outerLoop ] )->second; for( int innerLoop( outerLoop + 1 ); innerLoop < numberOfVertices; innerLoop++ ) { DescriptorType toVertexDescriptor = labelToIndexMap.find( positionToLabelVector[ innerLoop ] )->second; - int weight( 0 ); + double fiber_count( 0 ); if( boost::edge(toVertexDescriptor, fromVertexDescriptor, boostGraph ).second ) { - weight = m_InputNetwork->GetEdge( fromVertexDescriptor , toVertexDescriptor ).weight;; + fiber_count = m_InputNetwork->GetEdge( fromVertexDescriptor , toVertexDescriptor ).fiber_count; } - connectivityMatrix[outerLoop][innerLoop] = weight; - connectivityMatrix[innerLoop][outerLoop] = weight; + connectivityMatrix[outerLoop][innerLoop] = fiber_count; + connectivityMatrix[innerLoop][outerLoop] = fiber_count; } } OutputImageType::SpacingType spacing; spacing[0] = 1.0; spacing[1] = 1.0; OutputImageType::PointType origin; origin[0] = 0.0; origin[1] = 0.0; OutputImageType::IndexType index; index[0] = 0.0; index[1] = 0.0; OutputImageType::SizeType size; size[0] = numberOfVertices; size[1] = numberOfVertices; OutputImageType::RegionType region; region.SetIndex( index ); region.SetSize( size ); output->SetSpacing( spacing ); // Set the image spacing output->SetOrigin( origin ); // Set the image origin output->SetRegions( region ); output->Allocate(); output->FillBuffer(0); itk::ImageRegionIterator< OutputImageType > it_connect(output, output->GetLargestPossibleRegion()); int counter( 0 ); double rescaleFactor( 1.0 ); double rescaleMax( 255.0 ); if( m_RescaleConnectivity ) { rescaleFactor = rescaleMax / m_InputNetwork->GetMaximumWeight(); } // Colour pixels according to connectivity if( m_BinaryConnectivity ) { // binary connectivity while( !it_connect.IsAtEnd() ) { if( connectivityMatrix[ ( counter - counter % numberOfVertices ) / numberOfVertices][ counter % numberOfVertices ] ) { it_connect.Set( 1 ); } else { it_connect.Set( 0 ); } ++it_connect; counter++; } } else { // if desired rescale to the 0-255 range while( !it_connect.IsAtEnd() ) { it_connect.Set( ( unsigned short ) (rescaleFactor * connectivityMatrix[ ( counter - counter % numberOfVertices ) / numberOfVertices][ counter % numberOfVertices ]) ); ++it_connect; counter++; } } } #endif diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsNetworkCreator.cpp b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsNetworkCreator.cpp index 65a8d0567c..33ca1d4d34 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsNetworkCreator.cpp +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsNetworkCreator.cpp @@ -1,862 +1,862 @@ /*=================================================================== 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 "mitkConnectomicsNetworkCreator.h" #include #include #include "mitkConnectomicsConstantsManager.h" #include "mitkImageAccessByItk.h" #include "mitkImageStatisticsHolder.h" #include "mitkImageCast.h" #include "itkImageRegionIteratorWithIndex.h" // VTK #include #include #include mitk::ConnectomicsNetworkCreator::ConnectomicsNetworkCreator() : m_FiberBundle() , m_Segmentation() , m_ConNetwork( mitk::ConnectomicsNetwork::New() ) , idCounter(0) , m_LabelToVertexMap() , m_LabelToNodePropertyMap() , allowLoops( false ) , m_UseCoMCoordinates( false ) , m_LabelsToCoordinatesMap() , m_MappingStrategy( EndElementPositionAvoidingWhiteMatter ) , m_EndPointSearchRadius( 10.0 ) , m_ZeroLabelInvalid( true ) , m_AbortConnection( false ) { } mitk::ConnectomicsNetworkCreator::ConnectomicsNetworkCreator( mitk::Image::Pointer segmentation, mitk::FiberBundle::Pointer fiberBundle ) : m_FiberBundle(fiberBundle) , m_Segmentation(segmentation) , m_ConNetwork( mitk::ConnectomicsNetwork::New() ) , idCounter(0) , m_LabelToVertexMap() , m_LabelToNodePropertyMap() , allowLoops( false ) , m_LabelsToCoordinatesMap() , m_MappingStrategy( EndElementPositionAvoidingWhiteMatter ) , m_EndPointSearchRadius( 10.0 ) , m_ZeroLabelInvalid( true ) , m_AbortConnection( false ) { mitk::CastToItkImage( segmentation, m_SegmentationItk ); } mitk::ConnectomicsNetworkCreator::~ConnectomicsNetworkCreator() { } void mitk::ConnectomicsNetworkCreator::SetFiberBundle(mitk::FiberBundle::Pointer fiberBundle) { m_FiberBundle = fiberBundle; } void mitk::ConnectomicsNetworkCreator::SetSegmentation(mitk::Image::Pointer segmentation) { m_Segmentation = segmentation; mitk::CastToItkImage( segmentation, m_SegmentationItk ); } itk::Point mitk::ConnectomicsNetworkCreator::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } void mitk::ConnectomicsNetworkCreator::CreateNetworkFromFibersAndSegmentation() { //empty graph m_ConNetwork = mitk::ConnectomicsNetwork::New(); m_LabelToVertexMap.clear(); m_LabelToNodePropertyMap.clear(); idCounter = 0; vtkSmartPointer fiberPolyData = m_FiberBundle->GetFiberPolyData(); int numFibers = m_FiberBundle->GetNumFibers(); for( int fiberID( 0 ); fiberID < numFibers; fiberID++ ) { vtkCell* cell = fiberPolyData->GetCell(fiberID); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); TractType::Pointer singleTract = TractType::New(); for( int pointInCellID( 0 ); pointInCellID < numPoints ; pointInCellID++) { // push back point PointType point = GetItkPoint( points->GetPoint( pointInCellID ) ); singleTract->InsertElement( singleTract->Size(), point ); } if ( singleTract && ( singleTract->Size() > 0 ) ) { AddConnectionToNetwork( ReturnAssociatedVertexPairForLabelPair( ReturnLabelForFiberTract( singleTract, m_MappingStrategy ) - ) + ), m_FiberBundle->GetFiberWeight(fiberID) ); m_AbortConnection = false; } } // Prune unconnected nodes //m_ConNetwork->PruneUnconnectedSingleNodes(); // provide network with geometry m_ConNetwork->SetGeometry( dynamic_cast(m_Segmentation->GetGeometry()->Clone().GetPointer()) ); m_ConNetwork->UpdateBounds(); m_ConNetwork->SetIsModified( true ); MBI_INFO << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_INFO_NETWORK_CREATED; } -void mitk::ConnectomicsNetworkCreator::AddConnectionToNetwork(ConnectionType newConnection) +void mitk::ConnectomicsNetworkCreator::AddConnectionToNetwork(ConnectionType newConnection, double fiber_count) { if( m_AbortConnection ) { MITK_DEBUG << "Connection aborted"; return; } VertexType vertexA = newConnection.first; VertexType vertexB = newConnection.second; // check for loops (if they are not allowed) if( allowLoops || !( vertexA == vertexB ) ) { // If the connection already exists, increment weight, else create connection if ( m_ConNetwork->EdgeExists( vertexA, vertexB ) ) { - m_ConNetwork->IncreaseEdgeWeight( vertexA, vertexB ); + m_ConNetwork->IncreaseEdgeWeight( vertexA, vertexB, fiber_count ); } else { - m_ConNetwork->AddEdge( vertexA, vertexB ); + m_ConNetwork->AddEdge( vertexA, vertexB, fiber_count ); } } } mitk::ConnectomicsNetworkCreator::VertexType mitk::ConnectomicsNetworkCreator::ReturnAssociatedVertexForLabel( ImageLabelType label ) { if( m_ZeroLabelInvalid && ( label == 0 ) ) { m_AbortConnection = true; return ULONG_MAX; } // if label is not known, create entry if( ! ( m_LabelToVertexMap.count( label ) > 0 ) ) { VertexType newVertex = m_ConNetwork->AddVertex( idCounter ); idCounter++; SupplyVertexWithInformation(label, newVertex); m_LabelToVertexMap.insert( std::pair< ImageLabelType, VertexType >( label, newVertex ) ); } //return associated vertex return m_LabelToVertexMap.find( label )->second; } mitk::ConnectomicsNetworkCreator::ConnectionType mitk::ConnectomicsNetworkCreator::ReturnAssociatedVertexPairForLabelPair( ImageLabelPairType labelpair ) { //hand both labels through to the single label function ConnectionType connection( ReturnAssociatedVertexForLabel(labelpair.first), ReturnAssociatedVertexForLabel(labelpair.second) ); return connection; } mitk::ConnectomicsNetworkCreator::ImageLabelPairType mitk::ConnectomicsNetworkCreator::ReturnLabelForFiberTract( TractType::Pointer singleTract, mitk::ConnectomicsNetworkCreator::MappingStrategy strategy) { switch( strategy ) { case EndElementPosition: { return EndElementPositionLabel( singleTract ); } case JustEndPointVerticesNoLabel: { return JustEndPointVerticesNoLabelTest( singleTract ); } case EndElementPositionAvoidingWhiteMatter: { return EndElementPositionLabelAvoidingWhiteMatter( singleTract ); } case PrecomputeAndDistance: { return PrecomputeVertexLocationsBySegmentation( singleTract ); } } // To remove warnings, this code should never be reached MBI_ERROR << mitk::ConnectomicsConstantsManager::CONNECTOMICS_ERROR_INVALID_MAPPING; ImageLabelPairType nullPair( 0,0 ); return nullPair; } mitk::ConnectomicsNetworkCreator::ImageLabelPairType mitk::ConnectomicsNetworkCreator::EndElementPositionLabel( TractType::Pointer singleTract ) { ImageLabelPairType labelpair; {// Note: .fib image tracts are safed using index coordinates mitk::Point3D firstElementFiberCoord, lastElementFiberCoord; mitk::Point3D firstElementSegCoord, lastElementSegCoord; itk::Index<3> firstElementSegIndex, lastElementSegIndex; if( singleTract->front().Size() != 3 ) { MBI_ERROR << mitk::ConnectomicsConstantsManager::CONNECTOMICS_ERROR_INVALID_DIMENSION_NEED_3; } for( unsigned int index = 0; index < singleTract->front().Size(); index++ ) { firstElementFiberCoord.SetElement( index, singleTract->front().GetElement( index ) ); lastElementFiberCoord.SetElement( index, singleTract->back().GetElement( index ) ); } // convert from fiber index coordinates to segmentation index coordinates FiberToSegmentationCoords( firstElementFiberCoord, firstElementSegCoord ); FiberToSegmentationCoords( lastElementFiberCoord, lastElementSegCoord ); for( int index = 0; index < 3; index++ ) { firstElementSegIndex.SetElement( index, firstElementSegCoord.GetElement( index ) ); lastElementSegIndex.SetElement( index, lastElementSegCoord.GetElement( index ) ); } int firstLabel = m_SegmentationItk->GetPixel(firstElementSegIndex); int lastLabel = m_SegmentationItk->GetPixel(lastElementSegIndex ); labelpair.first = firstLabel; labelpair.second = lastLabel; // Add property to property map CreateNewNode( firstLabel, firstElementSegIndex, m_UseCoMCoordinates ); CreateNewNode( lastLabel, lastElementSegIndex, m_UseCoMCoordinates ); } return labelpair; } mitk::ConnectomicsNetworkCreator::ImageLabelPairType mitk::ConnectomicsNetworkCreator::PrecomputeVertexLocationsBySegmentation( TractType::Pointer /*singleTract*/ ) { ImageLabelPairType labelpair; return labelpair; } mitk::ConnectomicsNetworkCreator::ImageLabelPairType mitk::ConnectomicsNetworkCreator::EndElementPositionLabelAvoidingWhiteMatter( TractType::Pointer singleTract ) { ImageLabelPairType labelpair; {// Note: .fib image tracts are safed using index coordinates mitk::Point3D firstElementFiberCoord, lastElementFiberCoord; mitk::Point3D firstElementSegCoord, lastElementSegCoord; itk::Index<3> firstElementSegIndex, lastElementSegIndex; if( singleTract->front().Size() != 3 ) { MBI_ERROR << mitk::ConnectomicsConstantsManager::CONNECTOMICS_ERROR_INVALID_DIMENSION_NEED_3; } for( unsigned int index = 0; index < singleTract->front().Size(); index++ ) { firstElementFiberCoord.SetElement( index, singleTract->front().GetElement( index ) ); lastElementFiberCoord.SetElement( index, singleTract->back().GetElement( index ) ); } // convert from fiber index coordinates to segmentation index coordinates FiberToSegmentationCoords( firstElementFiberCoord, firstElementSegCoord ); FiberToSegmentationCoords( lastElementFiberCoord, lastElementSegCoord ); for( int index = 0; index < 3; index++ ) { firstElementSegIndex.SetElement( index, firstElementSegCoord.GetElement( index ) ); lastElementSegIndex.SetElement( index, lastElementSegCoord.GetElement( index ) ); } int firstLabel = m_SegmentationItk->GetPixel(firstElementSegIndex); int lastLabel = m_SegmentationItk->GetPixel(lastElementSegIndex ); // Check whether the labels belong to the white matter (which means, that the fibers ended early) bool extendFront(false), extendEnd(false), retractFront(false), retractEnd(false); extendFront = !IsNonWhiteMatterLabel( firstLabel ); extendEnd = !IsNonWhiteMatterLabel( lastLabel ); retractFront = IsBackgroundLabel( firstLabel ); retractEnd = IsBackgroundLabel( lastLabel ); //if( extendFront || extendEnd ) //{ //MBI_INFO << "Before Start: " << firstLabel << " at " << firstElementSegIndex[ 0 ] << " " << firstElementSegIndex[ 1 ] << " " << firstElementSegIndex[ 2 ] << " End: " << lastLabel << " at " << lastElementSegIndex[ 0 ] << " " << lastElementSegIndex[ 1 ] << " " << lastElementSegIndex[ 2 ]; //} if ( extendFront ) { std::vector< int > indexVectorOfPointsToUse; //Use first two points for direction indexVectorOfPointsToUse.push_back( 1 ); indexVectorOfPointsToUse.push_back( 0 ); // label and coordinate temp storage int tempLabel( firstLabel ); itk::Index<3> tempIndex = firstElementSegIndex; LinearExtensionUntilGreyMatter( indexVectorOfPointsToUse, singleTract, tempLabel, tempIndex ); firstLabel = tempLabel; firstElementSegIndex = tempIndex; } if ( extendEnd ) { std::vector< int > indexVectorOfPointsToUse; //Use last two points for direction indexVectorOfPointsToUse.push_back( singleTract->Size() - 2 ); indexVectorOfPointsToUse.push_back( singleTract->Size() - 1 ); // label and coordinate temp storage int tempLabel( lastLabel ); itk::Index<3> tempIndex = lastElementSegIndex; LinearExtensionUntilGreyMatter( indexVectorOfPointsToUse, singleTract, tempLabel, tempIndex ); lastLabel = tempLabel; lastElementSegIndex = tempIndex; } if ( retractFront ) { // label and coordinate temp storage int tempLabel( firstLabel ); itk::Index<3> tempIndex = firstElementSegIndex; RetractionUntilBrainMatter( true, singleTract, tempLabel, tempIndex ); firstLabel = tempLabel; firstElementSegIndex = tempIndex; } if ( retractEnd ) { // label and coordinate temp storage int tempLabel( lastLabel ); itk::Index<3> tempIndex = lastElementSegIndex; RetractionUntilBrainMatter( false, singleTract, tempLabel, tempIndex ); lastLabel = tempLabel; lastElementSegIndex = tempIndex; } //if( extendFront || extendEnd ) //{ // MBI_INFO << "After Start: " << firstLabel << " at " << firstElementSegIndex[ 0 ] << " " << firstElementSegIndex[ 1 ] << " " << firstElementSegIndex[ 2 ] << " End: " << lastLabel << " at " << lastElementSegIndex[ 0 ] << " " << lastElementSegIndex[ 1 ] << " " << lastElementSegIndex[ 2 ]; //} labelpair.first = firstLabel; labelpair.second = lastLabel; // Add property to property map CreateNewNode( firstLabel, firstElementSegIndex, m_UseCoMCoordinates ); CreateNewNode( lastLabel, lastElementSegIndex, m_UseCoMCoordinates ); } return labelpair; } mitk::ConnectomicsNetworkCreator::ImageLabelPairType mitk::ConnectomicsNetworkCreator::JustEndPointVerticesNoLabelTest( TractType::Pointer singleTract ) { ImageLabelPairType labelpair; {// Note: .fib image tracts are safed using index coordinates mitk::Point3D firstElementFiberCoord, lastElementFiberCoord; mitk::Point3D firstElementSegCoord, lastElementSegCoord; itk::Index<3> firstElementSegIndex, lastElementSegIndex; if( singleTract->front().Size() != 3 ) { MBI_ERROR << mitk::ConnectomicsConstantsManager::CONNECTOMICS_ERROR_INVALID_DIMENSION_NEED_3; } for( unsigned int index = 0; index < singleTract->front().Size(); index++ ) { firstElementFiberCoord.SetElement( index, singleTract->front().GetElement( index ) ); lastElementFiberCoord.SetElement( index, singleTract->back().GetElement( index ) ); } // convert from fiber index coordinates to segmentation index coordinates FiberToSegmentationCoords( firstElementFiberCoord, firstElementSegCoord ); FiberToSegmentationCoords( lastElementFiberCoord, lastElementSegCoord ); for( int index = 0; index < 3; index++ ) { firstElementSegIndex.SetElement( index, firstElementSegCoord.GetElement( index ) ); lastElementSegIndex.SetElement( index, lastElementSegCoord.GetElement( index ) ); } int firstLabel = 1 * firstElementSegIndex[ 0 ] + 1000 * firstElementSegIndex[ 1 ] + 1000000 * firstElementSegIndex[ 2 ]; int lastLabel = 1 * firstElementSegIndex[ 0 ] + 1000 * firstElementSegIndex[ 1 ] + 1000000 * firstElementSegIndex[ 2 ]; labelpair.first = firstLabel; labelpair.second = lastLabel; // Add property to property map CreateNewNode( firstLabel, firstElementSegIndex, m_UseCoMCoordinates ); CreateNewNode( lastLabel, lastElementSegIndex, m_UseCoMCoordinates ); } return labelpair; } void mitk::ConnectomicsNetworkCreator::SupplyVertexWithInformation( ImageLabelType& label, VertexType& vertex ) { // supply a vertex with the additional information belonging to the label // TODO: Implement additional information acquisition m_ConNetwork->SetLabel( vertex, m_LabelToNodePropertyMap.find( label )->second.label ); m_ConNetwork->SetCoordinates( vertex, m_LabelToNodePropertyMap.find( label )->second.coordinates ); } std::string mitk::ConnectomicsNetworkCreator::LabelToString( ImageLabelType& label ) { int tempInt = (int) label; std::stringstream ss;//create a stringstream std::string tempString; ss << tempInt;//add number to the stream tempString = ss.str(); return tempString;//return a string with the contents of the stream } mitk::ConnectomicsNetwork::Pointer mitk::ConnectomicsNetworkCreator::GetNetwork() { return m_ConNetwork; } void mitk::ConnectomicsNetworkCreator::FiberToSegmentationCoords( mitk::Point3D& fiberCoord, mitk::Point3D& segCoord ) { mitk::Point3D tempPoint; // convert from fiber index coordinates to segmentation index coordinates m_FiberBundle->GetGeometry()->IndexToWorld( fiberCoord, tempPoint ); m_Segmentation->GetGeometry()->WorldToIndex( tempPoint, segCoord ); } void mitk::ConnectomicsNetworkCreator::SegmentationToFiberCoords( mitk::Point3D& segCoord, mitk::Point3D& fiberCoord ) { mitk::Point3D tempPoint; // convert from fiber index coordinates to segmentation index coordinates m_Segmentation->GetGeometry()->IndexToWorld( segCoord, tempPoint ); m_FiberBundle->GetGeometry()->WorldToIndex( tempPoint, fiberCoord ); } bool mitk::ConnectomicsNetworkCreator::IsNonWhiteMatterLabel( int labelInQuestion ) { bool isWhite( false ); isWhite = ( ( labelInQuestion == freesurfer_Left_Cerebral_White_Matter ) || ( labelInQuestion == freesurfer_Left_Cerebellum_White_Matter ) || ( labelInQuestion == freesurfer_Right_Cerebral_White_Matter ) || ( labelInQuestion == freesurfer_Right_Cerebellum_White_Matter )|| ( labelInQuestion == freesurfer_Left_Cerebellum_Cortex ) || ( labelInQuestion == freesurfer_Right_Cerebellum_Cortex ) || ( labelInQuestion == freesurfer_Brain_Stem ) ); return !isWhite; } bool mitk::ConnectomicsNetworkCreator::IsBackgroundLabel( int labelInQuestion ) { bool isBackground( false ); isBackground = ( labelInQuestion == 0 ); return isBackground; } void mitk::ConnectomicsNetworkCreator::LinearExtensionUntilGreyMatter( std::vector & indexVectorOfPointsToUse, TractType::Pointer singleTract, int & label, itk::Index<3> & mitkIndex ) { if( indexVectorOfPointsToUse.size() > singleTract->Size() ) { MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_MORE_POINTS_THAN_PRESENT; return; } if( indexVectorOfPointsToUse.size() < 2 ) { MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_ESTIMATING_LESS_THAN_2; return; } for( unsigned int index( 0 ); index < indexVectorOfPointsToUse.size(); index++ ) { if( indexVectorOfPointsToUse[ index ] < 0 ) { MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_ESTIMATING_BEYOND_START; return; } if( (unsigned int)indexVectorOfPointsToUse[ index ] > singleTract->Size() ) { MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_ESTIMATING_BEYOND_END; return; } } mitk::Point3D startPoint, endPoint; std::vector< double > differenceVector; differenceVector.resize( singleTract->front().Size() ); { // which points to use, currently only last two //TODO correct using all points int endPointIndex = indexVectorOfPointsToUse.size() - 1; int startPointIndex = indexVectorOfPointsToUse.size() - 2; // convert to segmentation coords mitk::Point3D startFiber, endFiber; for( unsigned int index = 0; index < singleTract->front().Size(); index++ ) { endFiber.SetElement( index, singleTract->GetElement( indexVectorOfPointsToUse[ endPointIndex ] ).GetElement( index ) ); startFiber.SetElement( index, singleTract->GetElement( indexVectorOfPointsToUse[ startPointIndex ] ).GetElement( index ) ); } FiberToSegmentationCoords( endFiber, endPoint ); FiberToSegmentationCoords( startFiber, startPoint ); // calculate straight line for( unsigned int index = 0; index < singleTract->front().Size(); index++ ) { differenceVector[ index ] = endPoint.GetElement( index ) - startPoint.GetElement( index ); } // normalizing direction vector double length( 0.0 ); double sum( 0.0 ); for( unsigned int index = 0; index < differenceVector.size() ; index++ ) { sum = sum + differenceVector[ index ] * differenceVector[ index ]; } length = std::sqrt( sum ); for( unsigned int index = 0; index < differenceVector.size() ; index++ ) { differenceVector[ index ] = differenceVector[ index ] / length; } // follow line until first non white matter label itk::Index<3> tempIndex; int tempLabel( label ); bool keepOn( true ); itk::ImageRegion<3> itkRegion = m_SegmentationItk->GetLargestPossibleRegion(); for( int parameter( 0 ) ; keepOn ; parameter++ ) { if( parameter > 1000 ) { MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_DID_NOT_FIND_WHITE; break; } for( int index( 0 ); index < 3; index++ ) { tempIndex.SetElement( index, endPoint.GetElement( index ) + parameter * differenceVector[ index ] ); } if( itkRegion.IsInside( tempIndex ) ) { tempLabel = m_SegmentationItk->GetPixel( tempIndex ); } else { tempLabel = -1; } if( IsNonWhiteMatterLabel( tempLabel ) ) { if( tempLabel < 1 ) { keepOn = false; //MBI_WARN << mitk::ConnectomicsConstantsManager::CONNECTOMICS_WARNING_NOT_EXTEND_TO_WHITE; } else { label = tempLabel; mitkIndex = tempIndex; keepOn = false; } } } } } void mitk::ConnectomicsNetworkCreator::RetractionUntilBrainMatter( bool retractFront, TractType::Pointer singleTract, int & label, itk::Index<3> & mitkIndex ) { int retractionStartIndex( singleTract->Size() - 1 ); int retractionStepIndexSize( -1 ); int retractionTerminationIndex( 0 ); if( retractFront ) { retractionStartIndex = 0; retractionStepIndexSize = 1; retractionTerminationIndex = singleTract->Size() - 1; } int currentRetractionIndex = retractionStartIndex; bool keepRetracting( true ); mitk::Point3D currentPoint, nextPoint; std::vector< double > differenceVector; differenceVector.resize( singleTract->front().Size() ); while( keepRetracting && ( currentRetractionIndex != retractionTerminationIndex ) ) { // convert to segmentation coords mitk::Point3D currentPointFiberCoord, nextPointFiberCoord; for( unsigned int index = 0; index < singleTract->front().Size(); index++ ) { currentPointFiberCoord.SetElement( index, singleTract->GetElement( currentRetractionIndex ).GetElement( index ) ); nextPointFiberCoord.SetElement( index, singleTract->GetElement( currentRetractionIndex + retractionStepIndexSize ).GetElement( index ) ); } FiberToSegmentationCoords( currentPointFiberCoord, currentPoint ); FiberToSegmentationCoords( nextPointFiberCoord, nextPoint ); // calculate straight line for( unsigned int index = 0; index < singleTract->front().Size(); index++ ) { differenceVector[ index ] = nextPoint.GetElement( index ) - currentPoint.GetElement( index ); } // calculate length of direction vector double length( 0.0 ); double sum( 0.0 ); for( unsigned int index = 0; index < differenceVector.size() ; index++ ) { sum = sum + differenceVector[ index ] * differenceVector[ index ]; } length = std::sqrt( sum ); // retract itk::Index<3> tempIndex; int tempLabel( label ); for( int parameter( 0 ) ; parameter < length ; parameter++ ) { for( int index( 0 ); index < 3; index++ ) { tempIndex.SetElement( index, currentPoint.GetElement( index ) + ( 1.0 + parameter ) / ( 1.0 + length ) * differenceVector[ index ] ); } tempLabel = m_SegmentationItk->GetPixel( tempIndex ); if( !IsBackgroundLabel( tempLabel ) ) { // check whether result is within the search space { mitk::Point3D endPoint, foundPointSegmentation, foundPointFiber; for( unsigned int index = 0; index < singleTract->front().Size(); index++ ) { // this is in fiber (world) coordinates endPoint.SetElement( index, singleTract->GetElement( retractionStartIndex ).GetElement( index ) ); } for( int index( 0 ); index < 3; index++ ) { foundPointSegmentation.SetElement( index, currentPoint.GetElement( index ) + ( 1.0 + parameter ) / ( 1.0 + length ) * differenceVector[ index ] ); } SegmentationToFiberCoords( foundPointSegmentation, foundPointFiber ); std::vector< double > finalDistance; finalDistance.resize( singleTract->front().Size() ); for( unsigned int index = 0; index < singleTract->front().Size(); index++ ) { finalDistance[ index ] = foundPointFiber.GetElement( index ) - endPoint.GetElement( index ); } // calculate length of direction vector double finalLength( 0.0 ); double finalSum( 0.0 ); for( unsigned int index = 0; index < finalDistance.size() ; index++ ) { finalSum = finalSum + finalDistance[ index ] * finalDistance[ index ]; } finalLength = std::sqrt( finalSum ); if( finalLength > m_EndPointSearchRadius ) { // the found point was not within the search space return; } } label = tempLabel; mitkIndex = tempIndex; return; } // hit next point without finding brain matter currentRetractionIndex = currentRetractionIndex + retractionStepIndexSize; if( ( currentRetractionIndex < 1 ) || ( (unsigned int)currentRetractionIndex > ( singleTract->Size() - 2 ) ) ) { keepRetracting = false; } } } } void mitk::ConnectomicsNetworkCreator::CalculateCenterOfMass() { const int dimensions = 3; int max = m_Segmentation->GetStatistics()->GetScalarValueMax(); int min = m_Segmentation->GetStatistics()->GetScalarValueMin(); int range = max - min +1; // each label owns a vector of coordinates std::vector< std::vector< std::vector< double> > > coordinatesPerLabelVector; coordinatesPerLabelVector.resize( range ); itk::ImageRegionIteratorWithIndex it_itkImage( m_SegmentationItk, m_SegmentationItk->GetLargestPossibleRegion() ); for( it_itkImage.GoToBegin(); !it_itkImage.IsAtEnd(); ++it_itkImage ) { std::vector< double > coordinates; coordinates.resize(dimensions); itk::Index< dimensions > index = it_itkImage.GetIndex(); for( int loop(0); loop < dimensions; loop++) { coordinates.at( loop ) = index.GetElement( loop ); } // add the coordinates to the corresponding label vector coordinatesPerLabelVector.at( it_itkImage.Value() - min ).push_back( coordinates ); } for(int currentIndex(0), currentLabel( min ); currentIndex < range; currentIndex++, currentLabel++ ) { std::vector< double > currentCoordinates; currentCoordinates.resize(dimensions); int numberOfPoints = coordinatesPerLabelVector.at( currentIndex ).size(); std::vector< double > sumCoords; sumCoords.resize( dimensions ); for( int loop(0); loop < numberOfPoints; loop++ ) { for( int loopDimension( 0 ); loopDimension < dimensions; loopDimension++ ) { sumCoords.at( loopDimension ) += coordinatesPerLabelVector.at( currentIndex ).at( loop ).at( loopDimension ); } } for( int loopDimension( 0 ); loopDimension < dimensions; loopDimension++ ) { currentCoordinates.at( loopDimension ) = sumCoords.at( loopDimension ) / numberOfPoints; } m_LabelsToCoordinatesMap.insert( std::pair< int, std::vector >( currentLabel, currentCoordinates ) ); } //can now use center of mass coordinates m_UseCoMCoordinates = true; } std::vector< double > mitk::ConnectomicsNetworkCreator::GetCenterOfMass( int label ) { // if label is not known, warn if( ! ( m_LabelsToCoordinatesMap.count( label ) > 0 ) ) { MITK_ERROR << "Label " << label << " not found. Could not return coordinates."; std::vector< double > nullVector; nullVector.resize(3); return nullVector; } //return associated coordinates return m_LabelsToCoordinatesMap.find( label )->second; } void mitk::ConnectomicsNetworkCreator::CreateNewNode( int label, itk::Index<3> index, bool useCoM ) { // Only create node if it does not exist yet if( ! ( m_LabelToNodePropertyMap.count( label ) > 0 ) ) { NetworkNode newNode; newNode.coordinates.resize( 3 ); if( !useCoM ) { for( unsigned int loop = 0; loop < newNode.coordinates.size() ; loop++ ) { newNode.coordinates[ loop ] = index[ loop ] ; } } else { std::vector labelCoords = GetCenterOfMass( label ); for( unsigned int loop = 0; loop < newNode.coordinates.size() ; loop++ ) { newNode.coordinates[ loop ] = labelCoords.at( loop ) ; } } newNode.label = LabelToString( label ); m_LabelToNodePropertyMap.insert( std::pair< ImageLabelType, NetworkNode >( label, newNode ) ); } } diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsNetworkCreator.h b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsNetworkCreator.h index 192db2abbd..e7d9dd215a 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsNetworkCreator.h +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsNetworkCreator.h @@ -1,249 +1,249 @@ /*=================================================================== 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 mitkConnectomicsNetworkCreator_h #define mitkConnectomicsNetworkCreator_h #include #include #include #include "mitkCommon.h" #include "mitkImage.h" #include "mitkFiberBundle.h" #include "mitkConnectomicsNetwork.h" #include namespace mitk { /** * \brief Creates connectomics networks from fibers and parcellation * * This class needs a parcellation image and a fiber image to be set. Then you can create * a connectomics network from the two, using different strategies. */ class MITKCONNECTOMICS_EXPORT ConnectomicsNetworkCreator : public itk::Object { public: /** Enum for different ways to create the mapping from fibers to network */ enum MappingStrategy { EndElementPosition, EndElementPositionAvoidingWhiteMatter, JustEndPointVerticesNoLabel, PrecomputeAndDistance }; /** Standard class typedefs. */ /** Method for creation through the object factory. */ mitkClassMacroItkParent(ConnectomicsNetworkCreator, itk::Object); itkFactorylessNewMacro(Self) itkCloneMacro(Self) /** Type for Images **/ typedef itk::Image ITKImageType; /** Types for the standardized Tract **/ typedef itk::Point PointType; typedef itk::VectorContainer TractType; typedef itk::VectorContainer< unsigned int, TractType::Pointer > TractContainerType; //init via smartpointer /** Types for Network **/ typedef mitk::ConnectomicsNetwork::VertexDescriptorType VertexType; typedef mitk::ConnectomicsNetwork::EdgeDescriptorType EdgeType; typedef mitk::ConnectomicsNetwork::NetworkNode NetworkNode; typedef std::pair< VertexType, VertexType > ConnectionType; /** Types for labels **/ typedef int ImageLabelType; typedef std::pair< ImageLabelType, ImageLabelType > ImageLabelPairType; /** Given a fiber bundle and a parcellation are set, this will create a network from both */ void CreateNetworkFromFibersAndSegmentation(); void SetFiberBundle(mitk::FiberBundle::Pointer fiberBundle); void SetSegmentation(mitk::Image::Pointer segmentation); mitk::ConnectomicsNetwork::Pointer GetNetwork(); itkSetMacro(MappingStrategy, MappingStrategy); itkSetMacro(EndPointSearchRadius, double); itkSetMacro(ZeroLabelInvalid, bool); /** \brief Calculate the locations of vertices * * Calculate the center of mass for each label and store the information. This will need a set parcellation image. * Unless this function is called the first location where a label is encountered will be used. After calling this function * the center of mass will be used instead. */ void CalculateCenterOfMass(); protected: //////////////////// Functions /////////////////////// ConnectomicsNetworkCreator(); ConnectomicsNetworkCreator( mitk::Image::Pointer segmentation, mitk::FiberBundle::Pointer fiberBundle ); ~ConnectomicsNetworkCreator(); /** Add a connection to the network */ - void AddConnectionToNetwork(ConnectionType newConnection); + void AddConnectionToNetwork(ConnectionType newConnection, double fiber_count); /** Determine if a label is already identified with a vertex, otherwise create a new one */ VertexType ReturnAssociatedVertexForLabel( ImageLabelType label ); /** Return the vertexes associated with a pair of labels */ ConnectionType ReturnAssociatedVertexPairForLabelPair( ImageLabelPairType labelpair ); /** Return the pair of labels which identify the areas connected by a single fiber */ ImageLabelPairType ReturnLabelForFiberTract( TractType::Pointer singleTract, MappingStrategy strategy ); /** Assign the additional information which should be part of the vertex */ void SupplyVertexWithInformation( ImageLabelType& label, VertexType& vertex ); /** Create a string from the label */ std::string LabelToString( ImageLabelType& label ); /** Check whether the label in question belongs to white matter according to the freesurfer table */ bool IsNonWhiteMatterLabel( int labelInQuestion ); /** Check whether the label in question belongs to background according to the freesurfer table */ bool IsBackgroundLabel( int labelInQuestion ); /** Extend a straight line through the given points and look for the first non white matter label It will try extend in the direction of the points in the vector so a vector {B,C} will result in extending from C in the direction C-B */ void LinearExtensionUntilGreyMatter( std::vector & indexVectorOfPointsToUse, TractType::Pointer singleTract, int & label, itk::Index<3> & mitkIndex ); /** Retract fiber until the first brain matter label is hit The bool parameter controls whether the front or the end is retracted */ void RetractionUntilBrainMatter( bool retractFront, TractType::Pointer singleTract, int & label, itk::Index<3> & mitkIndex ); /** \brief Get the location of the center of mass for a specific label * This can throw an exception if the label is not found. */ std::vector< double > GetCenterOfMass( int label ); /** Convert point to itk point */ itk::Point GetItkPoint(double point[3]); /** \brief Creates a new node * * A new node will be created, using the label and either the supplied coordinates * or the center of mass coordinates, depending on the supplied bool. */ void CreateNewNode( int label, itk::Index<3>, bool useIndex ); ///////// Mapping strategies ////////// /** Use the position of the end and starting element only to map to labels Map a fiber to a vertex by taking the value of the parcellation image at the same world coordinates as the last and first element of the tract.*/ ImageLabelPairType EndElementPositionLabel( TractType::Pointer singleTract ); /** Map by distance between elements and vertices depending on their volume First go through the parcellation and compute the coordinates of the future vertices. Assign a radius according on their volume. Then map an edge to a label by considering the nearest vertices and comparing the distance to them to their radii. */ ImageLabelPairType PrecomputeVertexLocationsBySegmentation( TractType::Pointer singleTract ); /** Use the position of the end and starting element only to map to labels Just take first and last position, no labelling, nothing */ ImageLabelPairType JustEndPointVerticesNoLabelTest( TractType::Pointer singleTract ); /** Use the position of the end and starting element unless it is in white matter, then search for nearby parcellation to map to labels Map a fiber to a vertex by taking the value of the parcellation image at the same world coordinates as the last and first element of the tract. If this happens to be white matter, then try to extend the fiber in a line and take the first non-white matter parcel, that is intersected. */ ImageLabelPairType EndElementPositionLabelAvoidingWhiteMatter( TractType::Pointer singleTract ); ///////// Conversions ////////// /** Convert fiber index to segmentation index coordinates */ void FiberToSegmentationCoords( mitk::Point3D& fiberCoord, mitk::Point3D& segCoord ); /** Convert segmentation index to fiber index coordinates */ void SegmentationToFiberCoords( mitk::Point3D& segCoord, mitk::Point3D& fiberCoord ); /////////////////////// Variables //////////////////////// mitk::FiberBundle::Pointer m_FiberBundle; mitk::Image::Pointer m_Segmentation; ITKImageType::Pointer m_SegmentationItk; // the graph itself mitk::ConnectomicsNetwork::Pointer m_ConNetwork; // the id counter int idCounter; // the map mapping labels to vertices std::map< ImageLabelType, VertexType > m_LabelToVertexMap; // mapping labels to additional information std::map< ImageLabelType, NetworkNode > m_LabelToNodePropertyMap; // toggles whether edges between a node and itself can exist bool allowLoops; // toggles whether to use the center of mass coordinates bool m_UseCoMCoordinates; // stores the coordinates of labels std::map< int, std::vector< double> > m_LabelsToCoordinatesMap; // the straty to use for mapping MappingStrategy m_MappingStrategy; // search radius for finding a non white matter/background area. Should be in mm double m_EndPointSearchRadius; // toggles whether a node with the label 0 may be present bool m_ZeroLabelInvalid; // used internally to communicate a connection should not be added if the a problem // is encountered while adding it bool m_AbortConnection; //////////////////////// IDs //////////////////////////// // These IDs are the freesurfer ids used in parcellation static const int freesurfer_Left_Cerebral_White_Matter = 2; static const int freesurfer_Left_Cerebellum_White_Matter = 7; static const int freesurfer_Left_Cerebellum_Cortex = 8; static const int freesurfer_Brain_Stem = 16; static const int freesurfer_Right_Cerebral_White_Matter = 41; static const int freesurfer_Right_Cerebellum_White_Matter = 46; static const int freesurfer_Right_Cerebellum_Cortex = 47; }; }// end namespace mitk #endif // _mitkConnectomicsNetworkCreator_H_INCLUDED diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsNetworkThresholder.cpp b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsNetworkThresholder.cpp index 6cb7b3b5c4..28ebb35eb9 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsNetworkThresholder.cpp +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsNetworkThresholder.cpp @@ -1,251 +1,251 @@ /*=================================================================== 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 "mitkConnectomicsNetworkThresholder.h" #include #include "vnl/vnl_random.h" mitk::ConnectomicsNetworkThresholder::ConnectomicsNetworkThresholder() : m_Network( nullptr ) , m_ThresholdingScheme( mitk::ConnectomicsNetworkThresholder::ThresholdBased ) , m_TargetThreshold( 0.0 ) , m_TargetDensity( 1.0 ) { } mitk::ConnectomicsNetworkThresholder::~ConnectomicsNetworkThresholder() { } mitk::ConnectomicsNetwork::Pointer mitk::ConnectomicsNetworkThresholder::GetThresholdedNetwork() { mitk::ConnectomicsNetwork::Pointer result; if( ! CheckValidity() ) { MITK_ERROR << "Aborting"; return m_Network; } switch(m_ThresholdingScheme) { case RandomRemovalOfWeakest : { result = ThresholdByRandomRemoval( m_Network, m_TargetDensity ); break; } case LargestLowerThanDensity : { result = ThresholdBelowDensity( m_Network, m_TargetDensity ); break; } case ThresholdBased : { result = Threshold( m_Network, m_TargetThreshold ); break; } default : { MITK_ERROR << "Specified unknown Thresholding Scheme"; result = m_Network; } } return result; } bool mitk::ConnectomicsNetworkThresholder::CheckValidity() { bool valid(true); if( m_Network.IsNull() ) { valid = false; MITK_ERROR << "Network is nullptr."; } switch(m_ThresholdingScheme) { case RandomRemovalOfWeakest : case LargestLowerThanDensity : { if( m_TargetDensity < 0.0 ) { valid = false; MITK_ERROR << "Target density is negative."; } if( m_TargetDensity > 1.0 ) { valid = false; MITK_ERROR << "Target density is larger than 1."; } break; } case ThresholdBased : { if( m_TargetThreshold < 0 ) { valid = false; MITK_ERROR << "Target threshold is negative."; } break; } default : { valid = false; MITK_ERROR << "Specified unknown Thresholding Scheme"; } } return valid; } mitk::ConnectomicsNetwork::Pointer mitk::ConnectomicsNetworkThresholder::ThresholdByRandomRemoval( mitk::ConnectomicsNetwork::Pointer input, double targetDensity ) { mitk::ConnectomicsNetwork::Pointer result = mitk::ConnectomicsNetwork::New(); result->ImportNetwort( input ); mitk::ConnectomicsStatisticsCalculator::Pointer calculator = mitk::ConnectomicsStatisticsCalculator::New(); calculator->SetNetwork( result ); calculator->Update(); //the random number generator vnl_random rng( (unsigned int) rand() ); bool notBelow( targetDensity < calculator->GetConnectionDensity() ); double minWeight( result->GetMaximumWeight() ); int count( 0 ); while( notBelow ) { // result = Threshold( result, loop ); std::vector< EdgeDescriptorType > candidateVector; minWeight = result->GetMaximumWeight(); count = 0; // determine minimum weight and number of edges having that weight NetworkType* boostGraph = result->GetBoostGraph(); EdgeIteratorType iterator, end; // sets iterator to start end end to end boost::tie(iterator, end) = boost::edges( *boostGraph ); for ( ; iterator != end; ++iterator) { double tempWeight; // the value of an iterator is a descriptor - tempWeight = (*boostGraph)[ *iterator ].weight; + tempWeight = (*boostGraph)[ *iterator ].fiber_count; if( mitk::Equal( tempWeight, minWeight ) ) { candidateVector.push_back( *iterator ); count++; } else if( tempWeight < minWeight ) { candidateVector.clear(); candidateVector.push_back( *iterator ); minWeight = tempWeight; count = 1; } } // Which to delete int deleteNumber( rng.lrand32( count - 1 ) ); boost::remove_edge( candidateVector.at( deleteNumber ), *boostGraph ); calculator->SetNetwork( result ); calculator->Update(); notBelow = targetDensity < calculator->GetConnectionDensity(); } result->UpdateIDs(); return result; } mitk::ConnectomicsNetwork::Pointer mitk::ConnectomicsNetworkThresholder::ThresholdBelowDensity( mitk::ConnectomicsNetwork::Pointer input, double targetDensity ) { mitk::ConnectomicsNetwork::Pointer result = mitk::ConnectomicsNetwork::New(); result->ImportNetwort( input ); mitk::ConnectomicsStatisticsCalculator::Pointer calculator = mitk::ConnectomicsStatisticsCalculator::New(); calculator->SetNetwork( result ); calculator->Update(); bool notBelow( targetDensity < calculator->GetConnectionDensity() ); for( int loop( 1 ); notBelow; loop++ ) { result = Threshold( result, loop ); calculator->SetNetwork( result ); calculator->Update(); notBelow = targetDensity < calculator->GetConnectionDensity(); } return result; } mitk::ConnectomicsNetwork::Pointer mitk::ConnectomicsNetworkThresholder::Threshold( mitk::ConnectomicsNetwork::Pointer input, double targetThreshold ) { mitk::ConnectomicsNetwork::Pointer result = mitk::ConnectomicsNetwork::New(); result->ImportNetwort( input ); NetworkType* boostGraph = result->GetBoostGraph(); EdgeIteratorType iterator, end; // set to true if iterators are invalidated by deleting an edge bool edgeHasBeenRemoved( true ); // if no edge has been removed in the last loop, we are done while( edgeHasBeenRemoved ) { edgeHasBeenRemoved = false; // sets iterator to start and end to end boost::tie(iterator, end) = boost::edges( *boostGraph ); bool endReached( false ); while( !edgeHasBeenRemoved && !endReached ) { if( iterator != end ) { // If the edge is below the target threshold it is deleted - if( (*boostGraph)[ *iterator ].weight < targetThreshold ) + if( (*boostGraph)[ *iterator ].fiber_count < targetThreshold ) { edgeHasBeenRemoved = true; // this invalidates all iterators boost::remove_edge( *iterator, *boostGraph ); } else { ++iterator; } } else { endReached = true; } } } result->UpdateIDs(); return result; } diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSimulatedAnnealingPermutationModularity.cpp b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSimulatedAnnealingPermutationModularity.cpp index 8ea4fa6828..543d76a7c8 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSimulatedAnnealingPermutationModularity.cpp +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkConnectomicsSimulatedAnnealingPermutationModularity.cpp @@ -1,540 +1,540 @@ /*=================================================================== 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 "mitkConnectomicsSimulatedAnnealingPermutationModularity.h" #include "mitkConnectomicsSimulatedAnnealingCostFunctionModularity.h" #include "mitkConnectomicsSimulatedAnnealingManager.h" //for random number generation #include "vnl/vnl_random.h" #include "vnl/vnl_math.h" mitk::ConnectomicsSimulatedAnnealingPermutationModularity::ConnectomicsSimulatedAnnealingPermutationModularity() { } mitk::ConnectomicsSimulatedAnnealingPermutationModularity::~ConnectomicsSimulatedAnnealingPermutationModularity() { } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::SetNetwork( mitk::ConnectomicsNetwork::Pointer theNetwork ) { m_Network = theNetwork; } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::Initialize() { // create entry for every vertex std::vector< VertexDescriptorType > vertexVector = m_Network->GetVectorOfAllVertexDescriptors(); const int vectorSize = vertexVector.size(); for( int index( 0 ); index < vectorSize; index++) { m_BestSolution.insert( std::pair( vertexVector[ index ], 0 ) ); } // initialize with random distribution of n modules int n( 5 ); randomlyAssignNodesToModules( &m_BestSolution, n ); } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::Permutate( double temperature ) { ToModuleMapType currentSolution = m_BestSolution; ToModuleMapType currentBestSolution = m_BestSolution; int factor = 1; int numberOfVertices = m_BestSolution.size(); int singleNodeMaxNumber = factor * numberOfVertices * numberOfVertices; int moduleMaxNumber = factor * numberOfVertices; double currentBestCost = Evaluate( ¤tBestSolution ); // do singleNodeMaxNumber node permutations and evaluate for(int loop( 0 ); loop < singleNodeMaxNumber; loop++) { permutateMappingSingleNodeShift( ¤tSolution, m_Network ); if( AcceptChange( currentBestCost, Evaluate( ¤tSolution ), temperature ) ) { currentBestSolution = currentSolution; currentBestCost = Evaluate( ¤tBestSolution ); } } // do moduleMaxNumber module permutations for(int loop( 0 ); loop < moduleMaxNumber; loop++) { permutateMappingModuleChange( ¤tSolution, temperature, m_Network ); if( AcceptChange( currentBestCost, Evaluate( ¤tSolution ), temperature ) ) { currentBestSolution = currentSolution; currentBestCost = Evaluate( ¤tBestSolution ); } } // store the best solution after the run m_BestSolution = currentBestSolution; } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::CleanUp() { // delete empty modules, if any for( int loop( 0 ); loop < getNumberOfModules( &m_BestSolution ) ; loop++ ) { if( getNumberOfVerticesInModule( &m_BestSolution, loop ) < 1 ) { removeModule( &m_BestSolution, loop ); } } } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::permutateMappingSingleNodeShift( ToModuleMapType *vertexToModuleMap, mitk::ConnectomicsNetwork::Pointer network ) { const int nodeCount = vertexToModuleMap->size(); const int moduleCount = getNumberOfModules( vertexToModuleMap ); // the random number generators vnl_random rng( (unsigned int) rand() ); unsigned long randomNode = rng.lrand32( nodeCount - 1 ); // move the node either to any existing module, or to its own //unsigned long randomModule = rng.lrand32( moduleCount ); unsigned long randomModule = rng.lrand32( moduleCount - 1 ); // do some sanity checks if ( nodeCount < 2 ) { // no sense in doing anything return; } const std::vector< VertexDescriptorType > allNodesVector = network->GetVectorOfAllVertexDescriptors(); auto iter = vertexToModuleMap->find( allNodesVector[ randomNode ] ); const int previousModuleNumber = iter->second; // if we move the node to its own module, do nothing if( previousModuleNumber == (long)randomModule ) { return; } iter->second = randomModule; if( getNumberOfVerticesInModule( vertexToModuleMap, previousModuleNumber ) < 1 ) { removeModule( vertexToModuleMap, previousModuleNumber ); } } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::permutateMappingModuleChange( ToModuleMapType *vertexToModuleMap, double currentTemperature, mitk::ConnectomicsNetwork::Pointer network ) { //the random number generators vnl_random rng( (unsigned int) rand() ); //randomly generate threshold const double threshold = rng.drand64( 0.0 , 1.0); //for deciding whether to join two modules or split one double splitThreshold = 0.5; //stores whether to join or two split bool joinModules( false ); //select random module int numberOfModules = getNumberOfModules( vertexToModuleMap ); unsigned long randomModuleA = rng.lrand32( numberOfModules - 1 ); //select the second module to join, if joining unsigned long randomModuleB = rng.lrand32( numberOfModules - 1 ); if( ( threshold < splitThreshold ) && ( randomModuleA != randomModuleB ) ) { joinModules = true; } if( joinModules ) { // this being an kommutative operation, we will always join B to A joinTwoModules( vertexToModuleMap, randomModuleA, randomModuleB ); //eliminate the empty module removeModule( vertexToModuleMap, randomModuleB ); } else { //split module splitModule( vertexToModuleMap, currentTemperature, network, randomModuleA ); } } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::joinTwoModules( ToModuleMapType *vertexToModuleMap, int moduleA, int moduleB ) { auto iter = vertexToModuleMap->begin(); auto end = vertexToModuleMap->end(); while( iter != end ) { // if vertex belongs to module B move it to A if( iter->second == moduleB ) { iter->second = moduleA; } iter++; }// end while( iter != end ) } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::splitModule( ToModuleMapType *vertexToModuleMap, double currentTemperature, mitk::ConnectomicsNetwork::Pointer network, int moduleToSplit ) { if( m_Depth == 0 ) { // do nothing return; } // if the module contains only one node, no more division is sensible if( getNumberOfVerticesInModule( vertexToModuleMap, moduleToSplit ) < 2 ) { // do nothing return; } // create subgraph of the module, that is to be splitted mitk::ConnectomicsNetwork::Pointer subNetwork = mitk::ConnectomicsNetwork::New(); VertexToVertexMapType graphToSubgraphVertexMap; VertexToVertexMapType subgraphToGraphVertexMap; extractModuleSubgraph( vertexToModuleMap, network, moduleToSplit, subNetwork, &graphToSubgraphVertexMap, &subgraphToGraphVertexMap ); // The submap ToModuleMapType vertexToModuleSubMap; // run simulated annealing on the subgraph to determine how the module should be split if( m_Depth > 0 && m_StepSize > 0 ) { mitk::ConnectomicsSimulatedAnnealingManager::Pointer manager = mitk::ConnectomicsSimulatedAnnealingManager::New(); mitk::ConnectomicsSimulatedAnnealingPermutationModularity::Pointer permutation = mitk::ConnectomicsSimulatedAnnealingPermutationModularity::New(); mitk::ConnectomicsSimulatedAnnealingCostFunctionModularity::Pointer costFunction = mitk::ConnectomicsSimulatedAnnealingCostFunctionModularity::New(); permutation->SetCostFunction( costFunction.GetPointer() ); permutation->SetNetwork( subNetwork ); permutation->SetDepth( m_Depth - 1 ); permutation->SetStepSize( m_StepSize * 2 ); manager->SetPermutation( permutation.GetPointer() ); manager->RunSimulatedAnnealing( currentTemperature, m_StepSize * 2 ); vertexToModuleSubMap = permutation->GetMapping(); } // now carry the information over to the original map std::vector< int > moduleTranslationVector; moduleTranslationVector.resize( getNumberOfModules( &vertexToModuleSubMap ), 0 ); int originalNumber = getNumberOfModules( vertexToModuleMap ); // the new parts are added at the end for(unsigned int index( 0 ); index < moduleTranslationVector.size() ; index++) { moduleTranslationVector[ index ] = originalNumber + index; } auto iter2 = vertexToModuleSubMap.begin(); auto end2 = vertexToModuleSubMap.end(); while( iter2 != end2 ) { // translate vertex descriptor from subgraph to graph VertexDescriptorType key = subgraphToGraphVertexMap.find( iter2->first )->second; // translate module number from subgraph to graph int value = moduleTranslationVector[ iter2->second ]; // change the corresponding entry vertexToModuleMap->find( key )->second = value; iter2++; } // remove the now empty module, that was splitted removeModule( vertexToModuleMap, moduleToSplit ); } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::extractModuleSubgraph( ToModuleMapType *vertexToModuleMap, mitk::ConnectomicsNetwork::Pointer network, int moduleToSplit, mitk::ConnectomicsNetwork::Pointer subNetwork, VertexToVertexMapType* graphToSubgraphVertexMap, VertexToVertexMapType* subgraphToGraphVertexMap ) { const std::vector< VertexDescriptorType > allNodesVector = network->GetVectorOfAllVertexDescriptors(); // add vertices to subgraph for( unsigned int nodeNumber( 0 ); nodeNumber < allNodesVector.size() ; nodeNumber++) { if( moduleToSplit == vertexToModuleMap->find( allNodesVector[ nodeNumber ] )->second ) { int id = network->GetNode( allNodesVector[ nodeNumber ] ).id; VertexDescriptorType newVertex = subNetwork->AddVertex( id ); graphToSubgraphVertexMap->insert( std::pair( allNodesVector[ nodeNumber ], newVertex ) ); subgraphToGraphVertexMap->insert( std::pair( newVertex, allNodesVector[ nodeNumber ] ) ); } } // add edges to subgraph auto iter = graphToSubgraphVertexMap->begin(); auto end = graphToSubgraphVertexMap->end(); while( iter != end ) { const std::vector< VertexDescriptorType > adjacentNodexVector = network->GetVectorOfAdjacentNodes( iter->first ); for( unsigned int adjacentNodeNumber( 0 ); adjacentNodeNumber < adjacentNodexVector.size() ; adjacentNodeNumber++) { // if the adjacent vertex is part of the subgraph, // add edge, if it does not exist yet, else do nothing VertexDescriptorType adjacentVertex = adjacentNodexVector[ adjacentNodeNumber ]; if( graphToSubgraphVertexMap->count( adjacentVertex ) > 0 ) { if( !subNetwork->EdgeExists( iter->second, graphToSubgraphVertexMap->find( adjacentVertex )->second ) ) { //edge exists in parent network, but not yet in sub network const VertexDescriptorType vertexA = iter->second; const VertexDescriptorType vertexB = graphToSubgraphVertexMap->find( adjacentVertex )->second; const int sourceID = network->GetNode( vertexA ).id; const int targetID = network->GetNode( vertexB ).id; - const int weight = network->GetEdge( iter->first, graphToSubgraphVertexMap->find( adjacentVertex )->first ).weight; - subNetwork->AddEdge( vertexA , vertexB, sourceID, targetID, weight ); + const double fiber_count = network->GetEdge( iter->first, graphToSubgraphVertexMap->find( adjacentVertex )->first ).fiber_count; + subNetwork->AddEdge( vertexA , vertexB, sourceID, targetID, fiber_count ); } } } iter++; }// end while( iter != end ) } int mitk::ConnectomicsSimulatedAnnealingPermutationModularity::getNumberOfModules( ToModuleMapType *vertexToModuleMap ) const { int maxModule( 0 ); auto iter = vertexToModuleMap->begin(); auto end = vertexToModuleMap->end(); while( iter != end ) { if( iter->second > maxModule ) { maxModule = iter->second; } iter++; } return maxModule + 1; } int mitk::ConnectomicsSimulatedAnnealingPermutationModularity::getNumberOfVerticesInModule( ToModuleMapType *vertexToModuleMap, int module ) const { int number( 0 ); auto iter = vertexToModuleMap->begin(); auto end = vertexToModuleMap->end(); while( iter != end ) { if( iter->second == module ) { number++; } iter++; } return number; } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::removeModule( ToModuleMapType *vertexToModuleMap, int module ) { int lastModuleNumber = getNumberOfModules( vertexToModuleMap ) - 1; if( module == lastModuleNumber ) { // no need to do anything, the last module is deleted "automatically" return; } if( getNumberOfVerticesInModule( vertexToModuleMap, module ) > 0 ) { MBI_WARN << "Trying to remove non-empty module"; return; } auto iter = vertexToModuleMap->begin(); auto end = vertexToModuleMap->end(); while( iter != end ) { if( iter->second == lastModuleNumber ) { // renumber last module to to-be-deleted module iter->second = module; } iter++; } } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::randomlyAssignNodesToModules( ToModuleMapType *vertexToModuleMap, int numberOfIntendedModules ) { // we make sure that each intended module contains *at least* one node // thus if more modules are asked for than node exists we will only generate // as many modules as there are nodes if( numberOfIntendedModules > 0 && (unsigned int)numberOfIntendedModules > vertexToModuleMap->size() ) { MBI_ERROR << "Tried to generate more modules than vertices were provided"; numberOfIntendedModules = vertexToModuleMap->size(); } //the random number generators vnl_random rng( (unsigned int) rand() ); std::vector< int > histogram; std::vector< int > nodeList; histogram.resize( numberOfIntendedModules, 0 ); nodeList.resize( vertexToModuleMap->size(), 0 ); int numberOfVertices = vertexToModuleMap->size(); //randomly distribute nodes to modules for( unsigned int nodeIndex( 0 ); nodeIndex < nodeList.size(); nodeIndex++ ) { //select random module nodeList[ nodeIndex ] = rng.lrand32( numberOfIntendedModules - 1 ); histogram[ nodeList[ nodeIndex ] ]++; } // make sure no module contains no node, if one does assign it one of a random module // that does contain at least two for( unsigned int moduleIndex( 0 ); moduleIndex < histogram.size(); moduleIndex++ ) { while( histogram[ moduleIndex ] == 0 ) { int randomNodeIndex = rng.lrand32( numberOfVertices - 1 ); if( histogram[ nodeList[ randomNodeIndex ] ] > 1 ) { histogram[ moduleIndex ]++; histogram[ nodeList[ randomNodeIndex ] ]--; nodeList[ randomNodeIndex ] = moduleIndex; } } } auto iter = vertexToModuleMap->begin(); auto end = vertexToModuleMap->end(); for( unsigned int index( 0 ); ( iter != end ) && ( index < nodeList.size() ); index++, iter++ ) { iter->second = nodeList[ index ] ; } } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::SetMapping( ToModuleMapType mapping ) { m_BestSolution = mapping; } mitk::ConnectomicsSimulatedAnnealingPermutationModularity::ToModuleMapType mitk::ConnectomicsSimulatedAnnealingPermutationModularity::GetMapping() { return m_BestSolution; } double mitk::ConnectomicsSimulatedAnnealingPermutationModularity::Evaluate( ToModuleMapType* mapping ) const { mitk::ConnectomicsSimulatedAnnealingCostFunctionModularity* costMapping = dynamic_cast( m_CostFunction.GetPointer() ); if( costMapping ) { return costMapping->Evaluate( m_Network, mapping ); } else { return 0; } } bool mitk::ConnectomicsSimulatedAnnealingPermutationModularity::AcceptChange( double costBefore, double costAfter, double temperature ) const { if( costAfter <= costBefore ) {// if cost is lower after return true; } //the random number generators vnl_random rng( (unsigned int) rand() ); //randomly generate threshold const double threshold = rng.drand64( 0.0 , 1.0); //the likelihood of acceptance double likelihood = std::exp( - ( costAfter - costBefore ) / temperature ); if( threshold < likelihood ) { return true; } return false; } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::SetDepth( int depth ) { m_Depth = depth; } void mitk::ConnectomicsSimulatedAnnealingPermutationModularity::SetStepSize( double size ) { m_StepSize = size; } diff --git a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkCorrelationCalculator.txx b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkCorrelationCalculator.txx index f57bd01220..f5f6044a0d 100644 --- a/Modules/DiffusionImaging/Connectomics/Algorithms/mitkCorrelationCalculator.txx +++ b/Modules/DiffusionImaging/Connectomics/Algorithms/mitkCorrelationCalculator.txx @@ -1,454 +1,454 @@ /*=================================================================== 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_CORRELATIONCALCULATOR_TXX #define _MITK_CORRELATIONCALCULATOR_TXX #include #include #include #include #include #include #include #include template< class T > mitk::CorrelationCalculator::CorrelationCalculator() : m_InvalidTimeSeries( true ) , m_ParcellationImage( nullptr ) , m_TimeSeriesImage( nullptr ) { } template< class T > mitk::CorrelationCalculator::~CorrelationCalculator() { } template< class T > double mitk::CorrelationCalculator::CalculatePearsonCorrelationCoefficient( const std::vector& one, const std::vector& two ) { double standardDevOne( std::sqrt(CalculateCovariance( one, one )) ); double standardDevTwo( std::sqrt(CalculateCovariance( two, two )) ); return CalculateCovariance(one, two) / (standardDevOne * standardDevTwo); } template< class T > double mitk::CorrelationCalculator::CalculateCovariance( const std::vector& one, const std::vector& two ) { if( one.size() != two.size() ) { MITK_WARN << "Expect two same length vectors for covariance."; return 0; } double meanOne( std::accumulate( one.begin(), one.end(), 0.0 ) / double(one.size()) ); double meanTwo( std::accumulate( two.begin(), two.end(), 0.0 ) / double(two.size()) ); double sum( 0.0 ); for(unsigned int index(0); index < one.size(); ++index) { sum += (one[index] - meanOne ) * (two[index] - meanTwo); } double n( one.size() ); return sum/n; } template< class T > std::vector< double > mitk::CorrelationCalculator::ExtractAverageTimeSeriesOfParcel( int parcelValue ) { if( this->m_InvalidTimeSeries) { this->ExtractAllAverageTimeSeries(); this->m_InvalidTimeSeries = false; } std::vector< double > result; if( m_AverageTimeSeries.count(parcelValue) > 0 ) { result = m_AverageTimeSeries.find(parcelValue)->second; } return result; } template< class T > void mitk::CorrelationCalculator::DoWholeCorrelation( ) { if(this->m_TimeSeriesImage->GetDimension() != 4 ) { MITK_ERROR << "Expect 3D+t timeseries image."; return; } // calculate numbe of voxels unsigned int numberOfVoxels(1); unsigned int dim[3]; for(unsigned int loop(0); loop < 3; ++loop) { numberOfVoxels *= this->m_TimeSeriesImage->GetDimension( loop ); dim[loop] = this->m_TimeSeriesImage->GetDimension( loop ); } m_CorrelationMatrix = vnl_matrix(numberOfVoxels, numberOfVoxels); unsigned int numberOfSteps( this->m_TimeSeriesImage->GetDimension( 3 )); //iterate over all voxels and calculate correlation for( unsigned int i( 0 ); i < numberOfVoxels; ++i ) { for( unsigned int j(0); j < i; ++j) { std::vector< T > one, two; one.resize(numberOfSteps); two.resize(numberOfSteps); mitk::ImagePixelReadAccessor readAccess(m_TimeSeriesImage); itk::Index<4> idx_i; itk::Index<4> idx_j; idx_i[2] = (i / (dim[0] * dim[1])) % dim[2]; idx_i[1] = (i / dim[0]) % dim[1]; idx_i[0] = i % dim[0]; idx_j[2] = (j / (dim[0] * dim[1])) % dim[2]; idx_j[1] = (j / dim[0]) % dim[1]; idx_j[0] = j % dim[0]; for(unsigned int timestep(0); timestep < numberOfSteps; ++timestep) { idx_i[3] = timestep; idx_j[3] = timestep; one[timestep] = readAccess.GetPixelByIndex(idx_i); two[timestep] = readAccess.GetPixelByIndex(idx_j); } m_CorrelationMatrix[i][j] = mitk::CorrelationCalculator::CalculatePearsonCorrelationCoefficient( one, two ); m_CorrelationMatrix[j][i] = m_CorrelationMatrix[i][j]; } m_CorrelationMatrix[i][i] = 1; } } template< class T > void mitk::CorrelationCalculator::DoParcelCorrelation( typename mitk::CorrelationCalculator::ParcelMode mode ) { this->ExtractCenterOfMassForParcels(); m_CorrelationMatrix = vnl_matrix(m_ParcelCenterOfMass.size(), m_ParcelCenterOfMass.size()); AccessFixedDimensionByItk(this->m_TimeSeriesImage, ExtractAllAverageTimeSeries, 4); // fill matrix unsigned int i(0); for( std::map< int, std::vector >::const_iterator it(m_AverageTimeSeries.begin()); it != m_AverageTimeSeries.end(); ++it, ++i) { unsigned int j(0); for(std::map< int, std::vector >::const_iterator inner_it(m_AverageTimeSeries.begin()); inner_it != it; ++inner_it, ++j) { switch( mode ) { case UseAverageTimeSeries : m_CorrelationMatrix[i][j] = mitk::CorrelationCalculator::CalculatePearsonCorrelationCoefficient( it->second, inner_it->second ); break; case UseMaximumCorrelation : m_CorrelationMatrix[i][j] = mitk::CorrelationCalculator::GetParcelCorrelation(it->first, inner_it->first, mode); break; case UseAverageCorrelation : m_CorrelationMatrix[i][j] = mitk::CorrelationCalculator::GetParcelCorrelation(it->first, inner_it->first, mode); break; default: mitkThrow() << "No valid parcel correlation mode selected"; } m_CorrelationMatrix[j][i] = m_CorrelationMatrix[i][j]; } m_CorrelationMatrix[i][i] = 1; m_LabelOrderMap.insert(std::pair< unsigned int, int >(i, it->first)); } } template< class T > double mitk::CorrelationCalculator::GetParcelCorrelation(const int& parcelA, const int& parcelB, typename mitk::CorrelationCalculator::ParcelMode& mode) const { double result(0.0); if(m_ParcelTimeSeries.count(parcelA) < 1 || m_ParcelTimeSeries.count(parcelB) < 1) { MITK_ERROR << "Tried to calculate correlation between at least one non-existent parcel " << parcelA << " and " << parcelB; return result; } std::vector< std::vector< T > > parcelATimeSeriesVector = m_ParcelTimeSeries.find( parcelA )->second; std::vector< std::vector< T > > parcelBTimeSeriesVector = m_ParcelTimeSeries.find( parcelB )->second; switch( mode ) { case UseAverageTimeSeries : { mitkThrow() << "Wrong function called for this mode."; break; } case UseMaximumCorrelation : { for(unsigned int i(0); i < parcelATimeSeriesVector.size(); ++i) { for(unsigned int j(0); j < parcelBTimeSeriesVector.size(); ++j) { double corr = mitk::CorrelationCalculator::CalculatePearsonCorrelationCoefficient( parcelATimeSeriesVector[i], parcelBTimeSeriesVector[j] ); if( corr > result ) { result = corr; } } } break; } case UseAverageCorrelation : { double corr(0.0); for(unsigned int i(0); i < parcelATimeSeriesVector.size(); ++i) { for(unsigned int j(0); j < parcelBTimeSeriesVector.size(); ++j) { corr += mitk::CorrelationCalculator::CalculatePearsonCorrelationCoefficient( parcelATimeSeriesVector[i], parcelBTimeSeriesVector[j] ); } } result = corr / double( parcelATimeSeriesVector.size() * parcelBTimeSeriesVector.size() ); break; } default: { mitkThrow() << "No valid parcel correlation mode selected"; } } return result; } template< class T > void mitk::CorrelationCalculator::Modified( ) const { Superclass::Modified(); } template< class T > void mitk::CorrelationCalculator::Modified( ) { Superclass::Modified(); this->m_InvalidTimeSeries = true; } template< class T> template< typename TPixel, unsigned int VImageDimension > void mitk::CorrelationCalculator::ExtractAllAverageTimeSeries( itk::Image* itkTimeSeriesImage ) { // storage contains for each parcel value a vector of length time steps, // which manages the pixel value vectors for each time step std::map< int, std::vector< std::vector< T > > > storage; itk::ImageRegionConstIteratorWithIndex< itk::Image > it_itkTimeSeriesImage( itkTimeSeriesImage, itkTimeSeriesImage->GetLargestPossibleRegion() ); unsigned int timesteps( itkTimeSeriesImage->GetLargestPossibleRegion().GetSize()[3] ); for( it_itkTimeSeriesImage.GoToBegin(); !it_itkTimeSeriesImage.IsAtEnd(); ++it_itkTimeSeriesImage ) { itk::Index< 4 > itkIndex = it_itkTimeSeriesImage.GetIndex(); itk::Index< 3 > itkIndex3D; for(unsigned int axis( 0 ); axis < 3; ++axis ) { itkIndex3D.SetElement( axis, itkIndex.GetElement(axis) ); } mitk::Point3D tempPoint; m_TimeSeriesImage->GetGeometry()->IndexToWorld( itkIndex3D, tempPoint ); mitk::ImagePixelReadAccessor readAccess(m_ParcellationImage); int value( std::floor( readAccess.GetPixelByWorldCoordinates( tempPoint ) + 0.5 ) ); if(storage.count(value) == 0) { std::vector< std::vector< T > > temp; temp.resize( timesteps ); storage.insert(std::pair< int, std::vector< std::vector< T > > >(value, temp)); } storage[value][ itkIndex.GetElement( 3 ) ].push_back( it_itkTimeSeriesImage.Value() ); } // store means for( typename std::map< int, std::vector< std::vector< T > > >::iterator it = storage.begin(); it != storage.end(); ++it ) { std::vector< double > means; means.resize( timesteps ); for(unsigned int loop(0); loop < timesteps; ++loop) { means[loop] = std::accumulate( it->second[loop].begin(), it->second[loop].end(), 0.0 ) / double(it->second[loop].size()); } m_AverageTimeSeries.insert( std::pair< int, std::vector< double > >(it->first, means) ); // reorder the information in storage for m_ParcelTimeSeries // time series of each voxel by their parcellation value std::vector< std::vector< T > > vectorOfTimeSeriesVectors; vectorOfTimeSeriesVectors.resize(it->second[0].size()); for(unsigned int loop(0); loop < vectorOfTimeSeriesVectors.size(); ++loop) { vectorOfTimeSeriesVectors[loop].resize(timesteps); } for(unsigned int step(0); step < timesteps; ++step) { for(unsigned int number(0); number < vectorOfTimeSeriesVectors.size(); ++number) { vectorOfTimeSeriesVectors[number][step] = it->second[step][number]; } } m_ParcelTimeSeries.insert(std::pair< int, std::vector< std::vector< T > > >(it->first, vectorOfTimeSeriesVectors)); } } template< class T > void mitk::CorrelationCalculator::ExtractCenterOfMassForParcels() { itk::Image< int, 3 >::Pointer itkParcelImage; mitk::CastToItkImage( m_ParcellationImage, itkParcelImage ); itk::ImageRegionConstIteratorWithIndex< itk::Image > it_itkParcelImage( itkParcelImage, itkParcelImage->GetLargestPossibleRegion() ); std::map< int, std::vector< mitk::Point3D > > storage; for( it_itkParcelImage.GoToBegin(); !it_itkParcelImage.IsAtEnd(); ++it_itkParcelImage ) { mitk::Point3D tempPoint; m_ParcellationImage->GetGeometry()->IndexToWorld( it_itkParcelImage.GetIndex(), tempPoint ); if( storage.count( it_itkParcelImage.Value() ) == 1 ) { storage[ it_itkParcelImage.Value() ].push_back( tempPoint ); } else { storage.insert( std::pair< int, std::vector< mitk::Point3D > >( it_itkParcelImage.Value(), std::vector< mitk::Point3D >( 1, tempPoint ) )); } } for( std::map< int, std::vector< mitk::Point3D > >::iterator it( storage.begin() ); it != storage.end(); ++it ) { itk::Vector< int, 3 > tempVector( 0 ); for( unsigned int loop(0); loop < it->second.size(); ++loop) { for(unsigned int index(0); index < 3; ++index) { tempVector[index] = tempVector[index] + it->second[loop][index]; } } mitk::Point3D tempPoint; for( unsigned int loop(0); loop < 3; ++loop ) { tempPoint.SetElement(loop, tempVector.GetElement(loop) / it->second.size()); } m_ParcelCenterOfMass.insert( std::pair< int, mitk::Point3D >(it->first, tempPoint) ); } } template< class T > const vnl_matrix< double >* mitk::CorrelationCalculator::GetCorrelationMatrix() const { return &m_CorrelationMatrix; } template< class T > const std::map< unsigned int, int >* mitk::CorrelationCalculator::GetLabelOrderMap() const { return &m_LabelOrderMap; } template< class T > mitk::ConnectomicsNetwork::Pointer mitk::CorrelationCalculator::GetConnectomicsNetwork() { mitk::ConnectomicsNetwork::NetworkType* boostGraph = new mitk::ConnectomicsNetwork::NetworkType; std::map< int, mitk::ConnectomicsNetwork::VertexDescriptorType > idToVertexMap; // fill nodes unsigned int numberOfNodes( m_CorrelationMatrix.columns() ); for(unsigned int loop(0); loop < numberOfNodes; ++loop ) { idToVertexMap.insert( std::pair< int, mitk::ConnectomicsNetwork::VertexDescriptorType >(loop, boost::add_vertex( *boostGraph )) ); } if( m_ParcelCenterOfMass.size() > 0) { std::map< int, mitk::Point3D >::const_iterator it = m_ParcelCenterOfMass.begin(); for(unsigned int loop(0); (loop < numberOfNodes) && (it != m_ParcelCenterOfMass.end()); ++loop, ++it ) { (*boostGraph)[ idToVertexMap[loop] ].id = idToVertexMap[loop]; (*boostGraph)[ idToVertexMap[loop] ].label = std::to_string( it->first ); (*boostGraph)[ idToVertexMap[loop] ].coordinates.resize(3); for(unsigned int dimension(0); dimension < 3; ++dimension) { (*boostGraph)[ idToVertexMap[loop] ].coordinates[dimension] = it->second[dimension]; } } } //fill edges for( unsigned int i(0); i < numberOfNodes; ++i) { for(unsigned int j(0); j < i; ++j) { mitk::ConnectomicsNetwork::VertexDescriptorType vertexA = idToVertexMap[i]; mitk::ConnectomicsNetwork::VertexDescriptorType vertexB = idToVertexMap[j]; boost::add_edge( vertexA, vertexB, *boostGraph ); (*boostGraph)[ boost::edge(vertexA, vertexB, *boostGraph ).first ].sourceId = (*boostGraph)[vertexA].id; (*boostGraph)[ boost::edge(vertexA, vertexB, *boostGraph ).first ].targetId = (*boostGraph)[vertexB].id; - (*boostGraph)[ boost::edge(vertexA, vertexB, *boostGraph ).first ].weight = 1; + (*boostGraph)[ boost::edge(vertexA, vertexB, *boostGraph ).first ].fiber_count = 1; (*boostGraph)[ boost::edge(vertexA, vertexB, *boostGraph ).first ].edge_weight = m_CorrelationMatrix[i][j]; } } // create data node mitk::ConnectomicsNetwork::Pointer network = mitk::ConnectomicsNetwork::New(); network->SetBoostGraph( boostGraph ); network->SetGeometry( dynamic_cast(m_TimeSeriesImage->GetGeometry()->Clone().GetPointer()) ); network->UpdateBounds(); network->SetIsModified( true ); return network; } #endif /* _MITK_CORRELATIONCALCULATOR_TXX */ diff --git a/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetwork.cpp b/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetwork.cpp index 9fa38b48fe..75ab9332cf 100644 --- a/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetwork.cpp +++ b/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetwork.cpp @@ -1,784 +1,782 @@ /*=================================================================== 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 "mitkConnectomicsNetwork.h" #include #include #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4172) #endif #include #ifdef _MSC_VER # pragma warning(pop) #endif /* Constructor and Destructor */ mitk::ConnectomicsNetwork::ConnectomicsNetwork() : m_IsModified( false ) { } mitk::ConnectomicsNetwork::~ConnectomicsNetwork() { } /* Wrapper methods */ bool mitk::ConnectomicsNetwork::EdgeExists( mitk::ConnectomicsNetwork::VertexDescriptorType vertexA, mitk::ConnectomicsNetwork::VertexDescriptorType vertexB ) const { return boost::edge(vertexA, vertexB, m_Network ).second; } -void mitk::ConnectomicsNetwork::IncreaseEdgeWeight( - mitk::ConnectomicsNetwork::VertexDescriptorType vertexA, mitk::ConnectomicsNetwork::VertexDescriptorType vertexB ) +void mitk::ConnectomicsNetwork::IncreaseEdgeWeight(mitk::ConnectomicsNetwork::VertexDescriptorType vertexA, mitk::ConnectomicsNetwork::VertexDescriptorType vertexB , double fiber_count) { - m_Network[ boost::edge(vertexA, vertexB, m_Network ).first ].weight++; + m_Network[ boost::edge(vertexA, vertexB, m_Network ).first ].fiber_count += fiber_count; SetIsModified( true ); } -void mitk::ConnectomicsNetwork::AddEdge( - mitk::ConnectomicsNetwork::VertexDescriptorType vertexA, +void mitk::ConnectomicsNetwork::AddEdge(mitk::ConnectomicsNetwork::VertexDescriptorType vertexA, mitk::ConnectomicsNetwork::VertexDescriptorType vertexB - ) + , double fiber_count) { - AddEdge(vertexA, vertexB, m_Network[ vertexA ].id, m_Network[ vertexB ].id ); + AddEdge(vertexA, vertexB, m_Network[ vertexA ].id, m_Network[ vertexB ].id, fiber_count ); } void mitk::ConnectomicsNetwork::AddEdge( mitk::ConnectomicsNetwork::VertexDescriptorType vertexA, mitk::ConnectomicsNetwork::VertexDescriptorType vertexB, - int sourceID, int targetID, int weight, double edge_weight ) + int sourceID, int targetID, double fiber_count, double edge_weight ) { boost::add_edge( vertexA, vertexB, m_Network ); m_Network[ boost::edge(vertexA, vertexB, m_Network ).first ].sourceId = sourceID; m_Network[ boost::edge(vertexA, vertexB, m_Network ).first ].targetId = targetID; - m_Network[ boost::edge(vertexA, vertexB, m_Network ).first ].weight = weight; + m_Network[ boost::edge(vertexA, vertexB, m_Network ).first ].fiber_count = fiber_count; m_Network[ boost::edge(vertexA, vertexB, m_Network ).first ].edge_weight = edge_weight; SetIsModified( true ); } mitk::ConnectomicsNetwork::VertexDescriptorType mitk::ConnectomicsNetwork::AddVertex( int id ) { VertexDescriptorType vertex = boost::add_vertex( m_Network ); m_Network[vertex].id = id; SetIsModified( true ); return vertex; } void mitk::ConnectomicsNetwork::SetLabel( mitk::ConnectomicsNetwork::VertexDescriptorType vertex, std::string inLabel ) { m_Network[vertex].label = inLabel; SetIsModified( true ); } void mitk::ConnectomicsNetwork::SetCoordinates( mitk::ConnectomicsNetwork::VertexDescriptorType vertex, std::vector< float > inCoordinates ) { m_Network[vertex].coordinates = inCoordinates; SetIsModified( true ); } void mitk::ConnectomicsNetwork::clear() { m_Network.clear(); SetIsModified( true ); } /* Superclass methods, that need to be implemented */ void mitk::ConnectomicsNetwork::UpdateOutputInformation() { } void mitk::ConnectomicsNetwork::SetRequestedRegionToLargestPossibleRegion() { } bool mitk::ConnectomicsNetwork::RequestedRegionIsOutsideOfTheBufferedRegion() { return false; } bool mitk::ConnectomicsNetwork::VerifyRequestedRegion() { return true; } void mitk::ConnectomicsNetwork::SetRequestedRegion(const itk::DataObject * /*data*/ ) { } std::vector< mitk::ConnectomicsNetwork::NetworkNode > mitk::ConnectomicsNetwork::GetVectorOfAllNodes() const { boost::graph_traits::vertex_iterator iterator, end; // sets iterator to start end end to end boost::tie(iterator, end) = boost::vertices( m_Network ); std::vector< NetworkNode > vectorOfNodes; for ( ; iterator != end; ++iterator) { NetworkNode tempNode; // the value of an iterator is a descriptor tempNode = m_Network[ *iterator ]; vectorOfNodes.push_back( tempNode ); } return vectorOfNodes; } std::vector< mitk::ConnectomicsNetwork::VertexDescriptorType > mitk::ConnectomicsNetwork::GetVectorOfAllVertexDescriptors() const { boost::graph_traits::vertex_iterator iterator, end; // sets iterator to start end end to end boost::tie(iterator, end) = boost::vertices( m_Network ); std::vector< VertexDescriptorType > vectorOfDescriptors; for ( ; iterator != end; ++iterator) { vectorOfDescriptors.push_back( *iterator ); } return vectorOfDescriptors; } std::vector< std::pair< std::pair< mitk::ConnectomicsNetwork::NetworkNode, mitk::ConnectomicsNetwork::NetworkNode > , mitk::ConnectomicsNetwork::NetworkEdge > > mitk::ConnectomicsNetwork::GetVectorOfAllEdges() const { boost::graph_traits::edge_iterator iterator, end; // sets iterator to start end end to end boost::tie(iterator, end) = boost::edges( m_Network ); std::vector< std::pair< std::pair< NetworkNode, NetworkNode > , NetworkEdge > > vectorOfEdges; for ( ; iterator != end; ++iterator) { NetworkNode sourceNode, targetNode; NetworkEdge tempEdge; // the value of an iterator is a descriptor tempEdge = m_Network[ *iterator ]; sourceNode = m_Network[ boost::source( *iterator, m_Network ) ]; targetNode = m_Network[ boost::target( *iterator, m_Network ) ]; std::pair< NetworkNode, NetworkNode > nodePair( sourceNode, targetNode ); std::pair< std::pair< NetworkNode, NetworkNode > , NetworkEdge > edgePair( nodePair, tempEdge); vectorOfEdges.push_back( edgePair ); } return vectorOfEdges; } int mitk::ConnectomicsNetwork::GetNumberOfVertices() const { return boost::num_vertices( m_Network ); } int mitk::ConnectomicsNetwork::GetNumberOfEdges() const { return boost::num_edges( m_Network ); } -int mitk::ConnectomicsNetwork::GetMaximumWeight() const +double mitk::ConnectomicsNetwork::GetMaximumWeight() const { int maxWeight( 0 ); boost::graph_traits::edge_iterator iterator, end; // sets iterator to start end end to end boost::tie(iterator, end) = boost::edges( m_Network ); for ( ; iterator != end; ++iterator) { int tempWeight; // the value of an iterator is a descriptor - tempWeight = m_Network[ *iterator ].weight; + tempWeight = m_Network[ *iterator ].fiber_count; if( tempWeight > maxWeight ) { maxWeight = tempWeight; } } return maxWeight; } int mitk::ConnectomicsNetwork::GetNumberOfSelfLoops() { int noOfSelfLoops( 0 ); std::vector< std::pair< std::pair< NetworkNode, NetworkNode > , NetworkEdge > > edgeVector = GetVectorOfAllEdges(); for( unsigned int index = 0; index < edgeVector.size() ; index++ ) { double sourceX, sourceY, sourceZ, targetX, targetY, targetZ; sourceX = edgeVector[ index ].first.first.coordinates[0] ; sourceY = edgeVector[ index ].first.first.coordinates[1] ; sourceZ = edgeVector[ index ].first.first.coordinates[2] ; targetX = edgeVector[ index ].first.second.coordinates[0] ; targetY = edgeVector[ index ].first.second.coordinates[1] ; targetZ = edgeVector[ index ].first.second.coordinates[2] ; // if the coordinates are the same if( sourceX > ( targetX - 0.01 ) && sourceX < ( targetX + 0.01 ) && sourceY > ( targetY - 0.01 ) && sourceY < ( targetY + 0.01 ) && sourceZ > ( targetZ - 0.01 ) && sourceZ < ( targetZ + 0.01 ) ) { noOfSelfLoops++; } } return noOfSelfLoops; } double mitk::ConnectomicsNetwork::GetAverageDegree() { double vertices = (double) GetNumberOfVertices(); double edges = (double) GetNumberOfEdges(); return ( ( edges * 2.0 ) / vertices ); } double mitk::ConnectomicsNetwork::GetConnectionDensity() { double vertices = (double) GetNumberOfVertices(); double edges = (double) GetNumberOfEdges(); double numberOfPossibleEdges = vertices * ( vertices - 1 ) / 2 ; return ( edges / numberOfPossibleEdges ); } std::vector< int > mitk::ConnectomicsNetwork::GetDegreeOfNodes( ) const { std::vector< int > vectorOfDegree; boost::graph_traits::vertex_iterator iterator, end; // sets iterator to start end end to end boost::tie( iterator, end ) = boost::vertices( m_Network ); vectorOfDegree.resize( this->GetNumberOfVertices() ); for ( ; iterator != end; ++iterator) { // the value of an iterator is a descriptor vectorOfDegree[ m_Network[ *iterator ].id ] = GetVectorOfAdjacentNodes( *iterator ).size(); } return vectorOfDegree; } std::vector< mitk::ConnectomicsNetwork::VertexDescriptorType > mitk::ConnectomicsNetwork::GetVectorOfAdjacentNodes( mitk::ConnectomicsNetwork::VertexDescriptorType vertex ) const { std::vector< mitk::ConnectomicsNetwork::VertexDescriptorType > vectorOfAdjacentNodes; boost::graph_traits::adjacency_iterator adjIter, adjEnd; boost::tie( adjIter, adjEnd ) = boost::adjacent_vertices( vertex, m_Network); for ( ; adjIter != adjEnd; ++adjIter) { vectorOfAdjacentNodes.push_back( *adjIter ); } return vectorOfAdjacentNodes; } int mitk::ConnectomicsNetwork::GetMaximumDegree() const { int maximumDegree( 0 ); std::vector< int > vectorOfDegree = GetDegreeOfNodes(); for( unsigned int index( 0 ); index < vectorOfDegree.size(); ++index ) { if( maximumDegree < vectorOfDegree[ index ] ) { maximumDegree = vectorOfDegree[ index ]; } } return maximumDegree; } std::vector< double > mitk::ConnectomicsNetwork::GetLocalClusteringCoefficients( ) const { std::vector< double > vectorOfClusteringCoefficients; typedef boost::graph_traits::vertex_iterator vertexIter; vectorOfClusteringCoefficients.resize( this->GetNumberOfVertices() ); std::pair vertexPair; //for every vertex calculate the clustering coefficient int size = vectorOfClusteringCoefficients.size(); for (vertexPair = vertices(m_Network); vertexPair.first != vertexPair.second; ++vertexPair.first) { int index = m_Network[ *vertexPair.first ].id; if( index > size ) { MITK_ERROR << "Trying to access out of bounds clustering coefficient"; continue; } vectorOfClusteringCoefficients[ index ] = boost::clustering_coefficient(m_Network,*vertexPair.first) ; } return vectorOfClusteringCoefficients; } std::vector< double > mitk::ConnectomicsNetwork::GetClusteringCoefficientsByDegree( ) { std::vector< double > vectorOfClusteringCoefficients = GetLocalClusteringCoefficients(); std::vector< int > vectorOfDegree = GetDegreeOfNodes(); std::vector< double > vectorOfClusteringCoefficientsByDegree; vectorOfClusteringCoefficientsByDegree.resize( GetMaximumDegree() + 1, 0 ); // c_{mean}(k) = frac{1}_{N_{k}} sum_{i in Y(k)} c_{i} // where N_{k} is the number of vertices of degree k // Y(k) is the set of vertices of degree k // c_{i} is the local clustering coefficient of vertex i for( unsigned int degree( 0 ); degree < vectorOfClusteringCoefficientsByDegree.size(); ++degree ) { vectorOfClusteringCoefficientsByDegree[ degree ] = 0; int n_k( 0 ); for( unsigned int index( 0 ); index < vectorOfDegree.size(); ++index ) { if( degree == (unsigned int)vectorOfDegree[ index ] ) {// if in Y( degree ) vectorOfClusteringCoefficientsByDegree[ degree ] += vectorOfClusteringCoefficients[ index ]; n_k++; } } if( n_k != 0 ) { vectorOfClusteringCoefficientsByDegree[ degree ] = vectorOfClusteringCoefficientsByDegree[ degree ] / n_k; } } return vectorOfClusteringCoefficientsByDegree; } double mitk::ConnectomicsNetwork::GetGlobalClusteringCoefficient( ) { double globalClusteringCoefficient( 0.0 ); std::vector< double > vectorOfClusteringCoefficientsByDegree = GetClusteringCoefficientsByDegree(); std::vector< int > vectorOfDegree = GetDegreeOfNodes(); std::vector< int > degreeDistribution; degreeDistribution.resize( vectorOfClusteringCoefficientsByDegree.size(), 0 ); int normalizationParameter( 0 ); for( unsigned int index( 0 ); index < vectorOfDegree.size(); ++index ) { degreeDistribution[ vectorOfDegree[ index ] ]++; normalizationParameter++; } // c_{mean} = sum_{k} P_{k} c_{mean}(k) // where P_{k} is the degree distribution // k is the degree for( unsigned int degree( 0 ); degree < degreeDistribution.size(); ++degree ) { globalClusteringCoefficient += degreeDistribution[ degree ] / ( (double) normalizationParameter) * vectorOfClusteringCoefficientsByDegree[ degree ]; } return globalClusteringCoefficient; } mitk::ConnectomicsNetwork::NetworkType* mitk::ConnectomicsNetwork::GetBoostGraph() { return &m_Network; } void mitk::ConnectomicsNetwork::SetBoostGraph( NetworkType* newGraph ) { this->clear(); m_Network = *newGraph; this->SetIsModified( true ); } void mitk::ConnectomicsNetwork::ImportNetwort( mitk::ConnectomicsNetwork::Pointer source ) { typedef std::vector< std::pair< std::pair< NetworkNode, NetworkNode >, NetworkEdge > > EdgeVectorType; typedef std::vector< NetworkNode > VertexVectorType; this->clear(); this->SetGeometry( source->GetGeometry()); VertexVectorType vertexVector = source->GetVectorOfAllNodes(); EdgeVectorType edgeVector = source->GetVectorOfAllEdges(); std::map< int, VertexDescriptorType > idToVertexMap; for( unsigned int loop(0); loop < vertexVector.size(); loop++ ) { VertexDescriptorType newVertex = this->AddVertex( vertexVector[ loop ].id ); this->SetLabel( newVertex, vertexVector[ loop ].label ); this->SetCoordinates( newVertex, vertexVector[ loop ].coordinates ); if ( idToVertexMap.count( vertexVector[ loop ].id ) > 0 ) { MITK_ERROR << "Aborting network import, duplicate vertex ID discovered."; return; } idToVertexMap.insert( std::pair< int, VertexDescriptorType >( vertexVector[ loop ].id, newVertex) ); } for( unsigned int loop(0); loop < edgeVector.size(); loop++ ) { VertexDescriptorType source = idToVertexMap.find( edgeVector[ loop ].second.sourceId )->second; VertexDescriptorType target = idToVertexMap.find( edgeVector[ loop ].second.targetId )->second; - this->AddEdge( source, target, edgeVector[ loop ].second.sourceId, edgeVector[ loop ].second.targetId, edgeVector[ loop ].second.weight); + this->AddEdge( source, target, edgeVector[ loop ].second.sourceId, edgeVector[ loop ].second.targetId, edgeVector[ loop ].second.fiber_count); } this->SetIsModified( true ); } bool mitk::ConnectomicsNetwork::GetIsModified() const { return m_IsModified; } void mitk::ConnectomicsNetwork::SetIsModified( bool value) { m_IsModified = value; } mitk::ConnectomicsNetwork::NetworkNode mitk::ConnectomicsNetwork::GetNode( VertexDescriptorType vertex ) const { return m_Network[ vertex ]; } mitk::ConnectomicsNetwork::NetworkEdge mitk::ConnectomicsNetwork::GetEdge( VertexDescriptorType vertexA, VertexDescriptorType vertexB ) const { if( EdgeExists(vertexA, vertexB) ) { return m_Network[ boost::edge(vertexA, vertexB, m_Network ).first ]; } else { mitkThrow() << "Edge does not exist"; } } void mitk::ConnectomicsNetwork::UpdateBounds( ) { float min = itk::NumericTraits::min(); float max = itk::NumericTraits::max(); float bounds[] = {max, min, max, min, max, min}; std::vector< mitk::ConnectomicsNetwork::NetworkNode > nodeVector = this->GetVectorOfAllNodes(); if( nodeVector.size() == 0 ) { bounds[0] = 0; bounds[1] = 1; bounds[2] = 0; bounds[3] = 1; bounds[4] = 0; bounds[5] = 1; } // for each direction, make certain the point is in between for(auto & elem : nodeVector) { for( unsigned int direction(0); direction < elem.coordinates.size(); direction++ ) { if( elem.coordinates.at(direction) < bounds[ 2 * direction ] ) { bounds[ 2 * direction ] = elem.coordinates.at(direction); } if( elem.coordinates.at(direction) > bounds[ 2 * direction + 1] ) { bounds[ 2 * direction + 1] = elem.coordinates.at(direction); } } } // provide some border margin for(int i=0; i<=4; i+=2) { bounds[i] -=10; } for(int i=1; i<=5; i+=2) { bounds[i] +=10; } this->GetGeometry()->SetFloatBounds(bounds); this->GetTimeGeometry()->Update(); } void mitk::ConnectomicsNetwork::PruneUnconnectedSingleNodes() { boost::graph_traits::vertex_iterator iterator, end; // set to true if iterators are invalidated by deleting a vertex bool vertexHasBeenRemoved( true ); // if no vertex has been removed in the last loop, we are done while( vertexHasBeenRemoved ) { vertexHasBeenRemoved = false; // sets iterator to start and end to end boost::tie(iterator, end) = boost::vertices( m_Network ); for ( ; iterator != end && !vertexHasBeenRemoved; ++iterator) { // If the node has no adjacent vertices it should be deleted if( GetVectorOfAdjacentNodes( *iterator ).size() == 0 ) { vertexHasBeenRemoved = true; // this invalidates all iterators boost::remove_vertex( *iterator, m_Network ); } } } UpdateIDs(); } void mitk::ConnectomicsNetwork::UpdateIDs() { boost::graph_traits::vertex_iterator v_i, v_end; boost::graph_traits::edge_iterator e_i, e_end; // update node ids boost::tie( v_i, v_end ) = boost::vertices( m_Network ); for ( ; v_i != v_end; ++v_i) { m_Network[*v_i].id = *v_i; } // update edge information boost::tie(e_i, e_end) = boost::edges( m_Network ); for ( ; e_i != e_end; ++e_i) { m_Network[ *e_i ].sourceId = m_Network[ boost::source( *e_i, m_Network ) ].id; m_Network[ *e_i ].targetId = m_Network[ boost::target( *e_i, m_Network ) ].id; } this->SetIsModified( true ); } std::vector< double > mitk::ConnectomicsNetwork::GetNodeBetweennessVector() const { std::vector< double > betweennessVector; betweennessVector.clear(); betweennessVector.resize( this->GetNumberOfVertices() ); boost::brandes_betweenness_centrality( m_Network, boost::centrality_map( boost::make_iterator_property_map( betweennessVector.begin(), boost::get( &NetworkNode::id, m_Network ), double() ) ).vertex_index_map( boost::get( &NetworkNode::id, m_Network ) ) ); return betweennessVector; } std::vector< double > mitk::ConnectomicsNetwork::GetEdgeBetweennessVector() const { // std::map used for convenient initialization typedef std::map EdgeIndexStdMap; EdgeIndexStdMap stdEdgeIndex; // associative property map needed for iterator property map-wrapper typedef boost::associative_property_map< EdgeIndexStdMap > EdgeIndexMap; EdgeIndexMap edgeIndex(stdEdgeIndex); boost::graph_traits::edge_iterator iterator, end; // sets iterator to start end end to end boost::tie(iterator, end) = boost::edges( m_Network ); int i(0); for ( ; iterator != end; ++iterator, ++i) { stdEdgeIndex.insert(std::pair< EdgeDescriptorType, int >( *iterator, i)); } // Define EdgeCentralityMap std::vector< double > edgeBetweennessVector(boost::num_edges( m_Network ), 0.0); // Create the external property map boost::iterator_property_map< std::vector< double >::iterator, EdgeIndexMap > e_centrality_map(edgeBetweennessVector.begin(), edgeIndex); // Define VertexCentralityMap typedef boost::property_map< NetworkType, boost::vertex_index_t>::type VertexIndexMap; VertexIndexMap vertexIndex = get(boost::vertex_index, m_Network ); std::vector< double > betweennessVector(boost::num_vertices( m_Network ), 0.0); // Create the external property map boost::iterator_property_map< std::vector< double >::iterator, VertexIndexMap > v_centrality_map(betweennessVector.begin(), vertexIndex); boost::brandes_betweenness_centrality( m_Network, v_centrality_map, e_centrality_map ); return edgeBetweennessVector; } std::vector< double > mitk::ConnectomicsNetwork::GetShortestDistanceVectorFromLabel( std::string targetLabel ) const { std::vector< VertexDescriptorType > predecessorMap( boost::num_vertices( m_Network ) ); int numberOfNodes( boost::num_vertices( m_Network ) ); std::vector< double > distanceMatrix; distanceMatrix.resize( numberOfNodes ); boost::graph_traits::vertex_iterator iterator, end; boost::tie(iterator, end) = boost::vertices( m_Network ); while( (iterator != end) && (m_Network[ *iterator ].label != targetLabel) ) { ++iterator; } if( iterator == end ) { MITK_WARN << "Label not found"; return distanceMatrix; } boost::dijkstra_shortest_paths(m_Network, *iterator, boost::predecessor_map(&predecessorMap[ 0 ]).distance_map(&distanceMatrix[ 0 ]).weight_map( boost::get( &NetworkEdge::edge_weight ,m_Network ) ) ) ; return distanceMatrix; } bool mitk::ConnectomicsNetwork::CheckForLabel( std::string targetLabel ) const { boost::graph_traits::vertex_iterator iterator, end; boost::tie(iterator, end) = boost::vertices( m_Network ); while( (iterator != end) && (m_Network[ *iterator ].label != targetLabel) ) { ++iterator; } if( iterator == end ) { return false; } return true; } bool mitk::Equal( mitk::ConnectomicsNetwork* leftHandSide, mitk::ConnectomicsNetwork* rightHandSide, mitk::ScalarType eps, bool verbose ) { bool noDifferenceFound = true; if( rightHandSide == nullptr ) { if(verbose) { MITK_INFO << "[Equal( ConnectomicsNetwork*, ConnectomicsNetwork* )] rightHandSide nullptr."; } return false; } if( leftHandSide == nullptr ) { if(verbose) { MITK_INFO << "[Equal( ConnectomicsNetwork*, ConnectomicsNetwork* )] leftHandSide nullptr."; } return false; } mitk::ConnectomicsStatisticsCalculator::Pointer calculatorLeft = mitk::ConnectomicsStatisticsCalculator::New(); mitk::ConnectomicsStatisticsCalculator::Pointer calculatorRight = mitk::ConnectomicsStatisticsCalculator::New(); calculatorLeft->SetNetwork( leftHandSide ); calculatorRight->SetNetwork( rightHandSide ); calculatorLeft->Update(); calculatorRight->Update(); if( ! mitk::Equal( calculatorLeft->GetNumberOfVertices(), calculatorRight->GetNumberOfVertices(), eps ) ) { if(verbose) MITK_INFO << "[Equal( ConnectomicsNetwork*, ConnectomicsNetwork* )] Number of vertices not equal. " << calculatorLeft->GetNumberOfVertices() << " vs " << calculatorRight->GetNumberOfVertices(); noDifferenceFound = false; } if( ! mitk::Equal( calculatorLeft->GetNumberOfEdges(), calculatorRight->GetNumberOfEdges(), eps ) ) { if(verbose) MITK_INFO << "[Equal( ConnectomicsNetwork*, ConnectomicsNetwork* )] Number of edges not equal. " << calculatorLeft->GetNumberOfEdges() << " vs " << calculatorRight->GetNumberOfEdges(); noDifferenceFound = false; } if( ! mitk::Equal( calculatorLeft->GetSmallWorldness(), calculatorRight->GetSmallWorldness(), eps ) ) { if(verbose) MITK_INFO << "[Equal( ConnectomicsNetwork*, ConnectomicsNetwork* )] Small worldness not equal. " << calculatorLeft->GetSmallWorldness() << " vs " << calculatorRight->GetSmallWorldness(); noDifferenceFound = false; } return noDifferenceFound; -} \ No newline at end of file +} diff --git a/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetwork.h b/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetwork.h index 531da69929..97c2260984 100644 --- a/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetwork.h +++ b/Modules/DiffusionImaging/Connectomics/IODataStructures/mitkConnectomicsNetwork.h @@ -1,238 +1,238 @@ /*=================================================================== 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_ConnectomicsNetwork_H #define _MITK_ConnectomicsNetwork_H #include #include "mitkBaseData.h" #ifndef Q_MOC_RUN #include #endif namespace mitk { /** * \brief Connectomics Network Class * * This class is designed to represent a connectomics network (brain network). It encapsulates a * boost adjacency list and provides additional capabilities. The information contained in the nodes and edges is: * * Network Node: *
    *
  • int ID - The id of the node *
  • string label - The label of the node, this can be any string, such as an anatomical label *
  • vector coordinates - The coordinates the node should be displayed at *
* * Network Edge: *
    *
  • int sourceId - The Id of the source node *
  • int targetId - The Id of the target node *
  • int weight - Weight of the edge as int (used for counting fibers) *
  • double edge_weight - Used for boost and algorithms, should be between 0 and 1 *
*/ class MITKCONNECTOMICS_EXPORT ConnectomicsNetwork : public BaseData { public: /** Structs for the graph */ /** The Node */ struct NetworkNode { int id; std::string label; std::vector< float > coordinates; }; /** The Edge */ struct NetworkEdge { int sourceId; int targetId; - int weight; // For now the number of times it was present + double fiber_count; // For now the number of times it was present double edge_weight; // For boost, currently set to 1 by default for unweighted calculations }; /** Typedefs **/ //typedef boost::adjacency_list< boost::listS, boost::listS, boost::undirectedS, NetworkNode, NetworkEdge > NetworkType; typedef boost::adjacency_list< boost::vecS, boost::vecS, boost::undirectedS, NetworkNode, NetworkEdge > NetworkType; typedef boost::graph_traits::vertex_descriptor VertexDescriptorType; typedef boost::graph_traits::edge_descriptor EdgeDescriptorType; // virtual methods that need to be implemented virtual void UpdateOutputInformation() override; virtual void SetRequestedRegionToLargestPossibleRegion() override; virtual bool RequestedRegionIsOutsideOfTheBufferedRegion() override; virtual bool VerifyRequestedRegion() override; virtual void SetRequestedRegion(const itk::DataObject * ) override; // Macros mitkClassMacro( ConnectomicsNetwork, BaseData ); itkFactorylessNewMacro(Self) itkCloneMacro(Self) ////////////////// Interface /////////////////// /** return whether an edge exists between the two given vertices */ bool EdgeExists( VertexDescriptorType vertexA, VertexDescriptorType vertexB ) const; /** increase the weight of an edge between the two given vertices */ - void IncreaseEdgeWeight( VertexDescriptorType vertexA, VertexDescriptorType vertexB ); + void IncreaseEdgeWeight( VertexDescriptorType vertexA, VertexDescriptorType vertexB, double fiber_count ); /** add an edge between two given vertices */ - void AddEdge( VertexDescriptorType vertexA, VertexDescriptorType vertexB); + void AddEdge( VertexDescriptorType vertexA, VertexDescriptorType vertexB, double fiber_count); /** add an edge between two given vertices ( with a specific weight ) */ - void AddEdge( VertexDescriptorType vertexA, VertexDescriptorType vertexB, int sourceID, int targetID, int weight = 1, double edge_weight = 1.0 ); + void AddEdge(VertexDescriptorType vertexA, VertexDescriptorType vertexB, int sourceID, int targetID, double fiber_count, double edge_weight = 1.0 ); /** add a vertex with a specified id */ VertexDescriptorType AddVertex( int id); /** set the label of a vertex */ void SetLabel( VertexDescriptorType vertex, std::string inLabel ); /** set the coordinates of a vertex */ void SetCoordinates( VertexDescriptorType vertex, std::vector< float > inCoordinates ); /** clear the graph */ void clear(); /** return the node struct for a given node descriptor */ NetworkNode GetNode( VertexDescriptorType vertex ) const; /** return the edge struct for two given node descriptors */ NetworkEdge GetEdge( VertexDescriptorType vertexA, VertexDescriptorType vertexB ) const; /** get vector containing all the nodes of the network */ std::vector< NetworkNode > GetVectorOfAllNodes() const; /** get vector containing all the vertex descriptors of the network */ std::vector< VertexDescriptorType > GetVectorOfAllVertexDescriptors() const; /** get vector containing the descriptors of nodes adjacent to the vertex denoted by the given descriptor */ std::vector< VertexDescriptorType > GetVectorOfAdjacentNodes( VertexDescriptorType vertex ) const; /** get vector containing all the edges of the network and the connected nodes */ std::vector< std::pair< std::pair< NetworkNode, NetworkNode > , NetworkEdge > > GetVectorOfAllEdges() const; /** get overall number of vertices in the network */ int GetNumberOfVertices() const; /** get overall number of edges in the network */ int GetNumberOfEdges() const; /** get number of vertices, that are connected to themselves */ int GetNumberOfSelfLoops(); /** get number of vertices, that are connected to themselves */ double GetAverageDegree(); /** get number of edges divided by number of possible edges */ double GetConnectionDensity(); /** Get the maximum weight of all edges */ - int GetMaximumWeight() const; + double GetMaximumWeight() const; /** Get a vector in the format vector[ vertexID ] = degree */ std::vector< int > GetDegreeOfNodes( ) const; /** Get the maximum degree of all nodes */ int GetMaximumDegree() const; /** Get a vector in the format vector[ vertexID ] = clustering coefficient */ std::vector< double > GetLocalClusteringCoefficients( ) const; /** Get a vector in the format vector[ degree ] = average clustering coefficient */ std::vector< double > GetClusteringCoefficientsByDegree( ); /** Get the global clustering coefficient */ double GetGlobalClusteringCoefficient( ); /** Get the betweenness centrality for each vertex in form of a vector of length (number vertices)*/ std::vector< double > GetNodeBetweennessVector() const; /** Get the betweenness centrality for each edge in form of a vector of length (number edges)*/ std::vector< double > GetEdgeBetweennessVector() const; /** Check whether a vertex with the specified label exists*/ bool CheckForLabel( std::string targetLabel ) const; /** Get the shortest distance from a specified vertex to all other vertices in form of a vector of length (number vertices)*/ std::vector< double > GetShortestDistanceVectorFromLabel( std::string targetLabel ) const; /** Access boost graph directly */ NetworkType* GetBoostGraph(); /** Set the boost graph directly */ void SetBoostGraph( NetworkType* newGraph ); void ImportNetwort( mitk::ConnectomicsNetwork::Pointer source ); /** Get the modified flag */ bool GetIsModified() const; /** Set the modified flag */ void SetIsModified( bool ); /** Update the bounds of the geometry to fit the network */ void UpdateBounds( ); /** Remove nodes not connected to any other node */ void PruneUnconnectedSingleNodes(); /** This function will relabel all vertices and edges in a continuous manner * * Mainly important after removing vertices, to make sure that the ids run continuously from * 0 to number of vertices - 1 and edge target and source ids match the corresponding node. */ void UpdateIDs(); protected: ConnectomicsNetwork(); virtual ~ConnectomicsNetwork(); NetworkType m_Network; /// Flag which indicates whether the network has been modified since the last check /// /// mainly for rendering purposes bool m_IsModified; private: }; /** * \brief Returns true if the networks are considered equal. * * For now two networks are considered equal if they are equal in the following properties: * - Number of nodes * - Number of edges * - Smallworldness */ MITKCONNECTOMICS_EXPORT bool Equal( mitk::ConnectomicsNetwork* leftHandSide, mitk::ConnectomicsNetwork* rightHandSide, mitk::ScalarType eps, bool verbose); } // namespace mitk #endif /* _MITK_ConnectomicsNetwork_H */ diff --git a/Modules/DiffusionImaging/Connectomics/Rendering/mitkConnectomicsNetworkMapper3D.cpp b/Modules/DiffusionImaging/Connectomics/Rendering/mitkConnectomicsNetworkMapper3D.cpp index 4b1dba26ea..9d2c0bf086 100644 --- a/Modules/DiffusionImaging/Connectomics/Rendering/mitkConnectomicsNetworkMapper3D.cpp +++ b/Modules/DiffusionImaging/Connectomics/Rendering/mitkConnectomicsNetworkMapper3D.cpp @@ -1,835 +1,835 @@ /*=================================================================== 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 "mitkConnectomicsNetworkMapper3D.h" #include "vtkGlyph3D.h" #include "vtkGlyphSource2D.h" #include "vtkGraphLayout.h" #include "vtkGraphToPolyData.h" #include #include #include #include "mitkConnectomicsRenderingEdgeColorParameterProperty.h" #include "mitkConnectomicsRenderingEdgeFilteringProperty.h" #include "mitkConnectomicsRenderingEdgeRadiusParameterProperty.h" #include "mitkConnectomicsRenderingEdgeThresholdParameterProperty.h" #include "mitkConnectomicsRenderingNodeColorParameterProperty.h" #include "mitkConnectomicsRenderingNodeFilteringProperty.h" #include "mitkConnectomicsRenderingNodeRadiusParameterProperty.h" #include "mitkConnectomicsRenderingNodeThresholdParameterProperty.h" #include "mitkConnectomicsRenderingProperties.h" #include "mitkConnectomicsRenderingSchemeProperty.h" #include #include #include #include #include mitk::ConnectomicsNetworkMapper3D::ConnectomicsNetworkMapper3D() { m_NetworkAssembly = vtkPropAssembly::New(); m_Translator = mitk::FreeSurferParcellationTranslator::New(); } mitk::ConnectomicsNetworkMapper3D::~ConnectomicsNetworkMapper3D() { m_NetworkAssembly->Delete(); } void mitk::ConnectomicsNetworkMapper3D::GenerateDataForRenderer(mitk::BaseRenderer *renderer) { if (this->GetInput() == nullptr) { m_TextOverlay3D->UnRegisterMicroservice(); return; } bool propertiesHaveChanged = this->PropertiesChanged(); if (this->GetInput()->GetIsModified() || propertiesHaveChanged) { m_NetworkAssembly->Delete(); m_NetworkAssembly = vtkPropAssembly::New(); // Here is the part where a graph is given and converted to points and connections between points... std::vector vectorOfNodes = this->GetInput()->GetVectorOfAllNodes(); std::vector, mitk::ConnectomicsNetwork::NetworkEdge>> vectorOfEdges = this->GetInput()->GetVectorOfAllEdges(); // Decide on the style of rendering due to property if (m_ChosenRenderingScheme == connectomicsRenderingMITKScheme) { mitk::Point3D tempWorldPoint, tempCNFGeometryPoint; ////// Prepare BalloonWidgets/Overlays: //////////////////// if ((m_ChosenNodeLabel == "" || m_ChosenNodeLabel == "-1") && m_TextOverlay3D) { m_TextOverlay3D->UnRegisterMicroservice(); GetDataNode()->SetProperty( connectomicsRenderingBalloonTextName.c_str(), mitk::StringProperty::New(""), nullptr); GetDataNode()->SetProperty( connectomicsRenderingBalloonNodeStatsName.c_str(), mitk::StringProperty::New(""), nullptr); } //////////////////////Prepare coloring and radius//////////// std::vector vectorOfNodeRadiusParameterValues; vectorOfNodeRadiusParameterValues.resize(vectorOfNodes.size()); double maxNodeRadiusParameterValue( FillNodeParameterVector(&vectorOfNodeRadiusParameterValues, m_NodeRadiusParameter)); std::vector vectorOfNodeColorParameterValues; vectorOfNodeColorParameterValues.resize(vectorOfNodes.size()); double maxNodeColorParameterValue( FillNodeParameterVector(&vectorOfNodeColorParameterValues, m_NodeColorParameter)); std::vector vectorOfEdgeRadiusParameterValues; vectorOfEdgeRadiusParameterValues.resize(vectorOfEdges.size()); double maxEdgeRadiusParameterValue( FillEdgeParameterVector(&vectorOfEdgeRadiusParameterValues, m_EdgeRadiusParameter)); std::vector vectorOfEdgeColorParameterValues; vectorOfEdgeColorParameterValues.resize(vectorOfEdges.size()); double maxEdgeColorParameterValue( FillEdgeParameterVector(&vectorOfEdgeColorParameterValues, m_EdgeColorParameter)); //////////////////////Prepare Filtering////////////////////// // true will be rendered std::vector vectorOfNodeFilterBools(vectorOfNodes.size(), true); if (m_ChosenNodeFilter == connectomicsRenderingNodeThresholdingFilter) { FillNodeFilterBoolVector(&vectorOfNodeFilterBools, m_NodeThresholdParameter); } std::vector vectorOfEdgeFilterBools(vectorOfEdges.size(), true); if (m_ChosenEdgeFilter == connectomicsRenderingEdgeThresholdFilter) { FillEdgeFilterBoolVector(&vectorOfEdgeFilterBools, m_EdgeThresholdParameter); } //////////////////////Create Spheres///////////////////////// std::stringstream nodeLabelStream; // local stream variable to hold csv list of node label names and node label numbers. for (unsigned int i = 0; i < vectorOfNodes.size(); i++) { vtkSmartPointer sphereSource = vtkSmartPointer::New(); for (unsigned int dimension = 0; dimension < 3; dimension++) { tempCNFGeometryPoint.SetElement(dimension, vectorOfNodes[i].coordinates[dimension]); } GetDataNode()->GetData()->GetGeometry()->IndexToWorld(tempCNFGeometryPoint, tempWorldPoint); sphereSource->SetCenter(tempWorldPoint[0], tempWorldPoint[1], tempWorldPoint[2]); // determine radius double radiusFactor = vectorOfNodeRadiusParameterValues[i] / maxNodeRadiusParameterValue; double radius = m_NodeRadiusStart + (m_NodeRadiusEnd - m_NodeRadiusStart) * radiusFactor; sphereSource->SetRadius(radius); vtkSmartPointer mapper = vtkSmartPointer::New(); mapper->SetInputConnection(sphereSource->GetOutputPort()); vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper); // determine color double colorFactor = vectorOfNodeColorParameterValues[i] / maxNodeColorParameterValue; double redStart = m_NodeColorStart.GetElement(0); double greenStart = m_NodeColorStart.GetElement(1); double blueStart = m_NodeColorStart.GetElement(2); double redEnd = m_NodeColorEnd.GetElement(0); double greenEnd = m_NodeColorEnd.GetElement(1); double blueEnd = m_NodeColorEnd.GetElement(2); double red = redStart + (redEnd - redStart) * colorFactor; double green = greenStart + (greenEnd - greenStart) * colorFactor; double blue = blueStart + (blueEnd - blueStart) * colorFactor; actor->GetProperty()->SetColor(red, green, blue); // append to csv list of nodelabels. nodeLabelStream << m_Translator->GetName(std::stoi(vectorOfNodes[i].label)) << ": " << vectorOfNodes[i].label << ","; if (vectorOfNodeFilterBools[i]) { if (vectorOfNodes[i].label == m_ChosenNodeLabel) { // if chosen and enabled, show information in Balloon or TextOverlay: // What to show: std::stringstream balloonStringstream; balloonStringstream << "Node id: " << vectorOfNodes[i].id << "\nlabel: " << vectorOfNodes[i].label << "\nname: " << m_Translator->GetName(std::stoi(vectorOfNodes[i].label)) << std::endl; m_BalloonText = balloonStringstream.str(); GetDataNode()->SetProperty( connectomicsRenderingBalloonTextName.c_str(), mitk::StringProperty::New(m_BalloonText.c_str()), nullptr); std::stringstream balloonNodeStatsStream; balloonNodeStatsStream << "Coordinates: (" << vectorOfNodes[i].coordinates[0] << " ; " << vectorOfNodes[i].coordinates[1] << " ; " << vectorOfNodes[i].coordinates[2] << " )" << "\nDegree: " << (this->GetInput()->GetDegreeOfNodes()).at(vectorOfNodes[i].id) << "\nBetweenness centrality: " << (this->GetInput()->GetNodeBetweennessVector()).at(vectorOfNodes[i].id) << "\nClustering coefficient: " << (this->GetInput()->GetLocalClusteringCoefficients()).at(vectorOfNodes[i].id) << std::endl; m_BalloonNodeStats = balloonNodeStatsStream.str(); GetDataNode()->SetProperty(connectomicsRenderingBalloonNodeStatsName.c_str(), mitk::StringProperty::New(m_BalloonNodeStats.c_str()), nullptr); // Where to show: float r[3]; r[0] = vectorOfNodes[i].coordinates[0]; r[1] = vectorOfNodes[i].coordinates[1]; r[2] = vectorOfNodes[i].coordinates[2]; mitk::Point3D BalloonAnchor(r); mitk::Point3D BalloonAnchorWorldCoord(r); GetDataNode()->GetData()->GetGeometry()->IndexToWorld(BalloonAnchor, BalloonAnchorWorldCoord); // How to show: if (m_ChosenNodeLabel != "-1") { if (m_TextOverlay3D != nullptr) { m_TextOverlay3D->UnRegisterMicroservice(); } m_TextOverlay3D = mitk::TextAnnotation3D::New(); mitk::ManualPlacementAnnotationRenderer::AddAnnotation(m_TextOverlay3D.GetPointer(), renderer); m_TextOverlay3D->SetFontSize(2); m_TextOverlay3D->SetColor(0.96, 0.69, 0.01); m_TextOverlay3D->SetOpacity(0.81); m_TextOverlay3D->SetPosition3D(BalloonAnchorWorldCoord); m_TextOverlay3D->SetText("...." + m_BalloonText); m_TextOverlay3D->SetForceInForeground(true); // TODO: does not work anymore. m_TextOverlay3D->SetVisibility(GetDataNode()->IsVisible(renderer)); // Colorize chosen node: actor->GetProperty()->SetColor(1.0, 0.69, 0.01); } } m_NetworkAssembly->AddPart(actor); } } m_AllNodeLabels = nodeLabelStream.str(); // Store all Node Names and Node Labels in 1 Property. m_AllNodeLabels.erase(m_AllNodeLabels.rfind(","), 1); // remove trailing ,. GetDataNode()->SetProperty(connectomicsRenderingBalloonAllNodeLabelsName.c_str(), mitk::StringProperty::New(m_AllNodeLabels.c_str()), nullptr); //////////////////////Create Tubes///////////////////////// for (unsigned int i = 0; i < vectorOfEdges.size(); i++) { vtkSmartPointer lineSource = vtkSmartPointer::New(); for (unsigned int dimension = 0; dimension < 3; dimension++) { tempCNFGeometryPoint[dimension] = vectorOfEdges[i].first.first.coordinates[dimension]; } GetDataNode()->GetData()->GetGeometry()->IndexToWorld(tempCNFGeometryPoint, tempWorldPoint); lineSource->SetPoint1(tempWorldPoint[0], tempWorldPoint[1], tempWorldPoint[2]); for (unsigned int dimension = 0; dimension < 3; dimension++) { tempCNFGeometryPoint[dimension] = vectorOfEdges[i].first.second.coordinates[dimension]; } GetDataNode()->GetData()->GetGeometry()->IndexToWorld(tempCNFGeometryPoint, tempWorldPoint); lineSource->SetPoint2(tempWorldPoint[0], tempWorldPoint[1], tempWorldPoint[2]); vtkSmartPointer tubes = vtkSmartPointer::New(); tubes->SetInputConnection(lineSource->GetOutputPort()); tubes->SetNumberOfSides(12); // determine radius double radiusFactor = vectorOfEdgeRadiusParameterValues[i] / maxEdgeRadiusParameterValue; double radius = m_EdgeRadiusStart + (m_EdgeRadiusEnd - m_EdgeRadiusStart) * radiusFactor; tubes->SetRadius(radius); // originally we used a logarithmic scaling, // double radiusFactor = 1.0 + ((double) vectorOfEdges[i].second.weight) / 10.0 ; // tubes->SetRadius( std::log10( radiusFactor ) ); vtkSmartPointer mapper2 = vtkSmartPointer::New(); mapper2->SetInputConnection(tubes->GetOutputPort()); vtkSmartPointer actor = vtkSmartPointer::New(); actor->SetMapper(mapper2); // determine color double colorFactor = vectorOfEdgeColorParameterValues[i] / maxEdgeColorParameterValue; double redStart = m_EdgeColorStart.GetElement(0); double greenStart = m_EdgeColorStart.GetElement(1); double blueStart = m_EdgeColorStart.GetElement(2); double redEnd = m_EdgeColorEnd.GetElement(0); double greenEnd = m_EdgeColorEnd.GetElement(1); double blueEnd = m_EdgeColorEnd.GetElement(2); double red = redStart + (redEnd - redStart) * colorFactor; double green = greenStart + (greenEnd - greenStart) * colorFactor; double blue = blueStart + (blueEnd - blueStart) * colorFactor; actor->GetProperty()->SetColor(red, green, blue); if (vectorOfEdgeFilterBools[i]) { m_NetworkAssembly->AddPart(actor); } } } else if (m_ChosenRenderingScheme == connectomicsRenderingVTKScheme) { vtkSmartPointer graph = vtkSmartPointer::New(); std::vector networkToVTKvector; networkToVTKvector.resize(vectorOfNodes.size()); for (unsigned int i = 0; i < vectorOfNodes.size(); i++) { networkToVTKvector[vectorOfNodes[i].id] = graph->AddVertex(); } for (unsigned int i = 0; i < vectorOfEdges.size(); i++) { graph->AddEdge(networkToVTKvector[vectorOfEdges[i].first.first.id], networkToVTKvector[vectorOfEdges[i].first.second.id]); } vtkSmartPointer points = vtkSmartPointer::New(); for (unsigned int i = 0; i < vectorOfNodes.size(); i++) { double x = vectorOfNodes[i].coordinates[0]; double y = vectorOfNodes[i].coordinates[1]; double z = vectorOfNodes[i].coordinates[2]; points->InsertNextPoint(x, y, z); } graph->SetPoints(points); vtkGraphLayout *layout = vtkGraphLayout::New(); layout->SetInputData(graph); vtkPassThroughLayoutStrategy *ptls = vtkPassThroughLayoutStrategy::New(); layout->SetLayoutStrategy(ptls); vtkGraphToPolyData *graphToPoly = vtkGraphToPolyData::New(); graphToPoly->SetInputConnection(layout->GetOutputPort()); // Create the standard VTK polydata mapper and actor // for the connections (edges) in the tree. vtkPolyDataMapper *edgeMapper = vtkPolyDataMapper::New(); edgeMapper->SetInputConnection(graphToPoly->GetOutputPort()); vtkActor *edgeActor = vtkActor::New(); edgeActor->SetMapper(edgeMapper); edgeActor->GetProperty()->SetColor(0.0, 0.5, 1.0); // Glyph the points of the tree polydata to create // VTK_VERTEX cells at each vertex in the tree. vtkGlyph3D *vertGlyph = vtkGlyph3D::New(); vertGlyph->SetInputConnection(0, graphToPoly->GetOutputPort()); vtkGlyphSource2D *glyphSource = vtkGlyphSource2D::New(); glyphSource->SetGlyphTypeToVertex(); vertGlyph->SetInputConnection(1, glyphSource->GetOutputPort()); // Create a mapper for the vertices, and tell the mapper // to use the specified color array. vtkPolyDataMapper *vertMapper = vtkPolyDataMapper::New(); vertMapper->SetInputConnection(vertGlyph->GetOutputPort()); /*if (colorArray) { vertMapper->SetScalarModeToUsePointFieldData(); vertMapper->SelectColorArray(colorArray); vertMapper->SetScalarRange(colorRange); }*/ // Create an actor for the vertices. Move the actor forward // in the z direction so it is drawn on top of the edge actor. vtkActor *vertActor = vtkActor::New(); vertActor->SetMapper(vertMapper); vertActor->GetProperty()->SetPointSize(5); vertActor->SetPosition(0, 0, 0.001); // vtkProp3D.h: virtual void SetPosition(double,double,double): // Set/Get/Add the position of the Prop3D in world coordinates. m_NetworkAssembly->AddPart(edgeActor); m_NetworkAssembly->AddPart(vertActor); } (static_cast(GetDataNode()->GetData()))->SetIsModified(false); } } const mitk::ConnectomicsNetwork *mitk::ConnectomicsNetworkMapper3D::GetInput() { return static_cast(GetDataNode()->GetData()); } void mitk::ConnectomicsNetworkMapper3D::SetDefaultProperties(DataNode *node, BaseRenderer *renderer, bool overwrite) { // Initialize enumeration properties mitk::ConnectomicsRenderingSchemeProperty::Pointer connectomicsRenderingScheme = mitk::ConnectomicsRenderingSchemeProperty::New(); mitk::ConnectomicsRenderingEdgeFilteringProperty::Pointer connectomicsRenderingEdgeFiltering = mitk::ConnectomicsRenderingEdgeFilteringProperty::New(); mitk::ConnectomicsRenderingNodeFilteringProperty::Pointer connectomicsRenderingNodeFiltering = mitk::ConnectomicsRenderingNodeFilteringProperty::New(); mitk::ConnectomicsRenderingNodeColorParameterProperty::Pointer connectomicsRenderingNodeGradientColorParameter = mitk::ConnectomicsRenderingNodeColorParameterProperty::New(); mitk::ConnectomicsRenderingNodeRadiusParameterProperty::Pointer connectomicsRenderingNodeRadiusParameter = mitk::ConnectomicsRenderingNodeRadiusParameterProperty::New(); mitk::ConnectomicsRenderingEdgeColorParameterProperty::Pointer connectomicsRenderingEdgeGradientColorParameter = mitk::ConnectomicsRenderingEdgeColorParameterProperty::New(); mitk::ConnectomicsRenderingEdgeRadiusParameterProperty::Pointer connectomicsRenderingEdgeRadiusParameter = mitk::ConnectomicsRenderingEdgeRadiusParameterProperty::New(); mitk::ConnectomicsRenderingNodeThresholdParameterProperty::Pointer connectomicsRenderingNodeThresholdParameter = mitk::ConnectomicsRenderingNodeThresholdParameterProperty::New(); mitk::ConnectomicsRenderingEdgeThresholdParameterProperty::Pointer connectomicsRenderingEdgeThresholdParameter = mitk::ConnectomicsRenderingEdgeThresholdParameterProperty::New(); mitk::StringProperty::Pointer balloonText = mitk::StringProperty::New(); // set the properties node->AddProperty(connectomicsRenderingSchemePropertyName.c_str(), connectomicsRenderingScheme, renderer, overwrite); node->AddProperty( connectomicsRenderingEdgeFilteringPropertyName.c_str(), connectomicsRenderingEdgeFiltering, renderer, overwrite); node->AddProperty(connectomicsRenderingEdgeThresholdFilterParameterName.c_str(), connectomicsRenderingEdgeThresholdParameter, renderer, overwrite); node->AddProperty(connectomicsRenderingEdgeThresholdFilterThresholdName.c_str(), connectomicsRenderingEdgeThresholdFilterThresholdDefault, renderer, overwrite); node->AddProperty( connectomicsRenderingNodeFilteringPropertyName.c_str(), connectomicsRenderingNodeFiltering, renderer, overwrite); node->AddProperty(connectomicsRenderingNodeThresholdFilterParameterName.c_str(), connectomicsRenderingNodeThresholdParameter, renderer, overwrite); node->AddProperty(connectomicsRenderingNodeThresholdFilterThresholdName.c_str(), connectomicsRenderingNodeThresholdFilterThresholdDefault, renderer, overwrite); node->AddProperty(connectomicsRenderingNodeGradientStartColorName.c_str(), connectomicsRenderingNodeGradientStartColorDefault, renderer, overwrite); node->AddProperty(connectomicsRenderingNodeGradientEndColorName.c_str(), connectomicsRenderingNodeGradientEndColorDefault, renderer, overwrite); node->AddProperty(connectomicsRenderingNodeGradientColorParameterName.c_str(), connectomicsRenderingNodeGradientColorParameter, renderer, overwrite); node->AddProperty( connectomicsRenderingNodeRadiusStartName.c_str(), connectomicsRenderingNodeRadiusStartDefault, renderer, overwrite); node->AddProperty( connectomicsRenderingNodeRadiusEndName.c_str(), connectomicsRenderingNodeRadiusEndDefault, renderer, overwrite); node->AddProperty(connectomicsRenderingNodeRadiusParameterName.c_str(), connectomicsRenderingNodeRadiusParameter, renderer, overwrite); node->AddProperty( connectomicsRenderingNodeChosenNodeName.c_str(), connectomicsRenderingNodeChosenNodeDefault, renderer, overwrite); node->AddProperty(connectomicsRenderingEdgeGradientStartColorName.c_str(), connectomicsRenderingEdgeGradientStartColorDefault, renderer, overwrite); node->AddProperty(connectomicsRenderingEdgeGradientEndColorName.c_str(), connectomicsRenderingEdgeGradientEndColorDefault, renderer, overwrite); node->AddProperty(connectomicsRenderingEdgeGradientColorParameterName.c_str(), connectomicsRenderingEdgeGradientColorParameter, renderer, overwrite); node->AddProperty( connectomicsRenderingEdgeRadiusStartName.c_str(), connectomicsRenderingEdgeRadiusStartDefault, renderer, overwrite); node->AddProperty( connectomicsRenderingEdgeRadiusEndName.c_str(), connectomicsRenderingEdgeRadiusEndDefault, renderer, overwrite); node->AddProperty(connectomicsRenderingEdgeRadiusParameterName.c_str(), connectomicsRenderingEdgeRadiusParameter, renderer, overwrite); node->AddProperty(connectomicsRenderingBalloonTextName.c_str(), balloonText, nullptr, overwrite); // renderer=nullptr: Property is renderer independent. Superclass::SetDefaultProperties(node, renderer, overwrite); } void mitk::ConnectomicsNetworkMapper3D::SetVtkMapperImmediateModeRendering(vtkMapper *mapper) { mapper->ImmediateModeRenderingOn(); } void mitk::ConnectomicsNetworkMapper3D::UpdateVtkObjects() { // TODO: implement } vtkProp *mitk::ConnectomicsNetworkMapper3D::GetVtkProp(mitk::BaseRenderer * /*renderer*/) { return m_NetworkAssembly; } bool mitk::ConnectomicsNetworkMapper3D::PropertiesChanged() { mitk::ConnectomicsRenderingSchemeProperty *renderingScheme = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingSchemePropertyName.c_str())); mitk::ConnectomicsRenderingEdgeFilteringProperty *edgeFilter = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingEdgeFilteringPropertyName.c_str())); mitk::FloatProperty *edgeThreshold = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingEdgeThresholdFilterThresholdName.c_str())); mitk::ConnectomicsRenderingNodeFilteringProperty *nodeFilter = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingNodeFilteringPropertyName.c_str())); mitk::ConnectomicsRenderingNodeThresholdParameterProperty *nodeThresholdParameter = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingNodeThresholdFilterParameterName.c_str())); mitk::ConnectomicsRenderingEdgeThresholdParameterProperty *edgeThresholdParameter = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingEdgeThresholdFilterParameterName.c_str())); mitk::FloatProperty *nodeThreshold = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingNodeThresholdFilterThresholdName.c_str())); mitk::ColorProperty *nodeColorStart = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingNodeGradientStartColorName.c_str())); mitk::ColorProperty *nodeColorEnd = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingNodeGradientEndColorName.c_str())); mitk::FloatProperty *nodeRadiusStart = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingNodeRadiusStartName.c_str())); mitk::FloatProperty *nodeRadiusEnd = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingNodeRadiusEndName.c_str())); mitk::StringProperty *chosenNode = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingNodeChosenNodeName.c_str())); mitk::ColorProperty *edgeColorStart = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingEdgeGradientStartColorName.c_str())); mitk::ColorProperty *edgeColorEnd = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingEdgeGradientEndColorName.c_str())); mitk::FloatProperty *edgeRadiusStart = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingEdgeRadiusStartName.c_str())); mitk::FloatProperty *edgeRadiusEnd = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingEdgeRadiusEndName.c_str())); mitk::ConnectomicsRenderingNodeColorParameterProperty *nodeColorParameter = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingNodeGradientColorParameterName.c_str())); mitk::ConnectomicsRenderingNodeRadiusParameterProperty *nodeRadiusParameter = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingNodeRadiusParameterName.c_str())); mitk::ConnectomicsRenderingEdgeColorParameterProperty *edgeColorParameter = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingEdgeGradientColorParameterName.c_str())); mitk::ConnectomicsRenderingEdgeRadiusParameterProperty *edgeRadiusParameter = static_cast( this->GetDataNode()->GetProperty(connectomicsRenderingEdgeRadiusParameterName.c_str())); if (m_ChosenRenderingScheme != renderingScheme->GetValueAsString() || m_ChosenEdgeFilter != edgeFilter->GetValueAsString() || m_EdgeThreshold != edgeThreshold->GetValue() || m_EdgeThresholdParameter != edgeThresholdParameter->GetValueAsString() || m_ChosenNodeFilter != nodeFilter->GetValueAsString() || m_NodeThreshold != nodeThreshold->GetValue() || m_NodeThresholdParameter != nodeThresholdParameter->GetValueAsString() || m_NodeColorStart != nodeColorStart->GetValue() || m_NodeColorEnd != nodeColorEnd->GetValue() || m_NodeRadiusStart != nodeRadiusStart->GetValue() || m_NodeRadiusEnd != nodeRadiusEnd->GetValue() || m_ChosenNodeLabel != chosenNode->GetValueAsString() || m_EdgeColorStart != edgeColorStart->GetValue() || m_EdgeColorEnd != edgeColorEnd->GetValue() || m_EdgeRadiusStart != edgeRadiusStart->GetValue() || m_EdgeRadiusEnd != edgeRadiusEnd->GetValue() || m_NodeColorParameter != nodeColorParameter->GetValueAsString() || m_NodeRadiusParameter != nodeRadiusParameter->GetValueAsString() || m_EdgeColorParameter != edgeColorParameter->GetValueAsString() || m_EdgeRadiusParameter != edgeRadiusParameter->GetValueAsString()) { m_ChosenRenderingScheme = renderingScheme->GetValueAsString(); m_ChosenEdgeFilter = edgeFilter->GetValueAsString(); m_EdgeThreshold = edgeThreshold->GetValue(); m_EdgeThresholdParameter = edgeThresholdParameter->GetValueAsString(); m_ChosenNodeFilter = nodeFilter->GetValueAsString(); m_NodeThreshold = nodeThreshold->GetValue(); m_NodeThresholdParameter = nodeThresholdParameter->GetValueAsString(); m_NodeColorStart = nodeColorStart->GetValue(); m_NodeColorEnd = nodeColorEnd->GetValue(); m_NodeRadiusStart = nodeRadiusStart->GetValue(); m_NodeRadiusEnd = nodeRadiusEnd->GetValue(); m_ChosenNodeLabel = chosenNode->GetValueAsString(); m_EdgeColorStart = edgeColorStart->GetValue(); m_EdgeColorEnd = edgeColorEnd->GetValue(); m_EdgeRadiusStart = edgeRadiusStart->GetValue(); m_EdgeRadiusEnd = edgeRadiusEnd->GetValue(); m_NodeColorParameter = nodeColorParameter->GetValueAsString(); m_NodeRadiusParameter = nodeRadiusParameter->GetValueAsString(); m_EdgeColorParameter = edgeColorParameter->GetValueAsString(); m_EdgeRadiusParameter = edgeRadiusParameter->GetValueAsString(); return true; } return false; } double mitk::ConnectomicsNetworkMapper3D::FillNodeParameterVector(std::vector *parameterVector, std::string parameterName) { int end(parameterVector->size()); // constant parameter - uniform style if (parameterName == connectomicsRenderingNodeParameterConstant) { for (int index(0); index < end; index++) { parameterVector->at(index) = 1.0; } return 1.0; } double maximum(0.0); // using the degree as parameter if (parameterName == connectomicsRenderingNodeParameterDegree) { std::vector vectorOfDegree = this->GetInput()->GetDegreeOfNodes(); for (int index(0); index < end; index++) { parameterVector->at(index) = vectorOfDegree[index]; } maximum = *std::max_element(parameterVector->begin(), parameterVector->end()); } // using betweenness centrality as parameter if (parameterName == connectomicsRenderingNodeParameterBetweenness) { std::vector vectorOfBetweenness = this->GetInput()->GetNodeBetweennessVector(); for (int index(0); index < end; index++) { parameterVector->at(index) = vectorOfBetweenness[index]; } maximum = *std::max_element(parameterVector->begin(), parameterVector->end()); } // using clustering coefficient as parameter if (parameterName == connectomicsRenderingNodeParameterClustering) { const std::vector vectorOfClustering = this->GetInput()->GetLocalClusteringCoefficients(); for (int index(0); index < end; index++) { parameterVector->at(index) = vectorOfClustering[index]; } maximum = *std::max_element(parameterVector->begin(), parameterVector->end()); } // using distance to a specific node as parameter if (parameterName == connectomicsRenderingNodeParameterColoringShortestPath) { bool labelFound(this->GetInput()->CheckForLabel(m_ChosenNodeLabel)); // check whether the chosen node is valid if (!labelFound) { MITK_WARN << "Node chosen for rendering is not valid."; for (int index(0); index < end; index++) { parameterVector->at(index) = 1.0; } return 1.0; } else { const std::vector distanceVector = this->GetInput()->GetShortestDistanceVectorFromLabel(m_ChosenNodeLabel); for (int index(0); index < end; index++) { parameterVector->at(index) = distanceVector[index]; } maximum = *std::max_element(parameterVector->begin(), parameterVector->end()); } } // if the maximum is nearly zero if (std::abs(maximum) < mitk::eps) { maximum = 1.0; } return maximum; } double mitk::ConnectomicsNetworkMapper3D::FillEdgeParameterVector(std::vector *parameterVector, std::string parameterName) { int end(parameterVector->size()); // constant parameter - uniform style if (parameterName == connectomicsRenderingEdgeParameterConstant) { for (int index(0); index < end; index++) { parameterVector->at(index) = 1.0; } return 1.0; } double maximum(0.0); // using the weight as parameter if (parameterName == connectomicsRenderingEdgeParameterWeight) { std::vector, mitk::ConnectomicsNetwork::NetworkEdge>> vectorOfEdges = this->GetInput()->GetVectorOfAllEdges(); for (int index(0); index < end; index++) { - parameterVector->at(index) = vectorOfEdges[index].second.weight; + parameterVector->at(index) = vectorOfEdges[index].second.fiber_count; } maximum = *std::max_element(parameterVector->begin(), parameterVector->end()); } // using the edge centrality as parameter if (parameterName == connectomicsRenderingEdgeParameterCentrality) { const std::vector vectorOfCentrality = this->GetInput()->GetEdgeBetweennessVector(); for (int index(0); index < end; index++) { parameterVector->at(index) = vectorOfCentrality[index]; } maximum = *std::max_element(parameterVector->begin(), parameterVector->end()); } // if the maximum is nearly zero if (std::abs(maximum) < mitk::eps) { maximum = 1.0; } return maximum; } void mitk::ConnectomicsNetworkMapper3D::FillNodeFilterBoolVector(std::vector *boolVector, std::string parameterName) { std::vector parameterVector; parameterVector.resize(boolVector->size()); int end(parameterVector.size()); // using the degree as parameter if (parameterName == connectomicsRenderingNodeParameterDegree) { std::vector vectorOfDegree = this->GetInput()->GetDegreeOfNodes(); for (int index(0); index < end; index++) { parameterVector.at(index) = vectorOfDegree[index]; } } // using betweenness centrality as parameter if (parameterName == connectomicsRenderingNodeParameterBetweenness) { std::vector vectorOfBetweenness = this->GetInput()->GetNodeBetweennessVector(); for (int index(0); index < end; index++) { parameterVector.at(index) = vectorOfBetweenness[index]; } } // using clustering coefficient as parameter if (parameterName == connectomicsRenderingNodeParameterClustering) { const std::vector vectorOfClustering = this->GetInput()->GetLocalClusteringCoefficients(); for (int index(0); index < end; index++) { parameterVector.at(index) = vectorOfClustering[index]; } } for (int index(0), end(boolVector->size()); index < end; index++) { if (parameterVector.at(index) >= m_NodeThreshold) { boolVector->at(index) = true; } else { boolVector->at(index) = false; } } return; } void mitk::ConnectomicsNetworkMapper3D::FillEdgeFilterBoolVector(std::vector *boolVector, std::string parameterName) { std::vector parameterVector; parameterVector.resize(boolVector->size()); int end(parameterVector.size()); // using the weight as parameter if (parameterName == connectomicsRenderingEdgeParameterWeight) { std::vector, mitk::ConnectomicsNetwork::NetworkEdge>> vectorOfEdges = this->GetInput()->GetVectorOfAllEdges(); for (int index(0); index < end; index++) { - parameterVector.at(index) = vectorOfEdges[index].second.weight; + parameterVector.at(index) = vectorOfEdges[index].second.fiber_count; } } // using the edge centrality as parameter if (parameterName == connectomicsRenderingEdgeParameterCentrality) { const std::vector vectorOfCentrality = this->GetInput()->GetEdgeBetweennessVector(); for (int index(0); index < end; index++) { parameterVector.at(index) = vectorOfCentrality[index]; } } for (int index(0), end(boolVector->size()); index < end; index++) { if (parameterVector.at(index) >= m_EdgeThreshold) { boolVector->at(index) = true; } else { boolVector->at(index) = false; } } return; } diff --git a/Modules/DiffusionImaging/Connectomics/Testing/mitkConnectomicsNetworkTest.cpp b/Modules/DiffusionImaging/Connectomics/Testing/mitkConnectomicsNetworkTest.cpp index 85a2040485..480635edc5 100644 --- a/Modules/DiffusionImaging/Connectomics/Testing/mitkConnectomicsNetworkTest.cpp +++ b/Modules/DiffusionImaging/Connectomics/Testing/mitkConnectomicsNetworkTest.cpp @@ -1,530 +1,530 @@ /*=================================================================== 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 "mitkTestingMacros.h" #include "mitkConnectomicsNetwork.h" #include "mitkConnectomicsSyntheticNetworkGenerator.h" #include "mitkConnectomicsSimulatedAnnealingManager.h" #include "mitkConnectomicsSimulatedAnnealingPermutationModularity.h" #include "mitkConnectomicsSimulatedAnnealingCostFunctionModularity.h" #include #include #include #include /**Documentation * Test for synthetic connectomics generation and connectomics network functionality */ int mitkConnectomicsNetworkTest(int, char* []) { // Test begins MITK_TEST_BEGIN("mitkConnectomicsNetworkTest"); /// \todo Fix VTK memory leaks. Bug 18097. vtkDebugLeaks::SetExitError(0); // Typedefs typedef mitk::ConnectomicsNetwork::VertexDescriptorType VertexType; typedef mitk::ConnectomicsNetwork::NetworkNode NodeType; // The test network std::vector< NodeType > inNodes; NodeType node; node.id = 0; node.label = "1-1"; node.coordinates.clear(); node.coordinates.push_back( 0 ); node.coordinates.push_back( 0 ); node.coordinates.push_back( 0 ); inNodes.push_back(node); node.id = 1; node.label = "2-1"; node.coordinates.clear(); node.coordinates.push_back( 10 ); node.coordinates.push_back( 0 ); node.coordinates.push_back( 0 ); inNodes.push_back(node); node.id = 2; node.label = "3-1"; node.coordinates.clear(); node.coordinates.push_back( 20 ); node.coordinates.push_back( 10 ); node.coordinates.push_back( 0 ); inNodes.push_back(node); node.id = 3; node.label = "4-1"; node.coordinates.clear(); node.coordinates.push_back( 30 ); node.coordinates.push_back( 20 ); node.coordinates.push_back( 0 ); inNodes.push_back(node); node.id = 4; node.label = "5-1"; node.coordinates.clear(); node.coordinates.push_back( 40 ); node.coordinates.push_back( 50 ); node.coordinates.push_back( 0 ); inNodes.push_back(node); node.id = 5; node.label = "6-2"; node.coordinates.clear(); node.coordinates.push_back( 0 ); node.coordinates.push_back( 0 ); node.coordinates.push_back( 10 ); inNodes.push_back(node); node.id = 6; node.label = "7-2"; node.coordinates.clear(); node.coordinates.push_back( 0 ); node.coordinates.push_back( 10 ); node.coordinates.push_back( 20 ); inNodes.push_back(node); node.id = 7; node.label = "8-2"; node.coordinates.clear(); node.coordinates.push_back( 0 ); node.coordinates.push_back( 20 ); node.coordinates.push_back( 30 ); inNodes.push_back(node); node.id = 8; node.label = "9-2"; node.coordinates.clear(); node.coordinates.push_back( 0 ); node.coordinates.push_back( 30 ); node.coordinates.push_back( 40 ); inNodes.push_back(node); node.id = 9; node.label = "10-3"; node.coordinates.clear(); node.coordinates.push_back( 20 ); node.coordinates.push_back( 0 ); node.coordinates.push_back( 10 ); inNodes.push_back(node); node.id = 10; node.label = "11-3"; node.coordinates.clear(); node.coordinates.push_back( 30 ); node.coordinates.push_back( 0 ); node.coordinates.push_back( 20 ); inNodes.push_back(node); node.id = 11; node.label = "12-3"; node.coordinates.clear(); node.coordinates.push_back( 40 ); node.coordinates.push_back( 0 ); node.coordinates.push_back( 30 ); inNodes.push_back(node); std::vector< mitk::ConnectomicsNetwork::NetworkEdge > inEdges; mitk::ConnectomicsNetwork::NetworkEdge edge; edge.sourceId = 0; edge.targetId = 1; - edge.weight = 2; + edge.fiber_count = 2; inEdges.push_back( edge ); edge.sourceId = 0; edge.targetId = 2; - edge.weight = 2; + edge.fiber_count = 2; inEdges.push_back( edge ); edge.sourceId = 0; edge.targetId = 4; - edge.weight = 2; + edge.fiber_count = 2; inEdges.push_back( edge ); edge.sourceId = 1; edge.targetId = 4; - edge.weight = 2; + edge.fiber_count = 2; inEdges.push_back( edge ); edge.sourceId = 1; edge.targetId = 3; - edge.weight = 2; + edge.fiber_count = 2; inEdges.push_back( edge ); edge.sourceId = 2; edge.targetId = 3; - edge.weight = 2; + edge.fiber_count = 2; inEdges.push_back( edge ); edge.sourceId = 3; edge.targetId = 4; - edge.weight = 2; + edge.fiber_count = 2; inEdges.push_back( edge ); edge.sourceId = 4; edge.targetId = 5; - edge.weight = 2; + edge.fiber_count = 2; inEdges.push_back( edge ); edge.sourceId = 5; edge.targetId = 6; - edge.weight = 2; + edge.fiber_count = 2; inEdges.push_back( edge ); edge.sourceId = 5; edge.targetId = 7; - edge.weight = 2; + edge.fiber_count = 2; inEdges.push_back( edge ); edge.sourceId = 5; edge.targetId = 8; - edge.weight = 2; + edge.fiber_count = 2; inEdges.push_back( edge ); edge.sourceId = 7; edge.targetId = 8; - edge.weight = 2; + edge.fiber_count = 2; inEdges.push_back( edge ); edge.sourceId = 6; edge.targetId = 8; - edge.weight = 2; + edge.fiber_count = 2; inEdges.push_back( edge ); edge.sourceId = 6; edge.targetId = 9; - edge.weight = 2; + edge.fiber_count = 2; inEdges.push_back( edge ); edge.sourceId = 3; edge.targetId = 10; - edge.weight = 2; + edge.fiber_count = 2; inEdges.push_back( edge ); edge.sourceId = 9; edge.targetId = 10; - edge.weight = 2; + edge.fiber_count = 2; inEdges.push_back( edge ); edge.sourceId = 10; edge.targetId = 11; - edge.weight = 2; + edge.fiber_count = 2; inEdges.push_back( edge ); edge.sourceId = 9; edge.targetId = 11; - edge.weight = 2; + edge.fiber_count = 2; inEdges.push_back( edge ); // further variables double eps(0.001); try { // Testing synthetic network generation mitk::ConnectomicsSyntheticNetworkGenerator::Pointer generator = mitk::ConnectomicsSyntheticNetworkGenerator::New(); MITK_TEST_CONDITION_REQUIRED(generator.IsNotNull(),"Synthetic network generator has been instantiated") // first and second parameter std::vector< std::pair > parameterVector; // name and isRandom std::vector< std::pair > messageVector; // order of results is # vertices, # edges, # self loops, average degree, connection density // global clustering coefficient std::vector< std::vector< double > > resultVector; int numberOfOptions = 3; parameterVector.resize(numberOfOptions); messageVector.resize(numberOfOptions); resultVector.resize(numberOfOptions); // Create regular lattice network in the form of a cube with sidelength 5 and distance 10 between nodes parameterVector[0] = std::pair< int, double>(5, 10); messageVector[0] = std::pair("Regular Lattice Network", false); resultVector[0].push_back( 5 * 5 * 5 ); resultVector[0].push_back( 300 ); resultVector[0].push_back( 0 ); resultVector[0].push_back( 4.8 ); resultVector[0].push_back(0.0387); resultVector[0].push_back(0); // Create a heterogeneous sphere network with 1 central node and 49 nodes on the surface and radius 10 parameterVector[1] = std::pair< int, double>(50, 10); messageVector[1] = std::pair("Heterogeneous Sphere Network", false); resultVector[1].push_back( 50 ); resultVector[1].push_back( 49 ); resultVector[1].push_back( 0 ); resultVector[1].push_back( 1.96 ); resultVector[1].push_back(0.0400); resultVector[1].push_back(0); // Create random network with 50 nodes and edges between them generated with a 0.1 likelihood parameterVector[2] = std::pair< int, double>(50, 0.1); messageVector[2] = std::pair("Random Network", true); resultVector[2].push_back( 50 ); for(int loop(0); loop < numberOfOptions; loop++) { mitk::ConnectomicsNetwork::Pointer network = generator->CreateSyntheticNetwork(loop, parameterVector[loop].first, parameterVector[loop].second); bool generationWorked = generator->WasGenerationSuccessfull() && network.IsNotNull(); std::string message = messageVector[loop].first + " has been instantiated"; MITK_TEST_CONDITION_REQUIRED(generationWorked,message) bool verticesCloseEnough( std::abs(resultVector[loop][0] - network->GetNumberOfVertices()) < eps); MITK_TEST_CONDITION_REQUIRED( verticesCloseEnough, "Expected number of vertices") if(!messageVector[loop].second) { bool edgesCloseEnough( std::abs(resultVector[loop][1] - network->GetNumberOfEdges()) < eps); MITK_TEST_CONDITION_REQUIRED( edgesCloseEnough, "Expected number of edges") bool selfLoopsCloseEnough( std::abs(resultVector[loop][2] - network->GetNumberOfSelfLoops()) < eps); MITK_TEST_CONDITION_REQUIRED( selfLoopsCloseEnough, "Expected number of self loops") bool avDegCloseEnough( std::abs(resultVector[loop][3] - network->GetAverageDegree()) < eps); MITK_TEST_CONDITION_REQUIRED( avDegCloseEnough, "Expected average degree") bool conDensCloseEnough( std::abs(resultVector[loop][4] - network->GetConnectionDensity()) < eps); MITK_TEST_CONDITION_REQUIRED( conDensCloseEnough, "Expected connection density") bool clustCoeffCloseEnough( std::abs(resultVector[loop][5] - network->GetGlobalClusteringCoefficient()) < eps); MITK_TEST_CONDITION_REQUIRED( clustCoeffCloseEnough, "Expected global clustering coefficient") } } } catch (...) { MITK_ERROR << "Unhandled exception caught while testing synthetic network generation [FAILED]" ; return EXIT_FAILURE; } try { // Testing network interface // Create network mitk::ConnectomicsNetwork::Pointer network = mitk::ConnectomicsNetwork::New(); std::vector< VertexType > vertexVector; vertexVector.resize( inNodes.size() ); for(unsigned int loop(0); loop < inNodes.size(); loop++) { VertexType newVertex = network->AddVertex( inNodes[loop].id ); vertexVector[ inNodes[loop].id ] = newVertex; network->SetLabel( newVertex, inNodes[loop].label ); network->SetCoordinates( newVertex, inNodes[loop].coordinates ); } for(unsigned int loop(0); loop < inEdges.size(); loop++) { int sourceId = inEdges[loop].sourceId; int targetId = inEdges[loop].targetId; VertexType sourceVertex = vertexVector[ sourceId ]; VertexType targetVertex = vertexVector[ targetId ]; // there are two methods to add nodes if( loop % 2 == 0 ) { - network->AddEdge(sourceVertex, targetVertex); - for( int remaining( inEdges[loop].weight ); remaining > 1; remaining-- ) + network->AddEdge(sourceVertex, targetVertex, 1); + for( int remaining( inEdges[loop].fiber_count ); remaining > 1; remaining-- ) { - network->IncreaseEdgeWeight( sourceVertex, targetVertex ); + network->IncreaseEdgeWeight( sourceVertex, targetVertex, 1 ); } } else { - network->AddEdge(sourceVertex, targetVertex, sourceId, targetId, inEdges[loop].weight ); + network->AddEdge(sourceVertex, targetVertex, sourceId, targetId, inEdges[loop].fiber_count ); } } // Test whether network parameters are as expected MITK_TEST_CONDITION_REQUIRED( inNodes.size() == (unsigned int)network->GetNumberOfVertices(), "Expected number of vertices") MITK_TEST_CONDITION_REQUIRED( inEdges.size() == (unsigned int)network->GetNumberOfEdges(), "Expected number of edges") MITK_TEST_CONDITION_REQUIRED( 0 == network->GetNumberOfSelfLoops(), "Expected number of self loops") bool avDegCloseEnough( std::abs(3 - network->GetAverageDegree()) < eps); MITK_TEST_CONDITION_REQUIRED( avDegCloseEnough, "Expected average degree") bool conDensCloseEnough( std::abs(0.2727 - network->GetConnectionDensity()) < eps); MITK_TEST_CONDITION_REQUIRED( conDensCloseEnough, "Expected connection density") bool clustCoeffCloseEnough( std::abs(0.4583 - network->GetGlobalClusteringCoefficient()) < eps); MITK_TEST_CONDITION_REQUIRED( clustCoeffCloseEnough, "Expected global clustering coefficient") MITK_TEST_CONDITION_REQUIRED( network->GetMaximumWeight() == 2, "Expected maximum weight") MITK_TEST_CONDITION_REQUIRED( network->GetVectorOfAllVertexDescriptors().size() == vertexVector.size(), "Expected number of vertex descriptors") } catch (...) { MITK_ERROR << "Unhandled exception caught while testing network interface [FAILED]" ; return EXIT_FAILURE; } try { // Testing modularity calculation typedef std::map< VertexType, int > ToModuleMapType; // Create network mitk::ConnectomicsNetwork::Pointer network = mitk::ConnectomicsNetwork::New(); std::vector< VertexType > vertexVector; vertexVector.resize( inNodes.size() ); for(unsigned int loop(0); loop < inNodes.size(); loop++) { VertexType newVertex = network->AddVertex( inNodes[loop].id ); vertexVector[ inNodes[loop].id ] = newVertex; network->SetLabel( newVertex, inNodes[loop].label ); network->SetCoordinates( newVertex, inNodes[loop].coordinates ); } for(unsigned int loop(0); loop < inEdges.size(); loop++) { int sourceId = inEdges[loop].sourceId; int targetId = inEdges[loop].targetId; VertexType sourceVertex = vertexVector[ sourceId ]; VertexType targetVertex = vertexVector[ targetId ]; // there are two methods to add nodes if( loop % 2 == 0 ) { - network->AddEdge(sourceVertex, targetVertex); - for( int remaining( inEdges[loop].weight ); remaining > 1; remaining-- ) + network->AddEdge(sourceVertex, targetVertex, 1); + for( int remaining( inEdges[loop].fiber_count ); remaining > 1; remaining-- ) { - network->IncreaseEdgeWeight( sourceVertex, targetVertex ); + network->IncreaseEdgeWeight( sourceVertex, targetVertex, 1 ); } } else { - network->AddEdge(sourceVertex, targetVertex, sourceId, targetId, inEdges[loop].weight ); + network->AddEdge(sourceVertex, targetVertex, sourceId, targetId, inEdges[loop].fiber_count ); } } // Simulated annealing classes mitk::ConnectomicsSimulatedAnnealingManager::Pointer manager = mitk::ConnectomicsSimulatedAnnealingManager::New(); mitk::ConnectomicsSimulatedAnnealingPermutationModularity::Pointer permutation = mitk::ConnectomicsSimulatedAnnealingPermutationModularity::New(); mitk::ConnectomicsSimulatedAnnealingCostFunctionModularity::Pointer costFunction = mitk::ConnectomicsSimulatedAnnealingCostFunctionModularity::New(); // Test whether modularity calculation behaves as expected ToModuleMapType threeModuleSolution; std::vector< VertexType > vertexInVector = network->GetVectorOfAllVertexDescriptors(); threeModuleSolution.insert( std::pair( vertexInVector[ 0 ], 0 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 1 ], 0 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 2 ], 0 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 3 ], 0 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 4 ], 0 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 5 ], 1 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 6 ], 1 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 7 ], 1 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 8 ], 1 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 9 ], 2 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 10 ], 2 ) ); threeModuleSolution.insert( std::pair( vertexInVector[ 11 ], 2 ) ); bool threeModuleModularity( std::abs(0.4753 - costFunction->CalculateModularity( network, &threeModuleSolution )) < eps); MITK_TEST_CONDITION_REQUIRED( threeModuleModularity, "Expected three module modularity") bool correctNumberOfModules( permutation->getNumberOfModules( &threeModuleSolution ) == 3 ); MITK_TEST_CONDITION_REQUIRED( correctNumberOfModules, "Expected number of modules") bool correctNumberOfVertices( permutation->getNumberOfVerticesInModule( &threeModuleSolution, 0 ) == 5 && permutation->getNumberOfVerticesInModule( &threeModuleSolution, 1 ) == 4 && permutation->getNumberOfVerticesInModule( &threeModuleSolution, 2 ) == 3 ); MITK_TEST_CONDITION_REQUIRED( correctNumberOfVertices, "Expected number of vertices per module") ToModuleMapType oneModuleSolution; oneModuleSolution.insert( std::pair( vertexInVector[ 0 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 1 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 2 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 3 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 4 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 5 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 6 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 7 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 8 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 9 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 10 ], 0 ) ); oneModuleSolution.insert( std::pair( vertexInVector[ 11 ], 0 ) ); bool oneModuleModularity( std::abs(0.0 - costFunction->CalculateModularity( network, &oneModuleSolution )) < eps); MITK_TEST_CONDITION_REQUIRED( oneModuleModularity, "Expected one module modularity") ToModuleMapType badTwoModuleSolution; badTwoModuleSolution.insert( std::pair( vertexInVector[ 0 ], 0 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 1 ], 0 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 2 ], 0 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 3 ], 0 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 4 ], 0 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 5 ], 1 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 6 ], 1 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 7 ], 1 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 8 ], 0 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 9 ], 1 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 10 ], 1 ) ); badTwoModuleSolution.insert( std::pair( vertexInVector[ 11 ], 0 ) ); bool badTwoModuleModularity( std::abs(0.097222 - costFunction->CalculateModularity( network, &badTwoModuleSolution )) < eps); MITK_TEST_CONDITION_REQUIRED( badTwoModuleModularity, "Expected bad two module modularity") ToModuleMapType noInternalLinksThreeModuleSolution; noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 0 ], 0 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 1 ], 2 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 2 ], 1 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 3 ], 0 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 4 ], 1 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 5 ], 2 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 6 ], 0 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 7 ], 0 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 8 ], 1 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 9 ], 2 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 10 ], 1 ) ); noInternalLinksThreeModuleSolution.insert( std::pair( vertexInVector[ 11 ], 0 ) ); bool noInternalThreeModuleModularity( std::abs(-0.3395 - costFunction->CalculateModularity( network, &noInternalLinksThreeModuleSolution )) < eps); MITK_TEST_CONDITION_REQUIRED( noInternalThreeModuleModularity, "Expected three module modularity containing no internal links") } catch (...) { MITK_ERROR << "Unhandled exception caught while testing modularity calculation [FAILED]" ; return EXIT_FAILURE; } // Test ends MITK_TEST_END(); } diff --git a/Modules/DiffusionImaging/Connectomics/Testing/mitkCorrelationCalculatorTest.cpp b/Modules/DiffusionImaging/Connectomics/Testing/mitkCorrelationCalculatorTest.cpp index 5994cc9922..3d77bca95e 100644 --- a/Modules/DiffusionImaging/Connectomics/Testing/mitkCorrelationCalculatorTest.cpp +++ b/Modules/DiffusionImaging/Connectomics/Testing/mitkCorrelationCalculatorTest.cpp @@ -1,294 +1,294 @@ /*=================================================================== 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. ===================================================================*/ // Testing #include "mitkTestingMacros.h" #include "mitkTestFixture.h" // std includes #include // MITK includes #include "mitkCorrelationCalculator.h" #include #include #include #include // VTK includes #include class mitkCorrelationCalculatorTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkCorrelationCalculatorTestSuite); /// \todo Fix VTK memory leaks. Bug 18097. vtkDebugLeaks::SetExitError(0); MITK_TEST(CalculateWholeCorrelation); MITK_TEST(CalculateParcelCorrelation); CPPUNIT_TEST_SUITE_END(); private: mitk::Image::Pointer m_ParcellationImage; mitk::Image::Pointer m_TimeSeriesImage; public: /** * @brief Setup Always call this method before each Test-case to ensure correct and new intialization of the used members for a new test case. (If the members are not used in a test, the method does not need to be called). */ void setUp() override { // The setup is somewhat cumbersome, due to the fact, that the mitk-itk conversion // functions do not play nicely with 4D images //create test images itk::Image::Pointer timeSeriesTestImage = itk::Image::New(); itk::Image::RegionType timeSeriesTestRegion; itk::Image::IndexType timeSeriesTestIndex; itk::Image::SizeType timeSeriesTestSize; timeSeriesTestIndex[0] = 0; timeSeriesTestIndex[1] = 0; timeSeriesTestIndex[2] = 0; timeSeriesTestIndex[3] = 0; timeSeriesTestSize[0] = 3; timeSeriesTestSize[1] = 3; timeSeriesTestSize[2] = 3; timeSeriesTestSize[3] = 10; timeSeriesTestRegion.SetIndex(timeSeriesTestIndex); timeSeriesTestRegion.SetSize(timeSeriesTestSize); timeSeriesTestImage->SetRegions(timeSeriesTestRegion); timeSeriesTestImage->Allocate(); timeSeriesTestImage->FillBuffer(0); timeSeriesTestImage->Update(); itk::Image::Pointer parcellationTestImage = itk::Image::New(); itk::Image::RegionType parcellationTestRegion; itk::Image::IndexType parcellationTestIndex; itk::Image::SizeType parcellationTestSize; parcellationTestIndex[0] = 0; parcellationTestIndex[1] = 0; parcellationTestIndex[2] = 0; parcellationTestSize[0] = 3; parcellationTestSize[1] = 3; parcellationTestSize[2] = 3; parcellationTestRegion.SetIndex(parcellationTestIndex); parcellationTestRegion.SetSize(parcellationTestSize); parcellationTestImage->SetRegions(parcellationTestRegion); parcellationTestImage->Allocate(); //Fill test images with values mitk::Image::Pointer tsTestImage = mitk::Image::New(); mitk::GrabItkImageMemory( timeSeriesTestImage, tsTestImage.GetPointer() ); mitk::Image::Pointer pTestImage = mitk::Image::New(); mitk::GrabItkImageMemory( parcellationTestImage, pTestImage.GetPointer()); //divide parcellation image into 3 different parcels for( int loop(0); loop < 27; ++loop) { itk::Image::IndexType parcellationIndex; parcellationIndex[2] = (loop / 9); parcellationIndex[1] = (loop / 3) % 3; parcellationIndex[0] = loop % 3; if(loop < 9) { parcellationTestImage->SetPixel(parcellationIndex, 1); } else if( loop < 15 || (loop > 17 && loop < 21) ) { parcellationTestImage->SetPixel(parcellationIndex, 2); } else { parcellationTestImage->SetPixel(parcellationIndex, 3); } } mitk::ImagePixelWriteAccessor writeAccess( tsTestImage ); //fill time series image with similar time series in each parcel for( int loop(0); loop < 270; ++loop) { itk::Image::IndexType timeSeriesIndex; timeSeriesIndex[3] = (loop / 27); timeSeriesIndex[2] = (loop / 9) % 3; timeSeriesIndex[1] = (loop / 3) % 3; timeSeriesIndex[0] = loop % 3; itk::Image::IndexType parcellationIndex; parcellationIndex[2] = (loop / 9) % 3; parcellationIndex[1] = (loop / 3) % 3; parcellationIndex[0] = loop % 3; if( mitk::Equal(parcellationTestImage->GetPixel(parcellationIndex), 1) ) { writeAccess.SetPixelByIndex(timeSeriesIndex, 1 + loop); } else if( mitk::Equal(parcellationTestImage->GetPixel(parcellationIndex), 2) ) { writeAccess.SetPixelByIndex(timeSeriesIndex, 1 + (loop % 13 - loop % 11) ); } else { writeAccess.SetPixelByIndex(timeSeriesIndex, 1 + ( loop - loop % 2) ); } } //end create test images m_ParcellationImage = pTestImage; m_TimeSeriesImage = tsTestImage; } void tearDown() override { m_ParcellationImage = nullptr; m_TimeSeriesImage = nullptr; } void CalculateWholeCorrelation() { mitk::CorrelationCalculator::Pointer correlationCalculator = mitk::CorrelationCalculator::New(); correlationCalculator->SetTimeSeriesImage( m_TimeSeriesImage ); correlationCalculator->DoWholeCorrelation(); const vnl_matrix< double >* cM = correlationCalculator->GetCorrelationMatrix(); bool equal(true); // instead of checking the entire 27 x 27 matrix // just check 3 values and assume if they are equal entire // matrix is likely to be equal if( std::abs((*cM)[0][0] - 1) > 0.00001 ) { equal = false; } if( std::abs((*cM)[2][10] - 0.00828941) > 0.00001 ) { equal = false; } if( std::abs((*cM)[14][8] - 0.636613) > 0.00001 ) { equal = false; } CPPUNIT_ASSERT_MESSAGE( "Comparing created and reference correlation matrix sample points.", equal ); } void CalculateParcelCorrelation() { mitk::CorrelationCalculator::Pointer correlationCalculator = mitk::CorrelationCalculator::New(); correlationCalculator->SetTimeSeriesImage( m_TimeSeriesImage ); correlationCalculator->SetParcellationImage( m_ParcellationImage ); correlationCalculator->DoParcelCorrelation(); const vnl_matrix< double >* cM = correlationCalculator->GetCorrelationMatrix(); bool equal(true); // diagonal should be 1 if( std::abs((*cM)[0][0] - 1) > 0.00001 ) { equal = false; } if( std::abs((*cM)[1][1] - 1) > 0.00001 ) { equal = false; } if( std::abs((*cM)[2][2] - 1) > 0.00001 ) { equal = false; } // parcel 0 and parcel 1 should correlate with -0.431111 if( std::abs((*cM)[1][0] - -0.431111) > 0.00001 ) { equal = false; } if( std::abs((*cM)[0][1] - -0.431111) > 0.00001 ) { equal = false; } // parcel 0 and parcel 2 should correlate with 1 if( std::abs((*cM)[0][2] - 1) > 0.00001 ) { equal = false; } if( std::abs((*cM)[2][0] - 1) > 0.00001 ) { equal = false; } // parcel 1 and parcel 2 should correlate with -0.430522 if( std::abs((*cM)[1][2] - -0.430522) > 0.00001 ) { equal = false; } if( std::abs((*cM)[2][1] - -0.430522) > 0.00001 ) { equal = false; } CPPUNIT_ASSERT_MESSAGE( "Comparing created and reference correlation matrix.", equal ); mitk::ConnectomicsNetwork::Pointer network = correlationCalculator->GetConnectomicsNetwork(); mitk::ConnectomicsNetwork::Pointer refNetwork = mitk::ConnectomicsNetwork::New(); mitk::ConnectomicsNetwork::VertexDescriptorType x = refNetwork->AddVertex( 1 ); mitk::ConnectomicsNetwork::VertexDescriptorType y = refNetwork->AddVertex( 2 ); mitk::ConnectomicsNetwork::VertexDescriptorType z = refNetwork->AddVertex( 3 ); - refNetwork->AddEdge(x,y); - refNetwork->AddEdge(x,z); - refNetwork->AddEdge(y,z); + refNetwork->AddEdge(x,y,1); + refNetwork->AddEdge(x,z,1); + refNetwork->AddEdge(y,z,1); CPPUNIT_ASSERT_MESSAGE( "Comparing created and reference network.", mitk::Equal( network.GetPointer(), refNetwork, mitk::eps, true) ); // check sample parcels for other methods correlationCalculator->DoParcelCorrelation( mitk::CorrelationCalculator::UseAverageCorrelation ); cM = correlationCalculator->GetCorrelationMatrix(); // parcel 0 and parcel 1 should correlate with -0.0643023 equal = true; if( std::abs((*cM)[1][0] - -0.0643023) > 0.00001 ) { equal = false; } // parcel 0 and parcel 2 should correlate with 0.99998 if( std::abs((*cM)[2][0] - 0.99998) > 0.00001 ) { equal = false; } CPPUNIT_ASSERT_MESSAGE( "Comparing sample parcel correlation for average correlation.", equal ); correlationCalculator->DoParcelCorrelation( mitk::CorrelationCalculator::UseMaximumCorrelation ); cM = correlationCalculator->GetCorrelationMatrix(); // parcel 0 and parcel 1 should correlate with 0.636613 equal = true; if( std::abs((*cM)[1][0] - 0.636613) > 0.00001 ) { equal = false; } // parcel 0 and parcel 2 should correlate with 0.99998 if( std::abs((*cM)[2][0] - 0.99998) > 0.00001 ) { equal = false; } CPPUNIT_ASSERT_MESSAGE( "Comparing sample parcel correlation for maximum correlation.", equal ); } }; MITK_TEST_SUITE_REGISTRATION(mitkCorrelationCalculator) diff --git a/Modules/DiffusionImaging/Connectomics/cmdapps/NetworkCreation.cpp b/Modules/DiffusionImaging/Connectomics/cmdapps/NetworkCreation.cpp index ff18241008..8c00a19f6f 100644 --- a/Modules/DiffusionImaging/Connectomics/cmdapps/NetworkCreation.cpp +++ b/Modules/DiffusionImaging/Connectomics/cmdapps/NetworkCreation.cpp @@ -1,133 +1,119 @@ /*=================================================================== 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. ===================================================================*/ // std includes #include // CTK includes #include "mitkCommandLineParser.h" // MITK includes #include "mitkConnectomicsNetworkCreator.h" #include #include int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Network Creation"); parser.setCategory("Connectomics"); parser.setDescription(""); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); - parser.addArgument("fiberImage", "f", mitkCommandLineParser::InputFile, "Input image", "input fiber image (.fib)", us::Any(), false); - parser.addArgument("parcellation", "p", mitkCommandLineParser::InputFile, "Parcellation image", "parcellation image", us::Any(), false); - parser.addArgument("outputNetwork", "o", mitkCommandLineParser::String, "Output network", "where to save the output (.cnf)", us::Any(), false); + parser.addArgument("", "f", mitkCommandLineParser::InputFile, "Input Tractogram", "input tractogram (.fib)", us::Any(), false); + parser.addArgument("", "p", mitkCommandLineParser::InputFile, "Parcellation", "parcellation image", us::Any(), false); + parser.addArgument("", "o", mitkCommandLineParser::String, "Output network", "where to save the output (.cnf, .mat)", us::Any(), false); - parser.addArgument("radius", "r", mitkCommandLineParser::Int, "Radius", "Search radius in mm", 15, true); - parser.addArgument("noCenterOfMass", "com", mitkCommandLineParser::Bool, "No center of mass", "Do not use center of mass for node positions"); + parser.addArgument("noCenterOfMass", "", mitkCommandLineParser::Bool, "No center of mass", "Do not use center of mass for node positions"); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; //default values - int searchRadius( 15 ); bool noCenterOfMass( false ); // parse command line arguments - std::string fiberFilename = us::any_cast(parsedArgs["fiberImage"]); - std::string parcellationFilename = us::any_cast(parsedArgs["parcellation"]); - std::string outputFilename = us::any_cast(parsedArgs["outputNetwork"]); - - if (parsedArgs.count("radius")) - searchRadius = us::any_cast(parsedArgs["radius"]); - + std::string fiberFilename = us::any_cast(parsedArgs["f"]); + std::string parcellationFilename = us::any_cast(parsedArgs["p"]); + std::string outputFilename = us::any_cast(parsedArgs["o"]); if (parsedArgs.count("noCenterOfMass")) noCenterOfMass = us::any_cast(parsedArgs["noCenterOfMass"]); try { - - const std::string s1="", s2=""; - // load fiber image - std::vector fiberInfile = - mitk::IOUtil::Load( fiberFilename); + std::vector fiberInfile = mitk::IOUtil::Load( fiberFilename); + if( fiberInfile.empty() ) { std::string errorMessage = "Fiber Image at " + fiberFilename + " could not be read. Aborting."; MITK_ERROR << errorMessage; return EXIT_FAILURE; } mitk::BaseData* fiberBaseData = fiberInfile.at(0); mitk::FiberBundle* fiberBundle = dynamic_cast( fiberBaseData ); // load parcellation std::vector parcellationInFile = mitk::IOUtil::Load( parcellationFilename); if( parcellationInFile.empty() ) { std::string errorMessage = "Parcellation at " + parcellationFilename + " could not be read. Aborting."; MITK_ERROR << errorMessage; return EXIT_FAILURE; } mitk::BaseData* parcellationBaseData = parcellationInFile.at(0); mitk::Image* parcellationImage = dynamic_cast( parcellationBaseData ); - - // do creation mitk::ConnectomicsNetworkCreator::Pointer connectomicsNetworkCreator = mitk::ConnectomicsNetworkCreator::New(); connectomicsNetworkCreator->SetSegmentation( parcellationImage ); connectomicsNetworkCreator->SetFiberBundle( fiberBundle ); if( !noCenterOfMass ) { connectomicsNetworkCreator->CalculateCenterOfMass(); } - connectomicsNetworkCreator->SetEndPointSearchRadius( searchRadius ); + connectomicsNetworkCreator->SetMappingStrategy(mitk::ConnectomicsNetworkCreator::MappingStrategy::EndElementPosition); connectomicsNetworkCreator->CreateNetworkFromFibersAndSegmentation(); mitk::ConnectomicsNetwork::Pointer network = connectomicsNetworkCreator->GetNetwork(); - - std::cout << "searching writer"; - mitk::IOUtil::Save(network.GetPointer(), outputFilename ); return EXIT_SUCCESS; } 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; } std::cout << "DONE"; return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/Connectomics/cmdapps/NetworkStatistics.cpp b/Modules/DiffusionImaging/Connectomics/cmdapps/NetworkStatistics.cpp index b0322fde98..c43f90b2ed 100644 --- a/Modules/DiffusionImaging/Connectomics/cmdapps/NetworkStatistics.cpp +++ b/Modules/DiffusionImaging/Connectomics/cmdapps/NetworkStatistics.cpp @@ -1,568 +1,568 @@ /*=================================================================== 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. ===================================================================*/ // std includes #include #include #include #include #include #include // boost includes #include // ITK includes #include // CTK includes #include "mitkCommandLineParser.h" // MITK includes #include #include #include #include int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Network Creation"); parser.setCategory("Connectomics"); parser.setDescription(""); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("inputNetwork", "i", mitkCommandLineParser::InputFile, "Input network", "input connectomics network (.cnf)", us::Any(), false); parser.addArgument("outputFile", "o", mitkCommandLineParser::OutputFile, "Output file", "name of output file", us::Any(), false); parser.addArgument("noGlobalStatistics", "g", mitkCommandLineParser::Bool, "No global statistics", "Do not calculate global statistics"); parser.addArgument("createConnectivityMatriximage", "I", mitkCommandLineParser::Bool, "Write connectivity matrix image", "Write connectivity matrix image"); parser.addArgument("binaryConnectivity", "b", mitkCommandLineParser::Bool, "Binary connectivity", "Whether to create a binary connectivity matrix"); parser.addArgument("rescaleConnectivity", "r", mitkCommandLineParser::Bool, "Rescale connectivity", "Whether to rescale the connectivity matrix"); parser.addArgument("localStatistics", "L", mitkCommandLineParser::StringList, "Local statistics", "Provide a list of node labels for local statistics", us::Any()); parser.addArgument("regionList", "R", mitkCommandLineParser::StringList, "Region list", "A space separated list of regions. Each region has the format\n regionname;label1;label2;...;labelN", us::Any()); parser.addArgument("granularity", "gr", mitkCommandLineParser::Int, "Granularity", "How finely to test the density range and how many thresholds to consider",1); parser.addArgument("startDensity", "d", mitkCommandLineParser::Float, "Start Density", "Largest density for the range",1.0); parser.addArgument("thresholdStepSize", "t", mitkCommandLineParser::Int, "Step size threshold", "Distance of two adjacent thresholds",3); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; //default values bool noGlobalStatistics( false ); bool binaryConnectivity( false ); bool rescaleConnectivity( false ); bool createConnectivityMatriximage( false ); int granularity( 1 ); double startDensity( 1.0 ); int thresholdStepSize( 3 ); // parse command line arguments std::string networkName = us::any_cast(parsedArgs["inputNetwork"]); std::string outName = us::any_cast(parsedArgs["outputFile"]); mitkCommandLineParser::StringContainerType localLabels; if(parsedArgs.count("localStatistics")) { localLabels = us::any_cast(parsedArgs["localStatistics"]); } mitkCommandLineParser::StringContainerType unparsedRegions; std::map< std::string, std::vector > parsedRegions; std::map< std::string, std::vector >::iterator parsedRegionsIterator; if(parsedArgs.count("regionList")) { unparsedRegions = us::any_cast(parsedArgs["regionList"]); for(unsigned int index(0); index < unparsedRegions.size(); index++ ) { std::vector< std::string > tempRegionVector; boost::split(tempRegionVector, unparsedRegions.at(index), boost::is_any_of(";")); std::vector< std::string >::const_iterator begin = tempRegionVector.begin(); std::vector< std::string >::const_iterator last = tempRegionVector.begin() + tempRegionVector.size(); std::vector< std::string > insertRegionVector(begin + 1, last); if( parsedRegions.count( tempRegionVector.at(0) ) == 0 ) { parsedRegions.insert( std::pair< std::string, std::vector >( tempRegionVector.at(0), insertRegionVector) ); } else { MITK_ERROR << "Region already exists. Skipping second occurrence."; } } } if (parsedArgs.count("noGlobalStatistics")) noGlobalStatistics = us::any_cast(parsedArgs["noGlobalStatistics"]); if (parsedArgs.count("binaryConnectivity")) binaryConnectivity = us::any_cast(parsedArgs["binaryConnectivity"]); if (parsedArgs.count("rescaleConnectivity")) rescaleConnectivity = us::any_cast(parsedArgs["rescaleConnectivity"]); if (parsedArgs.count("createConnectivityMatriximage")) createConnectivityMatriximage = us::any_cast(parsedArgs["createConnectivityMatriximage"]); if (parsedArgs.count("granularity")) granularity = us::any_cast(parsedArgs["granularity"]); if (parsedArgs.count("startDensity")) startDensity = us::any_cast(parsedArgs["startDensity"]); if (parsedArgs.count("thresholdStepSize")) thresholdStepSize = us::any_cast(parsedArgs["thresholdStepSize"]); try { // load network std::vector networkFile = mitk::IOUtil::Load( networkName); if( networkFile.empty() ) { std::string errorMessage = "File at " + networkName + " could not be read. Aborting."; MITK_ERROR << errorMessage; return EXIT_FAILURE; } mitk::BaseData* networkBaseData = networkFile.at(0); mitk::ConnectomicsNetwork* network = dynamic_cast( networkBaseData ); if( !network ) { std::string errorMessage = "Read file at " + networkName + " could not be recognized as network. Aborting."; MITK_ERROR << errorMessage; return EXIT_FAILURE; } // streams std::stringstream globalHeaderStream; globalHeaderStream << "NumberOfVertices " << "NumberOfEdges " << "AverageDegree " << "ConnectionDensity " << "NumberOfConnectedComponents " << "AverageComponentSize " << "LargestComponentSize " << "RatioOfNodesInLargestComponent " << "HopPlotExponent " << "EffectiveHopDiameter " << "AverageClusteringCoefficientsC " << "AverageClusteringCoefficientsD " << "AverageClusteringCoefficientsE " << "AverageVertexBetweennessCentrality " << "AverageEdgeBetweennessCentrality " << "NumberOfIsolatedPoints " << "RatioOfIsolatedPoints " << "NumberOfEndPoints " << "RatioOfEndPoints " << "Diameter " << "Diameter90 " << "Radius " << "Radius90 " << "AverageEccentricity " << "AverageEccentricity90 " << "AveragePathLength " << "NumberOfCentralPoints " << "RatioOfCentralPoints " << "SpectralRadius " << "SecondLargestEigenValue " << "AdjacencyTrace " << "AdjacencyEnergy " << "LaplacianTrace " << "LaplacianEnergy " << "LaplacianSpectralGap " << "NormalizedLaplacianTrace " << "NormalizedLaplacianEnergy " << "NormalizedLaplacianNumberOf2s " << "NormalizedLaplacianNumberOf1s " << "NormalizedLaplacianNumberOf0s " << "NormalizedLaplacianLowerSlope " << "NormalizedLaplacianUpperSlope " << "SmallWorldness" << std::endl; std::stringstream localHeaderStream; std::stringstream regionalHeaderStream; std::stringstream globalDataStream; std::stringstream localDataStream; std::stringstream regionalDataStream; std::string globalOutName = outName + "_global.txt"; std::string localOutName = outName + "_local.txt"; std::string regionalOutName = outName + "_regional.txt"; bool firstRun( true ); // iterate over all three possible methods for(unsigned int method( 0 ); method < 3; method++) { // 0 - Random removal threshold // 1 - Largest density below threshold // 2 - Threshold based // iterate over possible targets for( int step = 0; step < granularity; ++step ) { double targetValue( 0.0 ); switch ( method ) { case mitk::ConnectomicsNetworkThresholder::RandomRemovalOfWeakest : case mitk::ConnectomicsNetworkThresholder::LargestLowerThanDensity : targetValue = startDensity * (1 - static_cast( step ) / ( granularity + 0.5 ) ); break; case mitk::ConnectomicsNetworkThresholder::ThresholdBased : targetValue = static_cast( thresholdStepSize * step ); break; default: MITK_ERROR << "Invalid thresholding method called, aborting."; return EXIT_FAILURE; break; } mitk::ConnectomicsNetworkThresholder::Pointer thresholder = mitk::ConnectomicsNetworkThresholder::New(); thresholder->SetNetwork( network ); thresholder->SetTargetThreshold( targetValue ); thresholder->SetTargetDensity( targetValue ); thresholder->SetThresholdingScheme( static_cast(method) ); mitk::ConnectomicsNetwork::Pointer thresholdedNetwork = thresholder->GetThresholdedNetwork(); mitk::ConnectomicsStatisticsCalculator::Pointer statisticsCalculator = mitk::ConnectomicsStatisticsCalculator::New(); statisticsCalculator->SetNetwork( thresholdedNetwork ); statisticsCalculator->Update(); // global statistics if( !noGlobalStatistics ) { globalDataStream << statisticsCalculator->GetNumberOfVertices() << " " << statisticsCalculator->GetNumberOfEdges() << " " << statisticsCalculator->GetAverageDegree() << " " << statisticsCalculator->GetConnectionDensity() << " " << statisticsCalculator->GetNumberOfConnectedComponents() << " " << statisticsCalculator->GetAverageComponentSize() << " " << statisticsCalculator->GetLargestComponentSize() << " " << statisticsCalculator->GetRatioOfNodesInLargestComponent() << " " << statisticsCalculator->GetHopPlotExponent() << " " << statisticsCalculator->GetEffectiveHopDiameter() << " " << statisticsCalculator->GetAverageClusteringCoefficientsC() << " " << statisticsCalculator->GetAverageClusteringCoefficientsD() << " " << statisticsCalculator->GetAverageClusteringCoefficientsE() << " " << statisticsCalculator->GetAverageVertexBetweennessCentrality() << " " << statisticsCalculator->GetAverageEdgeBetweennessCentrality() << " " << statisticsCalculator->GetNumberOfIsolatedPoints() << " " << statisticsCalculator->GetRatioOfIsolatedPoints() << " " << statisticsCalculator->GetNumberOfEndPoints() << " " << statisticsCalculator->GetRatioOfEndPoints() << " " << statisticsCalculator->GetDiameter() << " " << statisticsCalculator->GetDiameter90() << " " << statisticsCalculator->GetRadius() << " " << statisticsCalculator->GetRadius90() << " " << statisticsCalculator->GetAverageEccentricity() << " " << statisticsCalculator->GetAverageEccentricity90() << " " << statisticsCalculator->GetAveragePathLength() << " " << statisticsCalculator->GetNumberOfCentralPoints() << " " << statisticsCalculator->GetRatioOfCentralPoints() << " " << statisticsCalculator->GetSpectralRadius() << " " << statisticsCalculator->GetSecondLargestEigenValue() << " " << statisticsCalculator->GetAdjacencyTrace() << " " << statisticsCalculator->GetAdjacencyEnergy() << " " << statisticsCalculator->GetLaplacianTrace() << " " << statisticsCalculator->GetLaplacianEnergy() << " " << statisticsCalculator->GetLaplacianSpectralGap() << " " << statisticsCalculator->GetNormalizedLaplacianTrace() << " " << statisticsCalculator->GetNormalizedLaplacianEnergy() << " " << statisticsCalculator->GetNormalizedLaplacianNumberOf2s() << " " << statisticsCalculator->GetNormalizedLaplacianNumberOf1s() << " " << statisticsCalculator->GetNormalizedLaplacianNumberOf0s() << " " << statisticsCalculator->GetNormalizedLaplacianLowerSlope() << " " << statisticsCalculator->GetNormalizedLaplacianUpperSlope() << " " << statisticsCalculator->GetSmallWorldness() << std::endl; } // end global statistics //create connectivity matrix png if( createConnectivityMatriximage ) { std::string connectivity_png_postfix = "_connectivity"; if( binaryConnectivity ) { connectivity_png_postfix += "_binary"; } else if( rescaleConnectivity ) { connectivity_png_postfix += "_rescaled"; } connectivity_png_postfix += ".png"; /* File format * A png file depicting the binary connectivity matrix */ itk::ConnectomicsNetworkToConnectivityMatrixImageFilter::Pointer filter = itk::ConnectomicsNetworkToConnectivityMatrixImageFilter::New(); filter->SetInputNetwork( network ); filter->SetBinaryConnectivity( binaryConnectivity ); filter->SetRescaleConnectivity( rescaleConnectivity ); filter->Update(); typedef itk::ConnectomicsNetworkToConnectivityMatrixImageFilter::OutputImageType connectivityMatrixImageType; itk::ImageFileWriter< connectivityMatrixImageType >::Pointer connectivityWriter = itk::ImageFileWriter< connectivityMatrixImageType >::New(); connectivityWriter->SetInput( filter->GetOutput() ); connectivityWriter->SetFileName( outName + connectivity_png_postfix); connectivityWriter->Update(); std::cout << "Connectivity matrix image written."; } // end create connectivity matrix png /* * We can either calculate local indices for specific nodes, or specific regions */ // Create LabelToIndex translation std::map< std::string, int > labelToIdMap; std::vector< mitk::ConnectomicsNetwork::NetworkNode > nodeVector = thresholdedNetwork->GetVectorOfAllNodes(); for(std::size_t loop(0); loop < nodeVector.size(); loop++) { labelToIdMap.insert( std::pair< std::string, int>(nodeVector.at(loop).label, nodeVector.at(loop).id) ); } std::vector< int > degreeVector = thresholdedNetwork->GetDegreeOfNodes(); std::vector< double > ccVector = thresholdedNetwork->GetLocalClusteringCoefficients( ); std::vector< double > bcVector = thresholdedNetwork->GetNodeBetweennessVector( ); // calculate local indices { // only add to header for the first step of the first method if( firstRun ) { localHeaderStream << "Th_method " << "Th_target " << "density"; } double density = statisticsCalculator->GetConnectionDensity(); localDataStream << "\n" << method << " " << targetValue << " " << density; for(unsigned int loop(0); loop < localLabels.size(); loop++ ) { if( network->CheckForLabel(localLabels.at( loop )) ) { if( firstRun ) { localHeaderStream << " " << localLabels.at( loop ) << "_Degree " << localLabels.at( loop ) << "_CC " << localLabels.at( loop ) << "_BC"; } localDataStream << " " << degreeVector.at( labelToIdMap.find( localLabels.at( loop ) )->second ) << " " << ccVector.at( labelToIdMap.find( localLabels.at( loop ) )->second ) << " " << bcVector.at( labelToIdMap.find( localLabels.at( loop ) )->second ); } else { MITK_ERROR << "Illegal label. Label: \"" << localLabels.at( loop ) << "\" not found."; } } } // calculate regional indices { // only add to header for the first step of the first method if( firstRun ) { regionalHeaderStream << "Th_method " << "Th_target " << "density"; } double density = statisticsCalculator->GetConnectionDensity(); regionalDataStream << "\n" << method << " " << targetValue << " " << density; for( parsedRegionsIterator = parsedRegions.begin(); parsedRegionsIterator != parsedRegions.end(); parsedRegionsIterator++ ) { std::vector regionLabelsVector = parsedRegionsIterator->second; std::string regionName = parsedRegionsIterator->first; double sumDegree( 0 ); double sumCC( 0 ); double sumBC( 0 ); double count( 0 ); for( std::size_t loop(0); loop < regionLabelsVector.size(); loop++ ) { if( thresholdedNetwork->CheckForLabel(regionLabelsVector.at( loop )) ) { sumDegree = sumDegree + degreeVector.at( labelToIdMap.find( regionLabelsVector.at( loop ) )->second ); sumCC = sumCC + ccVector.at( labelToIdMap.find( regionLabelsVector.at( loop ) )->second ); sumBC = sumBC + bcVector.at( labelToIdMap.find( regionLabelsVector.at( loop ) )->second ); count = count + 1; } else { MITK_ERROR << "Illegal label. Label: \"" << regionLabelsVector.at( loop ) << "\" not found."; } } // only add to header for the first step of the first method if( firstRun ) { regionalHeaderStream << " " << regionName << "_LocalAverageDegree " << regionName << "_LocalAverageCC " << regionName << "_LocalAverageBC " << regionName << "_NumberOfNodes"; } regionalDataStream << " " << sumDegree / count << " " << sumCC / count << " " << sumBC / count << " " << count; // count number of connections and fibers between regions std::map< std::string, std::vector >::iterator loopRegionsIterator; for (loopRegionsIterator = parsedRegionsIterator; loopRegionsIterator != parsedRegions.end(); loopRegionsIterator++) { int numberConnections(0), possibleConnections(0); double summedFiberCount(0.0); std::vector loopLabelsVector = loopRegionsIterator->second; std::string loopName = loopRegionsIterator->first; for (std::size_t loop(0); loop < regionLabelsVector.size(); loop++) { if (thresholdedNetwork->CheckForLabel(regionLabelsVector.at(loop))) { for (std::size_t innerLoop(0); innerLoop < loopLabelsVector.size(); innerLoop++) { if (thresholdedNetwork->CheckForLabel(loopLabelsVector.at(loop))) { bool exists = thresholdedNetwork->EdgeExists( labelToIdMap.find(regionLabelsVector.at(loop))->second, labelToIdMap.find(loopLabelsVector.at(innerLoop))->second); possibleConnections++; if (exists) { numberConnections++; summedFiberCount += thresholdedNetwork->GetEdge( labelToIdMap.find(regionLabelsVector.at(loop))->second, - labelToIdMap.find(loopLabelsVector.at(innerLoop))->second).weight; + labelToIdMap.find(loopLabelsVector.at(innerLoop))->second).fiber_count; } } else { MITK_ERROR << "Illegal label. Label: \"" << loopLabelsVector.at(loop) << "\" not found."; } } } else { MITK_ERROR << "Illegal label. Label: \"" << regionLabelsVector.at(loop) << "\" not found."; } } if (firstRun) { regionalHeaderStream << " " << regionName << "_" << loopName << "_Connections " << " " << regionName << "_" << loopName << "_possibleConnections " << " " << regionName << "_" << loopName << "_ConnectingFibers"; } regionalDataStream << " " << numberConnections << " " << possibleConnections << " " << summedFiberCount; } } } firstRun = false; } }// end calculate local averages if( !noGlobalStatistics ) { std::cout << "Writing to " << globalOutName; std::ofstream glocalOutFile( globalOutName.c_str(), ios::out ); if( ! glocalOutFile.is_open() ) { std::string errorMessage = "Could not open " + globalOutName + " for writing."; MITK_ERROR << errorMessage; return EXIT_FAILURE; } glocalOutFile << globalHeaderStream.str() << globalDataStream.str(); glocalOutFile.close(); } if( localLabels.size() > 0 ) { std::cout << "Writing to " << localOutName; std::ofstream localOutFile( localOutName.c_str(), ios::out ); if( ! localOutFile.is_open() ) { std::string errorMessage = "Could not open " + localOutName + " for writing."; MITK_ERROR << errorMessage; return EXIT_FAILURE; } localOutFile << localHeaderStream.str() << localDataStream.str(); localOutFile.close(); } if( parsedRegions.size() > 0 ) { std::cout << "Writing to " << regionalOutName; std::ofstream regionalOutFile( regionalOutName.c_str(), ios::out ); if( ! regionalOutFile.is_open() ) { std::string errorMessage = "Could not open " + regionalOutName + " for writing."; MITK_ERROR << errorMessage; return EXIT_FAILURE; } regionalOutFile << regionalHeaderStream.str() << regionalDataStream.str(); regionalOutFile.close(); } return EXIT_SUCCESS; } 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; } std::cout << "DONE"; return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOMimeTypes.cpp b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOMimeTypes.cpp index b05a53cc8d..2f8fd6eeb3 100644 --- a/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOMimeTypes.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkDiffusionCoreIOMimeTypes.cpp @@ -1,515 +1,517 @@ /*=================================================================== 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 "mitkDiffusionCoreIOMimeTypes.h" #include "mitkIOMimeTypes.h" #include #include #include #include #include #include #include #include #include namespace mitk { std::vector DiffusionCoreIOMimeTypes::Get() { std::vector mimeTypes; // order matters here (descending rank for mime types) mimeTypes.push_back(DWI_NRRD_MIMETYPE().Clone()); mimeTypes.push_back(DWI_NIFTI_MIMETYPE().Clone()); mimeTypes.push_back(DWI_FSL_MIMETYPE().Clone()); mimeTypes.push_back(DWI_DICOM_MIMETYPE().Clone()); mimeTypes.push_back(DTI_MIMETYPE().Clone()); mimeTypes.push_back(ODF_MIMETYPE().Clone()); mimeTypes.push_back(PEAK_MIMETYPE().Clone()); return mimeTypes; } // Mime Types DiffusionCoreIOMimeTypes::DiffusionImageNrrdMimeType::DiffusionImageNrrdMimeType() : CustomMimeType(DWI_NRRD_MIMETYPE_NAME()) { std::string category = "Diffusion Weighted Images"; this->SetCategory(category); this->SetComment("Diffusion Weighted Images"); this->AddExtension("dwi"); //this->AddExtension("hdwi"); // saving with detached header does not work out of the box this->AddExtension("nrrd"); } bool DiffusionCoreIOMimeTypes::DiffusionImageNrrdMimeType::AppliesTo(const std::string &path) const { bool canRead( CustomMimeType::AppliesTo(path) ); // fix for bug 18572 // Currently this function is called for writing as well as reading, in that case // the image information can of course not be read // This is a bug, this function should only be called for reading. if( ! itksys::SystemTools::FileExists( path.c_str() ) ) { return canRead; } //end fix for bug 18572 std::string ext = this->GetExtension( path ); ext = itksys::SystemTools::LowerCase( ext ); // Simple NRRD files should only be considered for this mime type if they contain // corresponding tags if( ext == ".nrrd" ) { itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); io->SetFileName(path); try { io->ReadImageInformation(); itk::MetaDataDictionary imgMetaDictionary = io->GetMetaDataDictionary(); std::vector imgMetaKeys = imgMetaDictionary.GetKeys(); std::vector::const_iterator itKey = imgMetaKeys.begin(); std::string metaString; for (; itKey != imgMetaKeys.end(); itKey ++) { itk::ExposeMetaData (imgMetaDictionary, *itKey, metaString); if (itKey->find("modality") != std::string::npos) { if (metaString.find("DWMRI") != std::string::npos) { return canRead; } } } } catch( const itk::ExceptionObject &e ) { MITK_ERROR << "ITK Exception: " << e.what(); } canRead = false; } return canRead; } DiffusionCoreIOMimeTypes::DiffusionImageNrrdMimeType* DiffusionCoreIOMimeTypes::DiffusionImageNrrdMimeType::Clone() const { return new DiffusionImageNrrdMimeType(*this); } DiffusionCoreIOMimeTypes::DiffusionImageNrrdMimeType DiffusionCoreIOMimeTypes::DWI_NRRD_MIMETYPE() { return DiffusionImageNrrdMimeType(); } DiffusionCoreIOMimeTypes::DiffusionImageNiftiMimeType::DiffusionImageNiftiMimeType() : CustomMimeType(DWI_NIFTI_MIMETYPE_NAME()) { std::string category = "Diffusion Weighted Images"; this->SetCategory(category); this->SetComment("Diffusion Weighted Images"); this->AddExtension("nii.gz"); this->AddExtension("nii"); } bool DiffusionCoreIOMimeTypes::DiffusionImageNiftiMimeType::AppliesTo(const std::string &path) const { bool canRead(CustomMimeType::AppliesTo(path)); // fix for bug 18572 // Currently this function is called for writing as well as reading, in that case // the image information can of course not be read // This is a bug, this function should only be called for reading. if (!itksys::SystemTools::FileExists(path.c_str())) { return canRead; } //end fix for bug 18572 std::string ext = this->GetExtension(path); ext = itksys::SystemTools::LowerCase(ext); // Nifti files should only be considered for this mime type if they are // accompanied by bvecs and bvals files defining the diffusion information if (ext == ".nii" || ext == ".nii.gz") { std::string base_path = itksys::SystemTools::GetFilenamePath(path); std::string base = this->GetFilenameWithoutExtension(path); std::string filename = base; if (!base_path.empty()) { base = base_path + "/" + base; base_path += "/"; } if (itksys::SystemTools::FileExists(std::string(base + ".bvec").c_str()) && itksys::SystemTools::FileExists(std::string(base + ".bval").c_str()) ) { return canRead; } if (itksys::SystemTools::FileExists(std::string(base + ".bvecs").c_str()) && itksys::SystemTools::FileExists(std::string(base + ".bvals").c_str()) ) { return canRead; } // hack for HCP data if ( filename=="data" && itksys::SystemTools::FileExists(std::string(base_path + "bvec").c_str()) && itksys::SystemTools::FileExists(std::string(base_path + "bval").c_str()) ) { return canRead; } if ( filename=="data" && itksys::SystemTools::FileExists(std::string(base_path + "bvecs").c_str()) && itksys::SystemTools::FileExists(std::string(base_path + "bvals").c_str()) ) { return canRead; } canRead = false; } return canRead; } DiffusionCoreIOMimeTypes::DiffusionImageNiftiMimeType* DiffusionCoreIOMimeTypes::DiffusionImageNiftiMimeType::Clone() const { return new DiffusionImageNiftiMimeType(*this); } DiffusionCoreIOMimeTypes::DiffusionImageNiftiMimeType DiffusionCoreIOMimeTypes::DWI_NIFTI_MIMETYPE() { return DiffusionImageNiftiMimeType(); } DiffusionCoreIOMimeTypes::DiffusionImageFslMimeType::DiffusionImageFslMimeType() : CustomMimeType(DWI_FSL_MIMETYPE_NAME()) { std::string category = "Diffusion Weighted Image"; this->SetCategory(category); this->SetComment("Diffusion Weighted Images"); this->AddExtension("fslgz"); this->AddExtension("fsl"); } bool DiffusionCoreIOMimeTypes::DiffusionImageFslMimeType::AppliesTo(const std::string &path) const { bool canRead(CustomMimeType::AppliesTo(path)); // fix for bug 18572 // Currently this function is called for writing as well as reading, in that case // the image information can of course not be read // This is a bug, this function should only be called for reading. if (!itksys::SystemTools::FileExists(path.c_str())) { return canRead; } //end fix for bug 18572 std::string ext = this->GetExtension(path); ext = itksys::SystemTools::LowerCase(ext); // Nifti files should only be considered for this mime type if they are // accompanied by bvecs and bvals files defining the diffusion information if (ext == ".fsl" || ext == ".fslgz") { std::string base_path = itksys::SystemTools::GetFilenamePath(path); std::string base = this->GetFilenameWithoutExtension(path); if (!base_path.empty()) base = base_path + "/" + base; if (itksys::SystemTools::FileExists(std::string(base + ".bvec").c_str()) && itksys::SystemTools::FileExists(std::string(base + ".bval").c_str()) ) { return canRead; } if (itksys::SystemTools::FileExists(std::string(base + ".bvecs").c_str()) && itksys::SystemTools::FileExists(std::string(base + ".bvals").c_str()) ) { return canRead; } if (itksys::SystemTools::FileExists(std::string(base + ext + ".bvec").c_str()) && itksys::SystemTools::FileExists(std::string(base + ext + ".bval").c_str()) ) { return canRead; } if (itksys::SystemTools::FileExists(std::string(base + ext + ".bvecs").c_str()) && itksys::SystemTools::FileExists(std::string(base + ext + ".bvals").c_str()) ) { return canRead; } canRead = false; } return canRead; } DiffusionCoreIOMimeTypes::DiffusionImageFslMimeType* DiffusionCoreIOMimeTypes::DiffusionImageFslMimeType::Clone() const { return new DiffusionImageFslMimeType(*this); } DiffusionCoreIOMimeTypes::DiffusionImageFslMimeType DiffusionCoreIOMimeTypes::DWI_FSL_MIMETYPE() { return DiffusionImageFslMimeType(); } DiffusionCoreIOMimeTypes::DiffusionImageDicomMimeType::DiffusionImageDicomMimeType() : CustomMimeType(DWI_DICOM_MIMETYPE_NAME()) { std::string category = "Diffusion Weighted Images"; this->SetCategory(category); this->SetComment("Diffusion Weighted Images"); this->AddExtension("gdcm"); this->AddExtension("dcm"); this->AddExtension("DCM"); this->AddExtension("dc3"); this->AddExtension("DC3"); this->AddExtension("ima"); this->AddExtension("img"); } bool DiffusionCoreIOMimeTypes::DiffusionImageDicomMimeType::AppliesTo(const std::string &path) const { itk::GDCMImageIO::Pointer gdcmIO = itk::GDCMImageIO::New(); bool canRead = gdcmIO->CanReadFile(path.c_str()); if (!canRead) return canRead; mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New(); mitk::DICOMTag ImageTypeTag(0x0008, 0x0008); + mitk::DICOMTag SeriesDescriptionTag(0x0008, 0x103E); mitk::StringList relevantFiles; relevantFiles.push_back(path); scanner->AddTag(ImageTypeTag); + scanner->AddTag(SeriesDescriptionTag); scanner->SetInputFiles(relevantFiles); scanner->Scan(); mitk::DICOMTagCache::Pointer tagCache = scanner->GetScanCache(); mitk::DICOMImageFrameList imageFrameList = mitk::ConvertToDICOMImageFrameList(tagCache->GetFrameInfoList()); mitk::DICOMImageFrameInfo *firstFrame = imageFrameList.begin()->GetPointer(); std::string byteString = tagCache->GetTagValue(firstFrame, ImageTypeTag).value; - - if (byteString.empty()) { + if (byteString.empty()) return false; - } - std::size_t found = byteString.find("DIFFUSION"); - if (found==std::string::npos) + std::string byteString2 = tagCache->GetTagValue(firstFrame, SeriesDescriptionTag).value; + if (byteString2.empty()) return false; - found = byteString.find("NONE"); - if (found==std::string::npos) + + if (byteString.find("DIFFUSION")==std::string::npos && byteString2.find("diff")==std::string::npos) return false; +// if (byteString.find("NONE")==std::string::npos) +// return false; return canRead; } DiffusionCoreIOMimeTypes::DiffusionImageDicomMimeType* DiffusionCoreIOMimeTypes::DiffusionImageDicomMimeType::Clone() const { return new DiffusionImageDicomMimeType(*this); } DiffusionCoreIOMimeTypes::DiffusionImageDicomMimeType DiffusionCoreIOMimeTypes::DWI_DICOM_MIMETYPE() { return DiffusionImageDicomMimeType(); } DiffusionCoreIOMimeTypes::PeakImageMimeType::PeakImageMimeType() : CustomMimeType(PEAK_MIMETYPE_NAME()) { std::string category = "Peak Image"; this->SetCategory(category); this->SetComment("Peak Image"); this->AddExtension("nrrd"); this->AddExtension("nii"); this->AddExtension("nii.gz"); } bool DiffusionCoreIOMimeTypes::PeakImageMimeType::AppliesTo(const std::string &path) const { { itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); if ( io->CanReadFile( path.c_str() ) ) { io->SetFileName( path.c_str() ); io->ReadImageInformation(); if ( io->GetPixelType() == itk::ImageIOBase::SCALAR && io->GetNumberOfDimensions()==4 && io->GetDimensions(3)%3==0) return true; } } { itk::NiftiImageIO::Pointer io = itk::NiftiImageIO::New(); if ( io->CanReadFile( path.c_str() ) ) { io->SetFileName( path.c_str() ); io->ReadImageInformation(); if ( io->GetPixelType() == itk::ImageIOBase::SCALAR && io->GetNumberOfDimensions()==4 && io->GetDimensions(3)%3==0) return true; } } return false; } DiffusionCoreIOMimeTypes::PeakImageMimeType* DiffusionCoreIOMimeTypes::PeakImageMimeType::Clone() const { return new PeakImageMimeType(*this); } DiffusionCoreIOMimeTypes::PeakImageMimeType DiffusionCoreIOMimeTypes::PEAK_MIMETYPE() { return PeakImageMimeType(); } CustomMimeType DiffusionCoreIOMimeTypes::DTI_MIMETYPE() { CustomMimeType mimeType(DTI_MIMETYPE_NAME()); std::string category = "Tensor Images"; mimeType.SetComment("Diffusion Tensor Images"); mimeType.SetCategory(category); mimeType.AddExtension("dti"); return mimeType; } CustomMimeType DiffusionCoreIOMimeTypes::ODF_MIMETYPE() { CustomMimeType mimeType(ODF_MIMETYPE_NAME()); std::string category = "ODF Images"; mimeType.SetComment("Diffusion ODF Images"); mimeType.SetCategory(category); mimeType.AddExtension("odf"); mimeType.AddExtension("qbi"); // legacy support return mimeType; } // Names std::string DiffusionCoreIOMimeTypes::PEAK_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".nrrd"; return name; } std::string DiffusionCoreIOMimeTypes::DWI_NRRD_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".dwi"; return name; } std::string DiffusionCoreIOMimeTypes::DWI_NIFTI_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".nii.gz"; return name; } std::string DiffusionCoreIOMimeTypes::DWI_FSL_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".fslgz"; return name; } std::string DiffusionCoreIOMimeTypes::DWI_DICOM_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".IMA"; return name; } std::string DiffusionCoreIOMimeTypes::DTI_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".dti"; return name; } std::string DiffusionCoreIOMimeTypes::ODF_MIMETYPE_NAME() { static std::string name = IOMimeTypes::DEFAULT_BASE_NAME() + ".odf"; return name; } // Descriptions std::string DiffusionCoreIOMimeTypes::PEAK_MIMETYPE_DESCRIPTION() { static std::string description = "Peak Image"; return description; } std::string DiffusionCoreIOMimeTypes::DWI_NRRD_MIMETYPE_DESCRIPTION() { static std::string description = "Diffusion Weighted Images"; return description; } std::string DiffusionCoreIOMimeTypes::DWI_NIFTI_MIMETYPE_DESCRIPTION() { static std::string description = "Diffusion Weighted Images"; return description; } std::string DiffusionCoreIOMimeTypes::DWI_FSL_MIMETYPE_DESCRIPTION() { static std::string description = "Diffusion Weighted Images"; return description; } std::string DiffusionCoreIOMimeTypes::DWI_DICOM_MIMETYPE_DESCRIPTION() { static std::string description = "Diffusion Weighted Images"; return description; } std::string DiffusionCoreIOMimeTypes::DTI_MIMETYPE_DESCRIPTION() { static std::string description = "Diffusion Tensor Images"; return description; } std::string DiffusionCoreIOMimeTypes::ODF_MIMETYPE_DESCRIPTION() { static std::string description = "ODF Images"; return description; } } diff --git a/Modules/DiffusionImaging/DiffusionCore/cmdapps/CMakeLists.txt b/Modules/DiffusionImaging/DiffusionCore/cmdapps/CMakeLists.txt index df36d8afdc..a70ed5f074 100644 --- a/Modules/DiffusionImaging/DiffusionCore/cmdapps/CMakeLists.txt +++ b/Modules/DiffusionImaging/DiffusionCore/cmdapps/CMakeLists.txt @@ -1,44 +1,45 @@ option(BUILD_DiffusionCoreCmdApps "Build commandline tools for diffusion" OFF) if(BUILD_DiffusionCoreCmdApps OR MITK_BUILD_ALL_APPS) # needed include directories include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of diffusion cmdapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( diffusioncorecmdapps ImageResampler^^ - ExportShImage^^ CopyGeometry^^ Registration^^ DiffusionDICOMLoader^^ ResampleGradients^^ + DImp^^ + DReg^^ ) foreach(diffusioncorecmdapp ${diffusioncorecmdapps}) # extract cmd app name and dependencies string(REPLACE "^^" "\\;" cmdapp_info ${diffusioncorecmdapp}) set(cmdapp_info_list ${cmdapp_info}) list(GET cmdapp_info_list 0 appname) list(GET cmdapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitkFunctionCreateCommandLineApp( NAME ${appname} DEPENDS MitkCore MitkDiffusionCore ${dependencies_list} PACKAGE_DEPENDS ITK ) endforeach() endif() mitkFunctionCreateCommandLineApp( NAME Dicom2Nrrd DEPENDS MitkCore ${dependencies_list} ) diff --git a/Modules/DiffusionImaging/DiffusionCore/cmdapps/DImp.cpp b/Modules/DiffusionImaging/DiffusionCore/cmdapps/DImp.cpp new file mode 100644 index 0000000000..7b5aa3b823 --- /dev/null +++ b/Modules/DiffusionImaging/DiffusionCore/cmdapps/DImp.cpp @@ -0,0 +1,67 @@ +/*=================================================================== + +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 "mitkCommandLineParser.h" + +/*! +\brief Copies transformation matrix of one image to another +*/ +int main(int argc, char* argv[]) +{ + mitkCommandLineParser parser; + + parser.setTitle("DIMP"); + parser.setCategory("Preprocessing Tools"); + parser.setDescription("TEMPORARY: Converts DICOM to other image types"); + parser.setContributor("MIC"); + + parser.setArgumentPrefix("--", "-"); + parser.addArgument("in", "i", mitkCommandLineParser::InputFile, "Input:", "input image", us::Any(), false); + parser.addArgument("out", "o", mitkCommandLineParser::OutputFile, "Output:", "output image", us::Any(), false); + + std::map parsedArgs = parser.parseArguments(argc, argv); + if (parsedArgs.size()==0) + return EXIT_FAILURE; + + // mandatory arguments + std::string imageName = us::any_cast(parsedArgs["in"]); + std::string outImage = us::any_cast(parsedArgs["out"]); + + try + { + mitk::Image::Pointer source = dynamic_cast(mitk::IOUtil::Load(imageName)[0].GetPointer()); + mitk::IOUtil::Save(source, outImage); + } + 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/DiffusionCore/cmdapps/DReg.cpp b/Modules/DiffusionImaging/DiffusionCore/cmdapps/DReg.cpp new file mode 100644 index 0000000000..d129043cb9 --- /dev/null +++ b/Modules/DiffusionImaging/DiffusionCore/cmdapps/DReg.cpp @@ -0,0 +1,133 @@ +/*=================================================================== + +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 "mitkCommandLineParser.h" +#include +#include +#include +#include +#include +#include +#include + +typedef mitk::DiffusionPropertyHelper DPH; +/*! +\brief Copies transformation matrix of one image to another +*/ +int main(int argc, char* argv[]) +{ + mitkCommandLineParser parser; + + parser.setTitle("DREG"); + parser.setCategory("Preprocessing Tools"); + parser.setDescription("TEMPORARY: Rigid registration of two images"); + parser.setContributor("MIC"); + + parser.setArgumentPrefix("--", "-"); + parser.addArgument("", "f", mitkCommandLineParser::InputFile, "Fixed:", "fixed image", us::Any(), false); + parser.addArgument("", "m", mitkCommandLineParser::InputFile, "Moving:", "moving image", us::Any(), false); + parser.addArgument("", "o", mitkCommandLineParser::OutputFile, "Output:", "output image", us::Any(), false); + + std::map parsedArgs = parser.parseArguments(argc, argv); + if (parsedArgs.size()==0) + return EXIT_FAILURE; + + // mandatory arguments + std::string f = us::any_cast(parsedArgs["f"]); + std::string m = us::any_cast(parsedArgs["m"]); + std::string o = us::any_cast(parsedArgs["o"]); + + try + { + typedef itk::Image< float, 3 > ItkFloatImageType; + + mitk::Image::Pointer fixed = dynamic_cast(mitk::IOUtil::Load(f)[0].GetPointer()); + mitk::Image::Pointer moving = dynamic_cast(mitk::IOUtil::Load(m)[0].GetPointer()); + mitk::Image::Pointer fixed_single = fixed; + mitk::Image::Pointer moving_single = moving; + + mitk::MultiModalRigidDefaultRegistrationAlgorithm< ItkFloatImageType >::Pointer algo = mitk::MultiModalRigidDefaultRegistrationAlgorithm< ItkFloatImageType >::New(); + mitk::MITKAlgorithmHelper helper(algo); + + if (mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(fixed)) + { + DPH::ImageType::Pointer itkVectorImagePointer = DPH::ImageType::New(); + mitk::CastToItkImage(fixed, itkVectorImagePointer); + + itk::ExtractDwiChannelFilter< short >::Pointer filter = itk::ExtractDwiChannelFilter< short >::New(); + filter->SetInput( itkVectorImagePointer); + filter->SetChannelIndex(0); + filter->Update(); + + fixed_single = mitk::Image::New(); + fixed_single->InitializeByItk( filter->GetOutput() ); + fixed_single->SetImportChannel( filter->GetOutput()->GetBufferPointer() ); + } + + if (mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(moving)) + { + DPH::ImageType::Pointer itkVectorImagePointer = DPH::ImageType::New(); + mitk::CastToItkImage(moving, itkVectorImagePointer); + + itk::ExtractDwiChannelFilter< short >::Pointer filter = itk::ExtractDwiChannelFilter< short >::New(); + filter->SetInput( itkVectorImagePointer); + filter->SetChannelIndex(0); + filter->Update(); + + moving_single = mitk::Image::New(); + moving_single->InitializeByItk( filter->GetOutput() ); + moving_single->SetImportChannel( filter->GetOutput()->GetBufferPointer() ); + } + + helper.SetData(moving_single, fixed_single); + mitk::MAPRegistrationWrapper::Pointer reg = helper.GetMITKRegistrationWrapper(); + + mitk::Image::Pointer registered_image = mitk::ImageMappingHelper::refineGeometry(moving, reg, true); + + if (mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(registered_image)) + { + mitk::DiffusionPropertyHelper propertyHelper( registered_image ); + propertyHelper.InitializeImage(); + + std::string file_extension = itksys::SystemTools::GetFilenameExtension(o); + if (file_extension==".nii" || file_extension==".nii.gz") + mitk::IOUtil::Save(registered_image, "application/vnd.mitk.nii.gz", o); + else + mitk::IOUtil::Save(registered_image, o); + } + else + mitk::IOUtil::Save(registered_image, o); + } + 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/DiffusionCore/cmdapps/DwiDenoising.cpp b/Modules/DiffusionImaging/DiffusionCore/cmdapps/DwiDenoising.cpp deleted file mode 100644 index 6e6234be05..0000000000 --- a/Modules/DiffusionImaging/DiffusionCore/cmdapps/DwiDenoising.cpp +++ /dev/null @@ -1,137 +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. - -===================================================================*/ - -#include -#include "mitkCommandLineParser.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -typedef mitk::Image DiffusionImageType; -typedef itk::Image ImageType; - -/** - * Denoises DWI using the Nonlocal - Means algorithm - */ -int main(int argc, char* argv[]) -{ - mitkCommandLineParser parser; - - parser.setTitle("DWI Denoising"); - parser.setCategory("Preprocessing Tools"); - parser.setContributor("MIC"); - parser.setDescription("Denoising for diffusion weighted images using a non-local means algorithm."); - - parser.setArgumentPrefix("--", "-"); - parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input:", "input image (DWI)", us::Any(), false); - parser.addArgument("variance", "v", mitkCommandLineParser::Float, "Variance:", "noise variance", us::Any(), false); - - parser.addArgument("mask", "m", mitkCommandLineParser::InputFile, "Mask:", "brainmask for input image", us::Any(), true); - parser.addArgument("search", "s", mitkCommandLineParser::Int, "Search radius:", "search radius", us::Any(), true); - parser.addArgument("compare", "c", mitkCommandLineParser::Int, "Comparison radius:", "comparison radius", us::Any(), true); - parser.addArgument("joint", "j", mitkCommandLineParser::Bool, "Joint information:", "use joint information"); - parser.addArgument("rician", "r", mitkCommandLineParser::Bool, "Rician adaption:", "use rician adaption"); - - parser.changeParameterGroup("Output", "Output of this miniapp"); - - parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output:", "output image (DWI)", us::Any(), false); - - std::map parsedArgs = parser.parseArguments(argc, argv); - if (parsedArgs.size()==0) - return EXIT_FAILURE; - - std::string inFileName = us::any_cast(parsedArgs["input"]); - double variance = static_cast(us::any_cast(parsedArgs["variance"])); - std::string maskName; - if (parsedArgs.count("mask")) - maskName = us::any_cast(parsedArgs["mask"]); - std::string outFileName = us::any_cast(parsedArgs["output"]); -// boost::algorithm::erase_all(outFileName, ".dwi"); - int search = 4; - if (parsedArgs.count("search")) - search = us::any_cast(parsedArgs["search"]); - int compare = 1; - if (parsedArgs.count("compare")) - compare = us::any_cast(parsedArgs["compare"]); - bool joint = false; - if (parsedArgs.count("joint")) - joint = true; - bool rician = false; - if (parsedArgs.count("rician")) - rician = true; - - try - { - mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Diffusion Weighted Images"}, {}); - DiffusionImageType::Pointer dwi = dynamic_cast(mitk::IOUtil::LoadImage(inFileName, &functor).GetPointer()); - - mitk::DiffusionPropertyHelper::ImageType::Pointer itkVectorImagePointer = mitk::DiffusionPropertyHelper::ImageType::New(); - mitk::CastToItkImage(dwi, itkVectorImagePointer); - - itk::NonLocalMeansDenoisingFilter::Pointer filter = itk::NonLocalMeansDenoisingFilter::New(); - filter->SetNumberOfThreads(12); - filter->SetInputImage( itkVectorImagePointer ); - - if (!maskName.empty()) - { - mitk::Image::Pointer mask = dynamic_cast(mitk::IOUtil::Load(maskName)[0].GetPointer()); - ImageType::Pointer itkMask = ImageType::New(); - mitk::CastToItkImage(mask, itkMask); - filter->SetInputMask(itkMask); - } - - filter->SetUseJointInformation(joint); - filter->SetUseRicianAdaption(rician); - filter->SetSearchRadius(search); - filter->SetComparisonRadius(compare); - filter->SetVariance(variance); - filter->Update(); - - DiffusionImageType::Pointer output = mitk::GrabItkImageMemory( filter->GetOutput() ); - output->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( mitk::DiffusionPropertyHelper::GetReferenceBValue(dwi) ) ); - output->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( mitk::DiffusionPropertyHelper::GetGradientContainer(dwi) ) ); - mitk::DiffusionPropertyHelper propertyHelper( output ); - propertyHelper.InitializeImage(); - -// std::stringstream name; -// name << outFileName << "_NLM_" << search << "-" << compare << "-" << variance << ".dwi"; - - mitk::IOUtil::Save(output, outFileName.c_str()); - } - 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/DiffusionCore/cmdapps/ExportShImage.cpp b/Modules/DiffusionImaging/DiffusionCore/cmdapps/ExportShImage.cpp deleted file mode 100644 index 87b5c5185c..0000000000 --- a/Modules/DiffusionImaging/DiffusionCore/cmdapps/ExportShImage.cpp +++ /dev/null @@ -1,137 +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. - -===================================================================*/ - -#include -#include -#include -#include -#include "mitkCommandLineParser.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define _USE_MATH_DEFINES -#include - -/*! -\brief Convert MITK spherical harmonics image type to MRtrix spherical harmonics image -*/ -template -int StartShConversion(int argc, char* argv[]) -{ - mitkCommandLineParser parser; - - parser.setTitle("Export SH Image"); - parser.setCategory("Preprocessing Tools"); - parser.setDescription("Convert MITK spherical harmonics image type to MRtrix spherical harmonics image"); - parser.setContributor("MIC"); - - parser.setArgumentPrefix("--", "-"); - parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input:", "MITK SH image", us::Any(), false); - parser.addArgument("output", "o", mitkCommandLineParser::InputFile, "Output", "MRtrix SH image", us::Any(), false); - parser.addArgument("shOrder", "sh", mitkCommandLineParser::Int, "SH order:", "spherical harmonics order"); - - std::map parsedArgs = parser.parseArguments(argc, argv); - if (parsedArgs.size()==0) - return EXIT_FAILURE; - - std::string inFile = us::any_cast(parsedArgs["input"]); - std::string outFile = us::any_cast(parsedArgs["output"]); - - try - { - - typedef itk::Image< float, 4 > OutImageType; - typedef itk::Image< itk::Vector< float, (shOrder*shOrder + shOrder + 2)/2 + shOrder >, 3 > InputImageType; - - typename InputImageType::Pointer itkInImage = InputImageType::New(); - typedef itk::ImageFileReader< InputImageType > ReaderType; - typename ReaderType::Pointer reader = ReaderType::New(); - std::cout << "reading " << inFile; - reader->SetFileName(inFile.c_str()); - reader->Update(); - itkInImage = reader->GetOutput(); - - // extract directions from fiber bundle - typename itk::ShCoefficientImageExporter::Pointer filter = itk::ShCoefficientImageExporter::New(); - filter->SetInputImage(itkInImage); - filter->GenerateData(); - OutImageType::Pointer outImage = filter->GetOutputImage(); - - mitk::Image::Pointer image = mitk::GrabItkImageMemory(outImage.GetPointer()); - mitk::IOUtil::Save(image, outFile ); - } - 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; -} - -int main(int argc, char* argv[]) -{ - - mitkCommandLineParser parser; - parser.setArgumentPrefix("--", "-"); - parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input image", "MITK SH image", us::Any(), false); - parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output image", "MRtrix SH image", us::Any(), false); - parser.addArgument("shOrder", "sh", mitkCommandLineParser::Int, "Spherical harmonics order", "spherical harmonics order"); - - parser.setCategory("Preprocessing Tools"); - parser.setTitle("Export SH Image"); - parser.setDescription(" "); - parser.setContributor("MIC"); - - std::map parsedArgs = parser.parseArguments(argc, argv); - if (parsedArgs.size()==0) - return EXIT_FAILURE; - - int shOrder = -1; - if (parsedArgs.count("shOrder")) - shOrder = us::any_cast(parsedArgs["shOrder"]); - - switch (shOrder) - { - case 4: - return StartShConversion<4>(argc, argv); - case 6: - return StartShConversion<6>(argc, argv); - case 8: - return StartShConversion<8>(argc, argv); - case 10: - return StartShConversion<10>(argc, argv); - case 12: - return StartShConversion<12>(argc, argv); - } - return EXIT_FAILURE; -} diff --git a/Modules/DiffusionImaging/DiffusionCore/src/Algorithms/Registration/mitkDWIHeadMotionCorrectionFilter.cpp b/Modules/DiffusionImaging/DiffusionCore/src/Algorithms/Registration/mitkDWIHeadMotionCorrectionFilter.cpp index 19cc8f7ac4..e02338c015 100644 --- a/Modules/DiffusionImaging/DiffusionCore/src/Algorithms/Registration/mitkDWIHeadMotionCorrectionFilter.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/src/Algorithms/Registration/mitkDWIHeadMotionCorrectionFilter.cpp @@ -1,148 +1,148 @@ /*=================================================================== 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 MITKDWIHEADMOTIONCORRECTIONFILTER_CPP #define MITKDWIHEADMOTIONCORRECTIONFILTER_CPP #include "mitkDWIHeadMotionCorrectionFilter.h" #include "itkSplitDWImageFilter.h" #include "itkB0ImageExtractionToSeparateImageFilter.h" #include "mitkImageTimeSelector.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkIOUtil.h" #include typedef mitk::DiffusionPropertyHelper DPH; typedef itk::ExtractDwiChannelFilter< short > ExtractorType; mitk::DWIHeadMotionCorrectionFilter::DWIHeadMotionCorrectionFilter() { } mitk::Image::Pointer mitk::DWIHeadMotionCorrectionFilter::GetCorrectedImage() const { return m_CorrectedImage; } void mitk::DWIHeadMotionCorrectionFilter::UpdateOutputInformation() { Superclass::UpdateOutputInformation(); } void mitk::DWIHeadMotionCorrectionFilter::GenerateData() { InputImageType::Pointer input = const_cast(this->GetInput(0)); if (!DPH::IsDiffusionWeightedImage(input)) mitkThrow() << "Input is not a diffusion-weighted image!"; ITKDiffusionImageType::Pointer itkVectorImagePointer = DPH::GetItkVectorImage(input); int num_gradients = itkVectorImagePointer->GetVectorLength(); typedef itk::ComposeImageFilter < ITKDiffusionVolumeType > ComposeFilterType; ComposeFilterType::Pointer composer = ComposeFilterType::New(); // Extract unweighted volumes mitk::BValueMapProperty::BValueMap bval_map = DPH::GetBValueMap(input); int first_unweighted_index = bval_map.at(0).front(); ExtractorType::Pointer filter = ExtractorType::New(); filter->SetInput( itkVectorImagePointer); filter->SetChannelIndex(first_unweighted_index); filter->Update(); mitk::Image::Pointer fixedImage = mitk::Image::New(); fixedImage->InitializeByItk( filter->GetOutput() ); fixedImage->SetImportChannel( filter->GetOutput()->GetBufferPointer() ); composer->SetInput(0, filter->GetOutput()); mitk::MultiModalAffineDefaultRegistrationAlgorithm< ITKDiffusionVolumeType >::Pointer algo = mitk::MultiModalAffineDefaultRegistrationAlgorithm< ITKDiffusionVolumeType >::New(); mitk::MITKAlgorithmHelper helper(algo); typedef vnl_matrix_fixed< double, 3, 3> TransformMatrixType; std::vector< TransformMatrixType > estimated_transforms; std::vector< ITKDiffusionVolumeType::Pointer > registered_itk_images; for (int i=0; iSetInput( itkVectorImagePointer); filter->SetChannelIndex(i); filter->Update(); mitk::Image::Pointer movingImage = mitk::Image::New(); movingImage->InitializeByItk( filter->GetOutput() ); movingImage->SetImportChannel( filter->GetOutput()->GetBufferPointer() ); helper.SetData(movingImage, fixedImage); mitk::MAPRegistrationWrapper::Pointer reg = helper.GetMITKRegistrationWrapper(); mitk::MITKRegistrationHelper::Affine3DTransformType::Pointer affine = mitk::MITKRegistrationHelper::getAffineMatrix(reg, false); estimated_transforms.push_back(affine->GetMatrix().GetVnlMatrix()); - mitk::Image::Pointer registered_mitk_image = mitk::ImageMappingHelper::map(movingImage, reg, false, 0, nullptr, false, 0, mitk::ImageMappingInterpolator::WSinc_Hamming); + mitk::Image::Pointer registered_mitk_image = mitk::ImageMappingHelper::map(movingImage, reg, false, 0, nullptr, false, 0, mitk::ImageMappingInterpolator::BSpline_3); ITKDiffusionVolumeType::Pointer registered_itk_image = ITKDiffusionVolumeType::New(); mitk::CastToItkImage(registered_mitk_image, registered_itk_image); registered_itk_images.push_back(registered_itk_image); } int i=1; for (auto image : registered_itk_images) { composer->SetInput(i, image); ++i; } composer->Update(); m_CorrectedImage = mitk::GrabItkImageMemory( composer->GetOutput() ); DPH::CopyProperties(input, m_CorrectedImage, true); typedef mitk::DiffusionImageCorrectionFilter CorrectionFilterType; CorrectionFilterType::Pointer corrector = CorrectionFilterType::New(); corrector->SetImage( m_CorrectedImage ); corrector->CorrectDirections( estimated_transforms ); DPH propertyHelper( m_CorrectedImage ); propertyHelper.InitializeImage(); } #endif // MITKDWIHEADMOTIONCORRECTIONFILTER_CPP diff --git a/Modules/DiffusionImaging/DiffusionCore/src/DicomImport/mitkDiffusionDICOMFileReader.cpp b/Modules/DiffusionImaging/DiffusionCore/src/DicomImport/mitkDiffusionDICOMFileReader.cpp index 04db08099b..8bccc5786e 100644 --- a/Modules/DiffusionImaging/DiffusionCore/src/DicomImport/mitkDiffusionDICOMFileReader.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/src/DicomImport/mitkDiffusionDICOMFileReader.cpp @@ -1,437 +1,436 @@ /*=================================================================== 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 "mitkDiffusionDICOMFileReader.h" #include "mitkDiffusionDICOMFileReaderHelper.h" #include "mitkDiffusionHeaderSiemensDICOMFileReader.h" #include "mitkDiffusionHeaderSiemensMosaicDICOMFileReader.h" #include "mitkDiffusionHeaderGEDICOMFileReader.h" #include "mitkDiffusionHeaderPhilipsDICOMFileReader.h" #include #include #include "mitkStringProperty.h" #include static void PerformHeaderAnalysis( mitk::DiffusionHeaderDICOMFileReader::DICOMHeaderListType headers ) { unsigned int images = headers.size(); unsigned int unweighted_images = 0; unsigned int weighted_images = 0; mitk::DiffusionHeaderDICOMFileReader::DICOMHeaderListType::const_iterator c_iter = headers.begin(); while( c_iter != headers.end() ) { const mitk::DiffusionImageDICOMHeaderInformation h = *c_iter; if( h.baseline ) unweighted_images++; if( h.b_value > 0 ) weighted_images++; ++c_iter; } MITK_INFO << " :: Analyzed volumes " << images << "\n" << " :: \t"<< unweighted_images << " b = 0" << "\n" << " :: \t"<< weighted_images << " b > 0"; } mitk::DiffusionDICOMFileReader::DiffusionDICOMFileReader() { } mitk::DiffusionDICOMFileReader::~DiffusionDICOMFileReader() { } bool mitk::DiffusionDICOMFileReader ::LoadImages() { unsigned int numberOfOutputs = this->GetNumberOfOutputs(); bool success = true; for(unsigned int o = 0; o < numberOfOutputs; ++o) { success &= this->LoadSingleOutputImage( this->m_OutputHeaderContainer.at(o), this->InternalGetOutput(o), this->m_IsMosaicData.at(o) ); } return success; } bool mitk::DiffusionDICOMFileReader ::LoadSingleOutputImage( DiffusionHeaderDICOMFileReader::DICOMHeaderListType retrievedHeader, DICOMImageBlockDescriptor& block, bool is_mosaic) { // prepare data reading DiffusionDICOMFileReaderHelper helper; DiffusionDICOMFileReaderHelper::VolumeFileNamesContainer filenames; const DICOMImageFrameList& frames = block.GetImageFrameList(); int numberOfDWImages = block.GetIntProperty("timesteps", 1); int numberOfFramesPerDWImage = frames.size() / numberOfDWImages; assert( int( double((double) frames.size() / (double) numberOfDWImages)) == numberOfFramesPerDWImage ); for( int idx = 0; idx < numberOfDWImages; idx++ ) { std::vector< std::string > FileNamesPerVolume; auto timeStepStart = frames.begin() + idx * numberOfFramesPerDWImage; auto timeStepEnd = frames.begin() + (idx+1) * numberOfFramesPerDWImage; for (auto frameIter = timeStepStart; frameIter != timeStepEnd; ++frameIter) { FileNamesPerVolume.push_back( (*frameIter)->Filename ); } filenames.push_back( FileNamesPerVolume ); } // TODO : only prototyping to test loading of diffusion images // we need some solution for the different types mitk::Image::Pointer output_image = mitk::Image::New(); mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer directions = mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::New(); double max_bvalue = 0; for( int idx = 0; idx < numberOfDWImages; idx++ ) { DiffusionImageDICOMHeaderInformation header = retrievedHeader.at(idx); if( max_bvalue < header.b_value ) max_bvalue = header.b_value; } // normalize the retrieved gradient directions according to the set b-value (maximal one) for( int idx = 0; idx < numberOfDWImages; idx++ ) { DiffusionImageDICOMHeaderInformation header = retrievedHeader.at(idx); mitk::DiffusionPropertyHelper::GradientDirectionType grad = header.g_vector; grad.normalize(); grad *= sqrt( header.b_value / max_bvalue ); directions->push_back( grad ); } // initialize the output image output_image->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::ORIGINALGRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( directions ) ); output_image->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( max_bvalue ) ); if( is_mosaic && this->m_ResolveMosaic ) { mitk::DiffusionHeaderSiemensMosaicDICOMFileReader::Pointer mosaic_reader = mitk::DiffusionHeaderSiemensMosaicDICOMFileReader::New(); // retrieve the remaining meta-information needed for mosaic reconstruction // it suffices to get it exemplatory from the first file in the file list mosaic_reader->RetrieveMosaicInformation( filenames.at(0).at(0) ); mitk::MosaicDescriptor mdesc = mosaic_reader->GetMosaicDescriptor(); mitk::CastToMitkImage( helper.LoadMosaicToVector( filenames, mdesc ), output_image ); } else { mitk::CastToMitkImage( helper.LoadToVector( filenames ), output_image ); } mitk::DiffusionPropertyHelper propertyHelper( output_image ); propertyHelper.InitializeImage(); output_image->SetProperty("diffusion.dicom.importname", mitk::StringProperty::New( helper.GetOutputName(filenames) ) ); block.SetMitkImage( (mitk::Image::Pointer) output_image ); return block.GetMitkImage().IsNotNull(); } std::vector mitk::DiffusionDICOMFileReader::patient_ids() const { return m_patient_ids; } std::vector mitk::DiffusionDICOMFileReader::patient_names() const { return m_patient_names; } std::vector mitk::DiffusionDICOMFileReader::study_instance_uids() const { return m_study_instance_uids; } std::vector mitk::DiffusionDICOMFileReader::series_instance_uids() const { return m_series_instance_uids; } std::vector mitk::DiffusionDICOMFileReader::frame_of_reference_uids() const { return m_frame_of_reference_uids; } std::vector mitk::DiffusionDICOMFileReader::sop_instance_uids() const { return m_sop_instance_uids; } void mitk::DiffusionDICOMFileReader ::AnalyzeInputFiles() { m_Study_names.clear(); m_Series_names.clear(); this->SetGroup3DandT(true); Superclass::AnalyzeInputFiles(); // collect output from superclass size_t number_of_outputs = this->GetNumberOfOutputs(); if(number_of_outputs == 0) { MITK_ERROR << "Failed to parse input, retrieved 0 outputs from SeriesGDCMReader "; } MITK_INFO("diffusion.dicomreader") << "Retrieved " << number_of_outputs << " outputs."; std::vector< bool > valid_input_list; for( unsigned int outputidx = 0; outputidx < this->GetNumberOfOutputs(); outputidx++ ) { DICOMImageBlockDescriptor block_0 = this->GetOutput(outputidx); // collect vendor ID from the first output, first image StringList inputFilename; DICOMImageFrameInfo::Pointer frame_0 = block_0.GetImageFrameList().at(0); inputFilename.push_back( frame_0->Filename ); mitk::DiffusionHeaderDICOMFileReader::Pointer headerReader; bool isMosaic = false; gdcm::Scanner gdcmScanner; gdcm::Tag t_sop_instance_uid(0x0008, 0x0018); gdcm::Tag t_frame_of_reference_uid(0x0020, 0x0052); gdcm::Tag t_series_instance_uid(0x0020, 0x000E); gdcm::Tag t_study_instance_uid(0x0020, 0x000D); gdcm::Tag t_patient_name(0x0010, 0x0010); gdcm::Tag t_patient_id(0x0010, 0x0020); gdcm::Tag t_vendor(0x008, 0x0070); gdcm::Tag t_imagetype(0x0008, 0x0008); gdcm::Tag t_StudyDescription(0x0008, 0x1030); gdcm::Tag t_SeriesDescription(0x0008, 0x103E); // add DICOM Tag for vendor gdcmScanner.AddTag( t_vendor ); // add DICOM Tag for image type gdcmScanner.AddTag( t_imagetype ); gdcmScanner.AddTag( t_StudyDescription ); gdcmScanner.AddTag( t_SeriesDescription ); gdcmScanner.AddTag( t_sop_instance_uid ); gdcmScanner.AddTag( t_frame_of_reference_uid ); gdcmScanner.AddTag( t_series_instance_uid ); gdcmScanner.AddTag( t_study_instance_uid ); gdcmScanner.AddTag( t_patient_name ); gdcmScanner.AddTag( t_patient_id ); if( gdcmScanner.Scan( inputFilename ) ) { // retrieve both vendor and image type const char* ch_vendor = gdcmScanner.GetValue( frame_0->Filename.c_str(), t_vendor ); const char* ch_image_type = gdcmScanner.GetValue( frame_0->Filename.c_str(), t_imagetype ); const char* temp = gdcmScanner.GetValue( frame_0->Filename.c_str(), t_sop_instance_uid ); if (temp!=nullptr) m_sop_instance_uids.push_back(std::string(temp)); else m_sop_instance_uids.push_back("-"); temp = nullptr; temp = gdcmScanner.GetValue( frame_0->Filename.c_str(), t_frame_of_reference_uid ); if (temp!=nullptr) m_frame_of_reference_uids.push_back(std::string(temp)); else m_frame_of_reference_uids.push_back("-"); temp = nullptr; temp = gdcmScanner.GetValue( frame_0->Filename.c_str(), t_series_instance_uid ); if (temp!=nullptr) m_series_instance_uids.push_back(std::string(temp)); else m_series_instance_uids.push_back("-"); temp = nullptr; temp = gdcmScanner.GetValue( frame_0->Filename.c_str(), t_study_instance_uid ); if (temp!=nullptr) m_study_instance_uids.push_back(std::string(temp)); else m_study_instance_uids.push_back("-"); temp = nullptr; temp = gdcmScanner.GetValue( frame_0->Filename.c_str(), t_patient_name ); if (temp!=nullptr) m_patient_names.push_back(std::string(temp)); else m_patient_names.push_back("-"); temp = nullptr; temp = gdcmScanner.GetValue( frame_0->Filename.c_str(), t_patient_id ); if (temp!=nullptr) m_patient_ids.push_back(std::string(temp)); else m_patient_ids.push_back("-"); if( ch_vendor == nullptr || ch_image_type == nullptr ) { MITK_WARN << "Unable to retrieve vendor/image information from " << frame_0->Filename.c_str() << "\n" << "Output " << outputidx+1 << " is not valid, skipping analysis."; valid_input_list.push_back(false); continue; } std::string vendor = std::string( ch_vendor ); std::string image_type = std::string( ch_image_type ); MITK_INFO("diffusion.dicomreader") << "Output " << outputidx+1 << " Got vendor: " << vendor << " image type " << image_type; // parse vendor tag - if( vendor.find("SIEMENS") != std::string::npos ) - //&& image_type.find("DIFFUSION") != std::string::npos ) + if( vendor.find("SIEMENS") != std::string::npos || vendor.find("Siemens HealthCare GmbH") != std::string::npos ) { if( image_type.find("MOSAIC") != std::string::npos ) { headerReader = mitk::DiffusionHeaderSiemensMosaicDICOMFileReader::New(); isMosaic = true; } else { headerReader = mitk::DiffusionHeaderSiemensDICOMFileReader::New(); } } else if( vendor.find("GE") != std::string::npos ) { headerReader = mitk::DiffusionHeaderGEDICOMFileReader::New(); } else if( vendor.find("Philips") != std::string::npos ) { headerReader = mitk::DiffusionHeaderPhilipsDICOMFileReader::New(); } else { // unknown vendor } if( headerReader.IsNull() ) { MITK_ERROR << "No header reader for given vendor. "; valid_input_list.push_back(false); continue; } } else { valid_input_list.push_back(false); continue; } bool canread = false; // iterate over the threeD+t block int numberOfTimesteps = block_0.GetIntProperty("timesteps", 1); int framesPerTimestep = block_0.GetImageFrameList().size() / numberOfTimesteps; for( int idx = 0; idx < numberOfTimesteps; idx++ ) { int access_idx = idx * framesPerTimestep; DICOMImageFrameInfo::Pointer frame = this->GetOutput( outputidx ).GetImageFrameList().at( access_idx ); canread = headerReader->ReadDiffusionHeader( frame->Filename ); } if( canread ) { // collect the information mitk::DiffusionHeaderDICOMFileReader::DICOMHeaderListType retrievedHeader = headerReader->GetHeaderInformation(); m_IsMosaicData.push_back(isMosaic); m_OutputHeaderContainer.push_back( retrievedHeader ); m_OutputReaderContainer.push_back( headerReader ); valid_input_list.push_back(true); const char* ch_StudyDescription = gdcmScanner.GetValue( frame_0->Filename.c_str(), t_StudyDescription ); const char* ch_SeriesDescription = gdcmScanner.GetValue( frame_0->Filename.c_str(), t_SeriesDescription ); if( ch_StudyDescription != nullptr ) m_Study_names.push_back(ch_StudyDescription); else m_Study_names.push_back("-"); if( ch_SeriesDescription != nullptr ) m_Series_names.push_back(ch_SeriesDescription); else m_Series_names.push_back("-"); } } // check status of the outputs and remove the non-valid std::vector< DICOMImageBlockDescriptor > valid_outputs; for ( unsigned int outputidx = 0; outputidx < this->GetNumberOfOutputs(); ++outputidx ) { if( valid_input_list.at(outputidx) ) { valid_outputs.push_back( this->InternalGetOutput( outputidx ) ); } } // clear complete list this->ClearOutputs(); this->SetNumberOfOutputs( valid_outputs.size() ); // insert only the valid ones for ( unsigned int outputidx = 0; valid_outputs.size(); ++outputidx ) this->SetOutput( outputidx, valid_outputs.at( outputidx ) ); for( unsigned int outputidx = 0; outputidx < this->GetNumberOfOutputs(); outputidx++ ) { // TODO : Analyze outputs + header information, i.e. for the loading confidence MITK_INFO("diffusion.dicomreader") << "---- DICOM Analysis Report ---- :: Output " << outputidx+1 << " of " << this->GetNumberOfOutputs(); try{ PerformHeaderAnalysis( this->m_OutputHeaderContainer.at( outputidx) ); } catch( const std::exception& se) { MITK_ERROR << "STD Exception " << se.what(); } MITK_INFO("diffusion.dicomreader") << "==========================================="; } } bool mitk::DiffusionDICOMFileReader ::CanHandleFile(const std::string & /* filename */) { //FIXME : return true; } diff --git a/Modules/DiffusionImaging/DiffusionCore/src/DicomImport/mitkDiffusionHeaderSiemensDICOMFileReader.cpp b/Modules/DiffusionImaging/DiffusionCore/src/DicomImport/mitkDiffusionHeaderSiemensDICOMFileReader.cpp index 3c3288e256..a2b8de66c4 100644 --- a/Modules/DiffusionImaging/DiffusionCore/src/DicomImport/mitkDiffusionHeaderSiemensDICOMFileReader.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/src/DicomImport/mitkDiffusionHeaderSiemensDICOMFileReader.cpp @@ -1,247 +1,250 @@ /*=================================================================== 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 "mitkDiffusionHeaderSiemensDICOMFileReader.h" #include "mitkDiffusionHeaderSiemensDICOMFileHelper.h" #include "mitkDiffusionHeaderDICOMFileReader.h" #include "gdcmScanner.h" #include "gdcmReader.h" #include static bool GetTagFromHierarchy( std::vector< gdcm::Tag > hierarchy, const gdcm::Tag& t_tag, const gdcm::DataSet& dataset, gdcm::DataSet& target) { if( hierarchy.empty() ) return false; const gdcm::DataElement& de = dataset.GetDataElement( hierarchy.at(0) ); const auto seq = de.GetValueAsSQ(); + if (seq==nullptr) + return false; + // last level of hierarchy, retrieve the first apperance if( hierarchy.size() == 1 ) { gdcm::Item& item2 = seq->GetItem(1); gdcm::DataSet& nestedds2 = item2.GetNestedDataSet(); const gdcm::DataElement& nde2 = nestedds2.GetDataElement( t_tag ); if( !nde2.IsEmpty() ) { target = nestedds2; return true; } else { return false; } } else { if( seq->FindDataElement( hierarchy.at(1) ) ) { for( gdcm::SequenceOfItems::SizeType i=1; i< seq->GetNumberOfItems(); i++ ) { gdcm::Item& item = seq->GetItem(i); gdcm::DataSet &nestedds = item.GetNestedDataSet(); // recursive call return GetTagFromHierarchy( std::vector< gdcm::Tag >( hierarchy.begin() + 1, hierarchy.end() ), t_tag, nestedds, target); } } return false; } } /** * @brief Extract b value from the siemens diffusion tag */ bool mitk::DiffusionHeaderSiemensDICOMFileReader ::ExtractSiemensDiffusionTagInformation( std::string tag_value, mitk::DiffusionImageDICOMHeaderInformation& values) { SiemensDiffusionHeaderType hformat = mitk::GetHeaderType( tag_value ); Siemens_Header_Format specs = this->m_SiemensFormatsCollection.at( hformat ); MITK_DEBUG << " Header format: " << hformat; MITK_DEBUG << " :: Retrieving b value. "; std::string::size_type tag_position = tag_value.find( "B_value", 0 ); if( tag_position == std::string::npos ) { MITK_ERROR << "No b value information found. "; return false; } std::string value_string = tag_value.substr( tag_position, tag_value.size() - tag_position + 1 ); std::vector value_array; if( ParseInputString(value_string, value_array, specs) ) { values.b_value = value_array.at(0); } else { MITK_INFO("diffusion.dicomreader.siemens") << "No b-value tag found. "; return false; } // search for GradientDirectionInformation if the bvalue is not null if( values.b_value > 0 ) { std::string::size_type tag_position = tag_value.find( "DiffusionGradientDirection", 0 ); // Possibly it is a IVIM dataset, i.e. the gradient direction is not relevant // and possibly either not set or set to zero if( tag_position == std::string::npos ) { MITK_WARN << "No gradient direction information, but non-zero b-value. Possibly an IVIM dataset. " << "\n" << "Setting gradient to (1,1,1)."; values.isotropic = true; values.g_vector.fill(1); return false; } value_array.clear(); std::string gradient_direction_str = tag_value.substr( tag_position, tag_value.size() - tag_position + 1 ); if( ParseInputString(gradient_direction_str, value_array, specs) ) { if( value_array.size() != 3 ) { MITK_ERROR << " Retrieved gradient information of length " << value_array.size(); return false; } for( unsigned int i=0; iExtractSiemensDiffusionTagInformation( siemens_diffusionheader_str, values ); m_HeaderInformationList.push_back( values ); retVal = true; } else { const gdcm::Tag t_sie_bvalue( 0x0018, 0x9087); const gdcm::Tag t_sie_gradient( 0x0021, 0x1146); std::vector< gdcm::Tag > bv_hierarchy; bv_hierarchy.push_back( gdcm::Tag(0x5200,0x9230) ); bv_hierarchy.push_back( gdcm::Tag(0x0018,0x9117) ); gdcm::DataSet bvalueset; GetTagFromHierarchy( bv_hierarchy, t_sie_bvalue, dataset, bvalueset ); DiffusionImageDICOMHeaderInformation values; double dbvalue = 0; if( mitk::RevealBinaryTagC( t_sie_bvalue, bvalueset, (char*) &dbvalue) ) { MITK_INFO("siemens.dicom.diffusion.bvalue") << dbvalue; values.b_value = std::ceil( dbvalue ); if( values.b_value == 0) values.baseline = true; } if( !values.baseline ) { std::vector< gdcm::Tag > g_hierarchy; g_hierarchy.push_back( gdcm::Tag(0x5200,0x9230) ); g_hierarchy.push_back( gdcm::Tag(0x0021,0x11fe) ); GetTagFromHierarchy( g_hierarchy, t_sie_gradient, dataset, bvalueset ); double gr_dir_arr[3] = {1,0,-1}; if( mitk::RevealBinaryTagC( t_sie_gradient, bvalueset, (char*) &gr_dir_arr ) ) { MITK_INFO("siemens.dicom.diffusion.gradient") << "(" << gr_dir_arr[0] <<"," << gr_dir_arr[1] <<"," < #include mitk::ConnectomicsNetworkMatrixWriter::ConnectomicsNetworkMatrixWriter() : AbstractFileWriter(mitk::ConnectomicsNetwork::GetStaticNameOfClass(), CustomMimeType( mitk::DiffusionIOMimeTypes::CONNECTOMICS_MATRIX_MIMETYPE() ), "Write only Matrix Connectomics Networks" ) { RegisterService(); } mitk::ConnectomicsNetworkMatrixWriter::ConnectomicsNetworkMatrixWriter(const mitk::ConnectomicsNetworkMatrixWriter& other) : AbstractFileWriter(other) { } mitk::ConnectomicsNetworkMatrixWriter::~ConnectomicsNetworkMatrixWriter() {} mitk::ConnectomicsNetworkMatrixWriter* mitk::ConnectomicsNetworkMatrixWriter::Clone() const { return new ConnectomicsNetworkMatrixWriter(*this); } void mitk::ConnectomicsNetworkMatrixWriter::Write() { MITK_INFO << "Writing connectomics network"; InputType::ConstPointer input = dynamic_cast(this->GetInput()); if (input.IsNull() ) { MITK_ERROR <<"Sorry, input to ConnectomicsNetworkMatrixWriter is nullptr!"; return; } this->ValidateOutputLocation(); std::ostream* out; std::ofstream outStream; if( this->GetOutputStream() ) { out = this->GetOutputStream(); } else { outStream.open( this->GetOutputLocation().c_str() ); out = &outStream; } if ( !out->good() ) { mitkThrow() << "Could not open stream."; } try { const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, nullptr ); setlocale(LC_ALL, locale.c_str()); std::locale previousLocale(out->getloc()); std::locale I("C"); out->imbue(I); // construct header std::stringstream header; mitk::StringProperty::Pointer addHeaderInfoProperty = dynamic_cast(input->GetProperty(connectomicsDataAdditionalHeaderInformation.c_str()).GetPointer()); if(addHeaderInfoProperty.IsNotNull()) { std::string additionalHeaderInfo = addHeaderInfoProperty->GetValue(); // if the additional header info contains newlines we need to add # // in front of the new lines std::vector strings; boost::split(strings, additionalHeaderInfo, boost::is_any_of("\n")); for( unsigned int index(0); index < strings.size(); ++index) { header << "#" << strings[index] << "\n"; } } // add the order of labels to the header std::vector< InputType::VertexDescriptorType > nodes = input->GetVectorOfAllVertexDescriptors(); header << "#"; for(unsigned int index(0); index < nodes.size(); ++index) { header << " " << (input->GetNode(nodes[index])).label; } // construct body std::stringstream body; for(unsigned int i(0); i < nodes.size(); ++i) { for(unsigned int j(0); j < nodes.size(); ++j) { if( input->EdgeExists(nodes[i], nodes[j])) { - body << (input->GetEdge(nodes[i], nodes[j])).edge_weight; + body << (input->GetEdge(nodes[i], nodes[j])).fiber_count; } else { body << 0; } if(j < nodes.size() - 1) { body << " "; } } body << "\n"; } (*out)<< header.str() << "\n" << body.str(); setlocale(LC_ALL, currLocale.c_str()); MITK_INFO << "Connectomics network connection list written"; } catch(...) { mitkThrow() << "Error while writing to stream."; } } mitk::IFileIO::ConfidenceLevel mitk::ConnectomicsNetworkMatrixWriter::GetConfidenceLevel() const { if (AbstractFileWriter::GetConfidenceLevel() == Unsupported) { return Unsupported; } // exporting is supported but will result in loss of data // which prevents re-import return PartiallySupported; } diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkConnectomicsNetworkReader.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkConnectomicsNetworkReader.cpp index ef4f0335d0..9d70c55182 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkConnectomicsNetworkReader.cpp +++ b/Modules/DiffusionImaging/DiffusionIO/mitkConnectomicsNetworkReader.cpp @@ -1,228 +1,228 @@ /*=================================================================== 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 "mitkConnectomicsNetworkReader.h" #include "mitkConnectomicsNetworkDefinitions.h" #include #include "itksys/SystemTools.hxx" #include #include "mitkGeometry3D.h" #include #include "mitkDiffusionIOMimeTypes.h" namespace mitk { ConnectomicsNetworkReader::ConnectomicsNetworkReader(const ConnectomicsNetworkReader& other) : mitk::AbstractFileReader(other) { } ConnectomicsNetworkReader::ConnectomicsNetworkReader() : mitk::AbstractFileReader( CustomMimeType( mitk::DiffusionIOMimeTypes::CONNECTOMICS_MIMETYPE() ), mitk::DiffusionIOMimeTypes::CONNECTOMICS_MIMETYPE_DESCRIPTION() ) { m_ServiceReg = this->RegisterService(); } ConnectomicsNetworkReader::~ConnectomicsNetworkReader() { } std::vector > ConnectomicsNetworkReader::Read() { std::vector > result; std::string location = GetInputLocation(); std::string ext = itksys::SystemTools::GetFilenameLastExtension(location); ext = itksys::SystemTools::LowerCase(ext); if ( location == "") { MITK_ERROR << "No file name specified."; } else if (ext == ".cnf") { try { mitk::ConnectomicsNetwork::Pointer outputNetwork = mitk::ConnectomicsNetwork::New(); TiXmlDocument doc( location ); bool loadOkay = doc.LoadFile(); if(!loadOkay) { mitkThrow() << "Could not open file " << location << " for reading."; } TiXmlHandle hDoc(&doc); TiXmlElement* pElem; TiXmlHandle hRoot(0); pElem = hDoc.FirstChildElement().Element(); // save this for later hRoot = TiXmlHandle(pElem); //get file version std::string version(""); hRoot.Element()->QueryStringAttribute(mitk::ConnectomicsNetworkDefinitions::XML_FILE_VERSION, &version); // read geometry pElem = hRoot.FirstChildElement(mitk::ConnectomicsNetworkDefinitions::XML_GEOMETRY).Element(); mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); // read origin mitk::Point3D origin; double temp = 0; pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_ORIGIN_X, &temp); origin[0] = temp; pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_ORIGIN_Y, &temp); origin[1] = temp; pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_ORIGIN_Z, &temp); origin[2] = temp; geometry->SetOrigin(origin); // read spacing ScalarType spacing[3]; pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_SPACING_X, &temp); spacing[0] = temp; pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_SPACING_Y, &temp); spacing[1] = temp; pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_SPACING_Z, &temp); spacing[2] = temp; geometry->SetSpacing(spacing); // read transform vtkMatrix4x4* m = vtkMatrix4x4::New(); pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_XX, &temp); m->SetElement(0,0,temp); pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_XY, &temp); m->SetElement(1,0,temp); pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_XZ, &temp); m->SetElement(2,0,temp); pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_YX, &temp); m->SetElement(0,1,temp); pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_YY, &temp); m->SetElement(1,1,temp); pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_YZ, &temp); m->SetElement(2,1,temp); pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_ZX, &temp); m->SetElement(0,2,temp); pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_ZY, &temp); m->SetElement(1,2,temp); pElem->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_ZZ, &temp); m->SetElement(2,2,temp); m->SetElement(0,3,origin[0]); m->SetElement(1,3,origin[1]); m->SetElement(2,3,origin[2]); m->SetElement(3,3,1); geometry->SetIndexToWorldTransformByVtkMatrix(m); geometry->SetImageGeometry(true); outputNetwork->SetGeometry(geometry); // read network std::map< int, mitk::ConnectomicsNetwork::VertexDescriptorType > idToVertexMap; // read vertices pElem = hRoot.FirstChildElement(mitk::ConnectomicsNetworkDefinitions::XML_VERTICES).Element(); { // walk through the vertices TiXmlElement* vertexElement = pElem->FirstChildElement(); for( ; vertexElement; vertexElement=vertexElement->NextSiblingElement()) { std::vector< float > pos; std::string label; int vertexID(0); vertexElement->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_X, &temp); pos.push_back(temp); vertexElement->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_Y, &temp); pos.push_back(temp); vertexElement->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_Z, &temp); pos.push_back(temp); vertexElement->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_ID, &vertexID); vertexElement->QueryStringAttribute(mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_LABEL, &label); mitk::ConnectomicsNetwork::VertexDescriptorType newVertex = outputNetwork->AddVertex( vertexID ); outputNetwork->SetLabel( newVertex, label ); outputNetwork->SetCoordinates( newVertex, pos ); if ( idToVertexMap.count( vertexID ) > 0 ) { MITK_ERROR << "Aborting network creation, duplicate vertex ID in file."; return result; } idToVertexMap.insert( std::pair< int, mitk::ConnectomicsNetwork::VertexDescriptorType >( vertexID, newVertex) ); } } // read edges pElem = hRoot.FirstChildElement(mitk::ConnectomicsNetworkDefinitions::XML_EDGES).Element(); { // walk through the edges TiXmlElement* edgeElement = pElem->FirstChildElement(); for( ; edgeElement; edgeElement=edgeElement->NextSiblingElement()) { int edgeID(0), edgeSourceID(0), edgeTargetID(0), edgeWeight(0); double edgeDoubleWeight(0.0); edgeElement->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_EDGE_ID, &edgeID); edgeElement->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_EDGE_SOURCE_ID, &edgeSourceID); edgeElement->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_EDGE_TARGET_ID, &edgeTargetID); - edgeElement->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_EDGE_WEIGHT_ID, &edgeWeight); + edgeElement->Attribute(mitk::ConnectomicsNetworkDefinitions::XML_EDGE_FIBERCOUNT_ID, &edgeWeight); if(version == "0.1") { // in version 0.1 only the int weight was saved, assume double weight to be one by default edgeDoubleWeight = 1.0; } else { edgeElement->QueryDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_EDGE_DOUBLE_WEIGHT_ID, &edgeDoubleWeight); } mitk::ConnectomicsNetwork::VertexDescriptorType source = idToVertexMap.find( edgeSourceID )->second; mitk::ConnectomicsNetwork::VertexDescriptorType target = idToVertexMap.find( edgeTargetID )->second; outputNetwork->AddEdge( source, target, edgeSourceID, edgeTargetID, edgeWeight, edgeDoubleWeight); } } outputNetwork->UpdateBounds(); result.push_back(outputNetwork.GetPointer()); MITK_INFO << "Network read"; } catch (mitk::Exception e) { MITK_ERROR << e.GetDescription(); } catch(...) { MITK_ERROR << "Unknown error occured while trying to read file."; } } return result; } } //namespace MITK mitk::ConnectomicsNetworkReader* mitk::ConnectomicsNetworkReader::Clone() const { return new ConnectomicsNetworkReader(*this); } diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkConnectomicsNetworkWriter.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkConnectomicsNetworkWriter.cpp index 3d279594dc..34fe5a0f09 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkConnectomicsNetworkWriter.cpp +++ b/Modules/DiffusionImaging/DiffusionIO/mitkConnectomicsNetworkWriter.cpp @@ -1,144 +1,144 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "mitkConnectomicsNetworkWriter.h" #include "mitkConnectomicsNetworkDefinitions.h" #include #include "itksys/SystemTools.hxx" #include "mitkDiffusionIOMimeTypes.h" mitk::ConnectomicsNetworkWriter::ConnectomicsNetworkWriter() : AbstractFileWriter(mitk::ConnectomicsNetwork::GetStaticNameOfClass(), CustomMimeType( mitk::DiffusionIOMimeTypes::CONNECTOMICS_MIMETYPE() ), mitk::DiffusionIOMimeTypes::CONNECTOMICS_MIMETYPE_DESCRIPTION() ) { RegisterService(); } mitk::ConnectomicsNetworkWriter::ConnectomicsNetworkWriter(const mitk::ConnectomicsNetworkWriter& other) : AbstractFileWriter(other) { } mitk::ConnectomicsNetworkWriter::~ConnectomicsNetworkWriter() {} mitk::ConnectomicsNetworkWriter* mitk::ConnectomicsNetworkWriter::Clone() const { return new ConnectomicsNetworkWriter(*this); } void mitk::ConnectomicsNetworkWriter::Write() { MITK_INFO << "Writing connectomics network"; InputType::ConstPointer input = dynamic_cast(this->GetInput()); if (input.IsNull() ) { MITK_ERROR <<"Sorry, input to ConnectomicsNetworkWriter is nullptr!"; return; } if ( this->GetOutputLocation().empty() ) { MITK_ERROR << "Sorry, filename has not been set!" ; return ; } std::string ext = itksys::SystemTools::GetFilenameLastExtension(this->GetOutputLocation()); ext = itksys::SystemTools::LowerCase(ext); // default extension is .cnf if(ext == "") { ext = ".cnf"; this->SetOutputLocation(this->GetOutputLocation() + ext); } if (ext == ".cnf") { // Get geometry of the network mitk::BaseGeometry* geometry = input->GetGeometry(); // Create XML document TiXmlDocument documentXML; { // begin document TiXmlDeclaration* declXML = new TiXmlDeclaration( "1.0", "", "" ); // TODO what to write here? encoding? etc.... documentXML.LinkEndChild( declXML ); TiXmlElement* mainXML = new TiXmlElement(mitk::ConnectomicsNetworkDefinitions::XML_CONNECTOMICS_FILE); mainXML->SetAttribute(mitk::ConnectomicsNetworkDefinitions::XML_FILE_VERSION, mitk::ConnectomicsNetworkDefinitions::VERSION_STRING); documentXML.LinkEndChild(mainXML); TiXmlElement* geometryXML = new TiXmlElement(mitk::ConnectomicsNetworkDefinitions::XML_GEOMETRY); { // begin geometry geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_XX, geometry->GetMatrixColumn(0)[0]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_XY, geometry->GetMatrixColumn(0)[1]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_XZ, geometry->GetMatrixColumn(0)[2]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_YX, geometry->GetMatrixColumn(1)[0]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_YY, geometry->GetMatrixColumn(1)[1]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_YZ, geometry->GetMatrixColumn(1)[2]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_ZX, geometry->GetMatrixColumn(2)[0]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_ZY, geometry->GetMatrixColumn(2)[1]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_MATRIX_ZZ, geometry->GetMatrixColumn(2)[2]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_ORIGIN_X, geometry->GetOrigin()[0]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_ORIGIN_Y, geometry->GetOrigin()[1]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_ORIGIN_Z, geometry->GetOrigin()[2]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_SPACING_X, geometry->GetSpacing()[0]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_SPACING_Y, geometry->GetSpacing()[1]); geometryXML->SetDoubleAttribute(mitk::ConnectomicsNetworkDefinitions::XML_SPACING_Z, geometry->GetSpacing()[2]); } // end geometry mainXML->LinkEndChild(geometryXML); TiXmlElement* verticesXML = new TiXmlElement(mitk::ConnectomicsNetworkDefinitions::XML_VERTICES); { // begin vertices section VertexVectorType vertexVector = dynamic_cast(this->GetInput())->GetVectorOfAllNodes(); for( unsigned int index = 0; index < vertexVector.size(); index++ ) { // not localized as of yet TODO TiXmlElement* vertexXML = new TiXmlElement(mitk::ConnectomicsNetworkDefinitions::XML_VERTEX ); vertexXML->SetAttribute( mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_ID , vertexVector[ index ].id ); vertexXML->SetAttribute( mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_LABEL , vertexVector[ index ].label ); vertexXML->SetDoubleAttribute( mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_X , vertexVector[ index ].coordinates[0] ); vertexXML->SetDoubleAttribute( mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_Y , vertexVector[ index ].coordinates[1] ); vertexXML->SetDoubleAttribute( mitk::ConnectomicsNetworkDefinitions::XML_VERTEX_Z , vertexVector[ index ].coordinates[2] ); verticesXML->LinkEndChild(vertexXML); } } // end vertices section mainXML->LinkEndChild(verticesXML); TiXmlElement* edgesXML = new TiXmlElement(mitk::ConnectomicsNetworkDefinitions::XML_EDGES); { // begin edges section EdgeVectorType edgeVector = dynamic_cast(this->GetInput())->GetVectorOfAllEdges(); for(unsigned int index = 0; index < edgeVector.size(); index++ ) { TiXmlElement* edgeXML = new TiXmlElement(mitk::ConnectomicsNetworkDefinitions::XML_EDGE ); edgeXML->SetAttribute( mitk::ConnectomicsNetworkDefinitions::XML_EDGE_ID , index ); edgeXML->SetAttribute( mitk::ConnectomicsNetworkDefinitions::XML_EDGE_SOURCE_ID , edgeVector[ index ].second.sourceId ); edgeXML->SetAttribute( mitk::ConnectomicsNetworkDefinitions::XML_EDGE_TARGET_ID , edgeVector[ index ].second.targetId ); - edgeXML->SetAttribute( mitk::ConnectomicsNetworkDefinitions::XML_EDGE_WEIGHT_ID , edgeVector[ index ].second.weight ); + edgeXML->SetAttribute( mitk::ConnectomicsNetworkDefinitions::XML_EDGE_FIBERCOUNT_ID , edgeVector[ index ].second.fiber_count ); edgeXML->SetDoubleAttribute( mitk::ConnectomicsNetworkDefinitions::XML_EDGE_DOUBLE_WEIGHT_ID , edgeVector[ index ].second.edge_weight ); edgesXML->LinkEndChild(edgeXML); } } // end edges section mainXML->LinkEndChild(edgesXML); } // end document documentXML.SaveFile( this->GetOutputLocation().c_str() ); MITK_INFO << "Connectomics network written"; } } diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper2D.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper2D.cpp index 521dae66a5..39c8c6f82f 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper2D.cpp +++ b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper2D.cpp @@ -1,276 +1,277 @@ /*=================================================================== 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 "mitkFiberBundleMapper2D.h" #include "mitkBaseRenderer.h" #include "mitkDataNode.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include class vtkShaderCallback : public vtkCommand { public: static vtkShaderCallback *New() { return new vtkShaderCallback; } mitk::BaseRenderer *renderer; mitk::DataNode *node; void Execute(vtkObject *, unsigned long, void*cbo) override { vtkOpenGLHelper *cellBO = reinterpret_cast(cbo); float fiberOpacity; bool fiberFading = false; float fiberThickness = 0.0; node->GetOpacity(fiberOpacity, nullptr); node->GetFloatProperty("Fiber2DSliceThickness", fiberThickness); node->GetBoolProperty("Fiber2DfadeEFX", fiberFading); cellBO->Program->SetUniformf("fiberOpacity", fiberOpacity); cellBO->Program->SetUniformi("fiberFadingON", fiberFading); cellBO->Program->SetUniformf("fiberThickness", fiberThickness); if (this->renderer) { //get information about current position of views mitk::SliceNavigationController::Pointer sliceContr = renderer->GetSliceNavigationController(); mitk::PlaneGeometry::ConstPointer planeGeo = sliceContr->GetCurrentPlaneGeometry(); //generate according cutting planes based on the view position float planeNormal[3]; planeNormal[0] = planeGeo->GetNormal()[0]; planeNormal[1] = planeGeo->GetNormal()[1]; planeNormal[2] = planeGeo->GetNormal()[2]; float tmp1 = planeGeo->GetOrigin()[0] * planeNormal[0]; float tmp2 = planeGeo->GetOrigin()[1] * planeNormal[1]; float tmp3 = planeGeo->GetOrigin()[2] * planeNormal[2]; float thickness = tmp1 + tmp2 + tmp3; //attention, correct normalvector float* a = new float[4]; for (int i = 0; i < 3; ++i) a[i] = planeNormal[i]; a[3] = thickness; cellBO->Program->SetUniform4f("slicingPlane", a); } } vtkShaderCallback() { this->renderer = 0; } }; mitk::FiberBundleMapper2D::FiberBundleMapper2D() : m_LineWidth(1) { m_lut = vtkLookupTable::New(); m_lut->Build(); } mitk::FiberBundleMapper2D::~FiberBundleMapper2D() { } mitk::FiberBundle* mitk::FiberBundleMapper2D::GetInput() { return dynamic_cast< mitk::FiberBundle * > ( GetDataNode()->GetData() ); } void mitk::FiberBundleMapper2D::Update(mitk::BaseRenderer * renderer) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if ( !visible ) return; // Calculate time step of the input data for the specified renderer (integer value) // this method is implemented in mitkMapper this->CalculateTimeStep( renderer ); //check if updates occured in the node or on the display FBXLocalStorage *localStorage = m_LocalStorageHandler.GetLocalStorage(renderer); //set renderer independent shader properties const DataNode::Pointer node = this->GetDataNode(); float thickness = 2.0; if(!this->GetDataNode()->GetPropertyValue("Fiber2DSliceThickness",thickness)) MITK_INFO << "FIBER2D SLICE THICKNESS PROPERTY ERROR"; bool fiberfading = false; if(!this->GetDataNode()->GetPropertyValue("Fiber2DfadeEFX",fiberfading)) MITK_INFO << "FIBER2D SLICE FADE EFX PROPERTY ERROR"; mitk::FiberBundle* fiberBundle = this->GetInput(); if (fiberBundle==nullptr) return; int lineWidth = 0; node->GetIntProperty("LineWidth", lineWidth); if (m_LineWidth!=lineWidth) { m_LineWidth = lineWidth; fiberBundle->RequestUpdate2D(); } if ( localStorage->m_LastUpdateTimeGetCurrentWorldPlaneGeometryUpdateTime() || localStorage->m_LastUpdateTimeGetUpdateTime2D() ) { this->UpdateShaderParameter(renderer); this->GenerateDataForRenderer( renderer ); } } void mitk::FiberBundleMapper2D::UpdateShaderParameter(mitk::BaseRenderer *) { // see new vtkShaderCallback } // vtkActors and Mappers are feeded here void mitk::FiberBundleMapper2D::GenerateDataForRenderer(mitk::BaseRenderer *renderer) { mitk::FiberBundle* fiberBundle = this->GetInput(); //the handler of local storage gets feeded in this method with requested data for related renderwindow FBXLocalStorage *localStorage = m_LocalStorageHandler.GetLocalStorage(renderer); mitk::DataNode* node = this->GetDataNode(); if (node == nullptr) return; vtkSmartPointer fiberPolyData = fiberBundle->GetFiberPolyData(); if (fiberPolyData == nullptr) return; fiberPolyData->GetPointData()->AddArray(fiberBundle->GetFiberColors()); localStorage->m_FiberMapper->ScalarVisibilityOn(); localStorage->m_FiberMapper->SetScalarModeToUsePointFieldData(); localStorage->m_FiberMapper->SetLookupTable(m_lut); //apply the properties after the slice was set localStorage->m_PointActor->GetProperty()->SetOpacity(0.999); localStorage->m_FiberMapper->SelectColorArray("FIBER_COLORS"); localStorage->m_FiberMapper->SetInputData(fiberPolyData); localStorage->m_FiberMapper->SetVertexShaderCode( "//VTK::System::Dec\n" "attribute vec4 vertexMC;\n" "//VTK::Normal::Dec\n" "uniform mat4 MCDCMatrix;\n" "//VTK::Color::Dec\n" "varying vec4 positionWorld;\n" "varying vec4 colorVertex;\n" "void main(void)\n" "{\n" " colorVertex = scalarColor;\n" " positionWorld = vertexMC;\n" " gl_Position = MCDCMatrix * vertexMC;\n" "}\n" ); localStorage->m_FiberMapper->SetFragmentShaderCode( "//VTK::System::Dec\n" // always start with this line "//VTK::Output::Dec\n" // always have this line in your FS "uniform vec4 slicingPlane;\n" "uniform float fiberThickness;\n" "uniform int fiberFadingON;\n" "uniform float fiberOpacity;\n" "varying vec4 positionWorld;\n" "varying vec4 colorVertex;\n" + "out vec4 out_Color;\n" "void main(void)\n" "{\n" " float r1 = dot(positionWorld.xyz, slicingPlane.xyz) - slicingPlane.w;\n" " if (abs(r1) >= fiberThickness)\n" " discard;\n" " if (fiberFadingON != 0)\n" " {\n" " float x = (r1 + fiberThickness) / (fiberThickness*2.0);\n" " x = 1.0 - x;\n" - " gl_FragColor = vec4(colorVertex.xyz*x, fiberOpacity);\n" + " out_Color = vec4(colorVertex.xyz*x, fiberOpacity);\n" " }\n" " else{\n" - " gl_FragColor = vec4(colorVertex.xyz,fiberOpacity);\n" + " out_Color = vec4(colorVertex.xyz,fiberOpacity);\n" " }\n" "}\n" ); vtkSmartPointer myCallback = vtkSmartPointer::New(); myCallback->renderer = renderer; myCallback->node = this->GetDataNode(); localStorage->m_FiberMapper->AddObserver(vtkCommand::UpdateShaderEvent,myCallback); localStorage->m_PointActor->SetMapper(localStorage->m_FiberMapper); localStorage->m_PointActor->GetProperty()->ShadingOn(); localStorage->m_PointActor->GetProperty()->SetLineWidth(m_LineWidth); // We have been modified => save this for next Update() localStorage->m_LastUpdateTime.Modified(); } vtkProp* mitk::FiberBundleMapper2D::GetVtkProp(mitk::BaseRenderer *renderer) { this->Update(renderer); return m_LocalStorageHandler.GetLocalStorage(renderer)->m_PointActor; } void mitk::FiberBundleMapper2D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { Superclass::SetDefaultProperties(node, renderer, overwrite); // node->SetProperty("shader",mitk::ShaderProperty::New("mitkShaderFiberClipping")); //add other parameters to propertylist node->AddProperty( "Fiber2DSliceThickness", mitk::FloatProperty::New(1.0f), renderer, overwrite ); node->AddProperty( "Fiber2DfadeEFX", mitk::BoolProperty::New(true), renderer, overwrite ); node->AddProperty( "color", mitk::ColorProperty::New(1.0,1.0,1.0), renderer, overwrite); } mitk::FiberBundleMapper2D::FBXLocalStorage::FBXLocalStorage() { m_PointActor = vtkSmartPointer::New(); m_FiberMapper = vtkSmartPointer::New(); } diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper3D.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper3D.cpp index 7401c66929..6b019916b0 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper3D.cpp +++ b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleMapper3D.cpp @@ -1,411 +1,412 @@ /*=================================================================== 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 "mitkFiberBundleMapper3D.h" #include #include #include #include #include #include #include #include #include #include #include #include #include class vtkShaderCallback3D : public vtkCommand { public: static vtkShaderCallback3D *New() { return new vtkShaderCallback3D; } mitk::BaseRenderer *renderer; mitk::DataNode *node; void Execute(vtkObject *, unsigned long, void*cbo) override { vtkOpenGLHelper *cellBO = reinterpret_cast(cbo); float fiberOpacity; node->GetOpacity(fiberOpacity, nullptr); cellBO->Program->SetUniformf("fiberOpacity", fiberOpacity); if (this->renderer) { mitk::Vector3D plane_vec; node->GetPropertyValue("Fiber3DClippingPlane",plane_vec); float distance = plane_vec.GetNorm(); plane_vec.Normalize(); bool flip; node->GetBoolProperty("Fiber3DClippingPlaneFlip",flip); if (flip) { plane_vec *= -1; distance *= -1; } node->GetBoolProperty("Fiber3DClippingPlaneSecondFlip",flip); if (flip) { plane_vec *= -1; distance *= -1; } float* a = new float[4]; for (int i = 0; i < 3; ++i) a[i] = plane_vec[i]; a[3] = distance; cellBO->Program->SetUniform4f("slicingPlane", a); float v = 1; node->GetFloatProperty("light.ambient", v); cellBO->Program->SetUniformf("ambient", v); node->GetFloatProperty("light.diffuse", v); cellBO->Program->SetUniformf("diffuse", v); node->GetFloatProperty("light.specular", v); cellBO->Program->SetUniformf("intensity", v); node->GetFloatProperty("light.intensity", v); cellBO->Program->SetUniformf("intensity", v); bool enable_light = false; node->GetBoolProperty("light.enable_light", enable_light); cellBO->Program->SetUniformi("enable_light", enable_light); } } vtkShaderCallback3D() { this->renderer = 0; } }; mitk::FiberBundleMapper3D::FiberBundleMapper3D() : m_TubeRadius(0.0) , m_TubeSides(15) , m_LineWidth(1) { m_lut = vtkLookupTable::New(); m_lut->Build(); } mitk::FiberBundleMapper3D::~FiberBundleMapper3D() { } const mitk::FiberBundle* mitk::FiberBundleMapper3D::GetInput() { return static_cast ( GetDataNode()->GetData() ); } /* This method is called once the mapper gets new input, for UI rotation or changes in colorcoding this method is NOT called */ void mitk::FiberBundleMapper3D::InternalGenerateData(mitk::BaseRenderer *renderer) { m_FiberPolyData->GetPointData()->AddArray(m_FiberBundle->GetFiberColors()); float tmpopa; this->GetDataNode()->GetOpacity(tmpopa, nullptr); FBXLocalStorage3D *localStorage = m_LocalStorageHandler.GetLocalStorage(renderer); if (m_TubeRadius>0.0) { vtkSmartPointer tubeFilter = vtkSmartPointer::New(); tubeFilter->SetInputData(m_FiberPolyData); tubeFilter->SetNumberOfSides(m_TubeSides); tubeFilter->SetRadius(m_TubeRadius); tubeFilter->Update(); m_FiberPolyData = tubeFilter->GetOutput(); } else if (m_RibbonWidth>0.0) { vtkSmartPointer tubeFilter = vtkSmartPointer::New(); tubeFilter->SetInputData(m_FiberPolyData); tubeFilter->SetWidth(m_RibbonWidth); tubeFilter->Update(); m_FiberPolyData = tubeFilter->GetOutput(); } if (tmpopa<1) { vtkSmartPointer depthSort = vtkSmartPointer::New(); depthSort->SetInputData( m_FiberPolyData ); depthSort->SetCamera( renderer->GetVtkRenderer()->GetActiveCamera() ); depthSort->SetDirectionToBackToFront(); depthSort->Update(); localStorage->m_FiberMapper->SetInputConnection(depthSort->GetOutputPort()); } else { localStorage->m_FiberMapper->SetInputData(m_FiberPolyData); } if (m_Lighting) { float floatProp = 1.0; GetDataNode()->GetFloatProperty("light.ambient", floatProp); localStorage->m_FiberActor->GetProperty()->SetAmbient(floatProp); GetDataNode()->GetFloatProperty("light.diffuse", floatProp); localStorage->m_FiberActor->GetProperty()->SetDiffuse(floatProp); GetDataNode()->GetFloatProperty("light.specular", floatProp); localStorage->m_FiberActor->GetProperty()->SetSpecular(floatProp); GetDataNode()->GetFloatProperty("light.specularpower", floatProp); localStorage->m_FiberActor->GetProperty()->SetSpecularPower( floatProp ); mitk::ColorProperty* ambientC = dynamic_cast(GetDataNode()->GetProperty("light.ambientcolor")); mitk::ColorProperty* diffuseC = dynamic_cast(GetDataNode()->GetProperty("light.diffusecolor")); mitk::ColorProperty* specularC = dynamic_cast(GetDataNode()->GetProperty("light.specularcolor")); localStorage->m_FiberActor->GetProperty()->SetAmbientColor( ambientC->GetColor()[0], ambientC->GetColor()[1], ambientC->GetColor()[2] ); localStorage->m_FiberActor->GetProperty()->SetDiffuseColor( diffuseC->GetColor()[0], diffuseC->GetColor()[1], diffuseC->GetColor()[2] ); localStorage->m_FiberActor->GetProperty()->SetSpecularColor( specularC->GetColor()[0], specularC->GetColor()[1], specularC->GetColor()[2] ); localStorage->m_FiberActor->GetProperty()->SetLighting(true); } else { localStorage->m_FiberActor->GetProperty()->SetLighting(false); } localStorage->m_FiberMapper->SelectColorArray("FIBER_COLORS"); localStorage->m_FiberMapper->ScalarVisibilityOn(); localStorage->m_FiberMapper->SetScalarModeToUsePointFieldData(); localStorage->m_FiberActor->SetMapper(localStorage->m_FiberMapper); localStorage->m_FiberMapper->SetLookupTable(m_lut); // set Opacity localStorage->m_FiberActor->GetProperty()->SetOpacity((double) tmpopa); localStorage->m_FiberActor->GetProperty()->SetLineWidth(m_LineWidth); localStorage->m_FiberAssembly->AddPart(localStorage->m_FiberActor); localStorage->m_FiberMapper->SetVertexShaderCode( "//VTK::System::Dec\n" "attribute vec4 vertexMC;\n" "//VTK::Normal::Dec\n" "uniform mat4 MCDCMatrix;\n" "uniform mat4 MCVCMatrix;\n" "//VTK::Color::Dec\n" "attribute vec3 normalMC;\n" "uniform mat3 normalMatrix;\n" "varying vec4 positionWorld;\n" "varying vec4 colorVertex;\n" "varying vec3 N;\n" "varying vec4 v;\n" "void main(void)\n" "{\n" " colorVertex = scalarColor;\n" " positionWorld = vertexMC;\n" " v = MCVCMatrix * vertexMC;\n" " mat4 glNormalMatrix = transpose(inverse(MCVCMatrix));\n" " N = normalize(normalMatrix * normalMC);\n" " gl_Position = MCDCMatrix * vertexMC;\n" "}\n" ); localStorage->m_FiberMapper->SetFragmentShaderCode( "//VTK::System::Dec\n" // always start with this line "//VTK::Output::Dec\n" // always have this line in your FS "uniform vec4 slicingPlane;\n" "uniform float fiberOpacity;\n" "uniform float ambient;\n" "uniform float diffuse;\n" "uniform float specular;\n" "uniform float intensity;\n" "uniform int enable_light;\n" "varying vec4 positionWorld;\n" "varying vec4 colorVertex;\n" "varying vec3 N;\n" "varying vec4 v;\n" + "out vec4 out_Color;\n" "void main(void)\n" "{\n" " float r1 = dot(positionWorld.xyz, slicingPlane.xyz) - slicingPlane.w;\n" " if ( r1 > 0 )\n" " discard;\n" " if (enable_light!=0)\n" " {\n" " vec3 L = normalize(-v.xyz);\n" // "normalize(gl_LightSource[0].position.xyz - v.xyz);\n" " vec3 E = normalize(-v.xyz); // we are in Eye Coordinates, so EyePos is (0,0,0)\n" " vec3 R = normalize(-reflect(L,N));\n" //calculate Diffuse Term: " float Idiff = diffuse * max(dot(N,L), 0.0);\n" " Idiff = clamp(Idiff, 0.0, 1.0);\n" // calculate Specular Term: " float Ispec = specular * pow(max(dot(R,E),0.0),0.3);\n" " Ispec = clamp(Ispec, 0.0, 1.0);\n" - " gl_FragColor = vec4(colorVertex.xyz, fiberOpacity)*(1-intensity) + vec4(colorVertex.xyz * (ambient + Idiff + Ispec) * intensity, fiberOpacity);\n" + " out_Color = vec4(colorVertex.xyz, fiberOpacity)*(1-intensity) + vec4(colorVertex.xyz * (ambient + Idiff + Ispec) * intensity, fiberOpacity);\n" " }\n" " else\n" " {\n" - " gl_FragColor = vec4(colorVertex.xyz, fiberOpacity);\n" + " out_Color = vec4(colorVertex.xyz, fiberOpacity);\n" " }\n" "}\n" ); vtkSmartPointer myCallback = vtkSmartPointer::New(); myCallback->renderer = renderer; myCallback->node = this->GetDataNode(); localStorage->m_FiberMapper->AddObserver(vtkCommand::UpdateShaderEvent,myCallback); localStorage->m_LastUpdateTime.Modified(); } void mitk::FiberBundleMapper3D::GenerateDataForRenderer( mitk::BaseRenderer *renderer ) { bool visible = true; GetDataNode()->GetVisibility(visible, renderer, "visible"); if ( !visible ) return; const DataNode* node = this->GetDataNode(); FBXLocalStorage3D* localStorage = m_LocalStorageHandler.GetLocalStorage(renderer); m_FiberBundle = dynamic_cast(node->GetData()); m_FiberPolyData = m_FiberBundle->GetFiberPolyData(); // this->ApplyShaderProperties(renderer, "shader_3d"); // did any rendering properties change? float tubeRadius = 0; node->GetFloatProperty("shape.tuberadius", tubeRadius); if (m_TubeRadius!=tubeRadius) { m_TubeRadius = tubeRadius; m_FiberBundle->RequestUpdate3D(); } int tubeSides = 0; node->GetIntProperty("shape.tubesides", tubeSides); if (m_TubeSides!=tubeSides) { m_TubeSides = tubeSides; m_FiberBundle->RequestUpdate3D(); } int lineWidth = 0; node->GetIntProperty("shape.linewidth", lineWidth); if (m_LineWidth!=lineWidth) { m_LineWidth = lineWidth; m_FiberBundle->RequestUpdate3D(); } float ribbonWidth = 0; node->GetFloatProperty("shape.ribbonwidth", ribbonWidth); if (m_RibbonWidth!=ribbonWidth) { m_RibbonWidth = ribbonWidth; m_FiberBundle->RequestUpdate3D(); } bool lighting = false; node->GetBoolProperty("light.enable", lighting); if (m_Lighting!=lighting) { m_Lighting = lighting; m_FiberBundle->RequestUpdate3D(); } if (localStorage->m_LastUpdateTime>=m_FiberBundle->GetUpdateTime3D()) return; // Calculate time step of the input data for the specified renderer (integer value) // this method is implemented in mitkMapper this->CalculateTimeStep( renderer ); this->InternalGenerateData(renderer); } void mitk::FiberBundleMapper3D::UpdateShaderParameter(mitk::BaseRenderer * ) { // see new vtkShaderCallback3D } void mitk::FiberBundleMapper3D::SetDefaultProperties(mitk::DataNode* node, mitk::BaseRenderer* renderer, bool overwrite) { Superclass::SetDefaultProperties(node, renderer, overwrite); mitk::Vector3D plane_vec; plane_vec.Fill(0.0); node->AddProperty( "Fiber3DClippingPlane", mitk::Vector3DProperty::New( plane_vec ), renderer, overwrite ); node->AddProperty( "Fiber3DClippingPlaneId", mitk::IntProperty::New( 0 ), renderer, overwrite ); node->AddProperty( "Fiber3DClippingPlaneFlip", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "Fiber3DClippingPlaneSecondFlip", mitk::BoolProperty::New( false ), renderer, overwrite ); node->AddProperty( "opacity", mitk::FloatProperty::New( 1.0 ), renderer, overwrite); node->AddProperty( "color", mitk::ColorProperty::New(1.0,1.0,1.0), renderer, overwrite); node->AddProperty( "pickable", mitk::BoolProperty::New( true ), renderer, overwrite); node->AddProperty( "shape.linewidth", mitk::IntProperty::New( true ), renderer, overwrite ); node->AddProperty( "shape.tuberadius",mitk::FloatProperty::New( 0.0 ), renderer, overwrite); node->AddProperty( "shape.tubesides",mitk::IntProperty::New( 15 ), renderer, overwrite); node->AddProperty( "shape.ribbonwidth", mitk::FloatProperty::New( 0.0 ), renderer, overwrite); node->AddProperty( "light.intensity", mitk::FloatProperty::New( 0.6 ), renderer, overwrite); node->AddProperty( "light.enable_light", mitk::BoolProperty::New( false ), renderer, overwrite); node->AddProperty( "light.ambient", mitk::FloatProperty::New( 0.05 ), renderer, overwrite); node->AddProperty( "light.diffuse", mitk::FloatProperty::New( 1.0 ), renderer, overwrite); node->AddProperty( "light.specular", mitk::FloatProperty::New( 0.0 ), renderer, overwrite); node->AddProperty( "light.specularpower", mitk::FloatProperty::New( 1.0 ), renderer, overwrite); node->AddProperty( "light.ambientcolor", mitk::ColorProperty::New(1,1,1), renderer, overwrite); node->AddProperty( "light.diffusecolor", mitk::ColorProperty::New(1,1,1), renderer, overwrite); node->AddProperty( "light.specularcolor", mitk::ColorProperty::New(1,1,1), renderer, overwrite); } vtkProp* mitk::FiberBundleMapper3D::GetVtkProp(mitk::BaseRenderer *renderer) { return m_LocalStorageHandler.GetLocalStorage(renderer)->m_FiberAssembly; } void mitk::FiberBundleMapper3D::SetVtkMapperImmediateModeRendering(vtkMapper *) { } mitk::FiberBundleMapper3D::FBXLocalStorage3D::FBXLocalStorage3D() { m_FiberActor = vtkSmartPointer::New(); m_FiberMapper = vtkSmartPointer::New(); m_FiberAssembly = vtkSmartPointer::New(); } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberExtractionFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberExtractionFilter.cpp index e73eff0f05..7fef1f4db9 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberExtractionFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberExtractionFilter.cpp @@ -1,380 +1,391 @@ /*=================================================================== 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 __itkFiberExtractionFilter_cpp #define __itkFiberExtractionFilter_cpp #include "itkFiberExtractionFilter.h" #define _USE_MATH_DEFINES #include #include #include namespace itk{ template< class PixelType > FiberExtractionFilter< PixelType >::FiberExtractionFilter() : m_DontResampleFibers(false) , m_Mode(MODE::OVERLAP) , m_InputType(INPUT::SCALAR_MAP) , m_BothEnds(true) , m_OverlapFraction(0.8) , m_NoNegatives(false) , m_NoPositives(false) , m_Interpolate(false) , m_Threshold(0.5) , m_Labels({1}) , m_SkipSelfConnections(false) + , m_OnlySelfConnections(false) , m_SplitLabels(false) , m_MinFibersPerTract(0) { m_Interpolator = itk::LinearInterpolateImageFunction< itk::Image< PixelType, 3 >, float >::New(); } template< class PixelType > FiberExtractionFilter< PixelType >::~FiberExtractionFilter() { } template< class PixelType > void FiberExtractionFilter< PixelType >::SetRoiImages(const std::vector &rois) { for (auto roi : rois) { if (roi==nullptr) { MITK_INFO << "ROI image is NULL!"; return; } } m_RoiImages = rois; } template< class PixelType > mitk::FiberBundle::Pointer FiberExtractionFilter< PixelType >::CreateFib(std::vector< long >& ids) { vtkSmartPointer weights = vtkSmartPointer::New(); vtkSmartPointer pTmp = m_InputFiberBundle->GeneratePolyDataByIds(ids, weights); mitk::FiberBundle::Pointer fib = mitk::FiberBundle::New(pTmp); fib->SetFiberWeights(weights); return fib; } template< class PixelType > bool FiberExtractionFilter< PixelType >::IsPositive(const itk::Point& itkP) { if( m_InputType == INPUT::SCALAR_MAP ) return mitk::imv::IsInsideMask(itkP, m_Interpolate, m_Interpolator, m_Threshold); else if( m_InputType == INPUT::LABEL_MAP ) { auto val = mitk::imv::GetImageValue(itkP, m_Interpolate, m_Interpolator); for (auto l : m_Labels) if (l==val) return true; } else mitkThrow() << "No valid input type selected!"; return false; } template< class PixelType > std::vector< std::pair > FiberExtractionFilter< PixelType >::GetPositiveLabels() const { return m_PositiveLabels; } template< class PixelType > void FiberExtractionFilter< PixelType >::ExtractOverlap(mitk::FiberBundle::Pointer fib) { MITK_INFO << "Extracting fibers (min. overlap " << m_OverlapFraction << ")"; vtkSmartPointer polydata = fib->GetFiberPolyData(); std::vector< std::vector< long > > positive_ids; positive_ids.resize(m_RoiImages.size()); std::vector< long > negative_ids; // fibers not overlapping with ANY mask boost::progress_display disp(m_InputFiberBundle->GetNumFibers()); for (int i=0; iGetNumFibers(); i++) { ++disp; vtkCell* cell = polydata->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); bool positive = false; for (unsigned int m=0; mSetInputImage(roi); int inside = 0; int outside = 0; for (int j=0; jGetPoint(j); itk::Point itkP; itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; if ( IsPositive(itkP) ) inside++; else outside++; if ((float)inside/numPoints > m_OverlapFraction) { positive = true; positive_ids[m].push_back(i); break; } } } if (!positive) negative_ids.push_back(i); } if (!m_NoNegatives) m_Negatives.push_back(CreateFib(negative_ids)); if (!m_NoPositives) for (auto ids : positive_ids) if (ids.size()>=m_MinFibersPerTract) m_Positives.push_back(CreateFib(ids)); } template< class PixelType > void FiberExtractionFilter< PixelType >::ExtractEndpoints(mitk::FiberBundle::Pointer fib) { MITK_INFO << "Extracting fibers (endpoints in mask)"; vtkSmartPointer polydata = fib->GetFiberPolyData(); std::vector< std::vector< long > > positive_ids; positive_ids.resize(m_RoiImages.size()); std::vector< long > negative_ids; // fibers not overlapping with ANY mask boost::progress_display disp(m_InputFiberBundle->GetNumFibers()); for (int i=0; iGetNumFibers(); i++) { ++disp; vtkCell* cell = polydata->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); bool positive = false; if (numPoints>1) for (unsigned int m=0; mSetInputImage(roi); int inside = 0; // check first fiber point { double* p = points->GetPoint(0); itk::Point itkP; itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; if ( IsPositive(itkP) ) inside++; } // check second fiber point { double* p = points->GetPoint(numPoints-1); itk::Point itkP; itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; if ( IsPositive(itkP) ) inside++; } if (inside==2 || (inside==1 && !m_BothEnds)) { positive = true; positive_ids[m].push_back(i); } } if (!positive) negative_ids.push_back(i); } if (!m_NoNegatives) m_Negatives.push_back(CreateFib(negative_ids)); if (!m_NoPositives) for (auto ids : positive_ids) if (ids.size()>=m_MinFibersPerTract) m_Positives.push_back(CreateFib(ids)); } template< class PixelType > void FiberExtractionFilter< PixelType >::ExtractLabels(mitk::FiberBundle::Pointer fib) { MITK_INFO << "Extracting fibers by labels"; vtkSmartPointer polydata = fib->GetFiberPolyData(); - std::vector< std::map< unsigned int, std::vector< long > > > positive_ids; + std::vector< std::map< std::pair< unsigned int, unsigned int >, std::vector< long > > > positive_ids; positive_ids.resize(m_RoiImages.size()); std::vector< long > negative_ids; // fibers not overlapping with ANY label boost::progress_display disp(m_InputFiberBundle->GetNumFibers()); for (int i=0; iGetNumFibers(); i++) { ++disp; vtkCell* cell = polydata->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); bool positive = false; if (numPoints>1) for (unsigned int m=0; mSetInputImage(roi); int inside = 0; // check first fiber point short label1 = -1; { double* p = points->GetPoint(0); itk::Point itkP; itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; label1 = mitk::imv::GetImageValue(itkP, m_Interpolate, m_Interpolator); for (auto l : m_Labels) { if (l==label1) { inside++; break; } } } // check second fiber point short label2 = -1; { double* p = points->GetPoint(numPoints-1); itk::Point itkP; itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; label2 = mitk::imv::GetImageValue(itkP, m_Interpolate, m_Interpolator); for (auto l : m_Labels) { if (l==label2) { inside++; break; } } } - if ( inside==2 && (!m_SkipSelfConnections || label1!=label2) ) + if ( (inside==2 && (!m_SkipSelfConnections || label1!=label2)) || (inside==2 && m_OnlySelfConnections && label1==label2) ) { - unsigned int key; + std::pair< unsigned int, unsigned int > key; if (label1(label1, label2); else - key = m_Labels.size()*label2 + label1; + key = std::pair< unsigned int, unsigned int >(label2, label1); positive = true; if ( positive_ids[m].count(key)==0 ) - positive_ids[m].insert( std::pair< unsigned int, std::vector< long > >( key, {i}) ); + positive_ids[m].insert( std::pair< std::pair< unsigned int, unsigned int >, std::vector< long > >( key, {i}) ); else positive_ids[m][key].push_back(i); } } if (!positive) negative_ids.push_back(i); } if (!m_NoNegatives) m_Negatives.push_back(CreateFib(negative_ids)); if (!m_NoPositives) + { for (auto labels : positive_ids) for (auto tuple : labels) { if (tuple.second.size()>=m_MinFibersPerTract) { m_Positives.push_back(CreateFib(tuple.second)); - m_PositiveLabels.push_back(std::pair< unsigned int, unsigned int >( tuple.first/m_Labels.size(), tuple.first%m_Labels.size() )); + m_PositiveLabels.push_back(tuple.first); } } + if (!m_SplitLabels) + { + mitk::FiberBundle::Pointer output = mitk::FiberBundle::New(nullptr); + output = output->AddBundles(m_Positives); + m_Positives.clear(); + m_Positives.push_back(output); + m_PositiveLabels.clear(); + } + } } template< class PixelType > void FiberExtractionFilter< PixelType >::SetLabels(const std::vector &Labels) { m_Labels = Labels; } template< class PixelType > std::vector FiberExtractionFilter< PixelType >::GetNegatives() const { return m_Negatives; } template< class PixelType > std::vector FiberExtractionFilter< PixelType >::GetPositives() const { return m_Positives; } template< class PixelType > void FiberExtractionFilter< PixelType >::GenerateData() { mitk::FiberBundle::Pointer fib = m_InputFiberBundle; if (fib->GetNumFibers()<=0) { MITK_INFO << "No fibers in tractogram!"; return; } if (m_Mode==MODE::OVERLAP && !m_DontResampleFibers) { float minSpacing = 1; for (auto mask : m_RoiImages) { for (int i=0; i<3; ++i) if(mask->GetSpacing()[i]GetSpacing()[i]; } fib = m_InputFiberBundle->GetDeepCopy(); fib->ResampleLinear(minSpacing/5); } if (m_Mode == MODE::OVERLAP) ExtractOverlap(fib); else if (m_Mode == MODE::ENDPOINTS) { - if (m_InputType==INPUT::LABEL_MAP && m_BothEnds && m_SplitLabels) + if (m_InputType==INPUT::LABEL_MAP && m_BothEnds) ExtractLabels(fib); else ExtractEndpoints(fib); } } } #endif // __itkFiberExtractionFilter_cpp diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberExtractionFilter.h b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberExtractionFilter.h index 243c359e63..53723023bd 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberExtractionFilter.h +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkFiberExtractionFilter.h @@ -1,121 +1,123 @@ /*=================================================================== 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 itkFiberExtractionFilter_h #define itkFiberExtractionFilter_h // MITK #include // ITK #include #include namespace itk{ /** * \brief Extract streamlines from tractograms using ROI images */ template< class PixelType > class FiberExtractionFilter : public ProcessObject { public: enum MODE { OVERLAP, ENDPOINTS }; enum INPUT { SCALAR_MAP, ///< In this case, positive means roi image vlaue > threshold LABEL_MAP ///< In this case, positive means roi image value in labels vector }; typedef FiberExtractionFilter Self; typedef ProcessObject Superclass; typedef SmartPointer< Self > Pointer; typedef SmartPointer< const Self > ConstPointer; typedef itk::Image< PixelType , 3> ItkInputImgType; itkFactorylessNewMacro(Self) itkCloneMacro(Self) itkTypeMacro( FiberExtractionFilter, ProcessObject ) virtual void Update() override{ this->GenerateData(); } itkSetMacro( InputFiberBundle, mitk::FiberBundle::Pointer ) itkSetMacro( Mode, MODE ) ///< Overlap or endpoints itkSetMacro( InputType, INPUT ) ///< Scalar map or label image itkSetMacro( BothEnds, bool ) ///< Both streamline ends need to be inside of the ROI for the streamline to be considered positive itkSetMacro( OverlapFraction, float ) ///< Necessary fraction of streamline points inside the ROI for the streamline to be considered positive itkSetMacro( DontResampleFibers, bool ) ///< Don't resample input fibers to ensure coverage itkSetMacro( NoNegatives, bool ) ///< Don't create output tractograms from negative streamlines (save the computation) itkSetMacro( NoPositives, bool ) ///< Don't create output tractograms from positive streamlines (save the computation) itkSetMacro( Interpolate, bool ) ///< Interpolate input ROI image itkSetMacro( Threshold, float ) ///< Threshold on input ROI image value to determine positives/negatives itkSetMacro( SkipSelfConnections, bool ) ///< Ignore streamlines between two identical labels + itkSetMacro( OnlySelfConnections, bool ) ///< Only keep streamlines between two identical labels itkSetMacro( SplitLabels, bool ) ///< Output a separate tractogram for each label-->label tract itkSetMacro( MinFibersPerTract, unsigned int ) ///< Discard positives with less fibers void SetRoiImages(const std::vector< ItkInputImgType* > &rois); void SetLabels(const std::vector &Labels); std::vector GetPositives() const; ///< Get positive tracts (filtered by the input ROIs) std::vector GetNegatives() const; ///< Get negative tracts (not filtered by the ROIs) std::vector > GetPositiveLabels() const; ///< In case of label extraction, this vector contains the labels corresponding to the positive tracts protected: void GenerateData() override; FiberExtractionFilter(); virtual ~FiberExtractionFilter(); mitk::FiberBundle::Pointer CreateFib(std::vector< long >& ids); void ExtractOverlap(mitk::FiberBundle::Pointer fib); void ExtractEndpoints(mitk::FiberBundle::Pointer fib); void ExtractLabels(mitk::FiberBundle::Pointer fib); bool IsPositive(const itk::Point& itkP); mitk::FiberBundle::Pointer m_InputFiberBundle; std::vector< mitk::FiberBundle::Pointer > m_Positives; std::vector< mitk::FiberBundle::Pointer > m_Negatives; std::vector< ItkInputImgType* > m_RoiImages; bool m_DontResampleFibers; MODE m_Mode; INPUT m_InputType; bool m_BothEnds; float m_OverlapFraction; bool m_NoNegatives; bool m_NoPositives; bool m_Interpolate; float m_Threshold; std::vector< unsigned short > m_Labels; bool m_SkipSelfConnections; + bool m_OnlySelfConnections; bool m_SplitLabels; unsigned int m_MinFibersPerTract; std::vector< std::pair< unsigned int, unsigned int > > m_PositiveLabels; typename itk::LinearInterpolateImageFunction< itk::Image< PixelType, 3 >, float >::Pointer m_Interpolator; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkFiberExtractionFilter.cpp" #endif #endif diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorBasedScoring.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorBasedScoring.cpp index 325afde7dd..7b501f724e 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorBasedScoring.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorBasedScoring.cpp @@ -1,437 +1,437 @@ /*=================================================================== 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; } /*! \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("Anchor Based Scoring"); parser.setCategory("Fiber Tracking Evaluation"); parser.setDescription(""); 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::StringList, "Candidates:", "candidate tracts (separate files)", 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("dont_filter_outliers", "", mitkCommandLineParser::Bool, "Don't filter outliers:", "don't perform second optimization run with an upper weight bound based on the first weight estimation (95% quantile)", false); parser.addArgument("regu", "", mitkCommandLineParser::String, "Regularization:", "MSM, MSE, LocalMSE (default), NONE"); 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"]); mitkCommandLineParser::StringContainerType candidate_tract_files = 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 = true; if (parsedArgs.count("dont_filter_outliers")) filter_outliers = !us::any_cast(parsedArgs["dont_filter_outliers"]); std::string mask_file = ""; if (parsedArgs.count("mask")) mask_file = us::any_cast(parsedArgs["mask"]); mitkCommandLineParser::StringContainerType anchor_mask_files; if (parsedArgs.count("anchor_masks")) anchor_mask_files = us::any_cast(parsedArgs["anchor_masks"]); std::string regu = "NONE"; if (parsedArgs.count("regu")) regu = us::any_cast(parsedArgs["regu"]); try { itk::TimeProbe clock; clock.Start(); MITK_INFO << "Creating output directory"; if (ist::PathExists(out_folder)) ist::RemoveADirectory(out_folder); 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 = dynamic_cast(mitk::IOUtil::Load(mask_file)[0].GetPointer()); mitk::CastToItkImage(mitk_mask, mask); } // Load masks covering the true positives for evaluation purposes std::vector< itk::FitFibersToImageFilter::UcharImgType::Pointer > reference_masks; for (auto filename : anchor_mask_files) { itk::FitFibersToImageFilter::UcharImgType::Pointer ref_mask = nullptr; mitk::Image::Pointer ref_mitk_mask = dynamic_cast(mitk::IOUtil::Load(filename)[0].GetPointer()); 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< mitk::FiberBundle::Pointer > input_candidates; for (std::string f : candidate_tract_files) { mitk::FiberBundle::Pointer fib = dynamic_cast(mitk::IOUtil::Load(f)[0].GetPointer()); if (fib.IsNull()) continue; if (fib->GetNumFibers()<=0) continue; fib->ResampleLinear(minSpacing/10.0); input_candidates.push_back(fib); } std::cout.rdbuf (old); // <-- restore 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 = dynamic_cast(mitk::IOUtil::Load(anchors_file)[0].GetPointer()); 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); if (regu=="MSM") fitter->SetRegularization(VnlCostFunction::REGU::MSM); else if (regu=="MSE") fitter->SetRegularization(VnlCostFunction::REGU::MSE); else if (regu=="Local_MSE") fitter->SetRegularization(VnlCostFunction::REGU::Local_MSE); else if (regu=="NONE") fitter->SetRegularization(VnlCostFunction::REGU::NONE); fitter->Update(); rmse = fitter->GetRMSE(); 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 + "0_" + name + ".fib"); peak_image = fitter->GetUnderexplainedImage(); peak_image_writer->SetInput(peak_image); peak_image_writer->SetFileName(out_folder + boost::lexical_cast(iteration) + "_" + name + ".nrrd"); peak_image_writer->Update(); } 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=="MSE") fitter->SetRegularization(VnlCostFunction::REGU::MSE); else if (regu=="Local_MSE") fitter->SetRegularization(VnlCostFunction::REGU::Local_MSE); 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->ColorFibersByFiberWeights(false, true); + 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)(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); 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(); } std::cout.rdbuf (old); // <-- restore logfile << "RMS_DIFF: " << setprecision(5) << rms_diff[c] << " " << bundle_name << " " << num_voxels << "\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"); } 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 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); 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/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/ExtractAnchorTracts.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/ExtractAnchorTracts.cpp index 81440ae729..c67164b7d1 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/ExtractAnchorTracts.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/ExtractAnchorTracts.cpp @@ -1,284 +1,277 @@ /*=================================================================== 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::Image ItkFloatImgType; typedef std::tuple< ItkFloatImgType::Pointer, std::string > MaskType; void CreateFolderStructure(const std::string& path) { if (ist::PathExists(path)) ist::RemoveADirectory(path); ist::MakeDirectory(path); ist::MakeDirectory(path + "/anchor_tracts/"); ist::MakeDirectory(path + "/candidate_tracts/"); - ist::MakeDirectory(path + "/implausible_tracts/"); ist::MakeDirectory(path + "/skipped_masks/"); } ItkFloatImgType::Pointer LoadItkImage(const std::string& filename) { mitk::Image::Pointer img = dynamic_cast(mitk::IOUtil::Load(filename)[0].GetPointer()); ItkFloatImgType::Pointer itkMask = ItkFloatImgType::New(); mitk::CastToItkImage(img, itkMask); return itkMask; } std::vector< MaskType > get_file_list(const std::string& path, float anchor_fraction, const std::string& skipped_path, int random_seed) { if (anchor_fraction<0) anchor_fraction = 0; else if (anchor_fraction>1.0) anchor_fraction = 1.0; std::chrono::milliseconds ms = std::chrono::duration_cast< std::chrono::milliseconds >(std::chrono::system_clock::now().time_since_epoch()); if (random_seed<0) std::srand(ms.count()); else std::srand(random_seed); MITK_INFO << "random_seed: " << random_seed; std::vector< MaskType > mask_list; itk::Directory::Pointer dir = itk::Directory::New(); int skipped = 0; if (dir->Load(path.c_str())) { int n = dir->GetNumberOfFiles(); int num_images = 0; std::vector< int > im_indices; for (int r = 0; r < n; r++) { const char *filename = dir->GetFile(r); std::string ext = ist::GetFilenameExtension(filename); if (ext==".nii" || ext==".nii.gz" || ext==".nrrd") { ++num_images; im_indices.push_back(r); } } int skipping_num = num_images * (1.0 - anchor_fraction); std::random_shuffle(im_indices.begin(), im_indices.end()); MITK_INFO << "Skipping " << skipping_num << " images"; MITK_INFO << "Number of anchors: " << num_images-skipping_num; int c = -1; for (int r : im_indices) { c++; const char *filename = dir->GetFile(r); if (c matrix = vtkSmartPointer< vtkMatrix4x4 >::New(); matrix->Identity(); matrix->SetElement(0,0,-matrix->GetElement(0,0)); matrix->SetElement(1,1,-matrix->GetElement(1,1)); geometry->SetIndexToWorldTransformByVtkMatrix(matrix); vtkSmartPointer transformFilter = vtkSmartPointer::New(); transformFilter->SetInputData(fib->GetFiberPolyData()); transformFilter->SetTransform(geometry->GetVtkTransform()); transformFilter->Update(); mitk::FiberBundle::Pointer transformed_fib = mitk::FiberBundle::New(transformFilter->GetOutput()); return transformed_fib; } /*! \brief */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Extract Overlapping Tracts"); parser.setCategory("Fiber Tracking Evaluation"); parser.setDescription(""); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input:", "input tractogram (.fib, vtk ascii file format)", us::Any(), false); parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output folder", us::Any(), false); parser.addArgument("reference_mask_folder", "m", mitkCommandLineParser::String, "Reference Mask Folder:", "reference masks of known bundles", us::Any(), false); parser.addArgument("gray_matter_mask", "gm", mitkCommandLineParser::String, "GM mask:", "remove fibers not ending in the gray matter"); parser.addArgument("anchor_fraction", "", mitkCommandLineParser::Float, "Anchor fraction:", "Fraction of tracts used as anchors", 0.5); parser.addArgument("overlap", "", mitkCommandLineParser::Float, "Overlap threshold:", "Overlap threshold used to identify the anchor tracts", 0.8); parser.addArgument("subsample", "", mitkCommandLineParser::Float, "Subsampling factor:", "Only use specified fraction of input fibers for the analysis", 1.0); parser.addArgument("random_seed", "", mitkCommandLineParser::Int, ":", "", -1); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string fibFile = us::any_cast(parsedArgs["input"]); std::string reference_mask_folder = us::any_cast(parsedArgs["reference_mask_folder"]); std::string out_folder = us::any_cast(parsedArgs["out"]); std::string gray_matter_mask = ""; if (parsedArgs.count("gray_matter_mask")) gray_matter_mask = us::any_cast(parsedArgs["gray_matter_mask"]); float anchor_fraction = 0.5; if (parsedArgs.count("anchor_fraction")) anchor_fraction = us::any_cast(parsedArgs["anchor_fraction"]); int random_seed = -1; if (parsedArgs.count("random_seed")) random_seed = us::any_cast(parsedArgs["random_seed"]); float overlap = 0.8; if (parsedArgs.count("overlap")) overlap = us::any_cast(parsedArgs["overlap"]); float subsample = 1.0; if (parsedArgs.count("subsample")) subsample = us::any_cast(parsedArgs["subsample"]); try { CreateFolderStructure(out_folder); std::vector< MaskType > known_tract_masks = get_file_list(reference_mask_folder, anchor_fraction, out_folder + "/skipped_masks/", random_seed); mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::Load(fibFile)[0].GetPointer()); if (gray_matter_mask.compare("")!=0) { MITK_INFO << "Removing fibers not ending inside of GM"; std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect ItkFloatImgType::Pointer gm_image = LoadItkImage(gray_matter_mask); std::cout.rdbuf (old); // <-- restore itk::FiberExtractionFilter::Pointer extractor = itk::FiberExtractionFilter::New(); extractor->SetInputFiberBundle(inputTractogram); extractor->SetRoiImages({gm_image}); extractor->SetBothEnds(true); + extractor->SetNoNegatives(true); extractor->SetMode(itk::FiberExtractionFilter::MODE::ENDPOINTS); extractor->Update(); - - mitk::FiberBundle::Pointer not_gm_fibers = extractor->GetNegatives().at(0); - - old = cout.rdbuf(); // <-- save - std::cout.rdbuf (ss.rdbuf()); // <-- redirect - mitk::IOUtil::Save(not_gm_fibers, out_folder + "/implausible_tracts/no_gm_endings.trk"); inputTractogram = extractor->GetPositives().at(0); - std::cout.rdbuf (old); // <-- restore } std::srand(0); if (subsample<1.0) inputTractogram = inputTractogram->SubsampleFibers(subsample); mitk::FiberBundle::Pointer anchor_tractogram = mitk::FiberBundle::New(nullptr); mitk::FiberBundle::Pointer candidate_tractogram = mitk::FiberBundle::New(nullptr); if (!known_tract_masks.empty()) { MITK_INFO << "Find known tracts via overlap match"; std::vector< ItkFloatImgType::Pointer > mask_images; for (auto mask : known_tract_masks) mask_images.push_back(std::get<0>(mask)); std::vector< ItkFloatImgType* > roi_images2; for (auto roi : mask_images) roi_images2.push_back(roi); itk::FiberExtractionFilter::Pointer extractor = itk::FiberExtractionFilter::New(); extractor->SetInputFiberBundle(inputTractogram); extractor->SetRoiImages(roi_images2); extractor->SetOverlapFraction(overlap); extractor->SetMode(itk::FiberExtractionFilter::MODE::OVERLAP); extractor->Update(); std::vector< mitk::FiberBundle::Pointer > positives = extractor->GetPositives(); candidate_tractogram = extractor->GetNegatives().at(0); for ( unsigned int i=0; i(known_tract_masks.at(i)); mitk::IOUtil::Save(positives.at(i), out_folder + "/anchor_tracts/" + mask_name + ".trk"); std::cout.rdbuf (old); // <-- restore } anchor_tractogram = anchor_tractogram->AddBundles(positives); } mitk::IOUtil::Save(anchor_tractogram, out_folder + "/anchor_tracts/anchor_tractogram.trk"); mitk::IOUtil::Save(candidate_tractogram, out_folder + "/candidate_tracts/candidate_tractogram.trk"); mitk::IOUtil::Save(inputTractogram, out_folder + "/filtered_tractogram.trk"); } 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/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/Perspectives/QmitkConnectomicsPerspective.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/Perspectives/QmitkConnectomicsPerspective.cpp index 41d242cb19..0f9a3e68c9 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/Perspectives/QmitkConnectomicsPerspective.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.connectomics/src/internal/Perspectives/QmitkConnectomicsPerspective.cpp @@ -1,47 +1,47 @@ /*=================================================================== 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 "QmitkConnectomicsPerspective.h" #include "berryIViewLayout.h" void QmitkConnectomicsPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) { ///////////////////////////////////////////////////// // all di-app perspectives should have the following: ///////////////////////////////////////////////////// QString editorArea = layout->GetEditorArea(); layout->AddStandaloneViewPlaceholder("org.mitk.views.viewnavigatorview", berry::IPageLayout::LEFT, 0.3f, editorArea, false); layout->AddStandaloneView("org.mitk.views.datamanager", false, berry::IPageLayout::LEFT, 0.3f, editorArea); layout->AddStandaloneView("org.mitk.views.controlvisualizationpropertiesview", false, berry::IPageLayout::BOTTOM, .15f, "org.mitk.views.datamanager"); berry::IFolderLayout::Pointer left = - layout->CreateFolder("org.mbi.diffusionimaginginternal.leftcontrols", berry::IPageLayout::BOTTOM, 0.1f, "org.mitk.views.controlvisualizationpropertiesview"); + layout->CreateFolder("org.mbi.diffusionimaginginternal.leftcontrols", berry::IPageLayout::BOTTOM, 0.15f, "org.mitk.views.controlvisualizationpropertiesview"); layout->AddStandaloneViewPlaceholder("org.mitk.views.imagenavigator", berry::IPageLayout::BOTTOM, .7f, "org.mbi.diffusionimaginginternal.leftcontrols", false); ///////////////////////////////////////////// // here goes the perspective specific stuff ///////////////////////////////////////////// left->AddView("org.mitk.views.connectomicsdata"); left->AddView("org.mitk.views.connectomicsstatistics"); left->AddView("org.mitk.views.connectomicsnetworkoperations"); left->AddView("org.mitk.views.randomparcellationview"); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/Perspectives/QmitkDIAppSyntheticDataGenerationPerspective.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/Perspectives/QmitkDIAppSyntheticDataGenerationPerspective.cpp index f85c776dfa..eb8fe468e4 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/Perspectives/QmitkDIAppSyntheticDataGenerationPerspective.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberfox/src/internal/Perspectives/QmitkDIAppSyntheticDataGenerationPerspective.cpp @@ -1,51 +1,51 @@ /*=================================================================== 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 "QmitkDIAppSyntheticDataGenerationPerspective.h" #include "berryIViewLayout.h" void QmitkDIAppSyntheticDataGenerationPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) { ///////////////////////////////////////////////////// // all di-app perspectives should have the following: ///////////////////////////////////////////////////// QString editorArea = layout->GetEditorArea(); layout->AddStandaloneViewPlaceholder("org.mitk.views.viewnavigatorview", berry::IPageLayout::LEFT, 0.3f, editorArea, false); layout->AddStandaloneView("org.mitk.views.datamanager", false, berry::IPageLayout::LEFT, 0.3f, editorArea); layout->AddStandaloneView("org.mitk.views.controlvisualizationpropertiesview", false, berry::IPageLayout::BOTTOM, .15f, "org.mitk.views.datamanager"); berry::IFolderLayout::Pointer left = layout->CreateFolder("org.mbi.diffusionimaginginternal.leftcontrols", - berry::IPageLayout::BOTTOM, 0.1f, "org.mitk.views.controlvisualizationpropertiesview"); + berry::IPageLayout::BOTTOM, 0.15f, "org.mitk.views.controlvisualizationpropertiesview"); layout->AddStandaloneViewPlaceholder("org.mitk.views.imagenavigator", berry::IPageLayout::BOTTOM, .7f, "org.mbi.diffusionimaginginternal.leftcontrols", false); ///////////////////////////////////////////// // here goes the perspective specific stuff ///////////////////////////////////////////// left->AddView("org.mitk.views.fiberfoxview"); left->AddView("org.mitk.views.fieldmapgenerator"); left->AddView("org.mitk.views.segmentation"); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/Perspectives/QmitkFiberProcessingPerspective.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/Perspectives/QmitkFiberProcessingPerspective.cpp index a231283b84..5e61d1afaf 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/Perspectives/QmitkFiberProcessingPerspective.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/Perspectives/QmitkFiberProcessingPerspective.cpp @@ -1,52 +1,52 @@ /*=================================================================== 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 "QmitkFiberProcessingPerspective.h" #include "berryIViewLayout.h" void QmitkFiberProcessingPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) { ///////////////////////////////////////////////////// // all di-app perspectives should have the following: ///////////////////////////////////////////////////// QString editorArea = layout->GetEditorArea(); layout->AddStandaloneViewPlaceholder("org.mitk.views.viewnavigatorview", berry::IPageLayout::LEFT, 0.3f, editorArea, false); layout->AddStandaloneView("org.mitk.views.datamanager", false, berry::IPageLayout::LEFT, 0.3f, editorArea); layout->AddStandaloneView("org.mitk.views.controlvisualizationpropertiesview", false, berry::IPageLayout::BOTTOM, .15f, "org.mitk.views.datamanager"); berry::IFolderLayout::Pointer left = layout->CreateFolder("org.mbi.diffusionimaginginternal.leftcontrols", - berry::IPageLayout::BOTTOM, 0.1f, "org.mitk.views.controlvisualizationpropertiesview"); + berry::IPageLayout::BOTTOM, 0.15f, "org.mitk.views.controlvisualizationpropertiesview"); layout->AddStandaloneViewPlaceholder("org.mitk.views.imagenavigator", berry::IPageLayout::BOTTOM, .7f, "org.mbi.diffusionimaginginternal.leftcontrols", false); ///////////////////////////////////////////// // here goes the perspective specific stuff ///////////////////////////////////////////// left->AddView("org.mitk.views.fiberprocessing"); left->AddView("org.mitk.views.fiberquantification"); left->AddView("org.mitk.views.fiberclustering"); left->AddView("org.mitk.views.fiberfit"); left->AddView("org.mitk.views.segmentation"); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/Perspectives/QmitkDIAppIVIMPerspective.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/Perspectives/QmitkDIAppIVIMPerspective.cpp index b3539be4a4..0c8192235f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/Perspectives/QmitkDIAppIVIMPerspective.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.ivim/src/internal/Perspectives/QmitkDIAppIVIMPerspective.cpp @@ -1,51 +1,51 @@ /*=================================================================== 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 "QmitkDIAppIVIMPerspective.h" #include "berryIViewLayout.h" void QmitkDIAppIVIMPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) { ///////////////////////////////////////////////////// // all di-app perspectives should have the following: ///////////////////////////////////////////////////// QString editorArea = layout->GetEditorArea(); layout->AddStandaloneViewPlaceholder("org.mitk.views.viewnavigatorview", berry::IPageLayout::LEFT, 0.3f, editorArea, false); layout->AddStandaloneView("org.mitk.views.datamanager", false, berry::IPageLayout::LEFT, 0.3f, editorArea); layout->AddStandaloneView("org.mitk.views.controlvisualizationpropertiesview", false, berry::IPageLayout::BOTTOM, .15f, "org.mitk.views.datamanager"); berry::IFolderLayout::Pointer left = - layout->CreateFolder("org.mbi.diffusionimaginginternal.leftcontrols", berry::IPageLayout::BOTTOM, 0.1f, "org.mitk.views.controlvisualizationpropertiesview"); + layout->CreateFolder("org.mbi.diffusionimaginginternal.leftcontrols", berry::IPageLayout::BOTTOM, 0.15f, "org.mitk.views.controlvisualizationpropertiesview"); layout->AddStandaloneViewPlaceholder("org.mitk.views.imagenavigator", berry::IPageLayout::BOTTOM, .7f, "org.mbi.diffusionimaginginternal.leftcontrols", false); ///////////////////////////////////////////// // here goes the perspective specific stuff ///////////////////////////////////////////// left->AddView("org.mitk.views.ivim"); berry::IViewLayout::Pointer lo = layout->GetViewLayout("org.mitk.views.ivim"); left->AddView("org.mitk.views.segmentation"); lo = layout->GetViewLayout("org.mitk.views.segmentation"); left->AddView("org.mitk.views.diffusionquantification"); left->AddView("org.mitk.views.diffusionpreprocessing"); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/Perspectives/QmitkReconstructionPerspective.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/Perspectives/QmitkReconstructionPerspective.cpp index d1c156a3ec..5d41035ce5 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/Perspectives/QmitkReconstructionPerspective.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/Perspectives/QmitkReconstructionPerspective.cpp @@ -1,52 +1,52 @@ /*=================================================================== 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 "QmitkReconstructionPerspective.h" #include "berryIViewLayout.h" void QmitkReconstructionPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) { ///////////////////////////////////////////////////// // all di-app perspectives should have the following: ///////////////////////////////////////////////////// QString editorArea = layout->GetEditorArea(); layout->AddStandaloneViewPlaceholder("org.mitk.views.viewnavigatorview", berry::IPageLayout::LEFT, 0.3f, editorArea, false); layout->AddStandaloneView("org.mitk.views.datamanager", false, berry::IPageLayout::LEFT, 0.3f, editorArea); layout->AddStandaloneView("org.mitk.views.controlvisualizationpropertiesview", false, berry::IPageLayout::BOTTOM, .15f, "org.mitk.views.datamanager"); berry::IFolderLayout::Pointer left = layout->CreateFolder("org.mbi.diffusionimaginginternal.leftcontrols", - berry::IPageLayout::BOTTOM, 0.1f, "org.mitk.views.controlvisualizationpropertiesview"); + berry::IPageLayout::BOTTOM, 0.15f, "org.mitk.views.controlvisualizationpropertiesview"); layout->AddStandaloneViewPlaceholder("org.mitk.views.imagenavigator", berry::IPageLayout::BOTTOM, .7f, "org.mbi.diffusionimaginginternal.leftcontrols", false); ///////////////////////////////////////////// // here goes the perspective specific stuff ///////////////////////////////////////////// left->AddView("org.mitk.views.tensorreconstruction"); left->AddView("org.mitk.views.qballreconstruction"); left->AddView("org.mitk.views.diffusionquantification"); left->AddView("org.mitk.views.diffusionpreprocessing"); left->AddView("org.mitk.views.odfdetails"); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDwiRegistrationPerspective.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDwiRegistrationPerspective.cpp index 7f1109ce4d..a5762d2bd2 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDwiRegistrationPerspective.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.registration/src/internal/QmitkDwiRegistrationPerspective.cpp @@ -1,49 +1,49 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "QmitkDwiRegistrationPerspective.h" #include "berryIViewLayout.h" void QmitkDwiRegistrationPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) { ///////////////////////////////////////////////////// // all di-app perspectives should have the following: ///////////////////////////////////////////////////// QString editorArea = layout->GetEditorArea(); layout->AddStandaloneViewPlaceholder("org.mitk.views.viewnavigatorview", berry::IPageLayout::LEFT, 0.3f, editorArea, false); layout->AddStandaloneView("org.mitk.views.datamanager", false, berry::IPageLayout::LEFT, 0.3f, editorArea); layout->AddStandaloneView("org.mitk.views.controlvisualizationpropertiesview", false, berry::IPageLayout::BOTTOM, .15f, "org.mitk.views.datamanager"); berry::IFolderLayout::Pointer left = layout->CreateFolder("org.mbi.diffusionimaginginternal.leftcontrols", - berry::IPageLayout::BOTTOM, 0.1f, "org.mitk.views.controlvisualizationpropertiesview"); + berry::IPageLayout::BOTTOM, 0.15f, "org.mitk.views.controlvisualizationpropertiesview"); layout->AddStandaloneViewPlaceholder("org.mitk.views.imagenavigator", berry::IPageLayout::BOTTOM, .7f, "org.mbi.diffusionimaginginternal.leftcontrols", false); ///////////////////////////////////////////// // here goes the perspective specific stuff ///////////////////////////////////////////// left->AddView("org.mitk.views.simplerigidregistrationview"); left->AddView("org.mitk.views.diffusionregistrationview"); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/Perspectives/QmitkGibbsTractographyPerspective.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/Perspectives/QmitkGibbsTractographyPerspective.cpp index 7c043d6050..fc805e1180 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/Perspectives/QmitkGibbsTractographyPerspective.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/Perspectives/QmitkGibbsTractographyPerspective.cpp @@ -1,50 +1,50 @@ /*=================================================================== 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 "QmitkGibbsTractographyPerspective.h" #include "berryIViewLayout.h" void QmitkGibbsTractographyPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) { ///////////////////////////////////////////////////// // all di-app perspectives should have the following: ///////////////////////////////////////////////////// QString editorArea = layout->GetEditorArea(); layout->AddStandaloneViewPlaceholder("org.mitk.views.viewnavigatorview", berry::IPageLayout::LEFT, 0.3f, editorArea, false); layout->AddStandaloneView("org.mitk.views.datamanager", false, berry::IPageLayout::LEFT, 0.3f, editorArea); layout->AddStandaloneView("org.mitk.views.controlvisualizationpropertiesview", false, berry::IPageLayout::BOTTOM, .15f, "org.mitk.views.datamanager"); berry::IFolderLayout::Pointer left = layout->CreateFolder("org.mbi.diffusionimaginginternal.leftcontrols", - berry::IPageLayout::BOTTOM, 0.1f, "org.mitk.views.controlvisualizationpropertiesview"); + berry::IPageLayout::BOTTOM, 0.15f, "org.mitk.views.controlvisualizationpropertiesview"); layout->AddStandaloneViewPlaceholder("org.mitk.views.imagenavigator", berry::IPageLayout::BOTTOM, .7f, "org.mbi.diffusionimaginginternal.leftcontrols", false); ///////////////////////////////////////////// // here goes the perspective specific stuff ///////////////////////////////////////////// left->AddView("org.mitk.views.gibbstracking"); left->AddView("org.mitk.views.qballreconstruction"); left->AddView("org.mitk.views.tensorreconstruction"); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/Perspectives/QmitkMachineLearningTractographyPerspective.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/Perspectives/QmitkMachineLearningTractographyPerspective.cpp index dee7fc5715..9d899f42e0 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/Perspectives/QmitkMachineLearningTractographyPerspective.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/Perspectives/QmitkMachineLearningTractographyPerspective.cpp @@ -1,50 +1,50 @@ /*=================================================================== 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 "QmitkMachineLearningTractographyPerspective.h" #include "berryIViewLayout.h" void QmitkMachineLearningTractographyPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) { ///////////////////////////////////////////////////// // all di-app perspectives should have the following: ///////////////////////////////////////////////////// QString editorArea = layout->GetEditorArea(); layout->AddStandaloneViewPlaceholder("org.mitk.views.viewnavigatorview", berry::IPageLayout::LEFT, 0.3f, editorArea, false); layout->AddStandaloneView("org.mitk.views.datamanager", false, berry::IPageLayout::LEFT, 0.3f, editorArea); layout->AddStandaloneView("org.mitk.views.controlvisualizationpropertiesview", false, berry::IPageLayout::BOTTOM, .15f, "org.mitk.views.datamanager"); berry::IFolderLayout::Pointer left = layout->CreateFolder("org.mbi.diffusionimaginginternal.leftcontrols", - berry::IPageLayout::BOTTOM, 0.1f, "org.mitk.views.controlvisualizationpropertiesview"); + berry::IPageLayout::BOTTOM, 0.15f, "org.mitk.views.controlvisualizationpropertiesview"); layout->AddStandaloneViewPlaceholder("org.mitk.views.imagenavigator", berry::IPageLayout::BOTTOM, .7f, "org.mbi.diffusionimaginginternal.leftcontrols", false); ///////////////////////////////////////////// // here goes the perspective specific stuff ///////////////////////////////////////////// left->AddView("org.mitk.views.mlbtview"); left->AddView("org.mitk.views.segmentation"); left->AddView("org.mitk.views.diffusionpreprocessing"); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/Perspectives/QmitkStreamlineTractographyPerspective.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/Perspectives/QmitkStreamlineTractographyPerspective.cpp index 1fad90f86c..896f44a280 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/Perspectives/QmitkStreamlineTractographyPerspective.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/Perspectives/QmitkStreamlineTractographyPerspective.cpp @@ -1,50 +1,50 @@ /*=================================================================== 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 "QmitkStreamlineTractographyPerspective.h" #include "berryIViewLayout.h" void QmitkStreamlineTractographyPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) { ///////////////////////////////////////////////////// // all di-app perspectives should have the following: ///////////////////////////////////////////////////// QString editorArea = layout->GetEditorArea(); layout->AddStandaloneViewPlaceholder("org.mitk.views.viewnavigatorview", berry::IPageLayout::LEFT, 0.3f, editorArea, false); layout->AddStandaloneView("org.mitk.views.datamanager", false, berry::IPageLayout::LEFT, 0.3f, editorArea); layout->AddStandaloneView("org.mitk.views.controlvisualizationpropertiesview", false, berry::IPageLayout::BOTTOM, .15f, "org.mitk.views.datamanager"); berry::IFolderLayout::Pointer left = layout->CreateFolder("org.mbi.diffusionimaginginternal.leftcontrols", - berry::IPageLayout::BOTTOM, 0.1f, "org.mitk.views.controlvisualizationpropertiesview"); + berry::IPageLayout::BOTTOM, 0.15f, "org.mitk.views.controlvisualizationpropertiesview"); layout->AddStandaloneViewPlaceholder("org.mitk.views.imagenavigator", berry::IPageLayout::BOTTOM, .7f, "org.mbi.diffusionimaginginternal.leftcontrols", false); ///////////////////////////////////////////// // here goes the perspective specific stuff ///////////////////////////////////////////// left->AddView("org.mitk.views.streamlinetracking"); left->AddView("org.mitk.views.segmentation"); left->AddView("org.mitk.views.odfmaximaextraction"); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/Perspectives/QmitkDiffusionDefaultPerspective.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/Perspectives/QmitkDiffusionDefaultPerspective.cpp index 431e3acdb1..37aceceefa 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/Perspectives/QmitkDiffusionDefaultPerspective.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging/src/internal/Perspectives/QmitkDiffusionDefaultPerspective.cpp @@ -1,46 +1,46 @@ /*=================================================================== 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 "QmitkDiffusionDefaultPerspective.h" #include "berryIViewLayout.h" void QmitkDiffusionDefaultPerspective::CreateInitialLayout(berry::IPageLayout::Pointer layout) { ///////////////////////////////////////////////////// // all di-app perspectives should have the following: ///////////////////////////////////////////////////// QString editorArea = layout->GetEditorArea(); layout->AddStandaloneViewPlaceholder("org.mitk.views.viewnavigatorview", berry::IPageLayout::LEFT, 0.3f, editorArea, false); layout->AddStandaloneView("org.mitk.views.datamanager", false, berry::IPageLayout::LEFT, 0.3f, editorArea); layout->AddStandaloneView("org.mitk.views.controlvisualizationpropertiesview", false, berry::IPageLayout::BOTTOM, .15f, "org.mitk.views.datamanager"); berry::IFolderLayout::Pointer left = - layout->CreateFolder("org.mbi.diffusionimaginginternal.leftcontrols", berry::IPageLayout::BOTTOM, 0.1f, "org.mitk.views.controlvisualizationpropertiesview"); + layout->CreateFolder("org.mbi.diffusionimaginginternal.leftcontrols", berry::IPageLayout::BOTTOM, 0.15f, "org.mitk.views.controlvisualizationpropertiesview"); layout->AddStandaloneViewPlaceholder("org.mitk.views.imagenavigator", berry::IPageLayout::BOTTOM, .7f, "org.mbi.diffusionimaginginternal.leftcontrols", false); ///////////////////////////////////////////// // here goes the perspective specific stuff ///////////////////////////////////////////// left->AddView("org.mitk.views.diffusiondicomimport"); left->AddView("org.mitk.views.diffusionpreprocessing"); }