diff --git a/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt b/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt index 3f1e079d5c..51cd8aad24 100644 --- a/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt +++ b/Applications/PluginGenerator/ProjectTemplate/CMakeLists.txt @@ -1,340 +1,339 @@ cmake_minimum_required(VERSION 3.10 FATAL_ERROR) # Change project and application name to your own set(MY_PROJECT_NAME $(project-name)) set(MY_APP_NAME $(project-app-name)) #----------------------------------------------------------------------------- # Set the language standard (MITK requires C++14) #----------------------------------------------------------------------------- set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED 1) set(CMAKE_CXX_EXTENSIONS 0) #----------------------------------------------------------------------------- # Set a default build type if none was specified #----------------------------------------------------------------------------- if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Debug' as none was specified.") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() #----------------------------------------------------------------------------- # Superbuild Option - Enabled by default #----------------------------------------------------------------------------- option(${MY_PROJECT_NAME}_USE_SUPERBUILD "Build ${MY_PROJECT_NAME} and the projects it depends on via SuperBuild.cmake." ON) if(${MY_PROJECT_NAME}_USE_SUPERBUILD) project(${MY_PROJECT_NAME}-superbuild) set(${MY_PROJECT_NAME}_SOURCE_DIR ${PROJECT_SOURCE_DIR}) set(${MY_PROJECT_NAME}_BINARY_DIR ${PROJECT_BINARY_DIR}) else() project(${MY_PROJECT_NAME}) endif() #----------------------------------------------------------------------------- # See http://cmake.org/cmake/help/cmake-2-8-docs.html#section_Policies for details #----------------------------------------------------------------------------- set(project_policies CMP0001 # NEW: CMAKE_BACKWARDS_COMPATIBILITY should no longer be used. CMP0002 # NEW: Logical target names must be globally unique. CMP0003 # NEW: Libraries linked via full path no longer produce linker search paths. CMP0004 # NEW: Libraries linked may NOT have leading or trailing whitespace. CMP0005 # NEW: Preprocessor definition values are now escaped automatically. CMP0006 # NEW: Installing MACOSX_BUNDLE targets requires a BUNDLE DESTINATION. CMP0007 # NEW: List command no longer ignores empty elements. CMP0008 # NEW: Libraries linked by full-path must have a valid library file name. CMP0009 # NEW: FILE GLOB_RECURSE calls should not follow symlinks by default. CMP0010 # NEW: Bad variable reference syntax is an error. CMP0011 # NEW: Included scripts do automatic cmake_policy PUSH and POP. CMP0012 # NEW: if() recognizes numbers and boolean constants. CMP0013 # NEW: Duplicate binary directories are not allowed. CMP0014 # NEW: Input directories must have CMakeLists.txt CMP0020 # NEW: Automatically link Qt executables to qtmain target on Windows. CMP0028 # NEW: Double colon in target name means ALIAS or IMPORTED target. ) foreach(policy ${project_policies}) if(POLICY ${policy}) cmake_policy(SET ${policy} NEW) endif() endforeach() #----------------------------------------------------------------------------- # Update CMake module path #------------------------------------------------------------------------------ set(CMAKE_MODULE_PATH ${${MY_PROJECT_NAME}_SOURCE_DIR}/CMake ${CMAKE_MODULE_PATH} ) #----------------------------------------------------------------------------- # CMake Function(s) and Macro(s) #----------------------------------------------------------------------------- include(MacroEmptyExternalProject) #----------------------------------------------------------------------------- # Output directories. #----------------------------------------------------------------------------- foreach(type LIBRARY RUNTIME ARCHIVE) set(output_dir ${${MY_PROJECT_NAME}_BINARY_DIR}/bin) set(CMAKE_${type}_OUTPUT_DIRECTORY ${output_dir} CACHE INTERNAL "Single output directory for building all libraries.") mark_as_advanced(CMAKE_${type}_OUTPUT_DIRECTORY) endforeach() #----------------------------------------------------------------------------- # Additional Options (also shown during superbuild) #----------------------------------------------------------------------------- option(BUILD_SHARED_LIBS "Build ${MY_PROJECT_NAME} with shared libraries" ON) option(WITH_COVERAGE "Enable/Disable coverage" OFF) option(BUILD_TESTING "Test the project" ON) option(${MY_PROJECT_NAME}_BUILD_ALL_PLUGINS "Build all ${MY_PROJECT_NAME} plugins" OFF) mark_as_advanced(${MY_PROJECT_NAME}_INSTALL_RPATH_RELATIVE ${MY_PROJECT_NAME}_BUILD_ALL_PLUGINS ) #----------------------------------------------------------------------------- # Superbuild script #----------------------------------------------------------------------------- if(${MY_PROJECT_NAME}_USE_SUPERBUILD) include("${CMAKE_CURRENT_SOURCE_DIR}/SuperBuild.cmake") return() endif() #***************************************************************************** #**************************** END OF SUPERBUILD **************************** #***************************************************************************** #----------------------------------------------------------------------------- # Prerequesites #----------------------------------------------------------------------------- set(${PROJECT_NAME}_MODULES_PACKAGE_DEPENDS_DIR "${PROJECT_SOURCE_DIR}/CMake/PackageDepends") set(MODULES_PACKAGE_DEPENDS_DIRS ${${PROJECT_NAME}_MODULES_PACKAGE_DEPENDS_DIR}) find_package(MITK 2016.11.00 REQUIRED) if(COMMAND mitkFunctionCheckMitkCompatibility) mitkFunctionCheckMitkCompatibility(VERSIONS MITK_VERSION_PLUGIN_SYSTEM 1 REQUIRED) else() message(SEND_ERROR "Your MITK version is too old. Please use Git hash b86bf28 or newer") endif() link_directories(${MITK_LINK_DIRECTORIES}) #----------------------------------------------------------------------------- # CMake Function(s) and Macro(s) #----------------------------------------------------------------------------- set(CMAKE_MODULE_PATH ${MITK_SOURCE_DIR}/CMake ${CMAKE_MODULE_PATH} ) include(mitkFunctionCheckCompilerFlags) include(mitkFunctionGetGccVersion) include(mitkFunctionGetVersion) #----------------------------------------------------------------------------- # Set project specific options and variables (NOT available during superbuild) #----------------------------------------------------------------------------- set(${PROJECT_NAME}_VERSION_MAJOR "0") set(${PROJECT_NAME}_VERSION_MINOR "1") set(${PROJECT_NAME}_VERSION_PATCH "1") set(${PROJECT_NAME}_VERSION_STRING "${${PROJECT_NAME}_VERSION_MAJOR}.${${PROJECT_NAME}_VERSION_MINOR}.${${PROJECT_NAME}_VERSION_PATCH}") # Ask the user if a console window should be shown with the applications option(${PROJECT_NAME}_SHOW_CONSOLE_WINDOW "Use this to enable or disable the console window when starting GUI Applications" ON) mark_as_advanced(${PROJECT_NAME}_SHOW_CONSOLE_WINDOW) -if(NOT UNIX AND NOT MINGW) +if(NOT UNIX) set(MITK_WIN32_FORCE_STATIC "STATIC") endif() #----------------------------------------------------------------------------- # Get project version info #----------------------------------------------------------------------------- mitkFunctionGetVersion(${PROJECT_SOURCE_DIR} ${PROJECT_NAME}) #----------------------------------------------------------------------------- # Installation preparation # # These should be set before any MITK install macros are used #----------------------------------------------------------------------------- # on Mac OSX all CTK plugins get copied into every # application bundle (.app directory) specified here set(MACOSX_BUNDLE_NAMES) if(APPLE) list(APPEND MACOSX_BUNDLE_NAMES ${MY_APP_NAME}) endif(APPLE) #----------------------------------------------------------------------------- # Set symbol visibility Flags #----------------------------------------------------------------------------- -# MinGW does not export all symbols automatically, so no need to set flags -if(CMAKE_COMPILER_IS_GNUCXX AND NOT MINGW) +if(CMAKE_COMPILER_IS_GNUCXX) # The MITK module build system does not yet support default hidden visibility set(VISIBILITY_CXX_FLAGS ) # "-fvisibility=hidden -fvisibility-inlines-hidden") endif() #----------------------------------------------------------------------------- # Set coverage Flags #----------------------------------------------------------------------------- if(WITH_COVERAGE) if(CMAKE_COMPILER_IS_GNUCXX) set(coverage_flags "-g -fprofile-arcs -ftest-coverage -O0 -DNDEBUG") set(COVERAGE_CXX_FLAGS ${coverage_flags}) set(COVERAGE_C_FLAGS ${coverage_flags}) endif() endif() #----------------------------------------------------------------------------- # Project C/CXX Flags #----------------------------------------------------------------------------- set(${PROJECT_NAME}_C_FLAGS "${MITK_C_FLAGS} ${COVERAGE_C_FLAGS}") set(${PROJECT_NAME}_C_FLAGS_DEBUG ${MITK_C_FLAGS_DEBUG}) set(${PROJECT_NAME}_C_FLAGS_RELEASE ${MITK_C_FLAGS_RELEASE}) set(${PROJECT_NAME}_CXX_FLAGS "${MITK_CXX_FLAGS} ${VISIBILITY_CXX_FLAGS} ${COVERAGE_CXX_FLAGS}") set(${PROJECT_NAME}_CXX_FLAGS_DEBUG ${MITK_CXX_FLAGS_DEBUG}) set(${PROJECT_NAME}_CXX_FLAGS_RELEASE ${MITK_CXX_FLAGS_RELEASE}) set(${PROJECT_NAME}_EXE_LINKER_FLAGS ${MITK_EXE_LINKER_FLAGS}) set(${PROJECT_NAME}_SHARED_LINKER_FLAGS ${MITK_SHARED_LINKER_FLAGS}) set(${PROJECT_NAME}_MODULE_LINKER_FLAGS ${MITK_MODULE_LINKER_FLAGS}) #----------------------------------------------------------------------------- # Set C/CXX Flags #----------------------------------------------------------------------------- set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${${PROJECT_NAME}_C_FLAGS}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${${PROJECT_NAME}_C_FLAGS_DEBUG}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${${PROJECT_NAME}_C_FLAGS_RELEASE}") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${${PROJECT_NAME}_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${${PROJECT_NAME}_CXX_FLAGS_DEBUG}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${${PROJECT_NAME}_CXX_FLAGS_RELEASE}") set(CMAKE_EXE_LINKER_FLAGS ${${PROJECT_NAME}_EXE_LINKER_FLAGS}) set(CMAKE_SHARED_LINKER_FLAGS ${${PROJECT_NAME}_SHARED_LINKER_FLAGS}) set(CMAKE_MODULE_LINKER_FLAGS ${${PROJECT_NAME}_MODULE_LINKER_FLAGS}) #----------------------------------------------------------------------------- # Testing #----------------------------------------------------------------------------- if(BUILD_TESTING) enable_testing() include(CTest) mark_as_advanced(TCL_TCLSH DART_ROOT) # Setup file for setting custom ctest vars configure_file( CMake/CTestCustom.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/CTestCustom.cmake @ONLY ) # Configuration for the CMake-generated test driver set(CMAKE_TESTDRIVER_EXTRA_INCLUDES "#include ") set(CMAKE_TESTDRIVER_BEFORE_TESTMAIN " try {") set(CMAKE_TESTDRIVER_AFTER_TESTMAIN " } catch( std::exception & excp ) { fprintf(stderr,\"%s\\n\",excp.what()); return EXIT_FAILURE; } catch( ... ) { printf(\"Exception caught in the test driver\\n\"); return EXIT_FAILURE; } ") endif() #----------------------------------------------------------------------------- # ${MY_PROJECT_NAME}_SUPERBUILD_BINARY_DIR #----------------------------------------------------------------------------- # If ${MY_PROJECT_NAME}_SUPERBUILD_BINARY_DIR isn't defined, it means this project is # *NOT* build using Superbuild. In that specific case, ${MY_PROJECT_NAME}_SUPERBUILD_BINARY_DIR # should default to PROJECT_BINARY_DIR if(NOT DEFINED ${PROJECT_NAME}_SUPERBUILD_BINARY_DIR) set(${PROJECT_NAME}_SUPERBUILD_BINARY_DIR ${PROJECT_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # MITK modules #----------------------------------------------------------------------------- #add_subdirectory(Modules) #----------------------------------------------------------------------------- # CTK plugins #----------------------------------------------------------------------------- # The CMake code in this section *must* be in the top-level CMakeLists.txt file macro(GetMyTargetLibraries all_target_libraries varname) set(re_ctkplugin "^$(project-plugin-base)_[a-zA-Z0-9_]+$") set(_tmp_list) list(APPEND _tmp_list ${all_target_libraries}) ctkMacroListFilter(_tmp_list re_ctkplugin OUTPUT_VARIABLE ${varname}) endmacro() include(${CMAKE_CURRENT_SOURCE_DIR}/Plugins/Plugins.cmake) ctkMacroSetupPlugins(${PROJECT_PLUGINS} BUILD_OPTION_PREFIX ${MY_PROJECT_NAME}_ BUILD_ALL ${${MY_PROJECT_NAME}_BUILD_ALL_PLUGINS}) #----------------------------------------------------------------------------- # Add subdirectories #----------------------------------------------------------------------------- add_subdirectory(Apps/$(project-app-name)) #----------------------------------------------------------------------------- # Installation #----------------------------------------------------------------------------- # set MITK cpack variables include(mitkSetupCPack) # Customize CPack variables for this project include(CPackSetup) list(APPEND CPACK_CREATE_DESKTOP_LINKS "${MY_APP_NAME}") configure_file(${MITK_SOURCE_DIR}/MITKCPackOptions.cmake.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}CPackOptions.cmake @ONLY) set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_BINARY_DIR}/${PROJECT_NAME}CPackOptions.cmake") # include CPack model once all variables are set include(CPack) # Additional installation rules include(mitkInstallRules) #----------------------------------------------------------------------------- # Last configuration steps #----------------------------------------------------------------------------- diff --git a/CMake/GetPrerequisites.cmake b/CMake/GetPrerequisites.cmake index 7a085a9a3b..09f5d0f465 100644 --- a/CMake/GetPrerequisites.cmake +++ b/CMake/GetPrerequisites.cmake @@ -1,1096 +1,1095 @@ # Special version of GetPrerequisites that implements a caching mechanism. # Thank you to Daniel Maleike for the contribution message("Using MITK version of GetPrerequisites.cmake") # Distributed under the OSI-approved BSD 3-Clause License. See accompanying # file Copyright.txt or https://cmake.org/licensing for details. #.rst: # GetPrerequisites # ---------------- # # Functions to analyze and list executable file prerequisites. # # This module provides functions to list the .dll, .dylib or .so files # that an executable or shared library file depends on. (Its # prerequisites.) # # It uses various tools to obtain the list of required shared library # files: # # :: # # dumpbin (Windows) -# objdump (MinGW on Windows) # ldd (Linux/Unix) # otool (Mac OSX) # # The following functions are provided by this module: # # :: # # get_prerequisites # list_prerequisites # list_prerequisites_by_glob # gp_append_unique # is_file_executable # gp_item_default_embedded_path # (projects can override with gp_item_default_embedded_path_override) # gp_resolve_item # (projects can override with gp_resolve_item_override) # gp_resolved_file_type # (projects can override with gp_resolved_file_type_override) # gp_file_type # # Requires CMake 2.6 or greater because it uses function, break, return # and PARENT_SCOPE. # # :: # # GET_PREREQUISITES( # []) # # Get the list of shared library files required by . The list # in the variable named should be empty on first # entry to this function. On exit, will contain the # list of required shared library files. # # is the full path to an executable file. # is the name of a CMake variable to contain the results. # must be 0 or 1 indicating whether to include or # exclude "system" prerequisites. If is set to 1 all # prerequisites will be found recursively, if set to 0 only direct # prerequisites are listed. is the path to the top level # executable used for @executable_path replacment on the Mac. is # a list of paths where libraries might be found: these paths are # searched first when a target without any path info is given. Then # standard system locations are also searched: PATH, Framework # locations, /usr/lib... # # :: # # LIST_PREREQUISITES( [ [ []]]) # # Print a message listing the prerequisites of . # # is the name of a shared library or executable target or the # full path to a shared library or executable file. If is set # to 1 all prerequisites will be found recursively, if set to 0 only # direct prerequisites are listed. must be 0 or 1 # indicating whether to include or exclude "system" prerequisites. With # set to 0 only the full path names of the prerequisites are # printed, set to 1 extra informatin will be displayed. # # :: # # LIST_PREREQUISITES_BY_GLOB( ) # # Print the prerequisites of shared library and executable files # matching a globbing pattern. is GLOB or GLOB_RECURSE and # is a globbing expression used with "file(GLOB" or # "file(GLOB_RECURSE" to retrieve a list of matching files. If a # matching file is executable, its prerequisites are listed. # # Any additional (optional) arguments provided are passed along as the # optional arguments to the list_prerequisites calls. # # :: # # GP_APPEND_UNIQUE( ) # # Append to the list variable only if the value is # not already in the list. # # :: # # IS_FILE_EXECUTABLE( ) # # Return 1 in if is a binary executable, 0 # otherwise. # # :: # # GP_ITEM_DEFAULT_EMBEDDED_PATH( ) # # Return the path that others should refer to the item by when the item # is embedded inside a bundle. # # Override on a per-project basis by providing a project-specific # gp_item_default_embedded_path_override function. # # :: # # GP_RESOLVE_ITEM( # []) # # Resolve an item into an existing full path file. # # Override on a per-project basis by providing a project-specific # gp_resolve_item_override function. # # :: # # GP_RESOLVED_FILE_TYPE( # []) # # Return the type of with respect to . String # describing type of prerequisite is returned in variable named # . # # Use and if necessary to resolve non-absolute # values -- but only for non-embedded items. # # Possible types are: # # :: # # system # local # embedded # other # # Override on a per-project basis by providing a project-specific # gp_resolved_file_type_override function. # # :: # # GP_FILE_TYPE( ) # # Return the type of with respect to . String # describing type of prerequisite is returned in variable named # . # # Possible types are: # # :: # # system # local # embedded # other function(gp_append_unique list_var value) set(contains 0) foreach(item ${${list_var}}) if(item STREQUAL "${value}") set(contains 1) break() endif() endforeach() if(NOT contains) set(${list_var} ${${list_var}} "${value}" PARENT_SCOPE) endif() endfunction() function(is_file_executable file result_var) # # A file is not executable until proven otherwise: # set(${result_var} 0 PARENT_SCOPE) get_filename_component(file_full "${file}" ABSOLUTE) string(TOLOWER "${file_full}" file_full_lower) # If file name ends in .exe on Windows, *assume* executable: # if(WIN32 AND NOT UNIX) if("${file_full_lower}" MATCHES "\\.exe$") set(${result_var} 1 PARENT_SCOPE) return() endif() # A clause could be added here that uses output or return value of dumpbin # to determine ${result_var}. In 99%+? practical cases, the exe name # match will be sufficient... # endif() # Use the information returned from the Unix shell command "file" to # determine if ${file_full} should be considered an executable file... # # If the file command's output contains "executable" and does *not* contain # "text" then it is likely an executable suitable for prerequisite analysis # via the get_prerequisites macro. # if(UNIX) if(NOT file_cmd) find_program(file_cmd "file") mark_as_advanced(file_cmd) endif() if(file_cmd) execute_process(COMMAND "${file_cmd}" "${file_full}" RESULT_VARIABLE file_rv OUTPUT_VARIABLE file_ov ERROR_VARIABLE file_ev OUTPUT_STRIP_TRAILING_WHITESPACE ) if(NOT file_rv STREQUAL "0") message(FATAL_ERROR "${file_cmd} failed: ${file_rv}\n${file_ev}") endif() # Replace the name of the file in the output with a placeholder token # (the string " _file_full_ ") so that just in case the path name of # the file contains the word "text" or "executable" we are not fooled # into thinking "the wrong thing" because the file name matches the # other 'file' command output we are looking for... # string(REPLACE "${file_full}" " _file_full_ " file_ov "${file_ov}") string(TOLOWER "${file_ov}" file_ov) #message(STATUS "file_ov='${file_ov}'") if("${file_ov}" MATCHES "executable") #message(STATUS "executable!") if("${file_ov}" MATCHES "text") #message(STATUS "but text, so *not* a binary executable!") else() set(${result_var} 1 PARENT_SCOPE) return() endif() endif() # Also detect position independent executables on Linux, # where "file" gives "shared object ... (uses shared libraries)" if("${file_ov}" MATCHES "shared object.*\(uses shared libs\)") set(${result_var} 1 PARENT_SCOPE) return() endif() # "file" version 5.22 does not print "(used shared libraries)" # but uses "interpreter" if("${file_ov}" MATCHES "shared object.*interpreter") set(${result_var} 1 PARENT_SCOPE) return() endif() else() message(STATUS "warning: No 'file' command, skipping execute_process...") endif() endif() endfunction() function(gp_item_default_embedded_path item default_embedded_path_var) # On Windows and Linux, "embed" prerequisites in the same directory # as the executable by default: # set(path "@executable_path") set(overridden 0) # On the Mac, relative to the executable depending on the type # of the thing we are embedding: # if(APPLE) # # The assumption here is that all executables in the bundle will be # in same-level-directories inside the bundle. The parent directory # of an executable inside the bundle should be MacOS or a sibling of # MacOS and all embedded paths returned from here will begin with # "@executable_path/../" and will work from all executables in all # such same-level-directories inside the bundle. # # By default, embed things right next to the main bundle executable: # set(path "@executable_path/../../Contents/MacOS") # Embed .dylibs right next to the main bundle executable: # if(item MATCHES "\\.dylib$") set(path "@executable_path/../MacOS") set(overridden 1) endif() # Embed frameworks in the embedded "Frameworks" directory (sibling of MacOS): # if(NOT overridden) if(item MATCHES "[^/]+\\.framework/") set(path "@executable_path/../Frameworks") set(overridden 1) endif() endif() endif() # Provide a hook so that projects can override the default embedded location # of any given library by whatever logic they choose: # if(COMMAND gp_item_default_embedded_path_override) gp_item_default_embedded_path_override("${item}" path) endif() set(${default_embedded_path_var} "${path}" PARENT_SCOPE) endfunction() function(gp_resolve_item context item exepath dirs resolved_item_var) set(resolved 0) set(resolved_item "${item}") if(ARGC GREATER 5) set(rpaths "${ARGV5}") else() set(rpaths "") endif() # Is it already resolved? # if(IS_ABSOLUTE "${resolved_item}" AND EXISTS "${resolved_item}") set(resolved 1) endif() if(NOT resolved) if(item MATCHES "^@executable_path") # # @executable_path references are assumed relative to exepath # string(REPLACE "@executable_path" "${exepath}" ri "${item}") get_filename_component(ri "${ri}" ABSOLUTE) if(EXISTS "${ri}") #message(STATUS "info: embedded item exists (${ri})") set(resolved 1) set(resolved_item "${ri}") else() message(STATUS "warning: embedded item does not exist '${ri}'") endif() endif() endif() if(NOT resolved) if(item MATCHES "^@loader_path") # # @loader_path references are assumed relative to the # PATH of the given "context" (presumably another library) # get_filename_component(contextpath "${context}" PATH) string(REPLACE "@loader_path" "${contextpath}" ri "${item}") get_filename_component(ri "${ri}" ABSOLUTE) if(EXISTS "${ri}") #message(STATUS "info: embedded item exists (${ri})") set(resolved 1) set(resolved_item "${ri}") else() message(STATUS "warning: embedded item does not exist '${ri}'") endif() endif() endif() if(NOT resolved) if(item MATCHES "^@rpath") # # @rpath references are relative to the paths built into the binaries with -rpath # We handle this case like we do for other Unixes # string(REPLACE "@rpath/" "" norpath_item "${item}") set(ri "ri-NOTFOUND") find_file(ri "${norpath_item}" ${exepath} ${dirs} ${rpaths} NO_DEFAULT_PATH) if(ri) #message(STATUS "info: 'find_file' in exepath/dirs/rpaths (${ri})") set(resolved 1) set(resolved_item "${ri}") set(ri "ri-NOTFOUND") endif() endif() endif() if(NOT resolved) set(ri "ri-NOTFOUND") find_file(ri "${item}" ${exepath} ${dirs} NO_DEFAULT_PATH) find_file(ri "${item}" ${exepath} ${dirs} /usr/lib) get_filename_component(basename_item "${item}" NAME) find_file(ri "${basename_item}" PATHS ${exepath} ${dirs} NO_DEFAULT_PATH) find_file(ri "${basename_item}" PATHS /usr/lib) if(ri) #message(STATUS "info: 'find_file' in exepath/dirs (${ri})") set(resolved 1) set(resolved_item "${ri}") set(ri "ri-NOTFOUND") endif() endif() if(NOT resolved) if(item MATCHES "[^/]+\\.framework/") set(fw "fw-NOTFOUND") find_file(fw "${item}" "~/Library/Frameworks" "/Library/Frameworks" "/System/Library/Frameworks" ) if(fw) #message(STATUS "info: 'find_file' found framework (${fw})") set(resolved 1) set(resolved_item "${fw}") set(fw "fw-NOTFOUND") endif() endif() endif() # Using find_program on Windows will find dll files that are in the PATH. # (Converting simple file names into full path names if found.) # if(WIN32 AND NOT UNIX) if(NOT resolved) set(ri "ri-NOTFOUND") find_program(ri "${item}" PATHS ${exepath} ${dirs} NO_DEFAULT_PATH) find_program(ri "${item}" PATHS ${exepath} ${dirs}) if(ri) #message(STATUS "info: 'find_program' in exepath/dirs (${ri})") set(resolved 1) set(resolved_item "${ri}") set(ri "ri-NOTFOUND") endif() endif() endif() # Provide a hook so that projects can override item resolution # by whatever logic they choose: # if(COMMAND gp_resolve_item_override) gp_resolve_item_override("${context}" "${item}" "${exepath}" "${dirs}" resolved_item resolved) endif() if(NOT resolved) message(STATUS " warning: cannot resolve item '${item}' possible problems: need more directories? need to use InstallRequiredSystemLibraries? run in install tree instead of build tree? ") # message(STATUS " #****************************************************************************** #warning: cannot resolve item '${item}' # # possible problems: # need more directories? # need to use InstallRequiredSystemLibraries? # run in install tree instead of build tree? # # context='${context}' # item='${item}' # exepath='${exepath}' # dirs='${dirs}' # resolved_item_var='${resolved_item_var}' #****************************************************************************** #") endif() set(${resolved_item_var} "${resolved_item}" PARENT_SCOPE) endfunction() function(gp_resolved_file_type original_file file exepath dirs type_var) if(ARGC GREATER 5) set(rpaths "${ARGV5}") else() set(rpaths "") endif() #message(STATUS "**") if(NOT IS_ABSOLUTE "${original_file}") message(STATUS "warning: gp_resolved_file_type expects absolute full path for first arg original_file") endif() if(IS_ABSOLUTE "${original_file}") get_filename_component(original_file "${original_file}" ABSOLUTE) # canonicalize path endif() set(is_embedded 0) set(is_local 0) set(is_system 0) set(resolved_file "${file}") if("${file}" MATCHES "^@(executable|loader)_path") set(is_embedded 1) endif() if(NOT is_embedded) if(NOT IS_ABSOLUTE "${file}") gp_resolve_item("${original_file}" "${file}" "${exepath}" "${dirs}" resolved_file "${rpaths}") endif() if(IS_ABSOLUTE "${resolved_file}") get_filename_component(resolved_file "${resolved_file}" ABSOLUTE) # canonicalize path endif() string(TOLOWER "${original_file}" original_lower) string(TOLOWER "${resolved_file}" lower) if(UNIX) if(resolved_file MATCHES "^(/lib/|/lib32/|/libx32/|/lib64/|/usr/lib/|/usr/lib32/|/usr/libx32/|/usr/lib64/|/usr/X11R6/|/usr/bin/)") set(is_system 1) endif() endif() if(APPLE) if(resolved_file MATCHES "^(/System/Library/|/usr/lib/)") set(is_system 1) endif() endif() if(WIN32) string(TOLOWER "$ENV{SystemRoot}" sysroot) file(TO_CMAKE_PATH "${sysroot}" sysroot) string(TOLOWER "$ENV{windir}" windir) file(TO_CMAKE_PATH "${windir}" windir) if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*(msvc|api-ms-win-)[^/]+dll)") set(is_system 1) endif() if(UNIX) # if cygwin, we can get the properly formed windows paths from cygpath find_program(CYGPATH_EXECUTABLE cygpath) if(CYGPATH_EXECUTABLE) execute_process(COMMAND ${CYGPATH_EXECUTABLE} -W RESULT_VARIABLE env_rv OUTPUT_VARIABLE env_windir ERROR_VARIABLE env_ev OUTPUT_STRIP_TRAILING_WHITESPACE) if(NOT env_rv STREQUAL "0") message(FATAL_ERROR "${CYGPATH_EXECUTABLE} -W failed: ${env_rv}\n${env_ev}") endif() execute_process(COMMAND ${CYGPATH_EXECUTABLE} -S RESULT_VARIABLE env_rv OUTPUT_VARIABLE env_sysdir ERROR_VARIABLE env_ev OUTPUT_STRIP_TRAILING_WHITESPACE) if(NOT env_rv STREQUAL "0") message(FATAL_ERROR "${CYGPATH_EXECUTABLE} -S failed: ${env_rv}\n${env_ev}") endif() string(TOLOWER "${env_windir}" windir) string(TOLOWER "${env_sysdir}" sysroot) if(lower MATCHES "^(${sysroot}/sys(tem|wow)|${windir}/sys(tem|wow)|(.*/)*(msvc|api-ms-win-)[^/]+dll)") set(is_system 1) endif() endif() endif() endif() if(NOT is_system) get_filename_component(original_path "${original_lower}" PATH) get_filename_component(path "${lower}" PATH) if(original_path STREQUAL path) set(is_local 1) else() string(LENGTH "${original_path}/" original_length) string(LENGTH "${lower}" path_length) if(${path_length} GREATER ${original_length}) string(SUBSTRING "${lower}" 0 ${original_length} path) if("${original_path}/" STREQUAL path) set(is_embedded 1) endif() endif() endif() endif() endif() # Return type string based on computed booleans: # set(type "other") if(is_system) set(type "system") elseif(is_embedded) set(type "embedded") elseif(is_local) set(type "local") endif() #message(STATUS "gp_resolved_file_type: '${file}' '${resolved_file}'") #message(STATUS " type: '${type}'") if(NOT is_embedded) if(NOT IS_ABSOLUTE "${resolved_file}") if(lower MATCHES "^(msvc|api-ms-win-)[^/]+dll" AND is_system) message(STATUS "info: non-absolute msvc file '${file}' returning type '${type}'") else() message(STATUS "warning: gp_resolved_file_type non-absolute file '${file}' returning type '${type}' -- possibly incorrect") endif() endif() endif() # Provide a hook so that projects can override the decision on whether a # library belongs to the system or not by whatever logic they choose: # if(COMMAND gp_resolved_file_type_override) gp_resolved_file_type_override("${resolved_file}" type) endif() set(${type_var} "${type}" PARENT_SCOPE) #message(STATUS "**") endfunction() function(gp_file_type original_file file type_var) if(NOT IS_ABSOLUTE "${original_file}") message(STATUS "warning: gp_file_type expects absolute full path for first arg original_file") endif() get_filename_component(exepath "${original_file}" PATH) set(type "") gp_resolved_file_type("${original_file}" "${file}" "${exepath}" "" type) set(${type_var} "${type}" PARENT_SCOPE) endfunction() function(get_prerequisites_clear_cache) set_property(GLOBAL PROPERTY prerequisites_cachevariables "") endfunction(get_prerequisites_clear_cache) function(get_prerequisites target prerequisites_var exclude_system recurse exepath dirs) - + # See if we know the answer from our cache. If so, we are done early - + # incorporate all parameters into cache key string(SHA1 param_hash "${exclude_system}_${recurse}_${exepath}_${dirs}") set(prerequisites_cache_var_name "prerequisites_cache_${target}_${param_hash}") string(TOLOWER "${prerequisites_cache_var_name}" prerequisites_cache_var_name) string(REGEX REPLACE "[:-\\/.]" "_" prerequisites_cache_var_name "${prerequisites_cache_var_name}") get_property(cache_value GLOBAL PROPERTY ${prerequisites_cache_var_name} SET) if (cache_value) get_property(cache_value GLOBAL PROPERTY ${prerequisites_cache_var_name}) # if defined, then get value if (cache_value) # already something non-empty -> append set(${prerequisites_var} "${${prerequisites_var}};${cache_value}" PARENT_SCOPE) endif() return() endif() set(verbose 0) set(eol_char "E") if(ARGC GREATER 6) set(rpaths "${ARGV6}") else() set(rpaths "") endif() if(NOT IS_ABSOLUTE "${target}") message("warning: target '${target}' is not absolute...") endif() if(NOT EXISTS "${target}") message("warning: target '${target}' does not exist...") set(${prerequisites_var} "" PARENT_SCOPE) return() endif() set(gp_cmd_paths ${gp_cmd_paths} "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\14.0;InstallDir]/../../VC/bin" "$ENV{VS140COMNTOOLS}/../../VC/bin" "C:/Program Files (x86)/Microsoft Visual Studio 14.0/VC/bin" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\12.0;InstallDir]/../../VC/bin" "$ENV{VS120COMNTOOLS}/../../VC/bin" "C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\11.0;InstallDir]/../../VC/bin" "$ENV{VS110COMNTOOLS}/../../VC/bin" "C:/Program Files (x86)/Microsoft Visual Studio 11.0/VC/bin" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\10.0;InstallDir]/../../VC/bin" "$ENV{VS100COMNTOOLS}/../../VC/bin" "C:/Program Files (x86)/Microsoft Visual Studio 10.0/VC/bin" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\9.0;InstallDir]/../../VC/bin" "$ENV{VS90COMNTOOLS}/../../VC/bin" "C:/Program Files/Microsoft Visual Studio 9.0/VC/bin" "C:/Program Files (x86)/Microsoft Visual Studio 9.0/VC/bin" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\8.0;InstallDir]/../../VC/bin" "$ENV{VS80COMNTOOLS}/../../VC/bin" "C:/Program Files/Microsoft Visual Studio 8/VC/BIN" "C:/Program Files (x86)/Microsoft Visual Studio 8/VC/BIN" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\Microsoft\\VisualStudio\\7.1;InstallDir]/../../VC7/bin" "$ENV{VS71COMNTOOLS}/../../VC7/bin" "C:/Program Files/Microsoft Visual Studio .NET 2003/VC7/BIN" "C:/Program Files (x86)/Microsoft Visual Studio .NET 2003/VC7/BIN" "/usr/local/bin" "/usr/bin" ) # # # Try to choose the right tool by default. Caller can set gp_tool prior to # calling this function to force using a different tool. # if(NOT gp_tool) set(gp_tool "ldd") if(APPLE) set(gp_tool "otool") endif() if(WIN32 AND NOT UNIX) # This is how to check for cygwin, har! find_program(gp_dumpbin "dumpbin" PATHS ${gp_cmd_paths}) if(gp_dumpbin) set(gp_tool "dumpbin") - else() # Try harder. Maybe we're on MinGW + else() # Try harder. set(gp_tool "objdump") endif() endif() endif() find_program(gp_cmd ${gp_tool} PATHS ${gp_cmd_paths}) if(NOT gp_cmd) message(STATUS "warning: could not find '${gp_tool}' - cannot analyze prerequisites...") return() endif() set(gp_cmd_maybe_filter) # optional command to pre-filter gp_tool results if(gp_tool STREQUAL "ldd") set(gp_cmd_args "") set(gp_regex "^[\t ]*[^\t ]+ => ([^\t\(]+) .*${eol_char}$") set(gp_regex_error "not found${eol_char}$") set(gp_regex_fallback "^[\t ]*([^\t ]+) => ([^\t ]+).*${eol_char}$") set(gp_regex_cmp_count 1) elseif(gp_tool STREQUAL "otool") set(gp_cmd_args "-L") set(gp_regex "^\t([^\t]+) \\(compatibility version ([0-9]+.[0-9]+.[0-9]+), current version ([0-9]+.[0-9]+.[0-9]+)\\)${eol_char}$") set(gp_regex_error "") set(gp_regex_fallback "") set(gp_regex_cmp_count 3) elseif(gp_tool STREQUAL "dumpbin") set(gp_cmd_args "/dependents") set(gp_regex "^ ([^ ].*[Dd][Ll][Ll])${eol_char}$") set(gp_regex_error "") set(gp_regex_fallback "") set(gp_regex_cmp_count 1) elseif(gp_tool STREQUAL "objdump") set(gp_cmd_args "-p") set(gp_regex "^\t*DLL Name: (.*\\.[Dd][Ll][Ll])${eol_char}$") set(gp_regex_error "") set(gp_regex_fallback "") set(gp_regex_cmp_count 1) # objdump generates copious output so we create a grep filter to pre-filter results if(WIN32) find_program(gp_grep_cmd findstr) else() find_program(gp_grep_cmd grep) endif() if(gp_grep_cmd) set(gp_cmd_maybe_filter COMMAND ${gp_grep_cmd} "-a" "^[[:blank:]]*DLL Name: ") endif() else() message(STATUS "warning: gp_tool='${gp_tool}' is an unknown tool...") message(STATUS "CMake function get_prerequisites needs more code to handle '${gp_tool}'") message(STATUS "Valid gp_tool values are dumpbin, ldd, objdump and otool.") return() endif() if(gp_tool STREQUAL "dumpbin") # When running dumpbin, it also needs the "Common7/IDE" directory in the # PATH. It will already be in the PATH if being run from a Visual Studio # command prompt. Add it to the PATH here in case we are running from a # different command prompt. # get_filename_component(gp_cmd_dir "${gp_cmd}" PATH) get_filename_component(gp_cmd_dlls_dir "${gp_cmd_dir}/../../Common7/IDE" ABSOLUTE) # Use cmake paths as a user may have a PATH element ending with a backslash. # This will escape the list delimiter and create havoc! if(EXISTS "${gp_cmd_dlls_dir}") # only add to the path if it is not already in the path set(gp_found_cmd_dlls_dir 0) file(TO_CMAKE_PATH "$ENV{PATH}" env_path) foreach(gp_env_path_element ${env_path}) if(gp_env_path_element STREQUAL gp_cmd_dlls_dir) set(gp_found_cmd_dlls_dir 1) endif() endforeach() if(NOT gp_found_cmd_dlls_dir) file(TO_NATIVE_PATH "${gp_cmd_dlls_dir}" gp_cmd_dlls_dir) set(ENV{PATH} "$ENV{PATH};${gp_cmd_dlls_dir}") endif() endif() endif() # # if(gp_tool STREQUAL "ldd") set(old_ld_env "$ENV{LD_LIBRARY_PATH}") set(new_ld_env "${exepath}") foreach(dir ${dirs}) string(APPEND new_ld_env ":${dir}") endforeach() set(ENV{LD_LIBRARY_PATH} "${new_ld_env}:$ENV{LD_LIBRARY_PATH}") endif() # Track new prerequisites at each new level of recursion. Start with an # empty list at each level: # set(unseen_prereqs) # Run gp_cmd on the target: # execute_process( COMMAND ${gp_cmd} ${gp_cmd_args} ${target} ${gp_cmd_maybe_filter} RESULT_VARIABLE gp_rv OUTPUT_VARIABLE gp_cmd_ov ERROR_VARIABLE gp_ev ) if(gp_tool STREQUAL "dumpbin") # Exclude delay load dependencies under windows (they are listed in dumpbin output after the message below) string(FIND "${gp_cmd_ov}" "Image has the following delay load dependencies" gp_delayload_pos) if (${gp_delayload_pos} GREATER -1) string(SUBSTRING "${gp_cmd_ov}" 0 ${gp_delayload_pos} gp_cmd_ov_no_delayload_deps) string(SUBSTRING "${gp_cmd_ov}" ${gp_delayload_pos} -1 gp_cmd_ov_delayload_deps) if (verbose) message(STATUS "GetPrequisites(${target}) : ignoring the following delay load dependencies :\n ${gp_cmd_ov_delayload_deps}") endif() set(gp_cmd_ov ${gp_cmd_ov_no_delayload_deps}) endif() endif() if(NOT gp_rv STREQUAL "0") if(gp_tool STREQUAL "dumpbin") # dumpbin error messages seem to go to stdout message(FATAL_ERROR "${gp_cmd} failed: ${gp_rv}\n${gp_ev}\n${gp_cmd_ov}") else() message(FATAL_ERROR "${gp_cmd} failed: ${gp_rv}\n${gp_ev}") endif() endif() if(gp_tool STREQUAL "ldd") set(ENV{LD_LIBRARY_PATH} "${old_ld_env}") endif() if(verbose) message(STATUS "") message(STATUS "gp_cmd_ov='${gp_cmd_ov}'") message(STATUS "") endif() get_filename_component(target_dir "${target}" PATH) # Convert to a list of lines: # string(REPLACE ";" "\\;" candidates "${gp_cmd_ov}") string(REPLACE "\n" "${eol_char};" candidates "${candidates}") # check for install id and remove it from list, since otool -L can include a # reference to itself set(gp_install_id) if(gp_tool STREQUAL "otool") execute_process( COMMAND otool -D ${target} RESULT_VARIABLE otool_rv OUTPUT_VARIABLE gp_install_id_ov ERROR_VARIABLE otool_ev ) if(NOT otool_rv STREQUAL "0") message(FATAL_ERROR "otool -D failed: ${otool_rv}\n${otool_ev}") endif() # second line is install name string(REGEX REPLACE ".*:\n" "" gp_install_id "${gp_install_id_ov}") if(gp_install_id) # trim string(REGEX MATCH "[^\n ].*[^\n ]" gp_install_id "${gp_install_id}") #message("INSTALL ID is \"${gp_install_id}\"") endif() endif() # Analyze each line for file names that match the regular expression: # list(LENGTH ${prerequisites_var} list_length_before_candidates) set(targets_added "") foreach(candidate ${candidates}) if("${candidate}" MATCHES "${gp_regex}") # Extract information from each candidate: if(gp_regex_error AND "${candidate}" MATCHES "${gp_regex_error}") string(REGEX REPLACE "${gp_regex_fallback}" "\\1" raw_item "${candidate}") else() string(REGEX REPLACE "${gp_regex}" "\\1" raw_item "${candidate}") endif() if(gp_regex_cmp_count GREATER 1) string(REGEX REPLACE "${gp_regex}" "\\2" raw_compat_version "${candidate}") string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" compat_major_version "${raw_compat_version}") string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" compat_minor_version "${raw_compat_version}") string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" compat_patch_version "${raw_compat_version}") endif() if(gp_regex_cmp_count GREATER 2) string(REGEX REPLACE "${gp_regex}" "\\3" raw_current_version "${candidate}") string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\1" current_major_version "${raw_current_version}") string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\2" current_minor_version "${raw_current_version}") string(REGEX REPLACE "^([0-9]+)\\.([0-9]+)\\.([0-9]+)$" "\\3" current_patch_version "${raw_current_version}") endif() # Use the raw_item as the list entries returned by this function. Use the # gp_resolve_item function to resolve it to an actual full path file if # necessary. # set(item "${raw_item}") # Add each item unless it is excluded: # set(add_item 1) if(item STREQUAL gp_install_id) set(add_item 0) endif() if(add_item AND ${exclude_system}) set(type "") gp_resolved_file_type("${target}" "${item}" "${exepath}" "${dirs}" type "${rpaths}") if(type STREQUAL "system") set(add_item 0) endif() endif() if(add_item) list(LENGTH ${prerequisites_var} list_length_before_append) gp_append_unique(${prerequisites_var} "${item}") list(LENGTH ${prerequisites_var} list_length_after_append) if(${recurse}) # If item was really added, this is the first time we have seen it. # Add it to unseen_prereqs so that we can recursively add *its* # prerequisites... # # But first: resolve its name to an absolute full path name such # that the analysis tools can simply accept it as input. # if(NOT list_length_before_append EQUAL list_length_after_append) gp_resolve_item("${target}" "${item}" "${exepath}" "${dirs}" resolved_item "${rpaths}") if(EXISTS "${resolved_item}") # Recurse only if we could resolve the item. # Otherwise the prerequisites_var list will be cleared set(unseen_prereqs ${unseen_prereqs} "${resolved_item}") endif() endif() endif() endif() else() if(verbose) message(STATUS "ignoring non-matching line: '${candidate}'") endif() endif() endforeach() list(LENGTH ${prerequisites_var} prerequisites_var_length) if(prerequisites_var_length GREATER 0) list(SORT ${prerequisites_var}) endif() if(${recurse}) set(more_inputs ${unseen_prereqs}) foreach(input ${more_inputs}) get_prerequisites("${input}" ${prerequisites_var} ${exclude_system} ${recurse} "${exepath}" "${dirs}" "${rpaths}") endforeach() endif() # Make result visible to caller set(${prerequisites_var} ${${prerequisites_var}} PARENT_SCOPE) # See if we added anything list(LENGTH ${prerequisites_var} list_length_after_candidates) if(list_length_after_candidates GREATER ${list_length_before_candidates}) # Something has been added to prerequisites. Note this in cache set(targets_added "${${prerequisites_var}}") if (list_length_before_candidates GREATER 0) foreach(i RANGE 1 ${list_length_before_candidates}) # from 1 to old list length, remove first item, i.e. remove all pre-existing items list(REMOVE_AT targets_added 0) # not the most elegant way of cutting the list start. Simplifications welcome endforeach() endif() endif() # Update our cache set_property(GLOBAL PROPERTY ${prerequisites_cache_var_name} "${targets_added}") - + get_property(cache_variables GLOBAL PROPERTY prerequisites_cachevariables) if (cache_variables) list(APPEND cache_variables ${prerequisites_cache_var_name}) list(LENGTH cache_variables len) else() set(cache_variables ${prerequisites_cache_var_name}) endif() set_property(GLOBAL PROPERTY prerequisites_cachevariables ${cache_variables}) - + message("Analyzed prerequisites of ${target}") endfunction() function(list_prerequisites target) if(ARGC GREATER 1 AND NOT "${ARGV1}" STREQUAL "") set(all "${ARGV1}") else() set(all 1) endif() if(ARGC GREATER 2 AND NOT "${ARGV2}" STREQUAL "") set(exclude_system "${ARGV2}") else() set(exclude_system 0) endif() if(ARGC GREATER 3 AND NOT "${ARGV3}" STREQUAL "") set(verbose "${ARGV3}") else() set(verbose 0) endif() set(count 0) set(count_str "") set(print_count "${verbose}") set(print_prerequisite_type "${verbose}") set(print_target "${verbose}") set(type_str "") get_filename_component(exepath "${target}" PATH) set(prereqs "") get_prerequisites("${target}" prereqs ${exclude_system} ${all} "${exepath}" "") if(print_target) message(STATUS "File '${target}' depends on:") endif() foreach(d ${prereqs}) math(EXPR count "${count} + 1") if(print_count) set(count_str "${count}. ") endif() if(print_prerequisite_type) gp_file_type("${target}" "${d}" type) set(type_str " (${type})") endif() message(STATUS "${count_str}${d}${type_str}") endforeach() endfunction() function(list_prerequisites_by_glob glob_arg glob_exp) message(STATUS "=============================================================================") message(STATUS "List prerequisites of executables matching ${glob_arg} '${glob_exp}'") message(STATUS "") file(${glob_arg} file_list ${glob_exp}) foreach(f ${file_list}) is_file_executable("${f}" is_f_executable) if(is_f_executable) message(STATUS "=============================================================================") list_prerequisites("${f}" ${ARGN}) message(STATUS "") endif() endforeach() endfunction() diff --git a/CMake/MITKDashboardScript.TEMPLATE.cmake b/CMake/MITKDashboardScript.TEMPLATE.cmake index c3cb7fc55b..f319ca3a48 100644 --- a/CMake/MITKDashboardScript.TEMPLATE.cmake +++ b/CMake/MITKDashboardScript.TEMPLATE.cmake @@ -1,147 +1,147 @@ # # OS: Ubuntu 9.04 2.6.28-18-generic # Hardware: x86_64 GNU/Linux # GPU: NA # # Note: The specific version and processor type of this machine should be reported in the # header above. Indeed, this file will be send to the dashboard as a NOTE file. cmake_minimum_required(VERSION 3.10 FATAL_ERROR) # # Dashboard properties # set(MY_COMPILER "gcc-4.9.x") # For Windows, e.g. #set(MY_COMPILER "VC12.0") set(CTEST_CMAKE_COMMAND "/usr/bin/cmake") set(CTEST_CMAKE_GENERATOR "Unix Makefiles") set(CTEST_DASHBOARD_ROOT "/opt/dartclients") # For Windows, e.g. #set(CTEST_CMAKE_COMMAND "cmake") #set(CTEST_CMAKE_GENERATOR "Visual Studio 12 2013 Win64") #set(CTEST_DASHBOARD_ROOT "C:/dartclients") # The directory containing the Qt binaries set(QT5_INSTALL_PREFIX "/home/user/Qt/5.6/gcc_64") # For Windows, e.g. #set(QT5_INSTALL_PREFIX "C:/Qt/5.6/msvc2013_64") set(QT_BINARY_DIR "${QT5_INSTALL_PREFIX}/bin") # # Dashboard options # set(WITH_KWSTYLE FALSE) set(WITH_MEMCHECK FALSE) set(WITH_COVERAGE FALSE) set(WITH_DOCUMENTATION FALSE) #set(DOCUMENTATION_ARCHIVES_OUTPUT_DIRECTORY ) # for example: $ENV{HOME}/Projects/Doxygen set(CTEST_BUILD_CONFIGURATION "Release") set(CTEST_TEST_TIMEOUT 500) -if(UNIX OR MINGW) +if(UNIX) set(CTEST_BUILD_FLAGS "-j4") # Use multiple CPU cores to build else() set(CTEST_BUILD_FLAGS "") endif() # experimental: # - run_ctest() macro will be called *ONE* time # - binary directory will *NOT* be cleaned # continuous: # - run_ctest() macro will be called EVERY 5 minutes ... # - binary directory will *NOT* be cleaned # - configure/build will be executed *ONLY* if the repository has been updated # nightly: # - run_ctest() macro will be called *ONE* time # - binary directory *WILL BE* cleaned set(SCRIPT_MODE "experimental") # "experimental", "continuous", "nightly" # # Project specific properties # # In order to shorten the global path length, the build directory for each DartClient # uses the following abrevation sceme: # For build configuration: # Debug -> d # Release -> r # For scripte mode: # continuous -> c # nightly -> n # experimental -> e # Example directory: /MITK-sb-d-n/ for a nightly MITK superbuild in debug mode. set(short_of_ctest_build_configuration "") set(short_of_script_mode "") string(SUBSTRING ${CTEST_BUILD_CONFIGURATION} 0 1 short_of_ctest_build_configuration) string(SUBSTRING ${SCRIPT_MODE} 0 1 short_of_script_mode) set(CTEST_SOURCE_DIRECTORY "${CTEST_DASHBOARD_ROOT}/MITK") set(CTEST_BINARY_DIRECTORY "${CTEST_DASHBOARD_ROOT}/MITK-sb-${short_of_ctest_build_configuration}-${short_of_script_mode}") # Create an initial cache file for MITK. This file is used to configure the MITK-Build. Use ADDITIONAL_CMAKECACHE_OPTION # to configure the MITK-Superbuild. The set(MITK_INITIAL_CACHE " # Example how to set a boolean variable in the MITK-Build via this script: #SET(MITK_ENABLE_TOF_HARDWARE \"TRUE\" CACHE INTERNAL \"Enable ToF Hardware\") # Example how to set a path variable in the MITK-Build via this script: #SET(MITK_PMD_LIB \"/home/kilgus/thomas/PMDSDK2/Linux_x86_64/bin/libpmdaccess2.so\" CACHE INTERNAL \"PMD lib\") ") set(ADDITIONAL_CMAKECACHE_OPTION " # Superbuild variables are not passed through to the MITK-Build (or any other build like ITK, VTK, ...) # Use the MITK_INITIAL_CACHE the pass variables to the MITK-Build. # add entries like this #MITK_USE_OpenCV:BOOL=OFF CMAKE_PREFIX_PATH:PATH=${CMAKE_PREFIX_PATH} ") # List of test that should be explicitly disabled on this machine set(TEST_TO_EXCLUDE_REGEX "") # set any extra environment variables here set(ENV{DISPLAY} ":0") find_program(CTEST_COVERAGE_COMMAND NAMES gcov) find_program(CTEST_MEMORYCHECK_COMMAND NAMES valgrind) find_program(CTEST_GIT_COMMAND NAMES git) # # Git repository - Overwrite the default value provided by the driver script # # The git repository containing MITK code #set(GIT_REPOSITORY "/home/username/MITK") # The branch of the MITK git repository to check out #set(GIT_BRANCH "bug-xxx-label") ########################################## # WARNING: DO NOT EDIT BEYOND THIS POINT # ########################################## # # Convenient macro allowing to download a file # macro(downloadFile url dest) file(DOWNLOAD "${url}" "${dest}" STATUS status) list(GET status 0 error_code) list(GET status 1 error_msg) if(error_code) message(FATAL_ERROR "error: Failed to download ${url} - ${error_msg}") endif() endmacro() # # Download and include setup script # if(NOT DEFINED GIT_BRANCH OR GIT_BRANCH STREQUAL "") set(IS_PHABRICATOR_URL FALSE) set(url "https://raw.githubusercontent.com/MITK/MITK/master/CMake/MITKDashboardSetup.cmake") else() set(IS_PHABRICATOR_URL TRUE) string(REPLACE "/" "%252F" GIT_BRANCH_URL ${GIT_BRANCH}) set(url "https://phabricator.mitk.org/source/mitk/browse/${GIT_BRANCH_URL}/CMake/MITKDashboardSetup.cmake?view=raw") endif() set(dest ${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}.setup) downloadFile("${url}" "${dest}") include(${dest}) diff --git a/CMake/MITKDashboardSetup.cmake b/CMake/MITKDashboardSetup.cmake index 4bf2d289cf..652289861b 100644 --- a/CMake/MITKDashboardSetup.cmake +++ b/CMake/MITKDashboardSetup.cmake @@ -1,160 +1,161 @@ # This file is intended to be included at the end of a custom MITKDashboardScript.TEMPLATE.cmake file list(APPEND CTEST_NOTES_FILES "${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}") # # Automatically determined properties # set(MY_OPERATING_SYSTEM ) if(UNIX) # Download a utility script - if(IS_PHABRICATOR_URL) - set(url "https://phabricator.mitk.org/source/mitk/browse/${GIT_BRANCH}/CMake/mitkDetectOS.sh?view=raw") - else() + # See T24757. + # if(IS_PHABRICATOR_URL) + # set(url "https://phabricator.mitk.org/source/mitk/browse/${GIT_BRANCH}/CMake/mitkDetectOS.sh?view=raw") + # else() set(url "https://raw.githubusercontent.com/MITK/MITK/master/CMake/mitkDetectOS.sh") - endif() + # endif() set(dest "${CTEST_SCRIPT_DIRECTORY}/mitkDetectOS.sh") downloadFile("${url}" "${dest}") execute_process(COMMAND sh "${dest}" RESULT_VARIABLE _result OUTPUT_VARIABLE _out OUTPUT_STRIP_TRAILING_WHITESPACE) if(NOT _result) set(MY_OPERATING_SYSTEM "${_out}") endif() endif() if(NOT MY_OPERATING_SYSTEM) set(MY_OPERATING_SYSTEM "${CMAKE_HOST_SYSTEM}") # Windows 7, Linux-2.6.32, Darwin... endif() site_name(CTEST_SITE) if(NOT DEFINED MITK_USE_Qt5) set(MITK_USE_Qt5 1) endif() if(MITK_USE_Qt5) if(NOT QT_QMAKE_EXECUTABLE) find_program(QT_QMAKE_EXECUTABLE NAMES qmake qmake-qt5 HINTS ${QT_BINARY_DIR}) endif() execute_process(COMMAND ${QT_QMAKE_EXECUTABLE} --version OUTPUT_VARIABLE MY_QT_VERSION RESULT_VARIABLE qmake_error) if(qmake_error) message(FATAL_ERROR "Error when executing ${QT_QMAKE_EXECUTABLE} --version\n${qmake_error}") endif() string(REGEX REPLACE ".*Qt version ([0-9.]+) .*" "\\1" MY_QT_VERSION ${MY_QT_VERSION}) endif() # # Project specific properties # if(NOT CTEST_BUILD_NAME) if(MITK_USE_Qt5) set(CTEST_BUILD_NAME "${MY_OPERATING_SYSTEM} ${MY_COMPILER} Qt${MY_QT_VERSION} ${CTEST_BUILD_CONFIGURATION}") else() set(CTEST_BUILD_NAME "${MY_OPERATING_SYSTEM} ${MY_COMPILER} ${CTEST_BUILD_CONFIGURATION}") endif() set(CTEST_BUILD_NAME "${CTEST_BUILD_NAME}${CTEST_BUILD_NAME_SUFFIX}") endif() set(PROJECT_BUILD_DIR "MITK-build") set(CTEST_PATH "$ENV{PATH}") if(WIN32) if("${CTEST_CMAKE_GENERATOR}" MATCHES ".*Win64") set(CMAKE_LIBRARY_ARCHITECTURE x64) else() set(CMAKE_LIBRARY_ARCHITECTURE x86) endif() string(SUBSTRING "${MY_COMPILER}" 2 2 vc_version) set(OPENCV_BIN_DIR "${CTEST_BINARY_DIRECTORY}/ep/${CMAKE_LIBRARY_ARCHITECTURE}/vc${vc_version}/bin") set(BLUEBERRY_RUNTIME_DIR "${CTEST_BINARY_DIRECTORY}/MITK-build/bin/plugins/${CTEST_BUILD_CONFIGURATION}") set(PYTHON_BINARY_DIRS "${CTEST_BINARY_DIRECTORY}/ep/src/CTK-build/CMakeExternals/Install/bin") get_filename_component(_python_dir ${PYTHON_EXECUTABLE} DIRECTORY) list(APPEND PYTHON_BINARY_DIRS "${_python_dir}") set(CTEST_PATH "${CTEST_PATH};${CTEST_BINARY_DIRECTORY}/ep/bin;${QT_BINARY_DIR};${BLUEBERRY_RUNTIME_DIR};${OPENCV_BIN_DIR};${PYTHON_BINARY_DIRS}") endif() set(ENV{PATH} "${CTEST_PATH}") # If the dashscript doesn't define a GIT_REPOSITORY variable, let's define it here. if(NOT DEFINED GIT_REPOSITORY OR GIT_REPOSITORY STREQUAL "") set(GIT_REPOSITORY "https://phabricator.mitk.org/source/mitk.git") endif() # # Display build info # message("Site name: ${CTEST_SITE}") message("Build name: ${CTEST_BUILD_NAME}") message("Script Mode: ${SCRIPT_MODE}") message("Coverage: ${WITH_COVERAGE}, MemCheck: ${WITH_MEMCHECK}") # # Set initial cache options # if(CTEST_CMAKE_GENERATOR MATCHES ".*Makefiles.*") set(CTEST_USE_LAUNCHERS 1) else() set(CTEST_USE_LAUNCHERS 0) endif() set(ENV{CTEST_USE_LAUNCHERS_DEFAULT} ${CTEST_USE_LAUNCHERS}) # Remove this if block after all dartclients work if(DEFINED ADDITIONNAL_CMAKECACHE_OPTION) message(WARNING "Rename ADDITIONNAL to ADDITIONAL in your dartlclient script: ${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}") set(ADDITIONAL_CMAKECACHE_OPTION ${ADDITIONNAL_CMAKECACHE_OPTION}) endif() if(NOT DEFINED MITK_BUILD_CONFIGURATION) set(MITK_BUILD_CONFIGURATION "All") endif() if(NOT DEFINED MITK_VTK_DEBUG_LEAKS) set(MITK_VTK_DEBUG_LEAKS 1) endif() set(INITIAL_CMAKECACHE_OPTIONS " SUPERBUILD_EXCLUDE_MITKBUILD_TARGET:BOOL=TRUE MITK_BUILD_CONFIGURATION:STRING=${MITK_BUILD_CONFIGURATION} MITK_VTK_DEBUG_LEAKS:BOOL=${MITK_VTK_DEBUG_LEAKS} ${ADDITIONAL_CMAKECACHE_OPTION} ") if(MITK_USE_Qt5) set(INITIAL_CMAKECACHE_OPTIONS "${INITIAL_CMAKECACHE_OPTIONS} QT_QMAKE_EXECUTABLE:FILEPATH=${QT_QMAKE_EXECUTABLE}") endif() # Write a cache file for populating the MITK initial cache (not the superbuild cache). # This can be used to provide variables which are not passed through the # superbuild process to the MITK configure step) if(MITK_INITIAL_CACHE) set(mitk_cache_file "${CTEST_SCRIPT_DIRECTORY}/mitk_initial_cache.txt") file(WRITE "${mitk_cache_file}" "${MITK_INITIAL_CACHE}") set(INITIAL_CMAKECACHE_OPTIONS "${INITIAL_CMAKECACHE_OPTIONS} MITK_INITIAL_CACHE_FILE:INTERNAL=${mitk_cache_file} ") endif() # # Download and include dashboard driver script # if(IS_PHABRICATOR_URL) string(REPLACE "/" "%252F" GIT_BRANCH_URL ${GIT_BRANCH}) set(url "https://phabricator.mitk.org/source/mitk/browse/${GIT_BRANCH_URL}/CMake/MITKDashboardDriverScript.cmake?view=raw") else() set(url "https://raw.githubusercontent.com/MITK/MITK/master/CMake/MITKDashboardDriverScript.cmake") endif() set(dest ${CTEST_SCRIPT_DIRECTORY}/${CTEST_SCRIPT_NAME}.driver) downloadFile("${url}" "${dest}") include(${dest}) diff --git a/CMake/PackageDepends/MITK_DCMTK_Config.cmake b/CMake/PackageDepends/MITK_DCMTK_Config.cmake index 4a29a52ff1..155a9ab47b 100644 --- a/CMake/PackageDepends/MITK_DCMTK_Config.cmake +++ b/CMake/PackageDepends/MITK_DCMTK_Config.cmake @@ -1,10 +1,10 @@ if( NOT WIN32 AND NOT APPLE ) - set(MISSING_LIBS_REQUIRED_BY_DCMTK wrap tiff z) + set(MISSING_LIBS_REQUIRED_BY_DCMTK tiff z) endif( NOT WIN32 AND NOT APPLE ) set(QT_USE_QTSQL 1) find_package(DCMTK) list(APPEND ALL_INCLUDE_DIRECTORIES ${DCMTK_INCLUDE_DIRS}) list(APPEND ALL_LIBRARIES ${DCMTK_LIBRARIES} ${MISSING_LIBS_REQUIRED_BY_DCMTK}) diff --git a/CMake/mitkFunctionCreateModule.cmake b/CMake/mitkFunctionCreateModule.cmake index 0934298042..e7c9811ee0 100644 --- a/CMake/mitkFunctionCreateModule.cmake +++ b/CMake/mitkFunctionCreateModule.cmake @@ -1,656 +1,652 @@ ################################################################## # # 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}) 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/mitkFunctionGetMSVCVersion.cmake b/CMake/mitkFunctionGetMSVCVersion.cmake index f22c9bae1f..0bd5088116 100644 --- a/CMake/mitkFunctionGetMSVCVersion.cmake +++ b/CMake/mitkFunctionGetMSVCVersion.cmake @@ -1,53 +1,57 @@ #! \brief Get diverse visual studio ids not directly provided by CMake #! #! Sets the following variables in the parent scope #! VISUAL_STUDIO_VERSION_MAJOR - The Visual Studio Version #! VISUAL_STUDIO_PRODUCT_NAME - The Visual Studio Product Name function(mitkFunctionGetMSVCVersion ) if(MSVC) if(MSVC_VERSION EQUAL 1600) set(VISUAL_STUDIO_VERSION_MAJOR "10" PARENT_SCOPE) set(VISUAL_STUDIO_VERSION_MINOR "0" PARENT_SCOPE) set(VISUAL_STUDIO_PRODUCT_NAME "Visual Studio 2010" PARENT_SCOPE) elseif(MSVC_VERSION EQUAL 1700) set(VISUAL_STUDIO_VERSION_MAJOR "11" PARENT_SCOPE) set(VISUAL_STUDIO_VERSION_MINOR "0" PARENT_SCOPE) set(VISUAL_STUDIO_PRODUCT_NAME "Visual Studio 2012" PARENT_SCOPE) elseif(MSVC_VERSION EQUAL 1800) set(VISUAL_STUDIO_VERSION_MAJOR "12" PARENT_SCOPE) set(VISUAL_STUDIO_VERSION_MINOR "0" PARENT_SCOPE) set(VISUAL_STUDIO_PRODUCT_NAME "Visual Studio 2013" PARENT_SCOPE) elseif(MSVC_VERSION EQUAL 1900) set(VISUAL_STUDIO_VERSION_MAJOR "14" PARENT_SCOPE) set(VISUAL_STUDIO_VERSION_MINOR "0" PARENT_SCOPE) set(VISUAL_STUDIO_PRODUCT_NAME "Visual Studio 2015" PARENT_SCOPE) elseif(MSVC_VERSION EQUAL 1910) set(VISUAL_STUDIO_VERSION_MAJOR "14" PARENT_SCOPE) set(VISUAL_STUDIO_VERSION_MINOR "0" PARENT_SCOPE) set(VISUAL_STUDIO_PRODUCT_NAME "Visual Studio 2017" PARENT_SCOPE) elseif(MSVC_VERSION EQUAL 1911) set(VISUAL_STUDIO_VERSION_MAJOR "14" PARENT_SCOPE) set(VISUAL_STUDIO_VERSION_MINOR "1" PARENT_SCOPE) set(VISUAL_STUDIO_PRODUCT_NAME "Visual Studio 2017" PARENT_SCOPE) elseif(MSVC_VERSION EQUAL 1912) set(VISUAL_STUDIO_VERSION_MAJOR "14" PARENT_SCOPE) set(VISUAL_STUDIO_VERSION_MINOR "2" PARENT_SCOPE) set(VISUAL_STUDIO_PRODUCT_NAME "Visual Studio 2017" PARENT_SCOPE) elseif(MSVC_VERSION EQUAL 1913) set(VISUAL_STUDIO_VERSION_MAJOR "14" PARENT_SCOPE) set(VISUAL_STUDIO_VERSION_MINOR "3" PARENT_SCOPE) set(VISUAL_STUDIO_PRODUCT_NAME "Visual Studio 2017" PARENT_SCOPE) + elseif(MSVC_VERSION EQUAL 1914) + set(VISUAL_STUDIO_VERSION_MAJOR "14" PARENT_SCOPE) + set(VISUAL_STUDIO_VERSION_MINOR "4" PARENT_SCOPE) + set(VISUAL_STUDIO_PRODUCT_NAME "Visual Studio 2017" PARENT_SCOPE) else() message(WARNING "Unknown Visual Studio version ${MSVC_VERSION}. Please update CMake/mitkFunctionGetMSVCVersion.cmake.") endif() if("${CMAKE_GENERATOR}" MATCHES ".*Win64") set(CMAKE_LIBRARY_ARCHITECTURE x64 PARENT_SCOPE) else() set(CMAKE_LIBRARY_ARCHITECTURE x86 PARENT_SCOPE) endif() endif() endfunction() diff --git a/CMake/mitkLanguageOptions.cmake b/CMake/mitkLanguageOptions.cmake index d6e5cafc02..50284ce611 100644 --- a/CMake/mitkLanguageOptions.cmake +++ b/CMake/mitkLanguageOptions.cmake @@ -1,258 +1,72 @@ # -# - This module finds the languages supported by MITK, and -#present the option to enable support +# This module finds the languages supported by MITK, and +# present the option to enable support. # # -# Currently this will search for Python, -# Java, TCL, Ruby, C#, R, and additionally it give the option to wrap LUA. will be added # This script is based on SimpleITK scripts. # -#include(sitkTargetLinkLibrariesWithDynamicLookup) -# -#sitk_check_dynamic_lookup(MODULE -# SHARED -# SITK_UNDEFINED_SYMBOLS_ALLOWED -# ) - option(WRAP_DEFAULT "The default initial value for wrapping a language when it is detected on the system." OFF) mark_as_advanced(WRAP_DEFAULT) # # Macro to set "_QUIET" and "_QUIET_LIBRARY" based on the first # argument being defined and true, to either REQUIRED or QUIET. # macro(set_QUIET var) if ( DEFINED ${var} AND ${var} ) set( _QUIET "REQUIRED" ) else() set( _QUIET "QUIET" ) endif() if ( SITK_UNDEFINED_SYMBOLS_ALLOWED ) set( _QUIET_LIBRARY "QUIET" ) else() set( _QUIET_LIBRARY ${_QUIET} ) endif() endmacro() # # Setup the option for each language # -#----------------------------------------------------------- -# Lua - -#set_QUIET( WRAP_LUA ) -#find_package ( Lua ${_QUIET} ) -# -#if ( LUA_FOUND ) -# set( WRAP_LUA_DEFAULT ${WRAP_DEFAULT} ) -#else() -# set( WRAP_LUA_DEFAULT OFF ) -#endif() -# -#set( LUA_ADDITIONAL_LIBRARIES "" CACHE STRING "Additional libraries which may be needed for lua such as readline.") -#mark_as_advanced( LUA_ADDITIONAL_LIBRARIES ) -# -#option ( WRAP_LUA "Wrap Lua" ${WRAP_LUA_DEFAULT} ) -# -#if ( WRAP_LUA ) -# find_package( LuaInterp REQUIRED ) -# list( APPEND SITK_LANGUAGES_VARS -# LUA_EXECUTABLE -# LUA_LIBRARIES -# LUA_INCLUDE_DIR -# LUA_VERSION_STRING -# LUA_MATH_LIBRARY -# LUA_ADDITIONAL_LIBRARIES -# ) -#endif() - - #----------------------------------------------------------- # Python set_QUIET( WRAP_PYTHON ) find_package ( PythonInterp ${_QUIET}) if ( PYTHONINTERP_FOUND ) find_package ( PythonLibs ${PYTHON_VERSION_STRING} EXACT ${_QUIET_LIBRARY} ) else () find_package ( PythonLibs ${_QUIET_LIBRARY} ) endif() if ( PYTHONLIBS_FOUND AND PYTHONINTERP_FOUND AND (PYTHON_VERSION_STRING VERSION_EQUAL PYTHONLIBS_VERSION_STRING) ) set( WRAP_PYTHON_DEFAULT ${WRAP_DEFAULT} ) else() set( WRAP_PYTHON_DEFAULT OFF ) endif() option( WRAP_PYTHON "Wrap Python" ${WRAP_PYTHON_DEFAULT} ) if ( WRAP_PYTHON AND PYTHON_VERSION_STRING VERSION_LESS 2.7 ) message( WARNING "Python version less than 2.7: \"${PYTHON_VERSION_STRING}\"." ) endif() if ( WRAP_PYTHON ) list( APPEND SITK_LANGUAGES_VARS PYTHON_DEBUG_LIBRARY PYTHON_EXECUTABLE PYTHON_LIBRARY PYTHON_INCLUDE_DIR - # PYTHON_INCLUDE_PATH ( deprecated ) ) # Debian "jessie" has this additional variable required to match # python versions. if(PYTHON_INCLUDE_DIR2) list( APPEND SITK_LANGUAGES_VARS PYTHON_INCLUDE_DIR2 ) endif() endif () - - -#----------------------------------------------------------- -# Java - -#set_QUIET( WRAP_JAVA ) -#find_package ( Java COMPONENTS Development Runtime ${_QUIET} ) -#find_package ( JNI ${_QUIET} ) -#if ( JAVA_FOUND AND JNI_FOUND ) -# set( WRAP_JAVA_DEFAULT ${WRAP_DEFAULT} ) -#else ( ${JAVA_FOUND} AND JNI_FOUND ) -# set( WRAP_JAVA_DEFAULT OFF ) -#endif ( ) -# -#option ( WRAP_JAVA "Wrap Java" ${WRAP_JAVA_DEFAULT} ) -# -#if ( WRAP_JAVA ) -# list( APPEND SITK_LANGUAGES_VARS -# Java_JAVA_EXECUTABLE -# Java_JAVAC_EXECUTABLE -# Java_JAR_EXECUTABLE -# Java_JAVADOC_EXECUTABLE -# Java_JAVAH_EXECUTABLE -# Java_VERSION_STRING -# Java_VERSION_MAJOR -# Java_VERSION_MINOR -# Java_VERSION_PATCH -# Java_VERSION_TWEAK -# Java_VERSION -# Java_INCLUDE_DIRS -# Java_LIBRARIES -# JNI_INCLUDE_DIRS -# JNI_LIBRARIES -# JAVA_AWT_LIBRARY -# JAVA_JVM_LIBRARY -# JAVA_INCLUDE_PATH -# JAVA_INCLUDE_PATH2 -# JAVA_AWT_INCLUDE_PATH -# ) -#endif() -# - -#----------------------------------------------------------- -# Tcl - -#set_QUIET(WRAP_TCL) -# -#find_package ( TCL ${_QUIET} ) -# -#if ( TCL_FOUND ) -# set ( WRAP_TCL_DEFAULT ${WRAP_DEFAULT} ) -#else ( ) -# set ( WRAP_TCL_DEFAULT OFF ) -#endif ( ) -# -#option ( WRAP_TCL "Wrap Tcl" ${WRAP_TCL_DEFAULT} ) -# -#if ( WRAP_TCL ) -# list( APPEND SITK_LANGUAGES_VARS -# TCL_LIBRARY -# TCL_INCLUDE_PATH -# TCL_TCLSH -# TK_LIBRARY -# TK_INCLUDE_PATH -# TK_WISH -# ) -#endif() -# -# -##----------------------------------------------------------- -## Ruby -# -#set_QUIET( WRAP_RUBY ) -# -#find_package ( Ruby ${_QUIET} ) -#if ( RUBY_FOUND ) -# set ( WRAP_RUBY_DEFAULT ${WRAP_DEFAULT} ) -#else ( ) -# set ( WRAP_RUBY_DEFAULT OFF ) -#endif ( ) -# -#option ( WRAP_RUBY "Wrap Ruby" ${WRAP_RUBY_DEFAULT} ) -# -#if ( WRAP_RUBY ) -# list( APPEND SITK_LANGUAGES_VARS -# RUBY_EXECUTABLE -# RUBY_INCLUDE_DIRS -# RUBY_LIBRARY -# RUBY_VERSION -# RUBY_FOUND -# RUBY_INCLUDE_PATH -# ) -#endif() -# -# -##----------------------------------------------------------- -## CSharp -# -#set_QUIET( WRAP_CSHARP ) -# -#find_package( CSharp ${_QUIET} ) -#if ( CSHARP_FOUND AND NOT MINGW ) -# set ( WRAP_CSHARP_DEFAULT ${WRAP_DEFAULT} ) -#else () -# set ( WRAP_CSHARP_DEFAULT OFF ) -#endif () -# -#option ( WRAP_CSHARP "Wrap C#" ${WRAP_CSHARP_DEFAULT} ) -# -#if ( WRAP_CSHARP ) -# list( APPEND SITK_LANGUAGES_VARS -# CSHARP_COMPILER -# CSHARP_INTERPRETER -# CSHARP_PLATFORM -# ) -#endif() -# -# -##----------------------------------------------------------- -## R -# -#set_QUIET( WRAP_R ) -# -#find_package(R ${_QUIET}) -#if ( R_FOUND AND NOT WIN32 ) -# set ( WRAP_R_DEFAULT ${WRAP_DEFAULT} ) -#else( ) -# set ( WRAP_R_DEFAULT OFF ) -#endif( ) -# -#option ( WRAP_R "Wrap R" ${WRAP_R_DEFAULT} ) -# -#if ( WRAP_R ) -# list( APPEND SITK_LANGUAGES_VARS -# R_INCLUDE_DIR -# R_LIBRARIES -# R_LIBRARY_BASE -# R_COMMAND -# RSCRIPT_EXECUTABLE ) -#endif() -# -# -#if( WIN32 ) -# mark_as_advanced( WRAP_R ) -#endif() -# diff --git a/CMake/mitkMacroInstall.cmake b/CMake/mitkMacroInstall.cmake index d4150c57e7..f23729b066 100644 --- a/CMake/mitkMacroInstall.cmake +++ b/CMake/mitkMacroInstall.cmake @@ -1,182 +1,182 @@ # # MITK specific install macro # # On Mac everything is installed for each bundle listed in MACOSX_BUNDLE_NAMES # by replacing the DESTINATION parameter. Everything else is passed to the CMake INSTALL command # # Usage: MITK_INSTALL( ) # macro(MITK_INSTALL) set(ARGS ${ARGN}) set(install_directories "") list(FIND ARGS DESTINATION _destination_index) # set(_install_DESTINATION "") if(_destination_index GREATER -1) message(SEND_ERROR "MITK_INSTALL macro must not be called with a DESTINATION parameter.") ### This code was a try to replace a given DESTINATION #math(EXPR _destination_index ${_destination_index} + 1) #list(GET ARGS ${_destination_index} _install_DESTINATION) #string(REGEX REPLACE ^bin "" _install_DESTINATION ${_install_DESTINATION}) else() if(NOT MACOSX_BUNDLE_NAMES) install(${ARGS} DESTINATION bin) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) install(${ARGS} DESTINATION ${bundle_name}.app/Contents/MacOS/${_install_DESTINATION}) endforeach() endif() endif() endmacro() # Fix _target_location # This is used in several install macros macro(_fixup_target) if(NOT intermediate_dir) - if(WIN32 AND NOT MINGW) + if(WIN32) set(intermediate_dir Release) else() set(intermediate_dir .) endif() endif() mitkFunctionGetLibrarySearchPaths(_search_paths ${intermediate_dir}) install(CODE " set(_bundle_dest_dir \"${_bundle_dest_dir}\") if(_bundle_dest_dir) set(_bin_path \"\${CMAKE_INSTALL_PREFIX}/\${_bundle_dest_dir}\") else() set(_bin_path \"\${CMAKE_INSTALL_PREFIX}/bin\") endif() macro(gp_item_default_embedded_path_override item default_embedded_path_var) get_filename_component(_item_name \"\${item}\" NAME) get_filename_component(_item_path \"\${item}\" PATH) # We have to fix all path references to build trees for plugins if(NOT _item_path MATCHES \"\${CMAKE_INSTALL_PREFIX}/${_bundle_dest_dir}\") # item with relative path or embedded path pointing to some build dir set(full_path \"full_path-NOTFOUND\") file(GLOB_RECURSE full_path \${CMAKE_INSTALL_PREFIX}/${_bundle_dest_dir}/\${_item_name} ) list(LENGTH full_path full_path_length) if(full_path_length GREATER 1) list(GET full_path 0 full_path) endif() get_filename_component(_item_path \"\${full_path}\" PATH) endif() set(_plugins_path \"\${_bin_path}/plugins\") if(_item_path STREQUAL _plugins_path OR (_item_path MATCHES \"\${_plugins_path}/\" AND _item_name MATCHES \"liborg\") # this is for legacy BlueBerry bundle support ) # Only fix plugins message(\"override: \${item}\") message(\"found file: \${_item_path}/\${_item_name}\") if(APPLE) string(REPLACE \${CMAKE_INSTALL_PREFIX}/${_bundle_dest_dir} @executable_path \${default_embedded_path_var} \"\${_item_path}\" ) else() set(\${default_embedded_path_var} \"\${_item_path}\") endif() message(\"override result: \${\${default_embedded_path_var}}\") endif() endmacro(gp_item_default_embedded_path_override) macro(gp_resolved_file_type_override file type) if(NOT APPLE) get_filename_component(_file_path \"\${file}\" PATH) get_filename_component(_file_name \"\${file}\" NAME) if(_file_path MATCHES \"^\${CMAKE_INSTALL_PREFIX}\") set(\${type} \"local\") endif() if(_file_name MATCHES gdiplus) set(\${type} \"system\") endif(_file_name MATCHES gdiplus) endif() if(WIN32) if(file MATCHES \"BluetoothApis.dll\") set(\${type} \"system\" ) endif() endif() endmacro(gp_resolved_file_type_override) if(NOT APPLE) macro(gp_resolve_item_override context item exepath dirs resolved_item_var resolved_var) if(\${item} MATCHES \"blueberry_core_runtime\") get_filename_component(_item_name \${item} NAME) set(\${resolved_item_var} \"\${exepath}/plugins/\${_item_name}\") set(\${resolved_var} 1) endif() endmacro() endif() if(\"${_install_GLOB_PLUGINS}\" STREQUAL \"TRUE\") set(GLOBBED_PLUGINS ) set(_bb_runtime_lib \"\${_bin_path}/liborg_blueberry_core_runtime${CMAKE_SHARED_LIBRARY_SUFFIX}\") if(EXISTS \"\${_bb_runtime_lib}\") list(APPEND GLOBBED_PLUGINS \"\${_bb_runtime_lib}\") endif() # Iterate over all sub-directories which contain plug-ins # (BlueBerry plug-ins, Qt plug-ins, and auto-load modules) file(GLOB _children \"\${_bin_path}/*\") foreach(_child \${_children}) if(IS_DIRECTORY \${_child}) set(_plugins ) set(_modules ) file(GLOB_RECURSE _plugins \"\${_child}/*${CMAKE_SHARED_LIBRARY_SUFFIX}\") if(_plugins) list(APPEND GLOBBED_PLUGINS \${_plugins}) endif() # Now glob for all modules which might have a different extensions. # E.g. on MacOS plugins could have a .dylib extension as well as a .so extension if(NOT \"${CMAKE_SHARED_MODULE_SUFFIX}\" STREQUAL \"\" AND NOT \"${CMAKE_SHARED_MODULE_SUFFIX}\" STREQUAL \"${CMAKE_SHARED_LIBRARY_SUFFIX}\") file(GLOB_RECURSE _modules \"\${_child}/*${CMAKE_SHARED_MODULE_SUFFIX}\") endif() if(_modules) list(APPEND GLOBBED_PLUGINS \${_modules}) endif() endif() endforeach() endif() set(PLUGINS ) foreach(_plugin ${_install_PLUGINS} \${GLOBBED_PLUGINS}) get_filename_component(_plugin_realpath \${_plugin} REALPATH) list(APPEND PLUGINS \${_plugin_realpath}) endforeach() if(PLUGINS) list(REMOVE_DUPLICATES PLUGINS) endif(PLUGINS) message(\"globbed plugins: \${PLUGINS}\") set(CMAKE_MODULE_PATH ${MITK_SOURCE_DIR}/CMake ${CMAKE_MODULE_PATH} ) set(DIRS \"${_search_paths}\") set(_additional_search_paths ${_install_LIBRARY_DIRS}) if(_additional_search_paths) set(DIRS \"\${DIRS};\${_additional_search_paths}\") endif() foreach(_plugin \${PLUGINS}) get_filename_component(_pluginpath \${_plugin} PATH) list(APPEND DIRS \"\${_pluginpath}\") endforeach(_plugin) list(REMOVE_DUPLICATES DIRS) # use custom version of BundleUtilities include(BundleUtilities) fixup_bundle(\"\${CMAKE_INSTALL_PREFIX}/${_target_location}\" \"\${PLUGINS}\" \"\${DIRS}\") ") endmacro() diff --git a/CMake/mitkMacroInstallHelperApp.cmake b/CMake/mitkMacroInstallHelperApp.cmake index 788d121a58..f72bf92379 100644 --- a/CMake/mitkMacroInstallHelperApp.cmake +++ b/CMake/mitkMacroInstallHelperApp.cmake @@ -1,109 +1,109 @@ #! MITK specific cross plattform install macro #! #! Usage: MITK_INSTALL_HELPER_APP(target1 [target2] ....) #! macro(MITK_INSTALL_HELPER_APP) cmake_parse_arguments(_install "GLOB_PLUGINS" "" "TARGETS;EXECUTABLES;PLUGINS;LIBRARY_DIRS" ${ARGN}) list(APPEND _install_TARGETS ${_install_DEFAULT_ARGS}) # TODO: how to supply to correct intermediate directory?? # CMAKE_CFG_INTDIR is not expanded to actual values inside the install(CODE "...") macro ... set(intermediate_dir .) - if(WIN32 AND NOT MINGW) + if(WIN32) set(intermediate_dir Release) endif() mitkFunctionGetLibrarySearchPaths(DIRS ${intermediate_dir}) if(APPLE) list(APPEND DIRS "/usr/lib") endif(APPLE) if(QT_LIBRARY_DIR MATCHES "^(/lib|/lib32|/lib64|/usr/lib|/usr/lib32|/usr/lib64|/usr/X11R6)(/.*)?$") set(_qt_is_system_qt 1) endif() foreach(_target ${_install_EXECUTABLES}) set(_qt_plugins_install_dirs "") set(_qt_conf_install_dirs "") set(_target_locations "") get_filename_component(_target_name ${_target} NAME) if(APPLE) if(NOT MACOSX_BUNDLE_NAMES) set(_qt_conf_install_dirs bin) set(_target_locations bin/${_target_name}) set(${_target_locations}_qt_plugins_install_dir bin) install(PROGRAMS ${_target} DESTINATION bin) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) set(_current_target_location ${bundle_name}.app/Contents/MacOS/${_target_name}) list(APPEND _target_locations ${_current_target_location}) set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) install(PROGRAMS ${_target} DESTINATION ${bundle_name}.app/Contents/MacOS/) endforeach() endif(NOT MACOSX_BUNDLE_NAMES) else() set(_target_location bin/${_target_name}) set(${_target_location}_qt_plugins_install_dir bin) set(_qt_conf_install_dirs bin) install(PROGRAMS ${_target} DESTINATION bin) if(UNIX AND NOT WIN32) # Remove the rpath from helper applications. We assume that all dependencies # are installed into the same location as the helper application. install(CODE "file(RPATH_REMOVE FILE \"\${CMAKE_INSTALL_PREFIX}/${_target_location}\")") endif() endif() foreach(_target_location ${_target_locations}) if(NOT _qt_is_system_qt) if(QT_PLUGINS_DIR) if(WIN32) install(DIRECTORY "${QT_PLUGINS_DIR}" DESTINATION ${${_target_location}_qt_plugins_install_dir} CONFIGURATIONS Release FILES_MATCHING REGEX "[^4d]4?${CMAKE_SHARED_LIBRARY_SUFFIX}" ) install(DIRECTORY "${QT_PLUGINS_DIR}" DESTINATION ${${_target_location}_qt_plugins_install_dir} CONFIGURATIONS Debug FILES_MATCHING REGEX "d4?${CMAKE_SHARED_LIBRARY_SUFFIX}" ) else(WIN32) # install everything, see bug 7143 install(DIRECTORY "${QT_PLUGINS_DIR}" DESTINATION ${${_target_location}_qt_plugins_install_dir} FILES_MATCHING REGEX "${CMAKE_SHARED_LIBRARY_SUFFIX}" ) endif(WIN32) endif() endif() _fixup_target() endforeach(_target_location) if(NOT _qt_is_system_qt) #-------------------------------------------------------------------------------- # install a qt.conf file # this inserts some cmake code into the install script to write the file set(_qt_conf_plugin_install_prefix .) if(APPLE) set(_qt_conf_plugin_install_prefix ./MacOS) endif() foreach(_qt_conf_install_dir ${_qt_conf_install_dirs}) install(CODE "file(WRITE \"\${CMAKE_INSTALL_PREFIX}/${_qt_conf_install_dir}/qt.conf\" \" [Paths] Prefix=${_qt_conf_plugin_install_prefix} \")") endforeach() endif() endforeach() endmacro(MITK_INSTALL_HELPER_APP) diff --git a/CMake/mitkMacroInstallTargets.cmake b/CMake/mitkMacroInstallTargets.cmake index 007ae11840..dbe1367269 100644 --- a/CMake/mitkMacroInstallTargets.cmake +++ b/CMake/mitkMacroInstallTargets.cmake @@ -1,113 +1,113 @@ # # MITK specific cross plattform install macro # # Usage: MITK_INSTALL_TARGETS(target1 [target2] ....) # macro(MITK_INSTALL_TARGETS) cmake_parse_arguments(_install "GLOB_PLUGINS" "" "TARGETS;EXECUTABLES;PLUGINS;LIBRARY_DIRS" ${ARGN}) list(APPEND _install_TARGETS ${_install_DEFAULT_ARGS}) # TODO: how to supply the correct intermediate directory?? # CMAKE_CFG_INTDIR is not expanded to actual values inside the install(CODE "...") macro ... set(intermediate_dir .) - if(WIN32 AND NOT MINGW) + if(WIN32) set(intermediate_dir Release) endif() if(QT_LIBRARY_DIR MATCHES "^(/lib|/lib32|/lib64|/usr/lib|/usr/lib32|/usr/lib64|/usr/X11R6)(/.*)?$") set(_qt_is_system_qt 1) endif() foreach(_target ${_install_EXECUTABLES}) get_target_property(_is_bundle ${_target} MACOSX_BUNDLE) set(_qt_plugins_install_dirs "") set(_qt_conf_install_dirs "") set(_target_locations "") if(APPLE) if(_is_bundle) set(_target_locations ${_target}.app) set(${_target_locations}_qt_plugins_install_dir ${_target}.app/Contents/MacOS) set(_bundle_dest_dir ${_target}.app/Contents/MacOS) set(_qt_plugins_for_current_bundle ${_target}.app/Contents/MacOS) set(_qt_conf_install_dirs ${_target}.app/Contents/Resources) install(TARGETS ${_target} BUNDLE DESTINATION . ) else() if(NOT MACOSX_BUNDLE_NAMES) set(_qt_conf_install_dirs bin) set(_target_locations bin/${_target}) set(${_target_locations}_qt_plugins_install_dir bin) install(TARGETS ${_target} RUNTIME DESTINATION bin) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) set(_current_target_location ${bundle_name}.app/Contents/MacOS/${_target}) list(APPEND _target_locations ${_current_target_location}) set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") install(TARGETS ${_target} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) endforeach() endif() endif() else() set(_target_locations bin/${_target}${CMAKE_EXECUTABLE_SUFFIX}) set(${_target_locations}_qt_plugins_install_dir bin) set(_qt_conf_install_dirs bin) install(TARGETS ${_target} RUNTIME DESTINATION bin) endif() foreach(_target_location ${_target_locations}) if(NOT _qt_is_system_qt) if(QT_PLUGINS_DIR) if(WIN32) install(DIRECTORY "${QT_PLUGINS_DIR}" DESTINATION ${${_target_location}_qt_plugins_install_dir} CONFIGURATIONS Release FILES_MATCHING REGEX "[^4d]4?${CMAKE_SHARED_LIBRARY_SUFFIX}" ) install(DIRECTORY "${QT_PLUGINS_DIR}" DESTINATION ${${_target_location}_qt_plugins_install_dir} CONFIGURATIONS Debug FILES_MATCHING REGEX "d4?${CMAKE_SHARED_LIBRARY_SUFFIX}" ) else(WIN32) # install everything, see bug 7143 install(DIRECTORY "${QT_PLUGINS_DIR}" DESTINATION ${${_target_location}_qt_plugins_install_dir} FILES_MATCHING REGEX "${CMAKE_SHARED_LIBRARY_SUFFIX}" ) endif(WIN32) endif() endif() _fixup_target() endforeach() if(NOT _qt_is_system_qt) #-------------------------------------------------------------------------------- # install a qt.conf file # this inserts some cmake code into the install script to write the file set(_qt_conf_plugin_install_prefix .) if(APPLE) set(_qt_conf_plugin_install_prefix ./MacOS) endif() foreach(_qt_conf_install_dir ${_qt_conf_install_dirs}) install(CODE "file(WRITE \"\${CMAKE_INSTALL_PREFIX}/${_qt_conf_install_dir}/qt.conf\" \" [Paths] Prefix=${_qt_conf_plugin_install_prefix} \")") endforeach() endif() endforeach() endmacro() diff --git a/CMake/mitkSetupCPack.cmake b/CMake/mitkSetupCPack.cmake index aea793a6c0..53e40e34b4 100644 --- a/CMake/mitkSetupCPack.cmake +++ b/CMake/mitkSetupCPack.cmake @@ -1,126 +1,124 @@ # # First, set the generator variable # if(NOT CPACK_GENERATOR) if(WIN32) find_program(NSIS_MAKENSIS NAMES makensis PATHS [HKEY_LOCAL_MACHINE\\SOFTWARE\\NSIS] DOC "Where is makensis.exe located" ) if(NOT NSIS_MAKENSIS) set(CPACK_GENERATOR ZIP) else() set(CPACK_GENERATOR "NSIS;ZIP") endif(NOT NSIS_MAKENSIS) else() if(APPLE) set(CPACK_GENERATOR DragNDrop) else() set(CPACK_GENERATOR TGZ) endif() endif() endif(NOT CPACK_GENERATOR) # Set Redistributable information for windows if(${CMAKE_SYSTEM_NAME} MATCHES Windows) include(mitkFunctionGetMSVCVersion) mitkFunctionGetMSVCVersion() set(CPACK_VISUAL_STUDIO_VERSION_MAJOR "${VISUAL_STUDIO_VERSION_MAJOR}") set(CPACK_VISUAL_STUDIO_PRODUCT_NAME "${VISUAL_STUDIO_PRODUCT_NAME}") set(CPACK_LIBRARY_ARCHITECTURE "${CMAKE_LIBRARY_ARCHITECTURE}") set(CMAKE_${CPACK_VISUAL_STUDIO_PRODUCT_NAME}_REDISTRIBUTABLE "" CACHE FILEPATH "Path to the appropriate Microsoft Visual Studio Redistributable") endif() if(EXISTS ${CMAKE_${CPACK_VISUAL_STUDIO_PRODUCT_NAME}_REDISTRIBUTABLE} ) install(PROGRAMS ${CMAKE_${CPACK_VISUAL_STUDIO_PRODUCT_NAME}_REDISTRIBUTABLE} DESTINATION thirdpartyinstallers) get_filename_component(CPACK_REDISTRIBUTABLE_FILE_NAME ${CMAKE_${CPACK_VISUAL_STUDIO_PRODUCT_NAME}_REDISTRIBUTABLE} NAME ) endif() # On windows set default install directory appropriately for 32 and 64 bit # installers if not already set if(WIN32 AND NOT CPACK_NSIS_INSTALL_ROOT) if(CMAKE_CL_64) set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES64") else() set(CPACK_NSIS_INSTALL_ROOT "$PROGRAMFILES") endif() endif() # By default, do not warn when built on machines using only VS Express if(NOT DEFINED CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS) set(CMAKE_INSTALL_SYSTEM_RUNTIME_LIBS_NO_WARNINGS ON) endif() # include required mfc libraries include(InstallRequiredSystemLibraries) set(CPACK_PACKAGE_NAME "MITK") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "MITK is a medical image processing tool") set(CPACK_PACKAGE_VENDOR "German Cancer Research Center (DKFZ)") set(CPACK_PACKAGE_DESCRIPTION_FILE "${MITK_SOURCE_DIR}/LICENSE.txt") set(CPACK_RESOURCE_FILE_LICENSE "${MITK_SOURCE_DIR}/LICENSE.txt") set(CPACK_PACKAGE_VERSION_MAJOR "${MITK_VERSION_MAJOR}") set(CPACK_PACKAGE_VERSION_MINOR "${MITK_VERSION_MINOR}") # tell cpack to strip all debug symbols from all files set(CPACK_STRIP_FILES ON) # append revision number if available if(MITK_REVISION_ID AND MITK_VERSION_PATCH STREQUAL "99") if(MITK_WC_TYPE STREQUAL "git") set(git_hash ${MITK_REVISION_ID}) string(LENGTH "${git_hash}" hash_length) if(hash_length GREATER 6) string(SUBSTRING ${git_hash} 0 6 git_hash) endif() set(CPACK_PACKAGE_VERSION_PATCH "${MITK_VERSION_PATCH}_r${git_hash}") else() set(CPACK_PACKAGE_VERSION_PATCH "${MITK_VERSION_PATCH}_r${MITK_REVISION_ID}") endif() else() set(CPACK_PACKAGE_VERSION_PATCH "${MITK_VERSION_PATCH}") endif() # set version set(CPACK_PACKAGE_VERSION "${CPACK_PACKAGE_VERSION_MAJOR}.${CPACK_PACKAGE_VERSION_MINOR}.${CPACK_PACKAGE_VERSION_PATCH}") # determine possible system specific extension set(CPACK_PACKAGE_ARCH "unkown-architecture") if(${CMAKE_SYSTEM_NAME} MATCHES Windows) if(CMAKE_CL_64) set(CPACK_PACKAGE_ARCH "win64") - elseif(MINGW) - set(CPACK_PACKAGE_ARCH "mingw32") elseif(WIN32) set(CPACK_PACKAGE_ARCH "win32") endif() endif(${CMAKE_SYSTEM_NAME} MATCHES Windows) if(${CMAKE_SYSTEM_NAME} MATCHES Linux) if(${CMAKE_SYSTEM_PROCESSOR} MATCHES i686) set(CPACK_PACKAGE_ARCH "linux32") elseif(${CMAKE_SYSTEM_PROCESSOR} MATCHES x86_64) if(${CMAKE_CXX_FLAGS} MATCHES " -m32 ") set(CPACK_PACKAGE_ARCH "linux32") else() set(CPACK_PACKAGE_ARCH "linux64") endif(${CMAKE_CXX_FLAGS} MATCHES " -m32 ") else() set(CPACK_PACKAGE_ARCH "linux") endif() endif(${CMAKE_SYSTEM_NAME} MATCHES Linux) if(${CMAKE_SYSTEM_NAME} MATCHES Darwin) set(CPACK_PACKAGE_ARCH "mac64") endif(${CMAKE_SYSTEM_NAME} MATCHES Darwin) set(CPACK_PACKAGE_FILE_NAME "${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION}-${CPACK_PACKAGE_ARCH}") diff --git a/CMakeExternals/ITK.cmake b/CMakeExternals/ITK.cmake index 9fd4bbdb4f..cf66989655 100644 --- a/CMakeExternals/ITK.cmake +++ b/CMakeExternals/ITK.cmake @@ -1,86 +1,77 @@ #----------------------------------------------------------------------------- # ITK #----------------------------------------------------------------------------- # Sanity checks if(DEFINED ITK_DIR AND NOT EXISTS ${ITK_DIR}) message(FATAL_ERROR "ITK_DIR variable is defined but corresponds to non-existing directory") endif() set(proj ITK) set(proj_DEPENDENCIES GDCM) if(MITK_USE_OpenCV) list(APPEND proj_DEPENDENCIES OpenCV) endif() if(MITK_USE_HDF5) list(APPEND proj_DEPENDENCIES HDF5) endif() set(ITK_DEPENDS ${proj}) if(NOT DEFINED ITK_DIR) - set(additional_cmake_args ) - if(MINGW) - set(additional_cmake_args - -DCMAKE_USE_WIN32_THREADS:BOOL=ON - -DCMAKE_USE_PTHREADS:BOOL=OFF) - endif() - - list(APPEND additional_cmake_args - -DUSE_WRAP_ITK:BOOL=OFF - ) + set(additional_cmake_args -DUSE_WRAP_ITK:BOOL=OFF) if(MITK_USE_OpenCV) list(APPEND additional_cmake_args -DModule_ITKVideoBridgeOpenCV:BOOL=ON -DOpenCV_DIR:PATH=${OpenCV_DIR} ) endif() # Keep the behaviour of ITK 4.3 which by default turned on ITK Review # see MITK bug #17338 list(APPEND additional_cmake_args -DModule_ITKReview:BOOL=ON # for 4.7, the OpenJPEG is needed by review but the variable must be set -DModule_ITKOpenJPEG:BOOL=ON ) if(CTEST_USE_LAUNCHERS) list(APPEND additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/InsightToolkit-4.13.0.tar.xz URL_MD5 3badf70cfb0093054453f66c5974c5a4 # work with external GDCM # PATCH_COMMAND ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/ITK-4.11.0.patch CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} -DBUILD_EXAMPLES:BOOL=OFF -DITK_USE_SYSTEM_GDCM:BOOL=ON -DGDCM_DIR:PATH=${GDCM_DIR} -DITK_USE_SYSTEM_HDF5:BOOL=ON -DHDF5_DIR:PATH=${HDF5_DIR} CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) set(ITK_DIR ${ep_prefix}) mitkFunctionInstallExternalCMakeProject(${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() diff --git a/CMakeExternals/MITKData.cmake b/CMakeExternals/MITKData.cmake index dc12a0653a..5eedb42547 100644 --- a/CMakeExternals/MITKData.cmake +++ b/CMakeExternals/MITKData.cmake @@ -1,37 +1,37 @@ #----------------------------------------------------------------------------- # MITK Data #----------------------------------------------------------------------------- # Sanity checks if(DEFINED MITK_DATA_DIR AND NOT EXISTS ${MITK_DATA_DIR}) message(FATAL_ERROR "MITK_DATA_DIR variable is defined but corresponds to non-existing directory") endif() set(proj MITK-Data) set(proj_DEPENDENCIES) set(MITK-Data_DEPENDS ${proj}) if(BUILD_TESTING) - set(revision_tag 5ad3bb57) # first 8 characters of hash-tag + set(revision_tag da5dd4ff) # first 8 characters of hash-tag # ^^^^^^^^ these are just to check correct length of hash part ExternalProject_Add(${proj} SOURCE_DIR ${proj} GIT_REPOSITORY https://phabricator.mitk.org/source/mitkdata.git GIT_TAG ${revision_tag} # URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/mitk-data_${revision_tag}.tar.gz - UPDATE_COMMAND "" +# UPDATE_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" DEPENDS ${proj_DEPENDENCIES} ) set(MITK_DATA_DIR ${CMAKE_CURRENT_BINARY_DIR}/${proj}) else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif(BUILD_TESTING) diff --git a/CMakeExternals/OpenIGTLink.cmake b/CMakeExternals/OpenIGTLink.cmake index 5da8a3e2cb..d7910aa5e8 100644 --- a/CMakeExternals/OpenIGTLink.cmake +++ b/CMakeExternals/OpenIGTLink.cmake @@ -1,57 +1,52 @@ #----------------------------------------------------------------------------- # OpenIGTLink #----------------------------------------------------------------------------- if(MITK_USE_OpenIGTLink) # Sanity checks if(DEFINED OpenIGTLink_DIR AND NOT EXISTS ${OpenIGTLink_DIR}) message(FATAL_ERROR "OpenIGTLink_DIR variable is defined but corresponds to non-existing directory") endif() set(proj OpenIGTLink) set(proj_DEPENDENCIES ) set(${proj}_DEPENDS ${proj}) if(NOT DEFINED OpenIGTLink_DIR) set(additional_cmake_args ) - if(MINGW) - set(additional_cmake_args - -DCMAKE_USE_WIN32_THREADS:BOOL=ON - -DCMAKE_USE_PTHREADS:BOOL=OFF) - endif() if(CTEST_USE_LAUNCHERS) - list(APPEND additional_cmake_args + set(additional_cmake_args "-DCMAKE_PROJECT_${proj}_INCLUDE:FILEPATH=${CMAKE_ROOT}/Modules/CTestUseLaunchers.cmake" ) endif() ExternalProject_Add(${proj} URL ${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/OpenIGTLink-54df50de.tar.gz URL_MD5 b9fd8351b059f4ec615f2dfd74ab2458 PATCH_COMMAND ${PATCH_COMMAND} -N -p1 -i ${CMAKE_CURRENT_LIST_DIR}/OpenIGTLink-54df50de.patch CMAKE_GENERATOR ${gen} CMAKE_ARGS ${ep_common_args} ${additional_cmake_args} -DBUILD_EXAMPLES:BOOL=OFF -DOpenIGTLink_PROTOCOL_VERSION_2:BOOL=ON -DOpenIGTLink_INSTALL_LIB_DIR:STRING=lib -DOpenIGTLink_INSTALL_PACKAGE_DIR:STRING=lib/cmake/OpenIGTLink -DOpenIGTLink_INSTALL_NO_DOCUMENTATION:BOOL=ON CMAKE_CACHE_ARGS ${ep_common_cache_args} CMAKE_CACHE_DEFAULT_ARGS ${ep_common_cache_default_args} DEPENDS ${proj_DEPENDENCIES} ) set(OpenIGTLink_DIR "${ep_prefix}/lib/cmake/OpenIGTLink") else() mitkMacroEmptyExternalProject(${proj} "${proj_DEPENDENCIES}") endif() endif() diff --git a/CMakeLists.txt b/CMakeLists.txt index 228e87e623..39c5f3c21f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,1337 +1,1335 @@ set(MITK_CMAKE_MINIMUM_REQUIRED_VERSION 3.10) cmake_minimum_required(VERSION ${MITK_CMAKE_MINIMUM_REQUIRED_VERSION}) #----------------------------------------------------------------------------- # See https://cmake.org/cmake/help/v3.10/manual/cmake-policies.7.html for details #----------------------------------------------------------------------------- set(project_policies ) foreach(policy ${project_policies}) if(POLICY ${policy}) cmake_policy(SET ${policy} NEW) endif() endforeach() #----------------------------------------------------------------------------- # MITK Extension Feature #----------------------------------------------------------------------------- set(MITK_EXTENSION_DIRS "" CACHE STRING "") mark_as_advanced(MITK_EXTENSION_DIRS) #----------------------------------------------------------------------------- # Superbuild Option - Enabled by default #----------------------------------------------------------------------------- option(MITK_USE_SUPERBUILD "Build MITK and the projects it depends on via SuperBuild.cmake." ON) if(MITK_USE_SUPERBUILD) project(MITK-superbuild) set(MITK_SOURCE_DIR ${PROJECT_SOURCE_DIR}) set(MITK_BINARY_DIR ${PROJECT_BINARY_DIR}) else() project(MITK VERSION 2016.11.99) include_directories(SYSTEM ${MITK_SUPERBUILD_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # Update CMake module path #----------------------------------------------------------------------------- set(MITK_CMAKE_DIR ${MITK_SOURCE_DIR}/CMake) set(CMAKE_MODULE_PATH ${MITK_CMAKE_DIR}) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_CMAKE_EXTENSION_DIR ${MITK_EXTENSION_DIR}/CMake) get_filename_component(MITK_CMAKE_EXTENSION_DIR ${MITK_CMAKE_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_CMAKE_EXTENSION_DIR}) list(APPEND CMAKE_MODULE_PATH ${MITK_CMAKE_EXTENSION_DIR}) endif() endforeach() #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- # Standard CMake macros include(FeatureSummary) include(CTestUseLaunchers) include(CMakeParseArguments) include(FindPackageHandleStandardArgs) # MITK macros include(mitkFunctionGetGccVersion) include(mitkFunctionCheckCompilerFlags) include(mitkFunctionSuppressWarnings) # includes several functions include(mitkMacroEmptyExternalProject) include(mitkFunctionGenerateProjectXml) include(mitkFunctionEnableBuildConfiguration) include(mitkFunctionWhitelists) include(mitkFunctionAddExternalProject) SUPPRESS_VC_DEPRECATED_WARNINGS() #----------------------------------------------------------------------------- # Set a default build type if none was specified #----------------------------------------------------------------------------- if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Debug' as none was specified.") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() #----------------------------------------------------------------------------- # Check miminum Mac OS X version #----------------------------------------------------------------------------- # The minimum supported Mac OS X version is 10.9. If you use a version less than 10.9, there is no guarantee that the build still works. if(APPLE) exec_program(sw_vers ARGS -productVersion OUTPUT_VARIABLE osx_version) if (osx_version VERSION_LESS "10.9") message(WARNING "Detected OS X version \"${osx_version}\" is not supported anymore. Minimum required OS X version is 10.9 or greater.") endif() if (CMAKE_OSX_DEPLOYMENT_TARGET AND CMAKE_OSX_DEPLOYMENT_TARGET VERSION_LESS 10.9) message(WARNING "Detected OS X deployment target \"${CMAKE_OSX_DEPLOYMENT_TARGET}\" is not supported anymore. Minimum required OS X version is 10.9 or greater.") endif() endif() #----------------------------------------------------------------------------- # Check miminum compiler versions #----------------------------------------------------------------------------- if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") # require at least gcc 4.9 as provided by ppa:ubuntu-toolchain-r/test for Ubuntu 14.04 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 4.9) message(FATAL_ERROR "GCC version must be at least 4.9 If you are using Ubuntu 14.04, you can easily install gcc and g++ 4.9 (or any later version available) in addition to your version ${CMAKE_CXX_COMPILER_VERSION}: sudo add-apt-repository ppa:ubuntu-toolchain-r/test sudo apt-get update sudo apt-get install gcc-4.9 g++-4.9 Make sure to explicitly specify these compilers when configuring MITK: CMAKE_C_COMPILER:FILEPATH=/usr/bin/gcc-4.9 CMAKE_CXX_COMPILER:FILEPATH=/usr/bin/g++-4.9 For more information on the proposed PPA see the Toolchain Updates section of https://wiki.ubuntu.com/ToolChain.") endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") # require at least clang 3.4 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 3.4) message(FATAL_ERROR "Clang version must be at least 3.4") endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") # require at least clang 5.0 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 5.0) message(FATAL_ERROR "Apple Clang version must be at least 5.0") endif() elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC") # require at least Visual Studio 2015 if (CMAKE_CXX_COMPILER_VERSION VERSION_LESS 19) message(FATAL_ERROR "Microsoft Visual Studio 2015 Update 3 or newer required") endif() else() message(WARNING "You are using an unsupported compiler! Compilation has only been tested with Clang (Linux or Apple), GCC and MSVC.") endif() if(CMAKE_COMPILER_IS_GNUCXX) mitkFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) else() set(GCC_VERSION 0) endif() set(MITK_CXX_STANDARD 14) set(CMAKE_CXX_EXTENSIONS 0) set(CMAKE_CXX_STANDARD ${MITK_CXX_STANDARD}) set(CMAKE_CXX_STANDARD_REQUIRED 1) # This is necessary to avoid problems with compile feature checks. # CMAKE_CXX_STANDARD seems to only set the -std=c++14 flag for targets. # However, compile flag checks also need to be done with -std=c++14. # The MITK_CXX14_FLAG variable is also used for external projects # build during the MITK super-build. mitkFunctionCheckCompilerFlags("-std=c++14" MITK_CXX14_FLAG) #----------------------------------------------------------------------------- # Warn if source or build path is too long #----------------------------------------------------------------------------- if(WIN32) set(_src_dir_length_max 50) set(_bin_dir_length_max 50) if(MITK_USE_SUPERBUILD) set(_src_dir_length_max 34) # _src_dir_length_max - strlen(ep/src/ITK-build) set(_bin_dir_length_max 40) # _bin_dir_length_max - strlen(MITK-build) endif() string(LENGTH "${MITK_SOURCE_DIR}" _src_n) string(LENGTH "${MITK_BINARY_DIR}" _bin_n) # The warnings should be converted to errors if(_src_n GREATER _src_dir_length_max) message(WARNING "MITK source code directory path length is too long (${_src_n} > ${_src_dir_length_max})." "Please move the MITK source code directory to a directory with a shorter path." ) endif() if(_bin_n GREATER _bin_dir_length_max) message(WARNING "MITK build directory path length is too long (${_bin_n} > ${_bin_dir_length_max})." "Please move the MITK build directory to a directory with a shorter path." ) endif() endif() #----------------------------------------------------------------------------- # Additional MITK Options (also shown during superbuild) #----------------------------------------------------------------------------- macro(env_option name doc value) set(_value $ENV{${name}}) if("${_value}" STREQUAL "") set(_value ${value}) endif() option(${name} "${doc}" ${_value}) endmacro() # ----------------------------------------- # General build options option(BUILD_SHARED_LIBS "Build MITK with shared libraries" ON) option(WITH_COVERAGE "Enable/Disable coverage" OFF) option(BUILD_TESTING "Test the project" ON) env_option(MITK_BUILD_ALL_APPS "Build all MITK applications" OFF) env_option(MITK_BUILD_EXAMPLES "Build the MITK Examples" OFF) option(MITK_ENABLE_PIC_READER "Enable support for reading the DKFZ pic file format." ON) mark_as_advanced(MITK_BUILD_ALL_APPS MITK_ENABLE_PIC_READER ) # ----------------------------------------- # Qt version related variables env_option(MITK_USE_Qt5 "Use Qt 5 library" ON) if(MITK_USE_Qt5) set(MITK_QT5_MINIMUM_VERSION 5.6.0) set(MITK_QT5_COMPONENTS Concurrent OpenGL PrintSupport Script Sql Svg Widgets Xml XmlPatterns WebEngineWidgets UiTools Help LinguistTools) if(APPLE) set(MITK_QT5_COMPONENTS ${MITK_QT5_COMPONENTS} DBus) endif() find_package(Qt5 ${MITK_QT5_MINIMUM_VERSION} COMPONENTS ${MITK_QT5_COMPONENTS} REQUIRED) endif() set_property(GLOBAL PROPERTY MITK_EXTERNAL_PROJECTS "") include(CMakeExternals/ExternalProjectList.cmake) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_CMAKE_EXTERNALS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/CMakeExternals) get_filename_component(MITK_CMAKE_EXTERNALS_EXTENSION_DIR ${MITK_CMAKE_EXTERNALS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_CMAKE_EXTERNALS_EXTENSION_DIR}/ExternalProjectList.cmake) include(${MITK_CMAKE_EXTERNALS_EXTENSION_DIR}/ExternalProjectList.cmake) endif() endforeach() # ----------------------------------------- # Other MITK_USE_* options not related to # external projects build via the # MITK superbuild env_option(MITK_USE_BLUEBERRY "Build the BlueBerry platform" ON) env_option(MITK_USE_OpenCL "Use OpenCL GPU-Computing library" OFF) #----------------------------------------------------------------------------- # Build configurations #----------------------------------------------------------------------------- set(_buildConfigs "Custom") file(GLOB _buildConfigFiles CMake/BuildConfigurations/*.cmake) foreach(_buildConfigFile ${_buildConfigFiles}) get_filename_component(_buildConfigFile ${_buildConfigFile} NAME_WE) list(APPEND _buildConfigs ${_buildConfigFile}) endforeach() set(MITK_BUILD_CONFIGURATION "Custom" CACHE STRING "Use pre-defined MITK configurations") set_property(CACHE MITK_BUILD_CONFIGURATION PROPERTY STRINGS ${_buildConfigs}) mitkFunctionEnableBuildConfiguration() mitkFunctionCreateWhitelistPaths(MITK) mitkFunctionFindWhitelists(MITK) # ----------------------------------------- # Custom dependency logic option(MITK_USE_SYSTEM_Boost "Use the system Boost" OFF) set(MITK_USE_Boost_LIBRARIES "" CACHE STRING "A semi-colon separated list of required Boost libraries") # only windows can't build python in debug mode if(MITK_USE_Python AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug" AND WIN32) message(WARNING "Disabling Python support. Building MITK Python in debug mode on Windowsis not supported!") set(MITK_USE_Python OFF CACHE BOOL "Use python wrapping in MITK" FORCE) set(MITK_USE_Numpy OFF CACHE BOOL "Use Numpy" FORCE) set(MITK_USE_SimpleITK OFF CACHE BOOL "Use SimpleITK" FORCE) elseif(MITK_USE_Python) set(MITK_USE_ZLIB ON) if(NOT MITK_USE_Numpy) message("> Forcing MITK_USE_Numpy to ON because of MITK_USE_Python") set(MITK_USE_Numpy ON CACHE BOOL "Use Numpy" FORCE) endif() if(NOT MITK_USE_SimpleITK) message("> Forcing MITK_USE_SimpleITK to ON because of MITK_USE_Python") set(MITK_USE_SimpleITK ON CACHE BOOL "Use SimpleITK" FORCE) endif() find_package(PythonLibs REQUIRED) find_package(PythonInterp REQUIRED) elseif(MITK_USE_Python AND "${CMAKE_BUILD_TYPE}" STREQUAL "Debug" AND WIN32) message(WARNING "Disabling Python support. Building MITK Python in debug mode on Windowsis not supported!") set(MITK_USE_Python OFF CACHE BOOL "Use python wrapping in MITK" FORCE) endif() if(BUILD_TESTING AND NOT MITK_USE_CppUnit) message("> Forcing MITK_USE_CppUnit to ON because BUILD_TESTING=ON") set(MITK_USE_CppUnit ON CACHE BOOL "Use CppUnit for unit tests" FORCE) endif() if(MITK_USE_BLUEBERRY) option(MITK_BUILD_ALL_PLUGINS "Build all MITK plugins" OFF) mark_as_advanced(MITK_BUILD_ALL_PLUGINS) if(NOT MITK_USE_CTK) message("> Forcing MITK_USE_CTK to ON because of MITK_USE_BLUEBERRY") set(MITK_USE_CTK ON CACHE BOOL "Use CTK in MITK" FORCE) endif() endif() #----------------------------------------------------------------------------- # Pixel type multiplexing #----------------------------------------------------------------------------- # Customize the default pixel types for multiplex macros set(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES "int, unsigned int, short, unsigned short, char, unsigned char" CACHE STRING "List of integral pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES "double, float" CACHE STRING "List of floating pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES "itk::RGBPixel, itk::RGBAPixel" CACHE STRING "List of composite pixel types used in AccessByItk and InstantiateAccessFunction macros") set(MITK_ACCESSBYITK_DIMENSIONS "2,3" CACHE STRING "List of dimensions used in AccessByItk and InstantiateAccessFunction macros") mark_as_advanced(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES MITK_ACCESSBYITK_DIMENSIONS ) # consistency checks if(NOT MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES) set(MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES "int, unsigned int, short, unsigned short, char, unsigned char" CACHE STRING "List of integral pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES) set(MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES "double, float" CACHE STRING "List of floating pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES) set(MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES "itk::RGBPixel, itk::RGBAPixel" CACHE STRING "List of composite pixel types used in AccessByItk and InstantiateAccessFunction macros" FORCE) endif() if(NOT MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES) string(REPLACE "," ";" _integral_types ${MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES}) string(REPLACE "," ";" _floating_types ${MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES}) foreach(_scalar_type ${_integral_types} ${_floating_types}) set(MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES "${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}itk::VariableLengthVector<${_scalar_type}>,") endforeach() string(LENGTH "${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}" _length) math(EXPR _length "${_length} - 1") string(SUBSTRING "${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES}" 0 ${_length} MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES) set(MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES ${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES} CACHE STRING "List of vector pixel types used in AccessByItk and InstantiateAccessFunction macros for itk::VectorImage types" FORCE) endif() if(NOT MITK_ACCESSBYITK_DIMENSIONS) set(MITK_ACCESSBYITK_DIMENSIONS "2,3" CACHE STRING "List of dimensions used in AccessByItk and InstantiateAccessFunction macros") endif() #----------------------------------------------------------------------------- # Project.xml #----------------------------------------------------------------------------- # A list of topologically ordered targets set(CTEST_PROJECT_SUBPROJECTS) list(APPEND CTEST_PROJECT_SUBPROJECTS MITK-Core MITK-CoreUI MITK-IGT MITK-ToF MITK-DTI MITK-Modules # all modules not contained in a specific subproject MITK-Plugins # all plugins not contained in a specific subproject MITK-Examples Unlabeled # special "subproject" catching all unlabeled targets and tests ) # Configure CTestConfigSubProject.cmake that could be used by CTest scripts configure_file(${MITK_SOURCE_DIR}/CTestConfigSubProject.cmake.in ${MITK_BINARY_DIR}/CTestConfigSubProject.cmake) if(CTEST_PROJECT_ADDITIONAL_TARGETS) # those targets will be executed at the end of the ctest driver script # and they also get their own subproject label set(subproject_list "${CTEST_PROJECT_SUBPROJECTS};${CTEST_PROJECT_ADDITIONAL_TARGETS}") else() set(subproject_list "${CTEST_PROJECT_SUBPROJECTS}") endif() # Generate Project.xml file expected by the CTest driver script mitkFunctionGenerateProjectXml(${MITK_BINARY_DIR} MITK "${subproject_list}" ${MITK_USE_SUPERBUILD}) #----------------------------------------------------------------------------- # Superbuild script #----------------------------------------------------------------------------- if(MITK_USE_SUPERBUILD) include("${CMAKE_CURRENT_SOURCE_DIR}/SuperBuild.cmake") # Print configuration summary message("\n\n") feature_summary( DESCRIPTION "------- FEATURE SUMMARY FOR ${PROJECT_NAME} -------" WHAT ALL) return() endif() #***************************************************************************** #**************************** END OF SUPERBUILD **************************** #***************************************************************************** #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(WriteBasicConfigVersionFile) include(CheckCXXSourceCompiles) include(GenerateExportHeader) include(mitkFunctionAddCustomModuleTest) include(mitkFunctionCheckModuleDependencies) include(mitkFunctionCompileSnippets) include(mitkFunctionConfigureVisualStudioUserProjectFile) include(mitkFunctionConvertXPSchema) include(mitkFunctionCreateBlueBerryApplication) include(mitkFunctionCreateCommandLineApp) include(mitkFunctionCreateModule) include(mitkFunctionCreatePlugin) include(mitkFunctionCreateProvisioningFile) include(mitkFunctionGetLibrarySearchPaths) include(mitkFunctionGetVersion) include(mitkFunctionGetVersionDescription) include(mitkFunctionInstallAutoLoadModules) include(mitkFunctionInstallCTKPlugin) include(mitkFunctionInstallProvisioningFiles) include(mitkFunctionInstallThirdPartyCTKPlugins) include(mitkFunctionOrganizeSources) include(mitkFunctionTestPlugin) include(mitkFunctionUseModules) if( ${MITK_USE_MatchPoint} ) include(mitkFunctionCreateMatchPointDeployedAlgorithm) endif() include(mitkMacroConfigureItkPixelTypes) include(mitkMacroCreateExecutable) include(mitkMacroCreateModuleTests) include(mitkMacroGenerateToolsLibrary) include(mitkMacroGetLinuxDistribution) include(mitkMacroGetPMDPlatformString) include(mitkMacroInstall) include(mitkMacroInstallHelperApp) include(mitkMacroInstallTargets) include(mitkMacroMultiplexPicType) # Deprecated include(mitkMacroCreateCTKPlugin) #----------------------------------------------------------------------------- # Global CMake variables #----------------------------------------------------------------------------- # Required and enabled C++14 features for all MITK code. # These are added as PUBLIC compile features to all MITK modules. set(MITK_CXX_FEATURES cxx_auto_type cxx_decltype cxx_enum_forward_declarations cxx_extended_friend_declarations cxx_extern_templates cxx_final cxx_lambdas cxx_local_type_template_args cxx_long_long_type cxx_nullptr cxx_override cxx_range_for cxx_right_angle_brackets cxx_rvalue_references cxx_static_assert cxx_strong_enums cxx_template_template_parameters cxx_trailing_return_types cxx_variadic_macros ) if(NOT DEFINED CMAKE_DEBUG_POSTFIX) # We can't do this yet because the CTK Plugin Framework # cannot cope with a postfix yet. #set(CMAKE_DEBUG_POSTFIX d) endif() #----------------------------------------------------------------------------- # Output directories. #----------------------------------------------------------------------------- set(_default_LIBRARY_output_dir lib) set(_default_RUNTIME_output_dir bin) set(_default_ARCHIVE_output_dir lib) foreach(type LIBRARY RUNTIME ARCHIVE) # Make sure the directory exists if(MITK_CMAKE_${type}_OUTPUT_DIRECTORY AND NOT EXISTS ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}) message("Creating directory MITK_CMAKE_${type}_OUTPUT_DIRECTORY: ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}") file(MAKE_DIRECTORY "${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}") endif() if(MITK_CMAKE_${type}_OUTPUT_DIRECTORY) set(CMAKE_${type}_OUTPUT_DIRECTORY ${MITK_CMAKE_${type}_OUTPUT_DIRECTORY}) else() set(CMAKE_${type}_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/${_default_${type}_output_dir}) set(MITK_CMAKE_${type}_OUTPUT_DIRECTORY ${CMAKE_${type}_OUTPUT_DIRECTORY}) endif() set(CMAKE_${type}_OUTPUT_DIRECTORY ${CMAKE_${type}_OUTPUT_DIRECTORY} CACHE INTERNAL "Output directory for ${type} files.") mark_as_advanced(CMAKE_${type}_OUTPUT_DIRECTORY) endforeach() #----------------------------------------------------------------------------- # Set MITK specific options and variables (NOT available during superbuild) #----------------------------------------------------------------------------- # Look for optional Doxygen package find_package(Doxygen) option(BLUEBERRY_DEBUG_SMARTPOINTER "Enable code for debugging smart pointers" OFF) mark_as_advanced(BLUEBERRY_DEBUG_SMARTPOINTER) # ASK THE USER TO SHOW THE CONSOLE WINDOW FOR CoreApp and mitkWorkbench option(MITK_SHOW_CONSOLE_WINDOW "Use this to enable or disable the console window when starting MITK GUI Applications" ON) mark_as_advanced(MITK_SHOW_CONSOLE_WINDOW) # TODO: check if necessary option(USE_ITKZLIB "Use the ITK zlib for pic compression." ON) mark_as_advanced(USE_ITKZLIB) if(NOT MITK_FAST_TESTING) if(DEFINED MITK_CTEST_SCRIPT_MODE AND (MITK_CTEST_SCRIPT_MODE STREQUAL "continuous" OR MITK_CTEST_SCRIPT_MODE STREQUAL "experimental") ) set(MITK_FAST_TESTING 1) endif() endif() -if(NOT UNIX AND NOT MINGW) +if(NOT UNIX) set(MITK_WIN32_FORCE_STATIC "STATIC" CACHE INTERNAL "Use this variable to always build static libraries on non-unix platforms") endif() if(MITK_BUILD_ALL_PLUGINS) set(MITK_BUILD_ALL_PLUGINS_OPTION "FORCE_BUILD_ALL") endif() # Configure pixel types used for ITK image access multiplexing mitkMacroConfigureItkPixelTypes() # Configure module naming conventions set(MITK_MODULE_NAME_REGEX_MATCH "^[A-Z].*$") set(MITK_MODULE_NAME_REGEX_NOT_MATCH "^[Mm][Ii][Tt][Kk].*$") set(MITK_DEFAULT_MODULE_NAME_PREFIX "Mitk") set(MITK_MODULE_NAME_PREFIX ${MITK_DEFAULT_MODULE_NAME_PREFIX}) set(MITK_MODULE_NAME_DEFAULTS_TO_DIRECTORY_NAME 1) #----------------------------------------------------------------------------- # Get MITK version info #----------------------------------------------------------------------------- mitkFunctionGetVersion(${MITK_SOURCE_DIR} MITK) mitkFunctionGetVersionDescription(${MITK_SOURCE_DIR} MITK) # MITK_VERSION set(MITK_VERSION_STRING "${MITK_VERSION_MAJOR}.${MITK_VERSION_MINOR}.${MITK_VERSION_PATCH}") if(MITK_VERSION_PATCH STREQUAL "99") set(MITK_VERSION_STRING "${MITK_VERSION_STRING}-${MITK_REVISION_SHORTID}") endif() #----------------------------------------------------------------------------- # Installation preparation # # These should be set before any MITK install macros are used #----------------------------------------------------------------------------- # on Mac OSX all BlueBerry plugins get copied into every # application bundle (.app directory) specified here if(MITK_USE_BLUEBERRY AND APPLE) include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/AppList.cmake") foreach(mitk_app ${MITK_APPS}) # extract option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 1 option_name) list(GET target_info_list 0 app_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) set(MACOSX_BUNDLE_NAMES ${MACOSX_BUNDLE_NAMES} Mitk${app_name}) endif() endforeach() endif() #----------------------------------------------------------------------------- # Set coverage Flags #----------------------------------------------------------------------------- if(WITH_COVERAGE) if("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU") set(coverage_flags "-g -fprofile-arcs -ftest-coverage -O0 -DNDEBUG") set(COVERAGE_CXX_FLAGS ${coverage_flags}) set(COVERAGE_C_FLAGS ${coverage_flags}) endif() endif() #----------------------------------------------------------------------------- # MITK C/CXX Flags #----------------------------------------------------------------------------- set(MITK_C_FLAGS "${COVERAGE_C_FLAGS}") set(MITK_C_FLAGS_DEBUG ) set(MITK_C_FLAGS_RELEASE ) set(MITK_CXX_FLAGS "${COVERAGE_CXX_FLAGS} ${MITK_CXX14_FLAG}") set(MITK_CXX_FLAGS_DEBUG ) set(MITK_CXX_FLAGS_RELEASE ) set(MITK_EXE_LINKER_FLAGS ) set(MITK_SHARED_LINKER_FLAGS ) find_package(OpenMP) if (OPENMP_FOUND) set(MITK_C_FLAGS "${MITK_C_FLAGS} ${OpenMP_C_FLAGS}") set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} ${OpenMP_CXX_FLAGS}") endif() if(WIN32) set(MITK_CXX_FLAGS "${MITK_CXX_FLAGS} -D_WIN32_WINNT=0x0501 -DPOCO_NO_UNWINDOWS -DWIN32_LEAN_AND_MEAN -DNOMINMAX") mitkFunctionCheckCompilerFlags("/wd4005" MITK_CXX_FLAGS) # warning C4005: macro redefinition mitkFunctionCheckCompilerFlags("/wd4231" MITK_CXX_FLAGS) # warning C4231: nonstandard extension used : 'extern' before template explicit instantiation # the following line should be removed after fixing bug 17637 mitkFunctionCheckCompilerFlags("/wd4316" MITK_CXX_FLAGS) # warning C4316: object alignment on heap mitkFunctionCheckCompilerFlags("/wd4180" MITK_CXX_FLAGS) # warning C4180: qualifier applied to function type has no meaning endif() if(NOT MSVC_VERSION) foreach(_flag -Wall -Wextra -Wpointer-arith -Winvalid-pch -Wcast-align -Wwrite-strings -Wno-error=gnu -Wno-error=unknown-pragmas # The strict-overflow warning is generated by ITK template code -Wno-error=strict-overflow -Woverloaded-virtual -Wstrict-null-sentinel #-Wold-style-cast #-Wsign-promo -Wno-array-bounds -fdiagnostics-show-option ) mitkFunctionCheckCAndCXXCompilerFlags(${_flag} MITK_C_FLAGS MITK_CXX_FLAGS) endforeach() endif() if(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) mitkFunctionCheckCompilerFlags("-Wl,--no-undefined" MITK_SHARED_LINKER_FLAGS) mitkFunctionCheckCompilerFlags("-Wl,--as-needed" MITK_SHARED_LINKER_FLAGS) endif() if(CMAKE_COMPILER_IS_GNUCXX) mitkFunctionCheckCAndCXXCompilerFlags("-fstack-protector-all" MITK_C_FLAGS MITK_CXX_FLAGS) - - if(MINGW) - # suppress warnings about auto imported symbols - set(MITK_SHARED_LINKER_FLAGS "-Wl,--enable-auto-import ${MITK_SHARED_LINKER_FLAGS}") - endif() - set(MITK_CXX_FLAGS_RELEASE "-U_FORTIFY_SOURCES -D_FORTIFY_SOURCE=2 ${MITK_CXX_FLAGS_RELEASE}") endif() set(MITK_MODULE_LINKER_FLAGS ${MITK_SHARED_LINKER_FLAGS}) set(MITK_EXE_LINKER_FLAGS ${MITK_SHARED_LINKER_FLAGS}) #----------------------------------------------------------------------------- # MITK Packages #----------------------------------------------------------------------------- set(MITK_MODULES_PACKAGE_DEPENDS_DIR ${MITK_SOURCE_DIR}/CMake/PackageDepends) set(MODULES_PACKAGE_DEPENDS_DIRS ${MITK_MODULES_PACKAGE_DEPENDS_DIR}) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_PACKAGE_DEPENDS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/CMake/PackageDepends) get_filename_component(MITK_PACKAGE_DEPENDS_EXTENSION_DIR ${MITK_PACKAGE_DEPENDS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_PACKAGE_DEPENDS_EXTENSION_DIR}) list(APPEND MODULES_PACKAGE_DEPENDS_DIRS ${MITK_PACKAGE_DEPENDS_EXTENSION_DIR}) endif() endforeach() if(NOT MITK_USE_SYSTEM_Boost) set(Boost_NO_SYSTEM_PATHS 1) endif() set(Boost_USE_MULTITHREADED 1) set(Boost_USE_STATIC_LIBS 0) set(Boost_USE_STATIC_RUNTIME 0) set(Boost_ADDITIONAL_VERSIONS "1.65" "1.65.1") # We need this later for a DCMTK workaround set(_dcmtk_dir_orig ${DCMTK_DIR}) # This property is populated at the top half of this file get_property(MITK_EXTERNAL_PROJECTS GLOBAL PROPERTY MITK_EXTERNAL_PROJECTS) foreach(ep ${MITK_EXTERNAL_PROJECTS}) get_property(_package GLOBAL PROPERTY MITK_${ep}_PACKAGE) get_property(_components GLOBAL PROPERTY MITK_${ep}_COMPONENTS) if(MITK_USE_${ep} AND _package) if(_components) find_package(${_package} COMPONENTS ${_components} REQUIRED CONFIG) else() # Prefer config mode first because it finds external # Config.cmake files pointed at by _DIR variables. # Otherwise, existing Find.cmake files could fail. find_package(${_package} QUIET CONFIG) string(TOUPPER "${_package}" _package_uc) if(NOT (${_package}_FOUND OR ${_package_uc}_FOUND)) find_package(${_package} REQUIRED) endif() endif() endif() endforeach() # Ensure that the MITK CMake module path comes first set(CMAKE_MODULE_PATH ${MITK_CMAKE_DIR} ${CMAKE_MODULE_PATH} ) if(MITK_USE_DCMTK) # Due to the preferred CONFIG mode in find_package calls above, # the DCMTKConfig.cmake file is read, which does not provide useful # package information. We explictly need MODULE mode to find DCMTK. if(${_dcmtk_dir_orig} MATCHES "${MITK_EXTERNAL_PROJECT_PREFIX}.*") # Help our FindDCMTK.cmake script find our super-build DCMTK set(DCMTK_DIR ${MITK_EXTERNAL_PROJECT_PREFIX}) else() # Use the original value set(DCMTK_DIR ${_dcmtk_dir_orig}) endif() find_package(DCMTK REQUIRED MODULE) endif() if(MITK_USE_DCMQI) # Due to the preferred CONFIG mode in find_package calls above, # the DCMQIConfig.cmake file is read, which does not provide useful # package information. We explictly need MODULE mode to find DCMQI. # Help our FindDCMQI.cmake script find our super-build DCMQI set(DCMQI_DIR ${MITK_EXTERNAL_PROJECT_PREFIX}) find_package(DCMQI REQUIRED) endif() if(MITK_USE_Python) find_package(PythonLibs REQUIRED) find_package(PythonInterp REQUIRED) if(MITK_USE_Numpy) find_package(Numpy REQUIRED) endif() endif() link_directories(${Boost_LIBRARY_DIRS}) if(MITK_USE_OpenIGTLink) link_directories(${OpenIGTLink_LIBRARY_DIRS}) endif() if(MITK_USE_SimpleITK) link_directories(${SimpleITK_LIBRARY_DIRS}) endif() if(MITK_USE_OpenCL) find_package(OpenCL REQUIRED) endif() # Qt support if(MITK_USE_Qt5) find_package(Qt5Core ${MITK_QT5_MINIMUM_VERSION} REQUIRED) # at least Core required get_target_property(_qmake_exec Qt5::qmake LOCATION) execute_process(COMMAND ${_qmake_exec} -query QT_INSTALL_BINS RESULT_VARIABLE _result OUTPUT_VARIABLE QT_BINARY_DIR ERROR_VARIABLE _error ) string(STRIP "${QT_BINARY_DIR}" QT_BINARY_DIR) if(_result OR NOT EXISTS "${QT_BINARY_DIR}") message(FATAL_ERROR "Could not determine Qt binary directory: ${_result} ${QT_BINARY_DIR} ${_error}") endif() find_program(QT_HELPGENERATOR_EXECUTABLE NAMES qhelpgenerator qhelpgenerator-qt5 qhelpgenerator5 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_COLLECTIONGENERATOR_EXECUTABLE NAMES qcollectiongenerator qcollectiongenerator-qt5 qcollectiongenerator5 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_ASSISTANT_EXECUTABLE NAMES assistant assistant-qt5 assistant5 PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) find_program(QT_XMLPATTERNS_EXECUTABLE NAMES xmlpatterns PATHS ${QT_BINARY_DIR} NO_DEFAULT_PATH ) mark_as_advanced(QT_HELPGENERATOR_EXECUTABLE QT_COLLECTIONGENERATOR_EXECUTABLE QT_ASSISTANT_EXECUTABLE QT_XMLPATTERNS_EXECUTABLE ) if(MITK_USE_BLUEBERRY) option(BLUEBERRY_USE_QT_HELP "Enable support for integrating plugin documentation into Qt Help" ${DOXYGEN_FOUND}) mark_as_advanced(BLUEBERRY_USE_QT_HELP) # Sanity checks for in-application BlueBerry plug-in help generation if(BLUEBERRY_USE_QT_HELP) set(_force_blueberry_use_qt_help_to_off 0) if(NOT DOXYGEN_FOUND) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because Doxygen was not found.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(DOXYGEN_FOUND AND DOXYGEN_VERSION VERSION_LESS 1.8.7) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because Doxygen version 1.8.7 or newer not found.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(NOT QT_HELPGENERATOR_EXECUTABLE) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because QT_HELPGENERATOR_EXECUTABLE is empty.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(NOT MITK_USE_Qt5) message("> Forcing BLUEBERRY_USE_QT_HELP to OFF because MITK_USE_Qt5 is OFF.") set(_force_blueberry_use_qt_help_to_off 1) endif() if(NOT QT_XMLPATTERNS_EXECUTABLE) message("You have enabled Qt Help support, but QT_XMLPATTERNS_EXECUTABLE is empty") set(_force_blueberry_use_qt_help_to_off 1) endif() if(_force_blueberry_use_qt_help_to_off) set(BLUEBERRY_USE_QT_HELP OFF CACHE BOOL "Enable support for integrating plugin documentation into Qt Help" FORCE) endif() endif() if(BLUEBERRY_QT_HELP_REQUIRED AND NOT BLUEBERRY_USE_QT_HELP) message(FATAL_ERROR "BLUEBERRY_USE_QT_HELP is required to be set to ON") endif() endif() endif() #----------------------------------------------------------------------------- # Testing #----------------------------------------------------------------------------- if(BUILD_TESTING) enable_testing() include(CTest) mark_as_advanced(TCL_TCLSH DART_ROOT) option(MITK_ENABLE_RENDERING_TESTING OFF "Enable the MITK rendering tests. Requires x-server in Linux.") #Rendering testing does not work for Linux nightlies, thus it is disabled per default #and activated for Mac and Windows. if(WIN32 OR APPLE) set(MITK_ENABLE_RENDERING_TESTING ON) endif() mark_as_advanced( MITK_ENABLE_RENDERING_TESTING ) # Setup file for setting custom ctest vars configure_file( CMake/CTestCustom.cmake.in ${MITK_BINARY_DIR}/CTestCustom.cmake @ONLY ) # Initial cache for ProjectTemplate and PluginGenerator tests configure_file( CMake/mitkTestInitialCache.txt.in ${MITK_BINARY_DIR}/mitkTestInitialCache.txt @ONLY ) # Configuration for the CMake-generated test driver set(CMAKE_TESTDRIVER_EXTRA_INCLUDES "#include ") set(CMAKE_TESTDRIVER_BEFORE_TESTMAIN " try {") set(CMAKE_TESTDRIVER_AFTER_TESTMAIN " } catch( std::exception & excp ) { fprintf(stderr,\"%s\\n\",excp.what()); return EXIT_FAILURE; } catch( ... ) { printf(\"Exception caught in the test driver\\n\"); return EXIT_FAILURE; } ") set(MITK_TEST_OUTPUT_DIR "${MITK_BINARY_DIR}/test_output") if(NOT EXISTS ${MITK_TEST_OUTPUT_DIR}) file(MAKE_DIRECTORY ${MITK_TEST_OUTPUT_DIR}) endif() # Test the external project template if(MITK_USE_BLUEBERRY) include(mitkTestProjectTemplate) endif() # Test the package target include(mitkPackageTest) endif() configure_file(mitkTestingConfig.h.in ${MITK_BINARY_DIR}/mitkTestingConfig.h) #----------------------------------------------------------------------------- # MITK_SUPERBUILD_BINARY_DIR #----------------------------------------------------------------------------- # If MITK_SUPERBUILD_BINARY_DIR isn't defined, it means MITK is *NOT* build using Superbuild. # In that specific case, MITK_SUPERBUILD_BINARY_DIR should default to MITK_BINARY_DIR if(NOT DEFINED MITK_SUPERBUILD_BINARY_DIR) set(MITK_SUPERBUILD_BINARY_DIR ${MITK_BINARY_DIR}) endif() #----------------------------------------------------------------------------- # Set C/CXX and linker flags for MITK code #----------------------------------------------------------------------------- set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${MITK_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${MITK_CXX_FLAGS_DEBUG}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${MITK_CXX_FLAGS_RELEASE}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${MITK_C_FLAGS}") set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${MITK_C_FLAGS_DEBUG}") set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${MITK_C_FLAGS_RELEASE}") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${MITK_EXE_LINKER_FLAGS}") set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${MITK_SHARED_LINKER_FLAGS}") set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${MITK_MODULE_LINKER_FLAGS}") #----------------------------------------------------------------------------- # Add custom targets representing CDash subprojects #----------------------------------------------------------------------------- foreach(subproject ${CTEST_PROJECT_SUBPROJECTS}) if(NOT TARGET ${subproject} AND NOT subproject MATCHES "Unlabeled") add_custom_target(${subproject}) endif() endforeach() #----------------------------------------------------------------------------- # Add subdirectories #----------------------------------------------------------------------------- add_subdirectory(Utilities) add_subdirectory(Modules) include("${CMAKE_CURRENT_SOURCE_DIR}/Modules/ModuleList.cmake") mitkFunctionWhitelistModules(MITK MITK_MODULES) foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_MODULES_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Modules) get_filename_component(MITK_MODULES_EXTENSION_DIR ${MITK_MODULES_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_MODULES_EXTENSION_DIR}/ModuleList.cmake) set(MITK_MODULES "") include(${MITK_MODULES_EXTENSION_DIR}/ModuleList.cmake) foreach(mitk_module ${MITK_MODULES}) add_subdirectory(${MITK_MODULES_EXTENSION_DIR}/${mitk_module} Modules/${mitk_module}) endforeach() endif() set(MITK_MODULE_NAME_PREFIX ${MITK_DEFAULT_MODULE_NAME_PREFIX}) endforeach() add_subdirectory(Wrapping) if(MITK_USE_BLUEBERRY) set(BLUEBERRY_XPDOC_OUTPUT_DIR ${MITK_DOXYGEN_OUTPUT_DIR}/html/extension-points/html/) # Plug-in testing (needs some work to be enabled again) if(BUILD_TESTING) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CoreApp") if(TARGET CoreApp) get_target_property(_is_macosx_bundle CoreApp MACOSX_BUNDLE) if(APPLE AND _is_macosx_bundle) set(BLUEBERRY_UI_TEST_APP "${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/CoreApp.app/Contents/MacOS/CoreApp") endif() endif() set(BLUEBERRY_TEST_APP_ID "org.mitk.qt.coreapplication") endif() include("${CMAKE_CURRENT_SOURCE_DIR}/Plugins/PluginList.cmake") mitkFunctionWhitelistPlugins(MITK MITK_PLUGINS) set(mitk_plugins_fullpath "") foreach(mitk_plugin ${MITK_PLUGINS}) list(APPEND mitk_plugins_fullpath Plugins/${mitk_plugin}) endforeach() set(MITK_PLUGIN_REGEX_LIST "") foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) set(MITK_PLUGINS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/Plugins) get_filename_component(MITK_PLUGINS_EXTENSION_DIR ${MITK_PLUGINS_EXTENSION_DIR} ABSOLUTE) if(EXISTS ${MITK_PLUGINS_EXTENSION_DIR}/PluginList.cmake) set(MITK_PLUGINS "") include(${MITK_PLUGINS_EXTENSION_DIR}/PluginList.cmake) foreach(mitk_plugin ${MITK_PLUGINS}) list(APPEND mitk_plugins_fullpath ${MITK_PLUGINS_EXTENSION_DIR}/${mitk_plugin}) endforeach() endif() endforeach() if(EXISTS ${MITK_PRIVATE_MODULES}/PluginList.cmake) include(${MITK_PRIVATE_MODULES}/PluginList.cmake) foreach(mitk_plugin ${MITK_PRIVATE_PLUGINS}) list(APPEND mitk_plugins_fullpath ${MITK_PRIVATE_MODULES}/${mitk_plugin}) endforeach() endif() if(MITK_BUILD_EXAMPLES) include("${CMAKE_CURRENT_SOURCE_DIR}/Examples/Plugins/PluginList.cmake") set(mitk_example_plugins_fullpath ) foreach(mitk_example_plugin ${MITK_EXAMPLE_PLUGINS}) list(APPEND mitk_example_plugins_fullpath Examples/Plugins/${mitk_example_plugin}) list(APPEND mitk_plugins_fullpath Examples/Plugins/${mitk_example_plugin}) endforeach() endif() # Specify which plug-ins belong to this project macro(GetMyTargetLibraries all_target_libraries varname) set(re_ctkplugin_mitk "^org_mitk_[a-zA-Z0-9_]+$") set(re_ctkplugin_bb "^org_blueberry_[a-zA-Z0-9_]+$") set(_tmp_list) list(APPEND _tmp_list ${all_target_libraries}) ctkMacroListFilter(_tmp_list re_ctkplugin_mitk re_ctkplugin_bb MITK_PLUGIN_REGEX_LIST OUTPUT_VARIABLE ${varname}) endmacro() # Get infos about application directories and build options include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/AppList.cmake") set(mitk_apps_fullpath ) foreach(mitk_app ${MITK_APPS}) # extract option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 0 directory_name) list(GET target_info_list 1 option_name) if(${option_name}) list(APPEND mitk_apps_fullpath "${CMAKE_CURRENT_SOURCE_DIR}/Applications/${directory_name}^^${option_name}") endif() endforeach() if (mitk_plugins_fullpath) ctkMacroSetupPlugins(${mitk_plugins_fullpath} BUILD_OPTION_PREFIX MITK_BUILD_ APPS ${mitk_apps_fullpath} BUILD_ALL ${MITK_BUILD_ALL_PLUGINS} COMPACT_OPTIONS) endif() set(MITK_PLUGIN_USE_FILE "${MITK_BINARY_DIR}/MitkPluginUseFile.cmake") if(${PROJECT_NAME}_PLUGIN_LIBRARIES) ctkFunctionGeneratePluginUseFile(${MITK_PLUGIN_USE_FILE}) else() file(REMOVE ${MITK_PLUGIN_USE_FILE}) set(MITK_PLUGIN_USE_FILE ) endif() endif() #----------------------------------------------------------------------------- # Documentation #----------------------------------------------------------------------------- if(DOXYGEN_FOUND) add_subdirectory(Documentation) endif() #----------------------------------------------------------------------------- # Installation #----------------------------------------------------------------------------- # set MITK cpack variables # These are the default variables, which can be overwritten ( see below ) include(mitkSetupCPack) set(use_default_config ON) # MITK_APPS is set in Applications/AppList.cmake (included somewhere above # if MITK_USE_BLUEBERRY is set to ON). if(MITK_APPS) set(activated_apps_no 0) list(LENGTH MITK_APPS app_count) # Check how many apps have been enabled # If more than one app has been activated, the we use the # default CPack configuration. Otherwise that apps configuration # will be used, if present. foreach(mitk_app ${MITK_APPS}) # extract option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 1 option_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) MATH(EXPR activated_apps_no "${activated_apps_no} + 1") endif() endforeach() if(app_count EQUAL 1 AND (activated_apps_no EQUAL 1 OR MITK_BUILD_ALL_APPS)) # Corner case if there is only one app in total set(use_project_cpack ON) elseif(activated_apps_no EQUAL 1 AND NOT MITK_BUILD_ALL_APPS) # Only one app is enabled (no "build all" flag set) set(use_project_cpack ON) else() # Less or more then one app is enabled set(use_project_cpack OFF) endif() foreach(mitk_app ${MITK_APPS}) # extract target_dir and option_name string(REPLACE "^^" "\\;" target_info ${mitk_app}) set(target_info_list ${target_info}) list(GET target_info_list 0 target_dir) list(GET target_info_list 1 option_name) list(GET target_info_list 2 executable_name) # check if the application is enabled if(${option_name} OR MITK_BUILD_ALL_APPS) # check whether application specific configuration files will be used if(use_project_cpack) # use files if they exist if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/Applications/${target_dir}/CPackOptions.cmake") include("${CMAKE_CURRENT_SOURCE_DIR}/Applications/${target_dir}/CPackOptions.cmake") endif() if(EXISTS "${PROJECT_SOURCE_DIR}/Applications/${target_dir}/CPackConfig.cmake.in") set(CPACK_PROJECT_CONFIG_FILE "${PROJECT_BINARY_DIR}/Applications/${target_dir}/CPackConfig.cmake") configure_file(${PROJECT_SOURCE_DIR}/Applications/${target_dir}/CPackConfig.cmake.in ${CPACK_PROJECT_CONFIG_FILE} @ONLY) set(use_default_config OFF) endif() endif() # add link to the list list(APPEND CPACK_CREATE_DESKTOP_LINKS "${executable_name}") endif() endforeach() endif() # if no application specific configuration file was used, use default if(use_default_config) configure_file(${MITK_SOURCE_DIR}/MITKCPackOptions.cmake.in ${MITK_BINARY_DIR}/MITKCPackOptions.cmake @ONLY) set(CPACK_PROJECT_CONFIG_FILE "${MITK_BINARY_DIR}/MITKCPackOptions.cmake") endif() # include CPack model once all variables are set include(CPack) # Additional installation rules include(mitkInstallRules) #----------------------------------------------------------------------------- # Last configuration steps #----------------------------------------------------------------------------- # ---------------- Export targets ----------------- set(MITK_EXPORTS_FILE "${MITK_BINARY_DIR}/MitkExports.cmake") file(REMOVE ${MITK_EXPORTS_FILE}) set(targets_to_export) get_property(module_targets GLOBAL PROPERTY MITK_MODULE_TARGETS) if(module_targets) list(APPEND targets_to_export ${module_targets}) endif() if(MITK_USE_BLUEBERRY) if(MITK_PLUGIN_LIBRARIES) list(APPEND targets_to_export ${MITK_PLUGIN_LIBRARIES}) endif() endif() export(TARGETS ${targets_to_export} APPEND FILE ${MITK_EXPORTS_FILE}) set(MITK_EXPORTED_TARGET_PROPERTIES ) foreach(target_to_export ${targets_to_export}) get_target_property(autoload_targets ${target_to_export} MITK_AUTOLOAD_TARGETS) if(autoload_targets) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_AUTOLOAD_TARGETS \"${autoload_targets}\")") endif() get_target_property(autoload_dir ${target_to_export} MITK_AUTOLOAD_DIRECTORY) if(autoload_dir) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_AUTOLOAD_DIRECTORY \"${autoload_dir}\")") endif() get_target_property(deprecated_module ${target_to_export} MITK_MODULE_DEPRECATED_SINCE) if(deprecated_module) set(MITK_EXPORTED_TARGET_PROPERTIES "${MITK_EXPORTED_TARGET_PROPERTIES} set_target_properties(${target_to_export} PROPERTIES MITK_MODULE_DEPRECATED_SINCE \"${deprecated_module}\")") endif() endforeach() # ---------------- External projects ----------------- get_property(MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS_CONFIG GLOBAL PROPERTY MITK_ADDITIONAL_LIBRARY_SEARCH_PATHS) set(MITK_CONFIG_EXTERNAL_PROJECTS ) #string(REPLACE "^^" ";" _mitk_external_projects ${MITK_EXTERNAL_PROJECTS}) foreach(ep ${MITK_EXTERNAL_PROJECTS}) get_property(_components GLOBAL PROPERTY MITK_${ep}_COMPONENTS) set(MITK_CONFIG_EXTERNAL_PROJECTS "${MITK_CONFIG_EXTERNAL_PROJECTS} set(MITK_USE_${ep} ${MITK_USE_${ep}}) set(MITK_${ep}_DIR \"${${ep}_DIR}\") set(MITK_${ep}_COMPONENTS ${_components}) ") endforeach() foreach(ep ${MITK_EXTERNAL_PROJECTS}) get_property(_package GLOBAL PROPERTY MITK_${ep}_PACKAGE) get_property(_components GLOBAL PROPERTY MITK_${ep}_COMPONENTS) if(_components) set(_components_arg COMPONENTS \${_components}) else() set(_components_arg) endif() if(_package) set(MITK_CONFIG_EXTERNAL_PROJECTS "${MITK_CONFIG_EXTERNAL_PROJECTS} if(MITK_USE_${ep}) set(${ep}_DIR \${MITK_${ep}_DIR}) if(MITK_${ep}_COMPONENTS) mitkMacroFindDependency(${_package} COMPONENTS \${MITK_${ep}_COMPONENTS}) else() mitkMacroFindDependency(${_package}) endif() endif()") endif() endforeach() # ---------------- Tools ----------------- configure_file(${MITK_SOURCE_DIR}/CMake/ToolExtensionITKFactory.cpp.in ${MITK_BINARY_DIR}/ToolExtensionITKFactory.cpp.in COPYONLY) configure_file(${MITK_SOURCE_DIR}/CMake/ToolExtensionITKFactoryLoader.cpp.in ${MITK_BINARY_DIR}/ToolExtensionITKFactoryLoader.cpp.in COPYONLY) configure_file(${MITK_SOURCE_DIR}/CMake/ToolGUIExtensionITKFactory.cpp.in ${MITK_BINARY_DIR}/ToolGUIExtensionITKFactory.cpp.in COPYONLY) # ---------------- Configure files ----------------- configure_file(mitkVersion.h.in ${MITK_BINARY_DIR}/mitkVersion.h) configure_file(mitkConfig.h.in ${MITK_BINARY_DIR}/mitkConfig.h) set(IPFUNC_INCLUDE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities/ipFunc) set(UTILITIES_DIR ${CMAKE_CURRENT_SOURCE_DIR}/Utilities) configure_file(mitkConfig.h.in ${MITK_BINARY_DIR}/mitkConfig.h) configure_file(MITKConfig.cmake.in ${MITK_BINARY_DIR}/MITKConfig.cmake @ONLY) write_basic_config_version_file(${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake VERSION ${MITK_VERSION_STRING} COMPATIBILITY AnyNewerVersion) #----------------------------------------------------------------------------- # MITK Applications #----------------------------------------------------------------------------- # This must come after MITKConfig.h was generated, since applications # might do a find_package(MITK REQUIRED). add_subdirectory(Applications) +if(MSVC AND TARGET MitkWorkbench) + set_directory_properties(PROPERTIES VS_STARTUP_PROJECT MitkWorkbench) +endif() + #----------------------------------------------------------------------------- # MITK Examples #----------------------------------------------------------------------------- if(MITK_BUILD_EXAMPLES) # This must come after MITKConfig.h was generated, since applications # might do a find_package(MITK REQUIRED). add_subdirectory(Examples) endif() #----------------------------------------------------------------------------- # Print configuration summary #----------------------------------------------------------------------------- message("\n\n") feature_summary( DESCRIPTION "------- FEATURE SUMMARY FOR ${PROJECT_NAME} -------" WHAT ALL ) diff --git a/Documentation/Doxygen/3-DeveloperManual/Application/Deployment.dox b/Documentation/Doxygen/3-DeveloperManual/Application/Deployment.dox index 15df091493..e9d31cfa59 100644 --- a/Documentation/Doxygen/3-DeveloperManual/Application/Deployment.dox +++ b/Documentation/Doxygen/3-DeveloperManual/Application/Deployment.dox @@ -1,51 +1,49 @@ /** \page DeploymentPage Deploying MITK \section DeploymentPageIntroduction Introduction
  • easily create portable or installable versions of your MITK-based applications.
  • created packages include all MITK and 3rd party libraries necessary for running the application on other systems
  • distribute your binary application to other people without giving them your source code or putting them in the need for setting up a development environment themselves, eg for evaluation of your tool.
\note This does not install the MITK headers (like an SDK). If you want to develop applications based on MITK you still have to compile MITK yourself. \section DeploymentPagePlatform Platform specific notes \subsection DeploymentPagePlatformLinux Linux You can create a tarball (.tar.gz) of your MITK application which includes all necessary non-system libraries by following these steps:
  • Set the %CMake Variable CMAKE_BUILD_TYPE to either "Debug" or "Release". Any other type (or leaving the variable empty) will not work.
  • If you are using third-pary libraries not shipped with MITK, you might need to add the paths to the third-party libs to your LD_LIBRARY_PATH environment variable (not necessary if you use RPATH in your shared libraries).
  • Type "make package" in your build-tree. This will create a tarball in your build-tree directory.
\note Libraries in system locations (/lib/, /lib32/, /lib64/, /usr/lib/, /usr/lib32/,/usr/lib64/, and /usr/X11R6/) will not be included in the tarball. If you want to distribute Qt (for example), you have to do a custom Qt installation outside of these directories. \subsection DeploymentPagePlatformWindows Windows -You can create a Zip file (.zip) or an NSIS installer (needs an installation of NSIS) for Windows platforms. Only "Release" builds are supported during packaging, the results of trying to package "Debug" builds are undefined. - -\note Building installers based on MinGW is not supported. +You can create a Zip file (.zip) or an NSIS 2 installer (needs an installation of NSIS) for Windows platforms. Only "Release" builds are supported during packaging, the results of trying to package "Debug" builds are undefined.
  • In Visual Studio, build the "PACKAGE" project, this will create a .zip file and a .exe NSIS installer (if NSIS is installed).
On some systems, it might still be necessary to install the Microsoft Visual C++ Redistributable Package to start the installed application successfully. \note It is possible to include the Microsoft Visual C++ Redistributable Package in the application installer.\n A CMake variable "CMAKE_(Your Visual Studio Version)_REDISTRIBUTABLE" will be created. It has to be set to the appropriate executable (vcredist_x86.exe or vcredist_x64.exe), which will then be part of both the NSIS installer and the ZIP Archive.\n In the case of the NSIS installer it will be automatically run if no appropriate redistributable is present on the target system.\n Please note that it is not possible to automatically check the provided redistributable matches the Visual Studio version used to build the installer. \subsection DeploymentPagePlatformMacOS MacOS You can create a drag'n drop disk image (.dmg) file for MacOS. The procedure is pretty much the same as for Linux. \note On MacOS, libraries in system locations as pointed out in the Linux section \b and libraries located in /System/Library will not be copied. If you want to distribute any libraries from these locations, you have to install them somewhere else prior to configuring your MITK build. -*/ \ No newline at end of file +*/ diff --git a/Modules/AlgorithmsExt/files.cmake b/Modules/AlgorithmsExt/files.cmake index 895500561f..55da8aeb07 100644 --- a/Modules/AlgorithmsExt/files.cmake +++ b/Modules/AlgorithmsExt/files.cmake @@ -1,36 +1,36 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkAutoCropImageFilter.cpp mitkBoundingObjectCutter.cpp mitkBoundingObjectToSegmentationFilter.cpp mitkGeometryClipImageFilter.cpp mitkGeometryDataSource.cpp mitkHeightFieldSurfaceClipImageFilter.cpp mitkImageToUnstructuredGridFilter.cpp mitkLabeledImageToSurfaceFilter.cpp mitkMaskAndCutRoiImageFilter.cpp mitkMaskImageFilter.cpp mitkMovieGenerator.cpp mitkNonBlockingAlgorithm.cpp mitkPadImageFilter.cpp mitkPlaneFit.cpp mitkPlaneLandmarkProjector.cpp mitkPointLocator.cpp mitkSegmentationSink.cpp mitkSimpleHistogram.cpp mitkSimpleUnstructuredGridHistogram.cpp mitkCovarianceMatrixCalculator.cpp mitkAnisotropicIterativeClosestPointRegistration.cpp mitkWeightedPointTransform.cpp mitkAnisotropicRegistrationCommon.cpp mitkUnstructuredGridClusteringFilter.cpp mitkUnstructuredGridToUnstructuredGridFilter.cpp mitkSurfaceToPointSetFilter.cpp ) -if(WIN32 AND NOT MINGW) +if(WIN32) list(APPEND CPP_FILES mitkMovieGeneratorWin32.cpp ) endif() diff --git a/Modules/BasicImageProcessing/CMakeLists.txt b/Modules/BasicImageProcessing/CMakeLists.txt new file mode 100644 index 0000000000..2f337313f9 --- /dev/null +++ b/Modules/BasicImageProcessing/CMakeLists.txt @@ -0,0 +1,8 @@ +MITK_CREATE_MODULE( + DEPENDS MitkCore + PACKAGE_DEPENDS + PUBLIC + PRIVATE ITK|ITKIOImageBase+ITKIOGDCM +) + +add_subdirectory(MiniApps) diff --git a/Modules/BasicImageProcessing/MiniApps/CMakeLists.txt b/Modules/BasicImageProcessing/MiniApps/CMakeLists.txt new file mode 100644 index 0000000000..e107b85391 --- /dev/null +++ b/Modules/BasicImageProcessing/MiniApps/CMakeLists.txt @@ -0,0 +1,88 @@ +option(BUILD_BasicImageProcessingMiniApps "Build commandline tools for Basic Image Processing" OFF) + +if(BUILD_BasicImageProcessingMiniApps OR MITK_BUILD_ALL_APPS) + + + include_directories( + ${CMAKE_CURRENT_SOURCE_DIR} + ${CMAKE_CURRENT_BINARY_DIR} + ) + + # list of miniapps + # if an app requires additional dependencies + # they are added after a "^^" and separated by "_" + set( basicImageProcessingMiniApps + FileConverter^^MitkCore + ImageTypeConverter^^MitkCore + ) + + foreach(basicImageProcessingMiniApp ${basicImageProcessingMiniApps}) + # extract mini app name and dependencies + string(REPLACE "^^" "\\;" miniapp_info ${basicImageProcessingMiniApp}) + set(miniapp_info_list ${miniapp_info}) + list(GET miniapp_info_list 0 appname) + list(GET miniapp_info_list 1 raw_dependencies) + string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") + set(dependencies_list ${dependencies}) + + mitk_create_executable(${appname} + DEPENDS MitkCore MitkCommandLine ${dependencies_list} + PACKAGE_DEPENDS ITK + CPP_FILES ${appname}.cpp + ) + # CPP_FILES ${appname}.cpp mitkCommandLineParser.cpp + + if(EXECUTABLE_IS_ENABLED) + + # On Linux, create a shell script to start a relocatable application + if(UNIX AND NOT APPLE) + install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) + endif() + + get_target_property(_is_bundle ${EXECUTABLE_TARGET} MACOSX_BUNDLE) + + if(APPLE) + if(_is_bundle) + set(_target_locations ${EXECUTABLE_TARGET}.app) + set(${_target_locations}_qt_plugins_install_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) + set(_bundle_dest_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) + set(_qt_plugins_for_current_bundle ${EXECUTABLE_TARGET}.app/Contents/MacOS) + set(_qt_conf_install_dirs ${EXECUTABLE_TARGET}.app/Contents/Resources) + install(TARGETS ${EXECUTABLE_TARGET} BUNDLE DESTINATION . ) + else() + if(NOT MACOSX_BUNDLE_NAMES) + set(_qt_conf_install_dirs bin) + set(_target_locations bin/${EXECUTABLE_TARGET}) + set(${_target_locations}_qt_plugins_install_dir bin) + install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) + else() + foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) + list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) + set(_current_target_location ${bundle_name}.app/Contents/MacOS/${EXECUTABLE_TARGET}) + list(APPEND _target_locations ${_current_target_location}) + set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) + message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") + + install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) + endforeach() + endif() + endif() + else() + set(_target_locations bin/${EXECUTABLE_TARGET}${CMAKE_EXECUTABLE_SUFFIX}) + set(${_target_locations}_qt_plugins_install_dir bin) + set(_qt_conf_install_dirs bin) + install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) + endif() + endif() + endforeach() + + # On Linux, create a shell script to start a relocatable application + if(UNIX AND NOT APPLE) + install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) + endif() + + if(EXECUTABLE_IS_ENABLED) + MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) + endif() + +endif() diff --git a/Modules/BasicImageProcessing/MiniApps/FileConverter.cpp b/Modules/BasicImageProcessing/MiniApps/FileConverter.cpp new file mode 100644 index 0000000000..c349243f93 --- /dev/null +++ b/Modules/BasicImageProcessing/MiniApps/FileConverter.cpp @@ -0,0 +1,116 @@ +/*=================================================================== + +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 "mitkProperties.h" + +#include "mitkCommandLineParser.h" +#include "mitkIOUtil.h" + +#include + +#include "mitkPreferenceListReaderOptionsFunctor.h" + + +int main(int argc, char* argv[]) +{ + mitkCommandLineParser parser; + + parser.setTitle("File Converter"); + parser.setCategory("Basic Image Processing"); + parser.setDescription(""); + parser.setContributor("MBI"); + + parser.setArgumentPrefix("--","-"); + // Add command line argument names + parser.addArgument("help", "h",mitkCommandLineParser::Bool, "Help:", "Show this help text"); + parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input file:", "Input File",us::Any(),false); + parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output file:", "Output file", us::Any(), false); + parser.addArgument("reader", "r", mitkCommandLineParser::String, "Reader Name", "Reader Name", us::Any()); + parser.addArgument("list-readers", "lr", mitkCommandLineParser::Bool, "Reader Name", "Reader Name", us::Any()); + + + std::map parsedArgs = parser.parseArguments(argc, argv); + + if (parsedArgs.size()==0) + return EXIT_FAILURE; + + // Show a help message + if ( parsedArgs.count("help") || parsedArgs.count("h")) + { + std::cout << parser.helpText(); + return EXIT_SUCCESS; + } + + std::string inputFilename = us::any_cast(parsedArgs["input"]); + std::string outputFilename = us::any_cast(parsedArgs["output"]); + + mitk::PreferenceListReaderOptionsFunctor::ListType preference = {}; + if (parsedArgs.count("reader")) + { + preference.push_back(us::any_cast(parsedArgs["reader"])); + } + + if (parsedArgs.count("list-readers")) + { + mitk::IOUtil::LoadInfo loadInfo(inputFilename); + auto readers = loadInfo.m_ReaderSelector.Get(); + + std::string errMsg; + if (readers.empty()) + { + if (!itksys::SystemTools::FileExists(loadInfo.m_Path.c_str())) + { + errMsg += "File '" + loadInfo.m_Path + "' does not exist\n"; + } + else + { + errMsg += "No reader available for '" + loadInfo.m_Path + "'\n"; + } + MITK_ERROR << errMsg; + return 0; + } + + std::cout << "Available Readers: "< 0) + { + writeName = path + "/" + filename + "_" + std::to_string(count) + extension; + } + mitk::IOUtil::Save(node, writeName); + ++count; + } + + return EXIT_SUCCESS; +} diff --git a/Modules/BasicImageProcessing/MiniApps/ImageTypeConverter.cpp b/Modules/BasicImageProcessing/MiniApps/ImageTypeConverter.cpp new file mode 100644 index 0000000000..080f88e955 --- /dev/null +++ b/Modules/BasicImageProcessing/MiniApps/ImageTypeConverter.cpp @@ -0,0 +1,127 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include "mitkCommandLineParser.h" +#include "mitkIOUtil.h" +#include +#include + +#define CONVERT_IMAGE(TYPE, DIM) \ + { \ + MITK_INFO << "Data Type for Conversion: " << typeid(TYPE).name(); \ + itk::Image::Pointer itkImage = itk::Image::New(); \ + mitk::CastToItkImage(image, itkImage); \ + mitk::CastToMitkImage(itkImage, outputImage); \ + } + +#define CONVERT_IMAGE_TYPE(TYPE) \ + { \ + unsigned int dimension = image->GetDimension(); \ + MITK_INFO << "Image Dimension is: " << dimension; \ + switch (dimension) { \ + case 2 : CONVERT_IMAGE( TYPE , 2); \ + break; \ + case 3 : CONVERT_IMAGE( TYPE , 3); \ + break; \ + default: MITK_INFO << "This tool doesn't support a dimension of "< parsedArgs = parser.parseArguments(argc, argv); + + if (parsedArgs.size()==0) + return EXIT_FAILURE; + + // Show a help message + if ( parsedArgs.count("help") || parsedArgs.count("h")) + { + std::cout << parser.helpText(); + return EXIT_SUCCESS; + } + + std::string inputName = us::any_cast(parsedArgs["input"]); + std::string outputName = us::any_cast(parsedArgs["output"]); + std::string type = us::any_cast(parsedArgs["type"]); + + mitk::Image::Pointer image = mitk::IOUtil::Load(inputName); + mitk::Image::Pointer outputImage = mitk::Image::New(); + + if (type.compare("int") == 0) { + CONVERT_IMAGE_TYPE(int); + } + else if (type.compare("uint") == 0) + { + CONVERT_IMAGE_TYPE(unsigned int); + } + else if (type.compare("char") == 0) + { + CONVERT_IMAGE_TYPE(char); + } + else if (type.compare("uchar") == 0) + { + CONVERT_IMAGE_TYPE(unsigned char); + } + else if (type.compare("short") == 0) + { + CONVERT_IMAGE_TYPE(short); + } + else if (type.compare("ushort") == 0) + { + CONVERT_IMAGE_TYPE(unsigned short); + } + else if (type.compare("float") == 0) + { + CONVERT_IMAGE_TYPE(float); + } + else if (type.compare("double") == 0) + { + CONVERT_IMAGE_TYPE(double); + } + else if (type.compare("none") == 0) + { + MITK_INFO << " No conversion performed"; + outputImage = NULL; + } + else + { + CONVERT_IMAGE_TYPE(double); + } + + if (outputImage.IsNotNull()) + { + mitk::IOUtil::Save(outputImage, outputName); + } + return EXIT_SUCCESS; +} \ No newline at end of file diff --git a/Modules/BasicImageProcessing/files.cmake b/Modules/BasicImageProcessing/files.cmake new file mode 100644 index 0000000000..562652a41d --- /dev/null +++ b/Modules/BasicImageProcessing/files.cmake @@ -0,0 +1,9 @@ +file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") + +set(CPP_FILES + mitkArithmeticOperation.cpp +) + +set(RESOURCE_FILES + +) diff --git a/Modules/BasicImageProcessing/include/mitkArithmeticOperation.h b/Modules/BasicImageProcessing/include/mitkArithmeticOperation.h new file mode 100644 index 0000000000..7b75ebbd8a --- /dev/null +++ b/Modules/BasicImageProcessing/include/mitkArithmeticOperation.h @@ -0,0 +1,104 @@ +/*=================================================================== + +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 mitkArithmeticOperation_h +#define mitkArithmeticOperation_h + +#include +#include + +namespace mitk +{ + /** \brief Executes a arithmetic operations on one or two images + * + * All parameters of the arithmetic operations must be specified during construction. + * The actual operation is executed when calling GetResult(). + */ + class MITKBASICIMAGEPROCESSING_EXPORT ArithmeticOperation { + public: + static Image::Pointer Add(Image::Pointer & imageA, Image::Pointer & imageB, bool outputAsDouble = true); + static Image::Pointer Subtract(Image::Pointer & imageA, Image::Pointer & imageB, bool outputAsDouble = true); + static Image::Pointer Multiply(Image::Pointer & imageA, Image::Pointer & imageB, bool outputAsDouble = true); + static Image::Pointer Divide(Image::Pointer & imageA, Image::Pointer & imageB, bool outputAsDouble = true); + + static Image::Pointer Add(Image::Pointer & imageA, double value, bool outputAsDouble = true); + static Image::Pointer Subtract(Image::Pointer & imageA, double value, bool outputAsDouble = true); + static Image::Pointer Multiply(Image::Pointer & imageA, double value, bool outputAsDouble = true); + static Image::Pointer Divide(Image::Pointer & imageA, double value, bool outputAsDouble = true); + + static Image::Pointer Add(double value, Image::Pointer & imageB, bool outputAsDouble = true); + static Image::Pointer Subtract(double value, Image::Pointer & imageB, bool outputAsDouble = true); + static Image::Pointer Multiply(double value, Image::Pointer & imageB, bool outputAsDouble = true); + static Image::Pointer Divide(double value, Image::Pointer & imageB, bool outputAsDouble = true); + + static Image::Pointer Tan(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Atan(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Cos(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Acos(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Sin(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Asin(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Square(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Sqrt(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Abs(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Exp(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer ExpNeg(Image::Pointer & imageA, bool outputAsDouble = true); + static Image::Pointer Log10(Image::Pointer & imageA, bool outputAsDouble = true); + }; + + class MITKBASICIMAGEPROCESSING_EXPORT NonStaticArithmeticOperation { + public: + enum OperationsEnum + { + Add2, + Sub2, + Mult, + Div, + AddValue, + SubValue, + MultValue, + DivValue, + PowValue, + Tan, + ATan, + Cos, + ACos, + Sin, + ASin, + Square, + Sqrt, + Abs, + Exp, + ExpNeg, + Log10 + }; + + + void CallExecuteTwoImageFilter(mitk::Image::Pointer imageA, mitk::Image::Pointer imageB); + + template + void ExecuteTwoImageFilter(itk::Image* imageA, itk::Image* imageB); + + template + void ExecuteTwoImageFilterWithFunctor(Image1Type* imageA, Image2Type* imageB); + + mitk::Image::Pointer m_ResultImage; + OperationsEnum m_Algorithm; + bool m_GenerateDoubleOutput = false; + }; + + +} +#endif // mitkArithmeticOperation_h \ No newline at end of file diff --git a/Modules/BasicImageProcessing/src/mitkArithmeticOperation.cpp b/Modules/BasicImageProcessing/src/mitkArithmeticOperation.cpp new file mode 100644 index 0000000000..95ce7d1bc8 --- /dev/null +++ b/Modules/BasicImageProcessing/src/mitkArithmeticOperation.cpp @@ -0,0 +1,561 @@ +/*=================================================================== + +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 "mitkArithmeticOperation.h" + +#include +#include +#include + +#include +#include +#include "itkUnaryFunctorImageFilter.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace mitk +{ + namespace Functor + { + template< class TInput, class TOutput> + class AddValue + { + public: + AddValue() {}; + ~AddValue() {}; + bool operator!=(const AddValue &) const + { + return false; + } + bool operator==(const AddValue & other) const + { + return !(*this != other); + } + inline TOutput operator()(const TInput & A) const + { + return A + value; + } + + bool valueLeft = false; + double value = 0.0; + }; + template< class TInput, class TOutput> + class SubValue + { + public: + SubValue() {}; + ~SubValue() {}; + bool operator!=(const SubValue &) const + { + return false; + } + bool operator==(const SubValue & other) const + { + return !(*this != other); + } + inline TOutput operator()(const TInput & A) const + { + if (valueLeft) + return value - A; + else + return A - value; + } + + bool valueLeft = false; + double value = 0.0; + }; + template< class TInput, class TOutput> + class MultValue + { + public: + MultValue() {}; + ~MultValue() {}; + bool operator!=(const MultValue &) const + { + return false; + } + bool operator==(const MultValue & other) const + { + return !(*this != other); + } + inline TOutput operator()(const TInput & A) const + { + return A * value; + } + + bool valueLeft = false; + double value = 0.0; + }; + template< class TInput, class TOutput> + class DivValue + { + public: + DivValue() {}; + ~DivValue() {}; + bool operator!=(const DivValue &) const + { + return false; + } + bool operator==(const DivValue & other) const + { + return !(*this != other); + } + inline TOutput operator()(const TInput & A) const + { + if (valueLeft) + return value / A; + else + return A / value; + } + + bool valueLeft = false; + double value = 1.0; + }; + template< class TInput, class TOutput> + class PowValue + { + public: + PowValue() {}; + ~PowValue() {}; + bool operator!=(const PowValue &) const + { + return false; + } + bool operator==(const PowValue & other) const + { + return !(*this != other); + } + inline TOutput operator()(const TInput & A) const + { + if (valueLeft) + return static_cast(std::pow(value, A)); + else + return static_cast(std::pow(A, value)); + } + + bool valueLeft = false; + double value = 1.0; + }; + } +} + + +template +static void ExecuteOneImageFilterWithFunctor(ImageType* imageA, double value, bool returnDoubleImage, bool valueLeft, bool , mitk::Image::Pointer & outputImage) +{ + typedef itk::UnaryFunctorImageFilter< ImageType, ImageType, DefaultFunctorType > DefaultFilterType; + typedef itk::UnaryFunctorImageFilter< ImageType, DoubleImageType, DoubleFunctorType > DoubleFilterType; + + if (returnDoubleImage) + { + typename DoubleFilterType::Pointer filter = DoubleFilterType::New(); + filter->SetInput(imageA); + filter->GetFunctor().valueLeft = valueLeft; + filter->GetFunctor().value = value; + filter->Update(); + CastToMitkImage(filter->GetOutput(), outputImage); + } + else + { + typename DefaultFilterType::Pointer filter = DefaultFilterType::New(); + filter->SetInput(imageA); + filter->GetFunctor().valueLeft = valueLeft; + filter->GetFunctor().value = value; + filter->Update(); + CastToMitkImage(filter->GetOutput(), outputImage); + } +} + +template +static void ExecuteOneImageFilterWithFunctorNonParameter(ImageType* imageA, double , bool returnDoubleImage, bool , bool , mitk::Image::Pointer & outputImage) +{ + typedef itk::UnaryFunctorImageFilter< ImageType, ImageType, DefaultFunctorType > DefaultFilterType; + typedef itk::UnaryFunctorImageFilter< ImageType, DoubleImageType, DoubleFunctorType > DoubleFilterType; + + if (returnDoubleImage) + { + typename DoubleFilterType::Pointer filter = DoubleFilterType::New(); + filter->SetInput(imageA); + filter->Update(); + CastToMitkImage(filter->GetOutput(), outputImage); + } + else + { + typename DefaultFilterType::Pointer filter = DefaultFilterType::New(); + filter->SetInput(imageA); + filter->Update(); + CastToMitkImage(filter->GetOutput(), outputImage); + } +} + +template +static void ExecuteOneImageFilter(itk::Image* imageA, double value, bool returnDoubleImage, bool valueLeft, bool parameterFree, mitk::NonStaticArithmeticOperation::OperationsEnum algorithm, mitk::Image::Pointer & outputImage) +{ + typedef itk::Image ImageType; + typedef itk::Image DoubleOutputType; + + + switch (algorithm) { + case mitk::NonStaticArithmeticOperation::OperationsEnum::AddValue: + ExecuteOneImageFilterWithFunctor, + mitk::Functor::AddValue, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::SubValue: + ExecuteOneImageFilterWithFunctor, + mitk::Functor::SubValue, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::MultValue: + ExecuteOneImageFilterWithFunctor, + mitk::Functor::MultValue, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::DivValue: + ExecuteOneImageFilterWithFunctor, + mitk::Functor::DivValue, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::PowValue: + ExecuteOneImageFilterWithFunctor, + mitk::Functor::PowValue, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + + case mitk::NonStaticArithmeticOperation::OperationsEnum::Tan: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Tan, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::ATan: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Atan, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::Cos: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Cos, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::ACos: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Acos, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::Sin: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Sin, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::ASin: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Asin, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::Square: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Square, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::Sqrt: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Sqrt, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::Abs: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Abs, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::Exp: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Exp, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::ExpNeg: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::ExpNegative, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + case mitk::NonStaticArithmeticOperation::OperationsEnum::Log10: + ExecuteOneImageFilterWithFunctorNonParameter, + itk::Functor::Log10, + ImageType, DoubleOutputType>(imageA, value, valueLeft, returnDoubleImage, parameterFree, outputImage); + break; + default: + break; + } +} + +mitk::Image::Pointer mitk::ArithmeticOperation::Add(Image::Pointer & imageA, Image::Pointer & imageB, bool) +{ + NonStaticArithmeticOperation helper; + helper.m_Algorithm = NonStaticArithmeticOperation::OperationsEnum::Add2; + helper.CallExecuteTwoImageFilter(imageA, imageB); + return helper.m_ResultImage; +} + +mitk::Image::Pointer mitk::ArithmeticOperation::Subtract(Image::Pointer & imageA, Image::Pointer & imageB, bool) +{ + NonStaticArithmeticOperation helper; + helper.m_Algorithm = NonStaticArithmeticOperation::OperationsEnum::Sub2; + helper.CallExecuteTwoImageFilter(imageA, imageB); + return helper.m_ResultImage; +} + +mitk::Image::Pointer mitk::ArithmeticOperation::Multiply(Image::Pointer & imageA, Image::Pointer & imageB, bool) +{ + NonStaticArithmeticOperation helper; + helper.m_Algorithm = NonStaticArithmeticOperation::OperationsEnum::Mult; + helper.CallExecuteTwoImageFilter(imageA, imageB); + return helper.m_ResultImage; +} + +mitk::Image::Pointer mitk::ArithmeticOperation::Divide(Image::Pointer & imageA, Image::Pointer & imageB, bool) +{ + NonStaticArithmeticOperation helper; + helper.m_Algorithm = NonStaticArithmeticOperation::OperationsEnum::Div; + helper.CallExecuteTwoImageFilter(imageA, imageB); + return helper.m_ResultImage; +} + +mitk::Image::Pointer mitk::ArithmeticOperation::Add(Image::Pointer & imageA, double value, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, false, false, NonStaticArithmeticOperation::OperationsEnum::AddValue, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Subtract(Image::Pointer & imageA, double value, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, false, false, NonStaticArithmeticOperation::OperationsEnum::SubValue, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Multiply(Image::Pointer & imageA, double value, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, false, false, NonStaticArithmeticOperation::OperationsEnum::MultValue, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Divide(Image::Pointer & imageA, double value, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, false, false, NonStaticArithmeticOperation::OperationsEnum::DivValue, resultImage)); + return resultImage; +} + +mitk::Image::Pointer mitk::ArithmeticOperation::Add(double value, Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, true, false, NonStaticArithmeticOperation::OperationsEnum::AddValue, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Subtract(double value, Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, true, false, NonStaticArithmeticOperation::OperationsEnum::SubValue, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Multiply(double value, Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, true, false, NonStaticArithmeticOperation::OperationsEnum::MultValue, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Divide(double value, Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (value, outputAsDouble, true, false, NonStaticArithmeticOperation::OperationsEnum::DivValue, resultImage)); + return resultImage; +} + + +mitk::Image::Pointer mitk::ArithmeticOperation::Tan(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Tan, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Atan(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::ATan, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Sin(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Sin, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Asin(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::ASin, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Cos(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Cos, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Acos(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::ACos, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Square(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Square, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Sqrt(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Sqrt, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Abs(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Abs, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Exp(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Exp, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::ExpNeg(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::ExpNeg, resultImage)); + return resultImage; +} +mitk::Image::Pointer mitk::ArithmeticOperation::Log10(Image::Pointer & imageA, bool outputAsDouble) +{ + mitk::Image::Pointer resultImage; + AccessByItk_n(imageA, ExecuteOneImageFilter, (0.0, outputAsDouble, true, true, NonStaticArithmeticOperation::OperationsEnum::Log10, resultImage)); + return resultImage; +} + + +void mitk::NonStaticArithmeticOperation::CallExecuteTwoImageFilter(mitk::Image::Pointer imageA, mitk::Image::Pointer imageB) +{ + if (imageA->GetDimension() != imageB->GetDimension()) + { + mitkThrow() << "Image have different dimensions. This is not supported by mitk::ArithmeticOperation"; + } + + switch (imageA->GetDimension()) + { + case 1: + AccessTwoImagesFixedDimensionByItk(imageA, imageB, mitk::NonStaticArithmeticOperation::ExecuteTwoImageFilter, 1); + break; + case 2: + AccessTwoImagesFixedDimensionByItk(imageA, imageB, mitk::NonStaticArithmeticOperation::ExecuteTwoImageFilter, 2); + break; + case 3: + AccessTwoImagesFixedDimensionByItk(imageA, imageB, mitk::NonStaticArithmeticOperation::ExecuteTwoImageFilter, 3); + break; + case 4: + AccessTwoImagesFixedDimensionByItk(imageA, imageB, mitk::NonStaticArithmeticOperation::ExecuteTwoImageFilter, 4); + break; + default: + mitkThrow() << "Image Dimension of "<GetDimension() << " is not supported"; + break; + } +} + + +template +void mitk::NonStaticArithmeticOperation::ExecuteTwoImageFilter(itk::Image* imageA, itk::Image* imageB) +{ + typedef itk::Image Image1Type; + typedef itk::Image Image2Type; + typedef itk::Image DoubleOutputType; + + + switch (m_Algorithm) { + case OperationsEnum::Add2: + ExecuteTwoImageFilterWithFunctor, + itk::Functor::Add2, + Image1Type, Image2Type, DoubleOutputType>(imageA, imageB); + break; + + case OperationsEnum::Sub2: + ExecuteTwoImageFilterWithFunctor, + itk::Functor::Add2, + Image1Type, Image2Type, DoubleOutputType>(imageA, imageB); + break; + + case OperationsEnum::Mult: + ExecuteTwoImageFilterWithFunctor, + itk::Functor::Add2, + Image1Type, Image2Type, DoubleOutputType>(imageA, imageB); + break; + + case OperationsEnum::Div: + ExecuteTwoImageFilterWithFunctor, + itk::Functor::Add2, + Image1Type, Image2Type, DoubleOutputType>(imageA, imageB); + break; + default: + break; + } +} + +template +void mitk::NonStaticArithmeticOperation::ExecuteTwoImageFilterWithFunctor(Image1Type* imageA, Image2Type* imageB) +{ + typedef itk::BinaryFunctorImageFilter< Image1Type, Image2Type, Image1Type,DefaultFunctorType > DefaultFilterType; + typedef itk::BinaryFunctorImageFilter< Image1Type, Image2Type, DoubleImageType, DoubleFunctorType > DoubleFilterType; + + if (m_GenerateDoubleOutput) + { + typename DoubleFilterType::Pointer filter = DoubleFilterType::New(); + filter->SetInput1(imageA); + filter->SetInput2(imageB); + filter->Update(); + CastToMitkImage(filter->GetOutput(), m_ResultImage); + } + else + { + typename DefaultFilterType::Pointer filter = DefaultFilterType::New(); + filter->SetInput1(imageA); + filter->SetInput2(imageB); + filter->Update(); + CastToMitkImage(filter->GetOutput(), m_ResultImage); + } +} \ No newline at end of file diff --git a/Modules/Classification/CLMiniApps/CLImageConverter.cpp b/Modules/Classification/CLMiniApps/CLImageConverter.cpp deleted file mode 100644 index de2ab03538..0000000000 --- a/Modules/Classification/CLMiniApps/CLImageConverter.cpp +++ /dev/null @@ -1,54 +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 "mitkCommandLineParser.h" -#include "mitkIOUtil.h" - -int main(int argc, char* argv[]) -{ - mitkCommandLineParser parser; - - parser.setTitle("Dicom Loader"); - parser.setCategory("Preprocessing Tools"); - parser.setDescription(""); - parser.setContributor("MBI"); - - parser.setArgumentPrefix("--","-"); - // Add command line argument names - parser.addArgument("help", "h",mitkCommandLineParser::Bool, "Help:", "Show this help text"); - parser.addArgument("input", "i", mitkCommandLineParser::InputDirectory, "Input file:", "Input file",us::Any(),false); - parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output file:", "Output file",us::Any(),false); - - std::map parsedArgs = parser.parseArguments(argc, argv); - - if (parsedArgs.size()==0) - return EXIT_FAILURE; - - // Show a help message - if ( parsedArgs.count("help") || parsedArgs.count("h")) - { - std::cout << parser.helpText(); - return EXIT_SUCCESS; - } - - std::string inputName = us::any_cast(parsedArgs["input"]); - std::string outputName = us::any_cast(parsedArgs["output"]); - - mitk::Image::Pointer image = mitk::IOUtil::Load(inputName); - mitk::IOUtil::Save(image, outputName); - - return EXIT_SUCCESS; -} \ No newline at end of file diff --git a/Modules/Classification/CLMiniApps/CLImageTypeConverter.cpp b/Modules/Classification/CLMiniApps/CLImageTypeConverter.cpp deleted file mode 100644 index aeeaf8325a..0000000000 --- a/Modules/Classification/CLMiniApps/CLImageTypeConverter.cpp +++ /dev/null @@ -1,108 +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 "mitkCommandLineParser.h" -#include "mitkIOUtil.h" -#include -#include - -#define CONVERT_IMAGE(TYPE, DIM) itk::Image::Pointer itkImage = itk::Image::New(); \ - MITK_INFO << "Data Type for Conversion: "<< typeid(TYPE).name(); \ - mitk::CastToItkImage(image, itkImage); \ - mitk::CastToMitkImage(itkImage, outputImage) - -int main(int argc, char* argv[]) -{ - mitkCommandLineParser parser; - - parser.setTitle("Image Type Converter"); - parser.setCategory("Preprocessing Tools"); - parser.setDescription(""); - parser.setContributor("MBI"); - - parser.setArgumentPrefix("--","-"); - // Add command line argument names - parser.addArgument("help", "h",mitkCommandLineParser::Bool, "Help:", "Show this help text"); - parser.addArgument("input", "i", mitkCommandLineParser::InputDirectory, "Input file:", "Input file",us::Any(),false); - parser.addArgument("output", "o", mitkCommandLineParser::OutputFile, "Output file:", "Output file", us::Any(), false); - parser.addArgument("type", "t", mitkCommandLineParser::OutputFile, "Type definition:", "Define Scalar data type: int, uint, short, ushort, char, uchar, float, double", us::Any(), false); - - std::map parsedArgs = parser.parseArguments(argc, argv); - - if (parsedArgs.size()==0) - return EXIT_FAILURE; - - // Show a help message - if ( parsedArgs.count("help") || parsedArgs.count("h")) - { - std::cout << parser.helpText(); - return EXIT_SUCCESS; - } - - std::string inputName = us::any_cast(parsedArgs["input"]); - std::string outputName = us::any_cast(parsedArgs["output"]); - std::string type = us::any_cast(parsedArgs["type"]); - - mitk::Image::Pointer image = mitk::IOUtil::Load(inputName); - mitk::Image::Pointer outputImage = mitk::Image::New(); - - if (type.compare("int") == 0) - { - CONVERT_IMAGE(int, 3); - } - else if (type.compare("uint") == 0) - { - CONVERT_IMAGE(unsigned int, 3); - } - else if (type.compare("char") == 0) - { - CONVERT_IMAGE(char, 3); - } - else if (type.compare("uchar") == 0) - { - CONVERT_IMAGE(unsigned char, 3); - } - else if (type.compare("short") == 0) - { - CONVERT_IMAGE(short, 3); - } - else if (type.compare("ushort") == 0) - { - CONVERT_IMAGE(unsigned short, 3); - } - else if (type.compare("float") == 0) - { - CONVERT_IMAGE(float, 3); - } - else if (type.compare("double") == 0) - { - CONVERT_IMAGE(double, 3); - } - else if (type.compare("none") == 0) - { - MITK_INFO << " No conversion performed"; - outputImage = image; - } - else - { - CONVERT_IMAGE(double, 3); - } - - - mitk::IOUtil::Save(outputImage, outputName); - - return EXIT_SUCCESS; -} \ No newline at end of file diff --git a/Modules/Classification/CLMiniApps/CMakeLists.txt b/Modules/Classification/CLMiniApps/CMakeLists.txt index ab24948280..0bb6f5e560 100644 --- a/Modules/Classification/CLMiniApps/CMakeLists.txt +++ b/Modules/Classification/CLMiniApps/CMakeLists.txt @@ -1,143 +1,122 @@ option(BUILD_ClassificationMiniApps "Build commandline tools for classification" OFF) if(BUILD_ClassificationMiniApps OR MITK_BUILD_ALL_APPS) include_directories( ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_BINARY_DIR} ) # list of miniapps # if an app requires additional dependencies # they are added after a "^^" and separated by "_" set( classificationminiapps RandomForestTraining^^MitkCLVigraRandomForest NativeHeadCTSegmentation^^MitkCLVigraRandomForest ManualSegmentationEvaluation^^MitkCLVigraRandomForest CLScreenshot^^MitkCore_MitkQtWidgetsExt_MitkCLUtilities CLDicom2Nrrd^^MitkCore - CLImageTypeConverter^^MitkCore CLResampleImageToReference^^MitkCore CLGlobalImageFeatures^^MitkCLUtilities_MitkQtWidgetsExt CLMRNormalization^^MitkCLUtilities_MitkCLMRUtilities CLStaple^^MitkCLUtilities CLVoxelFeatures^^MitkCLUtilities CLPolyToNrrd^^ CLPlanarFigureToNrrd^^MitkCore_MitkSegmentation_MitkMultilabel CLSimpleVoxelClassification^^MitkDataCollection_MitkCLVigraRandomForest CLVoxelClassification^^MitkDataCollection_MitkCLImportanceWeighting_MitkCLVigraRandomForest CLBrainMask^^MitkCLUtilities XRaxSimulationFromCT^^MitkCLUtilities CLRandomSampling^^MitkCore_MitkCLUtilities CLRemoveEmptyVoxels^^MitkCore CLN4^^MitkCore CLSkullMask^^MitkCore CLPointSetToSegmentation^^ CLMultiForestPrediction^^MitkDataCollection_MitkCLVigraRandomForest CLNrrdToPoly^^MitkCore CL2Dto3DImage^^MitkCore CLWeighting^^MitkCore_MitkCLImportanceWeighting_MitkCLUtilities CLOverlayRoiCenterOfMass^^MitkCore_MitkCLUtilities_MitkQtWidgetsExt CLLungSegmentation^^MitkCore_MitkSegmentation_MitkMultilabel # RandomForestPrediction^^MitkCLVigraRandomForest ) foreach(classificationminiapps ${classificationminiapps}) # extract mini app name and dependencies string(REPLACE "^^" "\\;" miniapp_info ${classificationminiapps}) set(miniapp_info_list ${miniapp_info}) list(GET miniapp_info_list 0 appname) list(GET miniapp_info_list 1 raw_dependencies) string(REPLACE "_" "\\;" dependencies "${raw_dependencies}") set(dependencies_list ${dependencies}) mitk_create_executable(${appname} DEPENDS MitkCore MitkCLCore MitkCommandLine ${dependencies_list} PACKAGE_DEPENDS ITK Qt5|Core Vigra CPP_FILES ${appname}.cpp ) # CPP_FILES ${appname}.cpp mitkCommandLineParser.cpp if(EXECUTABLE_IS_ENABLED) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() get_target_property(_is_bundle ${EXECUTABLE_TARGET} MACOSX_BUNDLE) if(APPLE) if(_is_bundle) set(_target_locations ${EXECUTABLE_TARGET}.app) set(${_target_locations}_qt_plugins_install_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_bundle_dest_dir ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_plugins_for_current_bundle ${EXECUTABLE_TARGET}.app/Contents/MacOS) set(_qt_conf_install_dirs ${EXECUTABLE_TARGET}.app/Contents/Resources) install(TARGETS ${EXECUTABLE_TARGET} BUNDLE DESTINATION . ) else() if(NOT MACOSX_BUNDLE_NAMES) set(_qt_conf_install_dirs bin) set(_target_locations bin/${EXECUTABLE_TARGET}) set(${_target_locations}_qt_plugins_install_dir bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) else() foreach(bundle_name ${MACOSX_BUNDLE_NAMES}) list(APPEND _qt_conf_install_dirs ${bundle_name}.app/Contents/Resources) set(_current_target_location ${bundle_name}.app/Contents/MacOS/${EXECUTABLE_TARGET}) list(APPEND _target_locations ${_current_target_location}) set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) message( " set(${_current_target_location}_qt_plugins_install_dir ${bundle_name}.app/Contents/MacOS) ") install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION ${bundle_name}.app/Contents/MacOS/) endforeach() endif() endif() else() set(_target_locations bin/${EXECUTABLE_TARGET}${CMAKE_EXECUTABLE_SUFFIX}) set(${_target_locations}_qt_plugins_install_dir bin) set(_qt_conf_install_dirs bin) install(TARGETS ${EXECUTABLE_TARGET} RUNTIME DESTINATION bin) endif() endif() endforeach() # This mini app does not depend on mitkDiffusionImaging at all mitk_create_executable(CLMatchPointReg DEPENDS MitkCore MitkCLUtilities MitkMatchPointRegistration MitkCommandLine MitkMatchPointRegistrationUI PACKAGE_DEPENDS ITK Qt5|Core Vigra MatchPoint CPP_FILES CLMatchPointReg.cpp ) - #mitk_create_executable(CLGlobalImageFeatures - # DEPENDS MitkCore MitkCLUtilities - # CPP_FILES CLGlobalImageFeatures.cpp mitkCommandLineParser.cpp - #) - #mitk_create_executable(CLBrainMask - # DEPENDS MitkCore MitkCLUtilities - # CPP_FILES CLBrainMask.cpp mitkCommandLineParser.cpp - #) - #mitk_create_executable(CLImageConverter - # DEPENDS MitkCore - # CPP_FILES CLImageConverter.cpp mitkCommandLineParser.cpp - #) - #mitk_create_executable(CLSurWeighting - # DEPENDS MitkCore MitkCLUtilities MitkDataCollection #MitkCLImportanceWeighting - # CPP_FILES CLSurWeighting.cpp mitkCommandLineParser.cpp - #) - #mitk_create_executable(CLImageCropper - # DEPENDS MitkCore MitkCLUtilities MitkAlgorithmsExt - # CPP_FILES CLImageCropper.cpp mitkCommandLineParser.cpp - #) # On Linux, create a shell script to start a relocatable application if(UNIX AND NOT APPLE) install(PROGRAMS "${MITK_SOURCE_DIR}/CMake/RunInstalledApp.sh" DESTINATION "." RENAME ${EXECUTABLE_TARGET}.sh) endif() if(EXECUTABLE_IS_ENABLED) MITK_INSTALL_TARGETS(EXECUTABLES ${EXECUTABLE_TARGET}) endif() endif() diff --git a/Modules/Classification/CLMiniApps/ManualSegmentationEvaluation.cpp b/Modules/Classification/CLMiniApps/ManualSegmentationEvaluation.cpp index a20b0b4a53..a159c55a72 100644 --- a/Modules/Classification/CLMiniApps/ManualSegmentationEvaluation.cpp +++ b/Modules/Classification/CLMiniApps/ManualSegmentationEvaluation.cpp @@ -1,364 +1,364 @@ /*=================================================================== 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 "mitkImage.h" -#include +#include #include #include "mitkCommandLineParser.h" #include #include #include #include #include // ITK #include // MITK #include // Classification #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace mitk; std::vector m_FeatureImageVector; void ProcessFeatureImages(const mitk::Image::Pointer & raw_image, const mitk::Image::Pointer & brain_mask) { typedef itk::Image DoubleImageType; typedef itk::Image ShortImageType; typedef itk::ConstNeighborhoodIterator NeighborhoodType; // Neighborhood iterator to access image typedef itk::Functor::NeighborhoodFirstOrderStatistics FunctorType; typedef itk::NeighborhoodFunctorImageFilter FOSFilerType; m_FeatureImageVector.clear(); // RAW m_FeatureImageVector.push_back(raw_image); // GAUSS mitk::Image::Pointer smoothed; mitk::CLUtil::GaussianFilter(raw_image,smoothed,1); m_FeatureImageVector.push_back(smoothed); // Calculate Probability maps (parameters used from literatur) // CSF mitk::Image::Pointer csf_prob = mitk::Image::New(); mitk::CLUtil::ProbabilityMap(smoothed,13.9, 8.3,csf_prob); m_FeatureImageVector.push_back(csf_prob); // Lesion mitk::Image::Pointer les_prob = mitk::Image::New(); mitk::CLUtil::ProbabilityMap(smoothed,59, 11.6,les_prob); m_FeatureImageVector.push_back(les_prob); // Barin (GM/WM) mitk::Image::Pointer brain_prob = mitk::Image::New(); mitk::CLUtil::ProbabilityMap(smoothed,32, 5.6,brain_prob); m_FeatureImageVector.push_back(brain_prob); std::vector FOS_sizes; FOS_sizes.push_back(1); DoubleImageType::Pointer input; ShortImageType::Pointer mask; mitk::CastToItkImage(smoothed, input); mitk::CastToItkImage(brain_mask, mask); for(unsigned int i = 0 ; i < FOS_sizes.size(); i++) { FOSFilerType::Pointer filter = FOSFilerType::New(); filter->SetNeighborhoodSize(FOS_sizes[i]); filter->SetInput(input); filter->SetMask(mask); filter->Update(); FOSFilerType::DataObjectPointerArray array = filter->GetOutputs(); for( unsigned int i = 0; i < FunctorType::OutputCount; i++) { mitk::Image::Pointer featureimage; mitk::CastToMitkImage(dynamic_cast(array[i].GetPointer()),featureimage); m_FeatureImageVector.push_back(featureimage); // AddImageAsDataNode(featureimage,FunctorType::GetFeatureName(i))->SetVisibility(show_nodes); } } { itk::HessianMatrixEigenvalueImageFilter< DoubleImageType >::Pointer filter = itk::HessianMatrixEigenvalueImageFilter< DoubleImageType >::New(); filter->SetInput(input); filter->SetImageMask(mask); filter->SetSigma(3); filter->Update(); mitk::Image::Pointer o1,o2,o3; mitk::CastToMitkImage(filter->GetOutput(0),o1); mitk::CastToMitkImage(filter->GetOutput(1),o2); mitk::CastToMitkImage(filter->GetOutput(2),o3); m_FeatureImageVector.push_back(o1); m_FeatureImageVector.push_back(o2); m_FeatureImageVector.push_back(o3); } { itk::StructureTensorEigenvalueImageFilter< DoubleImageType >::Pointer filter = itk::StructureTensorEigenvalueImageFilter< DoubleImageType >::New(); filter->SetInput(input); filter->SetImageMask(mask); filter->SetInnerScale(1.5); filter->SetOuterScale(3); filter->Update(); mitk::Image::Pointer o1,o2,o3; mitk::CastToMitkImage(filter->GetOutput(0),o1); mitk::CastToMitkImage(filter->GetOutput(1),o2); mitk::CastToMitkImage(filter->GetOutput(2),o3); m_FeatureImageVector.push_back(o1); m_FeatureImageVector.push_back(o2); m_FeatureImageVector.push_back(o3); } { itk::LineHistogramBasedMassImageFilter< DoubleImageType >::Pointer filter = itk::LineHistogramBasedMassImageFilter< DoubleImageType >::New(); filter->SetInput(input); filter->SetImageMask(mask); filter->Update(); mitk::Image::Pointer o1; mitk::CastToMitkImage(filter->GetOutput(0),o1); m_FeatureImageVector.push_back(o1); } } std::vector PointSetToVector(const mitk::PointSet::Pointer & mps) { std::vector result; for(int i = 0 ; i < mps->GetSize(); i++) result.push_back(mps->GetPoint(i)); return result; } int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); // required params parser.addArgument("inputdir", "i", mitkCommandLineParser::InputDirectory, "Input Directory", "Contains input feature files.", us::Any(), false); parser.addArgument("outputdir", "o", mitkCommandLineParser::OutputDirectory, "Output Directory", "Destination of output files.", us::Any(), false); parser.addArgument("mitkprojectdata", "d", mitkCommandLineParser::InputFile, "original class mask and raw image", "Orig. data.", us::Any(), false); parser.addArgument("csfmps", "csf", mitkCommandLineParser::InputFile, "CSF Pointset", ".", us::Any(), false); parser.addArgument("lesmps", "les", mitkCommandLineParser::InputFile, "LES Pointset", ".", us::Any(), false); parser.addArgument("bramps", "bra", mitkCommandLineParser::InputFile, "BRA Pointset", ".", us::Any(), false); // parser.addArgument("points", "p", mitkCommandLineParser::Int, "Ensure that p points are selected", ".", us::Any(), false); // Miniapp Infos parser.setCategory("Classification Tools"); parser.setTitle("Evaluationtool for Manual-Segmentation"); parser.setDescription("Uses Datacollection to calculate DICE scores for CSF LES BRA"); parser.setContributor("MBI"); // Params parsing std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string inputdir = us::any_cast(parsedArgs["inputdir"]); std::string outputdir = us::any_cast(parsedArgs["outputdir"]); std::string mitkprojectdata = us::any_cast(parsedArgs["mitkprojectdata"]); std::string csf_mps_name = us::any_cast(parsedArgs["csfmps"]); std::string les_mps_name = us::any_cast(parsedArgs["lesmps"]); std::string bra_mps_name = us::any_cast(parsedArgs["bramps"]); mitk::Image::Pointer class_mask_sampled, raw_image, class_mask; mitk::PointSet::Pointer CSF_mps, LES_mps, BRA_mps; // Load from mitk-project auto so = mitk::IOUtil::Load(inputdir + "/" + mitkprojectdata); std::map map; mitk::CLUtil::CountVoxel(dynamic_cast(so[1].GetPointer()), map); raw_image = map.size() <= 7 ? dynamic_cast(so[0].GetPointer()) : dynamic_cast(so[1].GetPointer()); class_mask = map.size() <= 7 ? dynamic_cast(so[1].GetPointer()) : dynamic_cast(so[0].GetPointer()); CSF_mps = mitk::IOUtil::Load(inputdir + "/" + csf_mps_name); LES_mps = mitk::IOUtil::Load(inputdir + "/" + les_mps_name); BRA_mps = mitk::IOUtil::Load(inputdir + "/" + bra_mps_name); unsigned int num_points = CSF_mps->GetSize() + LES_mps->GetSize() + BRA_mps->GetSize(); MITK_INFO << "Found #" << num_points << " points over all classes."; ProcessFeatureImages(raw_image, class_mask); std::map tmpMap; tmpMap[0] = 0; tmpMap[1] = 1; tmpMap[2] = 1; tmpMap[3] = 1; tmpMap[4] = 2; tmpMap[5] = 3; tmpMap[6] = 3; mitk::CLUtil::MergeLabels( class_mask, tmpMap); class_mask_sampled = class_mask->Clone(); itk::Image::Pointer itk_classmask_sampled; mitk::CastToItkImage(class_mask_sampled,itk_classmask_sampled); itk::ImageRegionIteratorWithIndex >::IndexType index; itk::ImageRegionIteratorWithIndex > iit(itk_classmask_sampled,itk_classmask_sampled->GetLargestPossibleRegion()); std::ofstream myfile; myfile.open (inputdir + "/results_3.csv"); Eigen::MatrixXd X_test; unsigned int count_test = 0; mitk::CLUtil::CountVoxel(class_mask, count_test); X_test = Eigen::MatrixXd(count_test, m_FeatureImageVector.size()); unsigned int pos = 0; for( const auto & image : m_FeatureImageVector) { X_test.col(pos) = mitk::CLUtil::Transform(image,class_mask); ++pos; } unsigned int runs = 20; for(unsigned int k = 0 ; k < runs; k++) { auto CSF_vec = PointSetToVector(CSF_mps); auto LES_vec = PointSetToVector(LES_mps); auto BRA_vec = PointSetToVector(BRA_mps); itk_classmask_sampled->FillBuffer(0); // initial draws std::random_shuffle(CSF_vec.begin(), CSF_vec.end()); class_mask->GetGeometry()->WorldToIndex(CSF_vec.back(),index); iit.SetIndex(index); iit.Set(1); CSF_vec.pop_back(); std::random_shuffle(LES_vec.begin(), LES_vec.end()); class_mask->GetGeometry()->WorldToIndex(LES_vec.back(),index); iit.SetIndex(index); iit.Set(2); LES_vec.pop_back(); std::random_shuffle(BRA_vec.begin(), BRA_vec.end()); class_mask->GetGeometry()->WorldToIndex(BRA_vec.back(),index); iit.SetIndex(index); iit.Set(3); BRA_vec.pop_back(); std::stringstream ss; while(!(CSF_vec.empty() && LES_vec.empty() && BRA_vec.empty())) { mitk::CastToMitkImage(itk_classmask_sampled, class_mask_sampled); // Train forest mitk::VigraRandomForestClassifier::Pointer classifier = mitk::VigraRandomForestClassifier::New(); classifier->SetTreeCount(40); classifier->SetSamplesPerTree(0.66); Eigen::MatrixXd X_train; unsigned int count_train = 0; mitk::CLUtil::CountVoxel(class_mask_sampled, count_train); X_train = Eigen::MatrixXd(count_train, m_FeatureImageVector.size() ); unsigned int pos = 0; for( const auto & image : m_FeatureImageVector) { X_train.col(pos) = mitk::CLUtil::Transform(image,class_mask_sampled); ++pos; } Eigen::MatrixXi Y = mitk::CLUtil::Transform(class_mask_sampled,class_mask_sampled); classifier->Train(X_train,Y); Eigen::MatrixXi Y_test = classifier->Predict(X_test); mitk::Image::Pointer result_mask = mitk::CLUtil::Transform(Y_test, class_mask); itk::Image::Pointer itk_result_mask, itk_class_mask; mitk::CastToItkImage(result_mask,itk_result_mask); mitk::CastToItkImage(class_mask, itk_class_mask); itk::LabelOverlapMeasuresImageFilter >::Pointer overlap_filter = itk::LabelOverlapMeasuresImageFilter >::New(); overlap_filter->SetInput(0,itk_result_mask); overlap_filter->SetInput(1,itk_class_mask); overlap_filter->Update(); MITK_INFO << "DICE (" << num_points - (CSF_vec.size() + LES_vec.size() + BRA_vec.size()) << "): " << overlap_filter->GetDiceCoefficient(); ss << overlap_filter->GetDiceCoefficient() <<","; // random class selection if(!CSF_vec.empty()) { std::random_shuffle(CSF_vec.begin(), CSF_vec.end()); class_mask->GetGeometry()->WorldToIndex(CSF_vec.back(),index); iit.SetIndex(index); iit.Set(1); CSF_vec.pop_back(); } if(!LES_vec.empty()) { std::random_shuffle(LES_vec.begin(), LES_vec.end()); class_mask->GetGeometry()->WorldToIndex(LES_vec.back(),index); iit.SetIndex(index); iit.Set(2); LES_vec.pop_back(); } if(!BRA_vec.empty()) { std::random_shuffle(BRA_vec.begin(), BRA_vec.end()); class_mask->GetGeometry()->WorldToIndex(BRA_vec.back(),index); iit.SetIndex(index); iit.Set(3); BRA_vec.pop_back(); } } myfile << ss.str() << "\n"; myfile.flush(); } myfile.close(); return EXIT_SUCCESS; } diff --git a/Modules/Classification/CLMiniApps/NativeHeadCTSegmentation.cpp b/Modules/Classification/CLMiniApps/NativeHeadCTSegmentation.cpp index e1e33c607c..0d7a11d4da 100644 --- a/Modules/Classification/CLMiniApps/NativeHeadCTSegmentation.cpp +++ b/Modules/Classification/CLMiniApps/NativeHeadCTSegmentation.cpp @@ -1,236 +1,236 @@ /*=================================================================== 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 "mitkImage.h" -#include +#include #include "mitkCommandLineParser.h" #include #include #include #include #include // ITK #include // MITK #include // Classification #include #include #include #include #include #include #include using namespace mitk; typedef unsigned int uint; void ReadMitkProjectImageAndMask(std::string input_file, mitk::Image::Pointer & raw_image, mitk::Image::Pointer & class_mask, Image::Pointer &brain_mask); std::map VolumeUnderMaskByLabel(mitk::Image::Pointer mask); /** * */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); // required params parser.addArgument("inputdir", "i", mitkCommandLineParser::InputDirectory, "Input Directory", "Contains input feature files.", us::Any(), false); parser.addArgument("outputdir", "o", mitkCommandLineParser::OutputDirectory, "Output Directory", "Destination of output files.", us::Any(), false); // optional params parser.addArgument("select", "s", mitkCommandLineParser::String, "Item selection", "Using Regular expression, seperated by space e.g.: '*.nrrd *.vtk *test*'",std::string("*.mitk"),true); // parser.addArgument("treecount", "tc", mitkCommandLineParser::Int, "Treecount", "Number of trees.",50,true); // parser.addArgument("treedepth", "td", mitkCommandLineParser::Int, "Treedepth", "Maximal tree depth.",50,true); // parser.addArgument("minsplitnodesize", "min", mitkCommandLineParser::Int, "Minimum split node size.", "Minimum split node size.",2,true); // parser.addArgument("precision", "p", mitkCommandLineParser::Float, "Split precision.", "Precision.", mitk::eps,true); // parser.addArgument("fraction", "f", mitkCommandLineParser::Float, "Fraction of samples per tree.", "Fraction of samples per tree.", 0.6f,true); // parser.addArgument("replacment", "r", mitkCommandLineParser::Bool, "Sample with replacement.", "Sample with replacement.", true,true); // Miniapp Infos parser.setCategory("Classification Tools"); parser.setTitle("Native Head CT Segmentation"); parser.setDescription("Using vigra random forest"); parser.setContributor("Jonas Cordes"); // Params parsing std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string inputdir = us::any_cast(parsedArgs["inputdir"]); std::string outputdir = us::any_cast(parsedArgs["outputdir"]); // int treecount = parsedArgs.count("treecount") ? us::any_cast(parsedArgs["treecount"]) : 50; // int treedepth = parsedArgs.count("treedepth") ? us::any_cast(parsedArgs["treedepth"]) : 50; // int minsplitnodesize = parsedArgs.count("minsplitnodesize") ? us::any_cast(parsedArgs["minsplitnodesize"]) : 2; // float precision = parsedArgs.count("precision") ? us::any_cast(parsedArgs["precision"]) : mitk::eps; // float fraction = parsedArgs.count("fraction") ? us::any_cast(parsedArgs["fraction"]) : 0.6; // bool withreplacement = parsedArgs.count("replacment") ? us::any_cast(parsedArgs["replacment"]) : true; std::string filt_select = parsedArgs.count("select") ? us::any_cast(parsedArgs["select"]) : "*.mitk"; QString filter(filt_select.c_str()); QDir dir(inputdir.c_str()); auto strl = dir.entryList(filter.split(" "),QDir::Files); // create the one mitk::VigraRandomForestClassifier::Pointer classifier = mitk::VigraRandomForestClassifier::New(); uint n_samples = 45000; uint n_samples_per_image = n_samples / strl.size(); uint n_features = 2; {// Training Eigen::MatrixXd feature_matrix(n_samples, n_features); Eigen::MatrixXi label_matrix(n_samples, 1); uint pos = 0; for(auto entry : strl) { mitk::Image::Pointer raw_image, class_mask, brain_mask; ReadMitkProjectImageAndMask(inputdir + entry.toStdString(), raw_image, class_mask, brain_mask); mitk::Image::Pointer brain_mask_sampled; AccessFixedDimensionByItk_2(brain_mask, mitk::CLUtil::itkSampleLabel, 3, brain_mask_sampled, n_samples_per_image); mitk::Image::Pointer csf_prob; mitk::CLUtil::ProbabilityMap(raw_image,13.9, 8.3,csf_prob); mitk::CLUtil::ErodeGrayscale(csf_prob,1,mitk::CLUtil::Axial,csf_prob); mitk::CLUtil::DilateGrayscale(csf_prob,3,mitk::CLUtil::Axial,csf_prob); mitk::CLUtil::FillHoleGrayscale(csf_prob,csf_prob); feature_matrix.block(pos, 0, n_samples_per_image, 1) = mitk::CLUtil::Transform(raw_image,brain_mask_sampled); feature_matrix.block(pos, 1, n_samples_per_image, 1) = mitk::CLUtil::Transform(csf_prob,brain_mask_sampled); label_matrix.block(pos, 0, n_samples_per_image, 1) = mitk::CLUtil::Transform(class_mask, brain_mask_sampled); pos += n_samples_per_image; } classifier->Train(feature_matrix, label_matrix); classifier->PrintParameter(); } std::map > map_error; for(auto entry: strl) { mitk::Image::Pointer raw_image, class_mask, brain_mask; ReadMitkProjectImageAndMask(inputdir + entry.toStdString(), raw_image, class_mask, brain_mask); auto map_true = VolumeUnderMaskByLabel(class_mask); mitk::Image::Pointer csf_prob; mitk::CLUtil::ProbabilityMap(raw_image,13.9, 8.3,csf_prob); mitk::CLUtil::ErodeGrayscale(csf_prob,1,mitk::CLUtil::Axial,csf_prob); mitk::CLUtil::DilateGrayscale(csf_prob,3,mitk::CLUtil::Axial,csf_prob); mitk::CLUtil::FillHoleGrayscale(csf_prob,csf_prob); uint count = 0; mitk::CLUtil::CountVoxel(brain_mask,count); Eigen::MatrixXd feature_matrix(count,n_features); feature_matrix.block(0, 0, count, 1) = mitk::CLUtil::Transform(raw_image,brain_mask); feature_matrix.block(0, 1, count, 1) = mitk::CLUtil::Transform(csf_prob,brain_mask); mitk::Image::Pointer result_mask = mitk::CLUtil::Transform(classifier->Predict(feature_matrix),brain_mask); std::string name = itksys::SystemTools::GetFilenameWithoutExtension(entry.toStdString()); mitk::IOUtil::Save(result_mask,outputdir + name + ".nrrd"); auto map_pred = VolumeUnderMaskByLabel(result_mask); map_error[entry.toStdString()] = std::make_pair(std::abs(map_true[1] - map_pred[1]) / map_true[1], map_true[2] != 0 ? std::abs(map_true[2] - map_pred[2]) / map_true[2]: 0); } double mean_error_csf = 0; double mean_error_les = 0; double num_subjects = map_error.size(); for(auto entry: map_error) { MITK_INFO(entry.first.c_str()) << "CSF error: " << entry.second.first << "%\t LES error: " << entry.second.second << "%"; mean_error_csf += entry.second.first; mean_error_les += entry.second.second; } MITK_INFO("Mean") << "CSF error: " << mean_error_csf/num_subjects << "%\t LES error: " << mean_error_les/num_subjects << "%"; return EXIT_SUCCESS; } void ReadMitkProjectImageAndMask(std::string input_file, mitk::Image::Pointer & raw_image, mitk::Image::Pointer & class_mask, mitk::Image::Pointer & brain_mask) { auto so = mitk::IOUtil::Load(input_file); std::map map; mitk::CLUtil::CountVoxel(dynamic_cast(so[1].GetPointer()), map); raw_image = map.size() <= 7 ? dynamic_cast(so[0].GetPointer()) : dynamic_cast(so[1].GetPointer()); class_mask = map.size() <= 7 ? dynamic_cast(so[1].GetPointer()) : dynamic_cast(so[0].GetPointer()); std::map merge_instructions;// = {{0,0},{1,1},{2,1},{3,1},{4,2},{5,3},{6,3}}; merge_instructions[0] = 0; merge_instructions[1] = 1; merge_instructions[2] = 1; merge_instructions[3] = 1; merge_instructions[4] = 2; merge_instructions[5] = 3; merge_instructions[6] = 3; mitk::CLUtil::MergeLabels(class_mask, merge_instructions); brain_mask = class_mask->Clone(); //merge_instructions = {{0,0},{1,1},{2,1},{3,1},{4,1},{5,1},{6,1}}; merge_instructions[0] = 0; merge_instructions[1] = 1; merge_instructions[2] = 1; merge_instructions[3] = 1; merge_instructions[4] = 1; merge_instructions[5] = 1; merge_instructions[6] = 1; mitk::CLUtil::MergeLabels(brain_mask, merge_instructions); } std::map VolumeUnderMaskByLabel(mitk::Image::Pointer mask) { itk::Image::Pointer img; mitk::CastToItkImage(mask,img); std::map volume_map; itk::ImageRegionConstIterator> it(img,img->GetLargestPossibleRegion()); while(!it.IsAtEnd()) { itk::Image::PixelType value = it.Value(); if(volume_map.find(value)== volume_map.end()) volume_map[value] = 0; volume_map[value]++; ++it; } auto spacing = img->GetSpacing(); double volumeUnit = spacing[0] * spacing[1] * spacing[2]; volumeUnit *= 0.001; for(auto entry: volume_map) entry.second *= volumeUnit; return volume_map; } diff --git a/Modules/Classification/CLMiniApps/RandomForestTraining.cpp b/Modules/Classification/CLMiniApps/RandomForestTraining.cpp index e818994033..57b0e3db29 100644 --- a/Modules/Classification/CLMiniApps/RandomForestTraining.cpp +++ b/Modules/Classification/CLMiniApps/RandomForestTraining.cpp @@ -1,152 +1,152 @@ /*=================================================================== 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 "mitkImage.h" -#include +#include #include "mitkCommandLineParser.h" #include #include #include #include #include // ITK #include // MITK #include // Classification #include #include #include #include #include using namespace mitk; /** * */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); // required params parser.addArgument("inputdir", "i", mitkCommandLineParser::InputDirectory, "Input Directory", "Contains input feature files.", us::Any(), false); parser.addArgument("outputdir", "o", mitkCommandLineParser::OutputDirectory, "Output Directory", "Destination of output files.", us::Any(), false); parser.addArgument("classmask", "m", mitkCommandLineParser::InputFile, "Class mask image", "Contains several classes.", us::Any(), false); // optional params parser.addArgument("select", "s", mitkCommandLineParser::String, "Item selection", "Using Regular expression, seperated by space e.g.: '*.nrrd *.vtk *test*'",std::string("*.nrrd"),true); parser.addArgument("treecount", "tc", mitkCommandLineParser::Int, "Treecount", "Number of trees.",50,true); parser.addArgument("treedepth", "td", mitkCommandLineParser::Int, "Treedepth", "Maximal tree depth.",50,true); parser.addArgument("minsplitnodesize", "min", mitkCommandLineParser::Int, "Minimum split node size.", "Minimum split node size.",2,true); parser.addArgument("precision", "p", mitkCommandLineParser::Float, "Split precision.", "Precision.", mitk::eps,true); parser.addArgument("fraction", "f", mitkCommandLineParser::Float, "Fraction of samples per tree.", "Fraction of samples per tree.", 0.6f,true); parser.addArgument("replacment", "r", mitkCommandLineParser::Bool, "Sample with replacement.", "Sample with replacement.", true,true); // Miniapp Infos parser.setCategory("Classification Tools"); parser.setTitle("Random Forest Training"); parser.setDescription("Vigra RF impl."); parser.setContributor("MBI"); // Params parsing std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string inputdir = us::any_cast(parsedArgs["inputdir"]); std::string outputdir = us::any_cast(parsedArgs["outputdir"]); std::string classmask = us::any_cast(parsedArgs["classmask"]); int treecount = parsedArgs.count("treecount") ? us::any_cast(parsedArgs["treecount"]) : 50; int treedepth = parsedArgs.count("treedepth") ? us::any_cast(parsedArgs["treedepth"]) : 50; int minsplitnodesize = parsedArgs.count("minsplitnodesize") ? us::any_cast(parsedArgs["minsplitnodesize"]) : 2; float precision = parsedArgs.count("precision") ? us::any_cast(parsedArgs["precision"]) : mitk::eps; float fraction = parsedArgs.count("fraction") ? us::any_cast(parsedArgs["fraction"]) : 0.6; bool withreplacement = parsedArgs.count("replacment") ? us::any_cast(parsedArgs["replacment"]) : true; std::string filt_select =/* parsedArgs.count("select") ? us::any_cast(parsedArgs["select"]) :*/ "*.nrrd"; QString filter(filt_select.c_str()); // **** in principle repeat this block to create a feature matrix X_all for all subjects (in dir) // Get nrrd filepath QDir dir(inputdir.c_str()); auto strl = dir.entryList(filter.split(" "),QDir::Files); // load class mask mitk::Image::Pointer mask = mitk::IOUtil::Load(classmask); unsigned int num_samples = 0; mitk::CLUtil::CountVoxel(mask,num_samples); // initialize featurematrix [num_samples, num_featureimages] Eigen::MatrixXd X(num_samples, strl.size()); for(int i = 0 ; i < strl.size(); i++) { // load feature image mitk::Image::Pointer img = mitk::IOUtil::Load(inputdir + strl[i].toStdString()); // transfom it into a [num_samples, 1] vector depending on the classmask Eigen::MatrixXd _x = mitk::CLUtil::Transform(img,mask); // replace i-th (empty) col with feature vector in _x X.block(0,i,num_samples,1) = _x; } // **** // transform classmask into the label-vector [num_samples, 1] Eigen::MatrixXi Y = mitk::CLUtil::Transform(mask,mask); mitk::VigraRandomForestClassifier::Pointer classifier = mitk::VigraRandomForestClassifier::New(); classifier->SetTreeCount(treecount); classifier->SetMaximumTreeDepth(treedepth); classifier->SetMinimumSplitNodeSize(minsplitnodesize); classifier->SetPrecision(precision); classifier->SetSamplesPerTree(fraction); classifier->UseSampleWithReplacement(withreplacement); classifier->PrintParameter(); classifier->Train(X,Y); MITK_INFO << classifier->IsEmpty(); // no metainformations are saved currently // only the raw vigra rf data mitk::IOUtil::Save(classifier, outputdir + "RandomForest.hdf5"); Eigen::MatrixXi Y_pred = classifier->Predict(X); Eigen::MatrixXd Probs = classifier->GetPointWiseProbabilities(); MITK_INFO << Y_pred.rows() << " " << Y_pred.cols(); MITK_INFO << Probs.rows() << " " << Probs.cols(); // mitk::Image::Pointer prediction = mitk::CLUtil::Transform(Y_pred,mask); mitk::Image::Pointer probs_1 = mitk::CLUtil::Transform(Probs.col(0),mask); mitk::Image::Pointer probs_2 = mitk::CLUtil::Transform(Probs.col(1),mask); mitk::Image::Pointer probs_3 = mitk::CLUtil::Transform(Probs.col(2),mask); mitk::IOUtil::Save(probs_1, outputdir + "probs_1.nrrd"); mitk::IOUtil::Save(probs_2, outputdir + "probs_2.nrrd"); mitk::IOUtil::Save(probs_3, outputdir + "probs_3.nrrd"); // mitk::IOUtil::Save(probs_2, outputdir + "test.nrrd"); return EXIT_SUCCESS; } diff --git a/Modules/Classification/CLUtilities/files.cmake b/Modules/Classification/CLUtilities/files.cmake index 17b04b392f..64e037b845 100644 --- a/Modules/Classification/CLUtilities/files.cmake +++ b/Modules/Classification/CLUtilities/files.cmake @@ -1,38 +1,39 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES mitkCLResultWritter.cpp Algorithms/itkLabelSampler.cpp Algorithms/itkSmoothedClassProbabilites.cpp Algorithms/mitkRandomImageSampler.cpp Features/itkNeighborhoodFunctorImageFilter.cpp Features/itkLineHistogramBasedMassImageFilter.cpp GlobalImageFeatures/mitkGIFCooccurenceMatrix.cpp GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp GlobalImageFeatures/mitkGIFGreyLevelRunLength.cpp GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp GlobalImageFeatures/mitkGIFFirstOrderStatistics.cpp GlobalImageFeatures/mitkGIFFirstOrderHistogramStatistics.cpp + GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp GlobalImageFeatures/mitkGIFNeighbouringGreyLevelDependenceFeatures.cpp GlobalImageFeatures/mitkGIFNeighbourhoodGreyLevelDifference.cpp GlobalImageFeatures/mitkGIFGreyLevelSizeZone.cpp GlobalImageFeatures/mitkGIFGreyLevelDistanceZone.cpp GlobalImageFeatures/mitkGIFLocalIntensity.cpp GlobalImageFeatures/mitkGIFVolumetricDensityStatistics.cpp GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp GlobalImageFeatures/mitkGIFNeighbourhoodGreyToneDifferenceFeatures.cpp GlobalImageFeatures/mitkGIFCurvatureStatistic.cpp MiniAppUtils/mitkGlobalImageFeaturesParameter.cpp MiniAppUtils/mitkSplitParameterToVector.cpp mitkCLUtil.cpp ) set( TOOL_FILES ) diff --git a/Modules/Classification/CLUtilities/include/itkMultiHistogramFilter.h b/Modules/Classification/CLUtilities/include/itkMultiHistogramFilter.h index 8e5e41d396..3f2fcfa147 100644 --- a/Modules/Classification/CLUtilities/include/itkMultiHistogramFilter.h +++ b/Modules/Classification/CLUtilities/include/itkMultiHistogramFilter.h @@ -1,66 +1,66 @@ #ifndef itkMultiHistogramFilter_h #define itkMultiHistogramFilter_h #include "itkImageToImageFilter.h" namespace itk { template class MultiHistogramFilter : public ImageToImageFilter< TInputImageType, TOuputImageType> { public: typedef MultiHistogramFilter Self; typedef ImageToImageFilter< TInputImageType, TOuputImageType > Superclass; typedef SmartPointer< Self > Pointer; typedef typename TInputImageType::ConstPointer InputImagePointer; typedef typename TOuputImageType::Pointer OutputImagePointer; typedef typename TOuputImageType::RegionType OutputImageRegionType; itkNewMacro (Self); itkTypeMacro(MultiHistogramFilter, ImageToImageFilter); itkSetMacro(Delta, double); itkGetConstMacro(Delta, double); itkSetMacro(Offset, double); itkGetConstMacro(Offset, double); itkSetMacro(Bins, int); itkGetConstMacro(Bins, int); itkSetMacro(Size, int); itkGetConstMacro(Size, int); itkSetMacro(UseImageIntensityRange, bool); itkGetConstMacro(UseImageIntensityRange, bool); protected: MultiHistogramFilter(); ~MultiHistogramFilter(){}; - virtual void ThreadedGenerateData(const OutputImageRegionType & outputRegionForThread, ThreadIdType threadId); - virtual void BeforeThreadedGenerateData(void); + virtual void ThreadedGenerateData(const OutputImageRegionType & outputRegionForThread, ThreadIdType threadId) override; + virtual void BeforeThreadedGenerateData(void) override; using itk::ProcessObject::MakeOutput; itk::ProcessObject::DataObjectPointer MakeOutput(itk::ProcessObject::DataObjectPointerArraySizeType /*idx*/) override; void CreateOutputImage(InputImagePointer input, OutputImagePointer output); private: MultiHistogramFilter(const Self &); // purposely not implemented void operator=(const Self &); // purposely not implemented double m_Delta; double m_Offset; int m_Bins; int m_Size; bool m_UseImageIntensityRange; }; } #ifndef ITK_MANUAL_INSTANTIATION #include "itkMultiHistogramFilter.cpp" #endif #endif // itkMultiHistogramFilter_h diff --git a/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderNumericStatistics.h b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderNumericStatistics.h new file mode 100644 index 0000000000..9f28cde2d6 --- /dev/null +++ b/Modules/Classification/CLUtilities/include/mitkGIFFirstOrderNumericStatistics.h @@ -0,0 +1,156 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef mitkGIFFirstOrderStatistics_h +#define mitkGIFFirstOrderStatistics_h + +#include +#include +#include + +namespace mitk +{ + class MITKCLUTILITIES_EXPORT GIFFirstOrderNumericStatistics : public AbstractGlobalImageFeature + { + public: + /** + * \brief Calculates first order statistics of the given image. + * + * The first order statistics for the intensity distribution within a given Region of Interest (ROI) + * is caluclated. The ROI is defined using a mask. + * + * The features are calculated on a quantified image. If the bin-size is too big, the obtained values + * can be errornous and missleading. It is therefore important to use enough bins. The binned approach is + * used in order to avoid floating-point related errors. + * + * This feature calculator is activated by the option -first-order or -fo. + * + * The connected areas are based on the binned image, the binning parameters can be set via the default + * parameters as described in AbstractGlobalImageFeature. It is also possible to determine the + * dimensionality of the neighbourhood using direction-related commands as described in AbstractGlobalImageFeature. + * No other options are possible beside these two options. + * + * The features are calculated based on a mask. It is assumed that the mask is + * of the type of an unsigned short image. All voxels with the value 1 are treated as masked. + * + * The following features are then defined using the (binned) voxel intensity \f$ x_i \f$ of each voxel, the probability + * an intensity \f$ p_x \f$, and the overall number of voxels within the mask \f$ N_v \f$: + * - First Order::Mean: The mean intensity within the ROI + * \f[ \textup{Mean}= \mu = \frac{1}{N_v} \sum x_i \f] + * - First Order::Unbiased Variance: An unbiased estimation of the variance: + * \f[ \textup{Unbiased Variance} = \frac{1}{N_v - 1} \sum \left( x_i - \mu \right)^2 \f] + * - First Order::Biased Variance: An biased estimation of the variance. If not specified otherwise, this is + * used as the variance: + * \f[ \textup{Biased Variance} = \sigma^2 = \frac{1}{N_v} \sum \left( x_i - \mu \right)^2 \f] + * - First Order::Unbiased Standard Deviation: Estimation of diversity within the intensity values + * \f[ \textup{Unbiased Standard Deviation} = \sqrt{\frac{1}{N_v-1} \sum \left( x_i - \mu \right)^2} \f] + * - First Order::Biased Standard Deviation: Estimation of diversity within the intensity values + * \f[ \textup{Biased Standard Deviation} = \sigma = \sqrt{\frac{1}{N_v} \sum \left( x_i - \mu \right)^2} \f] + * - First Order::Skewness: + * \f[ \textup{Skewness} = \frac{\frac{1}{N_v} \sum \left( x_i - \mu \right)^3}{\sigma^3} \f] + * - First Order::Kurtosis: The kurtosis is a measurement of the peakness of the given + * distirbution: + * \f[ \textup{Kurtosis} = \frac{\frac{1}{N_v} \sum \left( x_i - \mu \right)^4}{\sigma^4} \f] + * - First Order::Excess Kurtosis: The kurtosis is a measurement of the peakness of the given + * distirbution. The excess kurtosis is similar to the kurtosis, but is corrected by a fisher correction, + * ensuring that a gaussian distribution has an excess kurtosis of 0. + * \f[ \textup{Excess Kurtosis} = \frac{\frac{1}{N_v} \sum \left( x_i - \mu \right)^4}{\sigma^4} - 3 \f] + * - First Order::Median: The median is defined as the median of the all intensities in the ROI. + * - First Order::Minimum: The minimum is defined as the minimum of the all intensities in the ROI. + * - First Order::05th Percentile: \f$ P_{5\%} \f$ The 5% percentile. 5% of all voxel do have this or a lower intensity. + * - First Order::10th Percentile: \f$ P_{10\%} \f$ The 10% percentile. 10% of all voxel do have this or a lower intensity. + * - First Order::15th Percentile: \f$ P_{15\%} \f$ The 15% percentile. 15% of all voxel do have this or a lower intensity. + * - First Order::20th Percentile: \f$ P_{20\%} \f$ The 20% percentile. 20% of all voxel do have this or a lower intensity. + * - First Order::25th Percentile: \f$ P_{25\%} \f$ The 25% percentile. 25% of all voxel do have this or a lower intensity. + * - First Order::30th Percentile: \f$ P_{30\%} \f$ The 30% percentile. 30% of all voxel do have this or a lower intensity. + * - First Order::35th Percentile: \f$ P_{35\%} \f$ The 35% percentile. 35% of all voxel do have this or a lower intensity. + * - First Order::40th Percentile: \f$ P_{40\%} \f$ The 40% percentile. 40% of all voxel do have this or a lower intensity. + * - First Order::45th Percentile: \f$ P_{45\%} \f$ The 45% percentile. 45% of all voxel do have this or a lower intensity. + * - First Order::50th Percentile: \f$ P_{50\%} \f$ The 50% percentile. 50% of all voxel do have this or a lower intensity. + * - First Order::55th Percentile: \f$ P_{55\%} \f$ The 55% percentile. 55% of all voxel do have this or a lower intensity. + * - First Order::60th Percentile: \f$ P_{60\%} \f$ The 60% percentile. 60% of all voxel do have this or a lower intensity. + * - First Order::65th Percentile: \f$ P_{65\%} \f$ The 65% percentile. 65% of all voxel do have this or a lower intensity. + * - First Order::70th Percentile: \f$ P_{70\%} \f$ The 70% percentile. 70% of all voxel do have this or a lower intensity. + * - First Order::75th Percentile: \f$ P_{75\%} \f$ The 75% percentile. 75% of all voxel do have this or a lower intensity. + * - First Order::80th Percentile: \f$ P_{80\%} \f$ The 80% percentile. 80% of all voxel do have this or a lower intensity. + * - First Order::85th Percentile: \f$ P_{85\%} \f$ The 85% percentile. 85% of all voxel do have this or a lower intensity. + * - First Order::90th Percentile: \f$ P_{90\%} \f$ The 90% percentile. 90% of all voxel do have this or a lower intensity. + * - First Order::95th Percentile: \f$ P_{95\%} \f$ The 95% percentile. 95% of all voxel do have this or a lower intensity. + * - First Order::Maximum: The maximum is defined as the minimum of the all intensities in the ROI. + * - First Order::Range: The range of intensity values is defined as the difference between the maximum + * and minimum intensity in the ROI. + * - First Order::Interquartile Range: The difference between the 75% and 25% quantile. + * - First Order::Mean Absolute Deviation: The mean absolute deviation gives the mean distance of each + * voxel intensity to the overal mean intensity and is a measure of the dispersion of the intensity form the + * mean value: + * \f[ \textup{Mean Absolute Deviation} = \frac{1}{N_v} \sum \left \| x_i - \mu \right \| \f] + * - First Order::Robust Mean: The mean intensity within the ROI for all voxels between the 10% and 90% quantile: + * \f[ \textup{Robust Mean}= \mu_R = \frac{1}{N_{vr}} \sum x_i \f] + * - First Order::Robust Mean Absolute Deviation: The absolute deviation of all intensities within the ROI for + * all voxels between the 10% and 90% quantilefrom the robust mean intensity: + * \f[ \textup{Robust Mean Absolute Deviation}= \mu_R = \frac{1}{N_{vr}} \sum \left \| x_i - \mu_R \right \| \f] + * - First Order::Median Absolute Deviation: Similar to the mean absolute deviation, but uses the median + * instead of the mean to measure the center of the distribution. + * - First Order::Coefficient Of Variation: Measures the dispersion of the intensity distribution: + * \f[ \textup{Coefficient Of Variation} = \frac{sigma}{\mu} \f] + * - First Order::Quantile Coefficient Of Dispersion: A robust alternative to teh coefficient of variance: + * \f[ \textup{Quantile Coefficient Of Dispersion} = \frac{P_{75\%} - P_{25\%} }{P_{75\%} + P_{25\%}} \f] + * - First Order::Energy: The intensity energy: + * \f[ \textup{Energy} = \sum x_i ^2 \f] + * - First Order::Root Mean Square: Root mean square is an important measure for the error. + * \f[ \textup{Root Mean Square} = \sqrt{\frac{\sum x_i ^2}{N_v}} \f] + * - First Order::Uniformity: + * \f[ \textup{Uniformity} = \sum p_x^2 \f] + * - First Order::Entropy: + * \f[ \textup{Entropy} = - \sum p_x \textup{log}_2(p_x) \f] + * - First Order::Entropy: + * \f[ \textup{Entropy} = - \sum p_x \textup{log}_2(p_x) \f] + * - First Order::Covered Image Intensity Range: Percentage of the image intensity range (maximum - minimum in whole + * image) that is covered by the ROI. + * - First Order::Sum: The sum of all intensities. It is correlated to the mean intensity. + * \f[ \textup{Sum} = \sum x_i \f] + * - First Order::Mode: The most common intensity. + * - First Order::Mode Probability: The likelihood of the most common intensity. + * - First Order::Number Of Voxels: \f$ N_v \f$ the number of voxels covered by the ROI. + * - First Order::Image Dimension: The dimensionality of the image (e.g. 2D, 3D, etc.). + * - First Order::Number Of Voxels: The product of all spacing along all dimensions. In 3D, this is equal to the + * volume. + * - First Order::Number Of Voxels: The volume of a single voxel. If the dimensionality is only 2D, this is the + * surface of an voxel. + */ + mitkClassMacro(GIFFirstOrderNumericStatistics,AbstractGlobalImageFeature) + itkFactorylessNewMacro(Self) + itkCloneMacro(Self) + + GIFFirstOrderNumericStatistics(); + + /** + * \brief Calculates the First Order Features based on a binned version of the image. + */ + FeatureListType CalculateFeatures(const Image::Pointer & image, const Image::Pointer &feature) override; + + /** + * \brief Returns a list of the names of all features that are calculated from this class + */ + FeatureNameListType GetFeatureNames() override; + virtual std::string GetCurrentFeatureEncoding() override; + + virtual void CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &maskNoNAN, FeatureListType &featureList); + virtual void AddArguments(mitkCommandLineParser &parser); + + }; +} +#endif //mitkGIFFirstOrderStatistics_h diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp index a50b98f65a..3bb2973578 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFCooccurenceMatrix2.cpp @@ -1,693 +1,693 @@ #include // MITK #include #include #include // ITK #include #include #include // STL #include #include namespace mitk { struct CoocurenceMatrixHolder { public: CoocurenceMatrixHolder(double min, double max, int number); int IntensityToIndex(double intensity); double IndexToMinIntensity(int index); double IndexToMeanIntensity(int index); double IndexToMaxIntensity(int index); double m_MinimumRange; double m_MaximumRange; double m_Stepsize; int m_NumberOfBins; Eigen::MatrixXd m_Matrix; }; struct CoocurenceMatrixFeatures { CoocurenceMatrixFeatures() : JointMaximum(0), JointAverage(0), JointVariance(0), JointEntropy(0), RowMaximum(0), RowAverage(0), RowVariance(0), RowEntropy(0), FirstRowColumnEntropy(0), SecondRowColumnEntropy(0), DifferenceAverage(0), DifferenceVariance(0), DifferenceEntropy(0), SumAverage(0), SumVariance(0), SumEntropy(0), AngularSecondMoment(0), Contrast(0), Dissimilarity(0), InverseDifference(0), InverseDifferenceNormalised(0), InverseDifferenceMoment(0), InverseDifferenceMomentNormalised(0), InverseVariance(0), Correlation(0), Autocorrelation(0), ClusterTendency(0), ClusterShade(0), ClusterProminence(0), FirstMeasureOfInformationCorrelation(0), SecondMeasureOfInformationCorrelation(0) { } public: double JointMaximum; double JointAverage; double JointVariance; double JointEntropy; double RowMaximum; double RowAverage; double RowVariance; double RowEntropy; double FirstRowColumnEntropy; double SecondRowColumnEntropy; double DifferenceAverage; double DifferenceVariance; double DifferenceEntropy; double SumAverage; double SumVariance; double SumEntropy; double AngularSecondMoment; double Contrast; double Dissimilarity; double InverseDifference; double InverseDifferenceNormalised; double InverseDifferenceMoment; double InverseDifferenceMomentNormalised; double InverseVariance; double Correlation; double Autocorrelation; double ClusterTendency; double ClusterShade; double ClusterProminence; double FirstMeasureOfInformationCorrelation; double SecondMeasureOfInformationCorrelation; }; } static void MatrixFeaturesTo(mitk::CoocurenceMatrixFeatures features, std::string prefix, mitk::GIFCooccurenceMatrix2::FeatureListType &featureList); static void CalculateMeanAndStdDevFeatures(std::vector featureList, mitk::CoocurenceMatrixFeatures &meanFeature, mitk::CoocurenceMatrixFeatures &stdFeature); static void NormalizeMatrixFeature(mitk::CoocurenceMatrixFeatures &features, std::size_t number); mitk::CoocurenceMatrixHolder::CoocurenceMatrixHolder(double min, double max, int number) : m_MinimumRange(min), m_MaximumRange(max), m_NumberOfBins(number) { m_Matrix.resize(number, number); m_Matrix.fill(0); m_Stepsize = (max - min) / (number); } int mitk::CoocurenceMatrixHolder::IntensityToIndex(double intensity) { int index = std::floor((intensity - m_MinimumRange) / m_Stepsize); return std::max(0, std::min(index, m_NumberOfBins - 1)); } double mitk::CoocurenceMatrixHolder::IndexToMinIntensity(int index) { return m_MinimumRange + index * m_Stepsize; } double mitk::CoocurenceMatrixHolder::IndexToMeanIntensity(int index) { return m_MinimumRange + (index+0.5) * m_Stepsize; } double mitk::CoocurenceMatrixHolder::IndexToMaxIntensity(int index) { return m_MinimumRange + (index + 1) * m_Stepsize; } template void CalculateCoOcMatrix(itk::Image* itkImage, itk::Image* mask, itk::Offset offset, int range, mitk::CoocurenceMatrixHolder &holder) { typedef itk::Image ImageType; typedef itk::Image MaskImageType; typedef itk::ShapedNeighborhoodIterator ShapeIterType; typedef itk::ShapedNeighborhoodIterator ShapeMaskIterType; typedef itk::ImageRegionConstIterator ConstIterType; typedef itk::ImageRegionConstIterator ConstMaskIterType; itk::Size radius; radius.Fill(range+1); ShapeIterType imageOffsetIter(radius, itkImage, itkImage->GetLargestPossibleRegion()); ShapeMaskIterType maskOffsetIter(radius, mask, mask->GetLargestPossibleRegion()); imageOffsetIter.ActivateOffset(offset); maskOffsetIter.ActivateOffset(offset); ConstIterType imageIter(itkImage, itkImage->GetLargestPossibleRegion()); ConstMaskIterType maskIter(mask, mask->GetLargestPossibleRegion()); // iterator.GetIndex() + ci.GetNeighborhoodOffset() auto region = mask->GetLargestPossibleRegion(); while (!maskIter.IsAtEnd()) { auto ciMask = maskOffsetIter.Begin(); auto ciValue = imageOffsetIter.Begin(); if (maskIter.Value() > 0 && ciMask.Get() > 0 && imageIter.Get() == imageIter.Get() && ciValue.Get() == ciValue.Get() && region.IsInside(maskOffsetIter.GetIndex() + ciMask.GetNeighborhoodOffset())) { int i = holder.IntensityToIndex(imageIter.Get()); int j = holder.IntensityToIndex(ciValue.Get()); holder.m_Matrix(i, j) += 1; holder.m_Matrix(j, i) += 1; } ++imageOffsetIter; ++maskOffsetIter; ++imageIter; ++maskIter; } } void CalculateFeatures( mitk::CoocurenceMatrixHolder &holder, mitk::CoocurenceMatrixFeatures & results ) { auto pijMatrix = holder.m_Matrix; auto piMatrix = holder.m_Matrix; auto pjMatrix = holder.m_Matrix; double Ng = holder.m_NumberOfBins; int NgSize = holder.m_NumberOfBins; pijMatrix /= pijMatrix.sum(); piMatrix.rowwise().normalize(); pjMatrix.colwise().normalize(); for (int i = 0; i < holder.m_NumberOfBins; ++i) for (int j = 0; j < holder.m_NumberOfBins; ++j) { if (pijMatrix(i, j) != pijMatrix(i, j)) pijMatrix(i, j) = 0; if (piMatrix(i, j) != piMatrix(i, j)) piMatrix(i, j) = 0; if (pjMatrix(i, j) != pjMatrix(i, j)) pjMatrix(i, j) = 0; } Eigen::VectorXd piVector = pijMatrix.colwise().sum(); Eigen::VectorXd pjVector = pijMatrix.rowwise().sum(); double sigmai = 0;; for (int i = 0; i < holder.m_NumberOfBins; ++i) { double iInt = i + 1;// holder.IndexToMeanIntensity(i); results.RowAverage += iInt * piVector(i); if (piVector(i) > 0) { results.RowEntropy -= piVector(i) * std::log(piVector(i)) / std::log(2); } } for (int i = 0; i < holder.m_NumberOfBins; ++i) { double iInt = i + 1; // holder.IndexToMeanIntensity(i); results.RowVariance += (iInt - results.RowAverage)*(iInt - results.RowAverage) * piVector(i); } results.RowMaximum = piVector.maxCoeff(); sigmai = std::sqrt(results.RowVariance); Eigen::VectorXd pimj(NgSize); pimj.fill(0); Eigen::VectorXd pipj(2*NgSize); pipj.fill(0); results.JointMaximum += pijMatrix.maxCoeff(); for (int i = 0; i < holder.m_NumberOfBins; ++i) { for (int j = 0; j < holder.m_NumberOfBins; ++j) { //double iInt = holder.IndexToMeanIntensity(i); //double jInt = holder.IndexToMeanIntensity(j); double iInt = i + 1;// holder.IndexToMeanIntensity(i); double jInt = j + 1;// holder.IndexToMeanIntensity(j); double pij = pijMatrix(i, j); int deltaK = (i - j)>0?(i-j) : (j-i); pimj(deltaK) += pij; pipj(i + j) += pij; results.JointAverage += iInt * pij; if (pij > 0) { results.JointEntropy -= pij * std::log(pij) / std::log(2); results.FirstRowColumnEntropy -= pij * std::log(piVector(i)*pjVector(j)) / std::log(2); } if (piVector(i) > 0 && pjVector(j) > 0 ) { results.SecondRowColumnEntropy -= piVector(i)*pjVector(j) * std::log(piVector(i)*pjVector(j)) / std::log(2); } results.AngularSecondMoment += pij*pij; results.Contrast += (iInt - jInt)* (iInt - jInt) * pij; results.Dissimilarity += std::abs(iInt - jInt) * pij; results.InverseDifference += pij / (1 + (std::abs(iInt - jInt))); results.InverseDifferenceNormalised += pij / (1 + (std::abs(iInt - jInt) / Ng)); results.InverseDifferenceMoment += pij / (1 + (iInt - jInt)*(iInt - jInt)); results.InverseDifferenceMomentNormalised += pij / (1 + (iInt - jInt)*(iInt - jInt)/Ng/Ng); results.Autocorrelation += iInt*jInt * pij; double cluster = (iInt + jInt - 2 * results.RowAverage); results.ClusterTendency += cluster*cluster * pij; results.ClusterShade += cluster*cluster*cluster * pij; results.ClusterProminence += cluster*cluster*cluster*cluster * pij; if (iInt != jInt) { results.InverseVariance += pij / (iInt - jInt) / (iInt - jInt); } } } results.Correlation = 1 / sigmai / sigmai * (-results.RowAverage*results.RowAverage+ results.Autocorrelation); results.FirstMeasureOfInformationCorrelation = (results.JointEntropy - results.FirstRowColumnEntropy) / results.RowEntropy; if (results.JointEntropy < results.SecondRowColumnEntropy) { results.SecondMeasureOfInformationCorrelation = sqrt(1 - exp(-2 * (results.SecondRowColumnEntropy - results.JointEntropy))); } else { results.SecondMeasureOfInformationCorrelation = 0; } for (int i = 0; i < holder.m_NumberOfBins; ++i) { for (int j = 0; j < holder.m_NumberOfBins; ++j) { //double iInt = holder.IndexToMeanIntensity(i); //double jInt = holder.IndexToMeanIntensity(j); double iInt = i + 1; double pij = pijMatrix(i, j); results.JointVariance += (iInt - results.JointAverage)* (iInt - results.JointAverage)*pij; } } for (int k = 0; k < NgSize; ++k) { results.DifferenceAverage += k* pimj(k); if (pimj(k) > 0) { results.DifferenceEntropy -= pimj(k) * log(pimj(k)) / std::log(2); } } for (int k = 0; k < NgSize; ++k) { results.DifferenceVariance += (results.DifferenceAverage-k)* (results.DifferenceAverage-k)*pimj(k); } for (int k = 0; k <2* NgSize ; ++k) { results.SumAverage += (2+k)* pipj(k); if (pipj(k) > 0) { results.SumEntropy -= pipj(k) * log(pipj(k)) / std::log(2); } } for (int k = 0; k < 2*NgSize; ++k) { results.SumVariance += (2+k - results.SumAverage)* (2+k - results.SumAverage)*pipj(k); } //MITK_INFO << std::endl << holder.m_Matrix; //MITK_INFO << std::endl << pijMatrix; //MITK_INFO << std::endl << piMatrix; //MITK_INFO << std::endl << pjMatrix; //for (int i = 0; i < holder.m_NumberOfBins; ++i) //{ // MITK_INFO << "Bin " << i << " Min: " << holder.IndexToMinIntensity(i) << " Max: " << holder.IndexToMaxIntensity(i); //} //MITK_INFO << pimj; //MITK_INFO << pipj; } template void CalculateCoocurenceFeatures(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFCooccurenceMatrix2::FeatureListType & featureList, mitk::GIFCooccurenceMatrix2::GIFCooccurenceMatrix2Configuration config) { typedef itk::Image MaskType; typedef itk::Neighborhood NeighborhoodType; typedef itk::Offset OffsetType; /////////////////////////////////////////////////////////////////////////////////////////////// double rangeMin = config.MinimumIntensity; double rangeMax = config.MaximumIntensity; int numberOfBins = config.Bins; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); //Find possible directions std::vector < itk::Offset > offsetVector; NeighborhoodType hood; hood.SetRadius(1); unsigned int centerIndex = hood.GetCenterNeighborhoodIndex(); OffsetType offset; for (unsigned int d = 0; d < centerIndex; d++) { offset = hood.GetOffset(d); bool useOffset = true; for (unsigned int i = 0; i < VImageDimension; ++i) { offset[i] *= config.range; if (config.direction == i + 2 && offset[i] != 0) { useOffset = false; } } if (useOffset) { offsetVector.push_back(offset); } } if (config.direction == 1) { offsetVector.clear(); offset[0] = 0; offset[1] = 0; offset[2] = 1; } std::vector resultVector; mitk::CoocurenceMatrixHolder holderOverall(rangeMin, rangeMax, numberOfBins); mitk::CoocurenceMatrixFeatures overallFeature; for (std::size_t i = 0; i < offsetVector.size(); ++i) { if (config.direction > 1) { if (offsetVector[i][config.direction - 2] != 0) { continue; } } offset = offsetVector[i]; mitk::CoocurenceMatrixHolder holder(rangeMin, rangeMax, numberOfBins); mitk::CoocurenceMatrixFeatures coocResults; CalculateCoOcMatrix(itkImage, maskImage, offset, config.range, holder); holderOverall.m_Matrix += holder.m_Matrix; CalculateFeatures(holder, coocResults); resultVector.push_back(coocResults); } CalculateFeatures(holderOverall, overallFeature); //NormalizeMatrixFeature(overallFeature, offsetVector.size()); mitk::CoocurenceMatrixFeatures featureMean; mitk::CoocurenceMatrixFeatures featureStd; CalculateMeanAndStdDevFeatures(resultVector, featureMean, featureStd); std::ostringstream ss; ss << config.range; std::string strRange = ss.str(); - MatrixFeaturesTo(overallFeature, config.prefix + " Overall", featureList); - MatrixFeaturesTo(featureMean, config.prefix + " Mean", featureList); - MatrixFeaturesTo(featureStd, config.prefix + " Std.Dev.", featureList); + MatrixFeaturesTo(overallFeature, config.prefix + "Overall ", featureList); + MatrixFeaturesTo(featureMean, config.prefix + "Mean ", featureList); + MatrixFeaturesTo(featureStd, config.prefix + "Std.Dev. ", featureList); } static void MatrixFeaturesTo(mitk::CoocurenceMatrixFeatures features, std::string prefix, mitk::GIFCooccurenceMatrix2::FeatureListType &featureList) { featureList.push_back(std::make_pair(prefix + "Joint Maximum", features.JointMaximum)); featureList.push_back(std::make_pair(prefix + "Joint Average", features.JointAverage)); featureList.push_back(std::make_pair(prefix + "Joint Variance", features.JointVariance)); featureList.push_back(std::make_pair(prefix + "Joint Entropy", features.JointEntropy)); - featureList.push_back(std::make_pair(prefix + "Row Maximum", features.RowMaximum)); - featureList.push_back(std::make_pair(prefix + "Row Average", features.RowAverage)); - featureList.push_back(std::make_pair(prefix + "Row Variance", features.RowVariance)); - featureList.push_back(std::make_pair(prefix + "Row Entropy", features.RowEntropy)); - featureList.push_back(std::make_pair(prefix + "First Row-Column Entropy", features.FirstRowColumnEntropy)); - featureList.push_back(std::make_pair(prefix + "Second Row-Column Entropy", features.SecondRowColumnEntropy)); featureList.push_back(std::make_pair(prefix + "Difference Average", features.DifferenceAverage)); featureList.push_back(std::make_pair(prefix + "Difference Variance", features.DifferenceVariance)); featureList.push_back(std::make_pair(prefix + "Difference Entropy", features.DifferenceEntropy)); featureList.push_back(std::make_pair(prefix + "Sum Average", features.SumAverage)); featureList.push_back(std::make_pair(prefix + "Sum Variance", features.SumVariance)); featureList.push_back(std::make_pair(prefix + "Sum Entropy", features.SumEntropy)); featureList.push_back(std::make_pair(prefix + "Angular Second Moment", features.AngularSecondMoment)); featureList.push_back(std::make_pair(prefix + "Contrast", features.Contrast)); featureList.push_back(std::make_pair(prefix + "Dissimilarity", features.Dissimilarity)); featureList.push_back(std::make_pair(prefix + "Inverse Difference", features.InverseDifference)); featureList.push_back(std::make_pair(prefix + "Inverse Difference Normalized", features.InverseDifferenceNormalised)); featureList.push_back(std::make_pair(prefix + "Inverse Difference Moment", features.InverseDifferenceMoment)); featureList.push_back(std::make_pair(prefix + "Inverse Difference Moment Normalized", features.InverseDifferenceMomentNormalised)); - featureList.push_back(std::make_pair(prefix + " Inverse Variance", features.InverseVariance)); + featureList.push_back(std::make_pair(prefix + "Inverse Variance", features.InverseVariance)); featureList.push_back(std::make_pair(prefix + "Correlation", features.Correlation)); - featureList.push_back(std::make_pair(prefix + "Autocorrleation", features.Autocorrelation)); + featureList.push_back(std::make_pair(prefix + "Autocorrelation", features.Autocorrelation)); featureList.push_back(std::make_pair(prefix + "Cluster Tendency", features.ClusterTendency)); featureList.push_back(std::make_pair(prefix + "Cluster Shade", features.ClusterShade)); featureList.push_back(std::make_pair(prefix + "Cluster Prominence", features.ClusterProminence)); featureList.push_back(std::make_pair(prefix + "First Measure of Information Correlation", features.FirstMeasureOfInformationCorrelation)); featureList.push_back(std::make_pair(prefix + "Second Measure of Information Correlation", features.SecondMeasureOfInformationCorrelation)); + featureList.push_back(std::make_pair(prefix + "Row Maximum", features.RowMaximum)); + featureList.push_back(std::make_pair(prefix + "Row Average", features.RowAverage)); + featureList.push_back(std::make_pair(prefix + "Row Variance", features.RowVariance)); + featureList.push_back(std::make_pair(prefix + "Row Entropy", features.RowEntropy)); + featureList.push_back(std::make_pair(prefix + "First Row-Column Entropy", features.FirstRowColumnEntropy)); + featureList.push_back(std::make_pair(prefix + "Second Row-Column Entropy", features.SecondRowColumnEntropy)); } static void CalculateMeanAndStdDevFeatures(std::vector featureList, mitk::CoocurenceMatrixFeatures &meanFeature, mitk::CoocurenceMatrixFeatures &stdFeature) { #define ADDFEATURE(a) meanFeature.a += featureList[i].a;stdFeature.a += featureList[i].a*featureList[i].a #define CALCVARIANCE(a) stdFeature.a =sqrt(stdFeature.a - meanFeature.a*meanFeature.a) for (std::size_t i = 0; i < featureList.size(); ++i) { ADDFEATURE(JointMaximum); ADDFEATURE(JointAverage); ADDFEATURE(JointVariance); ADDFEATURE(JointEntropy); ADDFEATURE(RowMaximum); ADDFEATURE(RowAverage); ADDFEATURE(RowVariance); ADDFEATURE(RowEntropy); ADDFEATURE(FirstRowColumnEntropy); ADDFEATURE(SecondRowColumnEntropy); ADDFEATURE(DifferenceAverage); ADDFEATURE(DifferenceVariance); ADDFEATURE(DifferenceEntropy); ADDFEATURE(SumAverage); ADDFEATURE(SumVariance); ADDFEATURE(SumEntropy); ADDFEATURE(AngularSecondMoment); ADDFEATURE(Contrast); ADDFEATURE(Dissimilarity); ADDFEATURE(InverseDifference); ADDFEATURE(InverseDifferenceNormalised); ADDFEATURE(InverseDifferenceMoment); ADDFEATURE(InverseDifferenceMomentNormalised); ADDFEATURE(InverseVariance); ADDFEATURE(Correlation); ADDFEATURE(Autocorrelation); ADDFEATURE(ClusterShade); ADDFEATURE(ClusterTendency); ADDFEATURE(ClusterProminence); ADDFEATURE(FirstMeasureOfInformationCorrelation); ADDFEATURE(SecondMeasureOfInformationCorrelation); } NormalizeMatrixFeature(meanFeature, featureList.size()); NormalizeMatrixFeature(stdFeature, featureList.size()); CALCVARIANCE(JointMaximum); CALCVARIANCE(JointAverage); CALCVARIANCE(JointVariance); CALCVARIANCE(JointEntropy); CALCVARIANCE(RowMaximum); CALCVARIANCE(RowAverage); CALCVARIANCE(RowVariance); CALCVARIANCE(RowEntropy); CALCVARIANCE(FirstRowColumnEntropy); CALCVARIANCE(SecondRowColumnEntropy); CALCVARIANCE(DifferenceAverage); CALCVARIANCE(DifferenceVariance); CALCVARIANCE(DifferenceEntropy); CALCVARIANCE(SumAverage); CALCVARIANCE(SumVariance); CALCVARIANCE(SumEntropy); CALCVARIANCE(AngularSecondMoment); CALCVARIANCE(Contrast); CALCVARIANCE(Dissimilarity); CALCVARIANCE(InverseDifference); CALCVARIANCE(InverseDifferenceNormalised); CALCVARIANCE(InverseDifferenceMoment); CALCVARIANCE(InverseDifferenceMomentNormalised); CALCVARIANCE(InverseVariance); CALCVARIANCE(Correlation); CALCVARIANCE(Autocorrelation); CALCVARIANCE(ClusterShade); CALCVARIANCE(ClusterTendency); CALCVARIANCE(ClusterProminence); CALCVARIANCE(FirstMeasureOfInformationCorrelation); CALCVARIANCE(SecondMeasureOfInformationCorrelation); #undef ADDFEATURE #undef CALCVARIANCE } static void NormalizeMatrixFeature(mitk::CoocurenceMatrixFeatures &features, std::size_t number) { features.JointMaximum = features.JointMaximum / number; features.JointAverage = features.JointAverage / number; features.JointVariance = features.JointVariance / number; features.JointEntropy = features.JointEntropy / number; features.RowMaximum = features.RowMaximum / number; features.RowAverage = features.RowAverage / number; features.RowVariance = features.RowVariance / number; features.RowEntropy = features.RowEntropy / number; features.FirstRowColumnEntropy = features.FirstRowColumnEntropy / number; features.SecondRowColumnEntropy = features.SecondRowColumnEntropy / number; features.DifferenceAverage = features.DifferenceAverage / number; features.DifferenceVariance = features.DifferenceVariance / number; features.DifferenceEntropy = features.DifferenceEntropy / number; features.SumAverage = features.SumAverage / number; features.SumVariance = features.SumVariance / number; features.SumEntropy = features.SumEntropy / number; features.AngularSecondMoment = features.AngularSecondMoment / number; features.Contrast = features.Contrast / number; features.Dissimilarity = features.Dissimilarity / number; features.InverseDifference = features.InverseDifference / number; features.InverseDifferenceNormalised = features.InverseDifferenceNormalised / number; features.InverseDifferenceMoment = features.InverseDifferenceMoment / number; features.InverseDifferenceMomentNormalised = features.InverseDifferenceMomentNormalised / number; features.InverseVariance = features.InverseVariance / number; features.Correlation = features.Correlation / number; features.Autocorrelation = features.Autocorrelation / number; features.ClusterShade = features.ClusterShade / number; features.ClusterTendency = features.ClusterTendency / number; features.ClusterProminence = features.ClusterProminence / number; features.FirstMeasureOfInformationCorrelation = features.FirstMeasureOfInformationCorrelation / number; features.SecondMeasureOfInformationCorrelation = features.SecondMeasureOfInformationCorrelation / number; } mitk::GIFCooccurenceMatrix2::GIFCooccurenceMatrix2(): m_Range(1.0) { SetShortName("cooc2"); SetLongName("cooccurence2"); SetFeatureClassName("Co-occurenced Based Features"); } mitk::GIFCooccurenceMatrix2::FeatureListType mitk::GIFCooccurenceMatrix2::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { InitializeQuantifier(image, mask); FeatureListType featureList; GIFCooccurenceMatrix2Configuration config; config.direction = GetDirection(); config.range = m_Range; config.MinimumIntensity = GetQuantifier()->GetMinimum(); config.MaximumIntensity = GetQuantifier()->GetMaximum(); config.Bins = GetQuantifier()->GetBins(); config.prefix = FeatureDescriptionPrefix(); AccessByItk_3(image, CalculateCoocurenceFeatures, mask, featureList,config); return featureList; } mitk::GIFCooccurenceMatrix2::FeatureNameListType mitk::GIFCooccurenceMatrix2::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFCooccurenceMatrix2::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Co-occurence matrix", "calculates Co-occurence based features (new implementation)", us::Any()); parser.addArgument(name+"::range", name+"::range", mitkCommandLineParser::String, "Cooc 2 Range", "Define the range that is used (Semicolon-separated)", us::Any()); AddQuantifierArguments(parser); } void mitk::GIFCooccurenceMatrix2::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) { auto parsedArgs = GetParameter(); std::string name = GetOptionPrefix(); if (parsedArgs.count(GetLongName())) { InitializeQuantifierFromParameters(feature, maskNoNAN); std::vector ranges; if (parsedArgs.count(name + "::range")) { ranges = SplitDouble(parsedArgs[name + "::range"].ToString(), ';'); } else { ranges.push_back(1); } for (std::size_t i = 0; i < ranges.size(); ++i) { MITK_INFO << "Start calculating coocurence with range " << ranges[i] << "...."; this->SetRange(ranges[i]); auto localResults = this->CalculateFeatures(feature, maskNoNAN); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating coocurence with range " << ranges[i] << "...."; } } } std::string mitk::GIFCooccurenceMatrix2::GetCurrentFeatureEncoding() { std::ostringstream ss; ss << m_Range; std::string strRange = ss.str(); return QuantifierParameterString() + "_Range-" + ss.str(); } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp new file mode 100644 index 0000000000..38f3a7ad77 --- /dev/null +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFFirstOrderNumericStatistics.cpp @@ -0,0 +1,357 @@ +/*=================================================================== + +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 + +// MITK +#include +#include +#include + +// ITK +#include +#include +#include + +// STL +#include + +struct FirstOrderNumericParameterStruct { + mitk::IntensityQuantifier::Pointer quantifier; + double MinimumIntensity; + double MaximumIntensity; + int Bins; + std::string prefix; +}; + +template +void +CalculateFirstOrderStatistics(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFFirstOrderNumericStatistics::FeatureListType & featureList, FirstOrderNumericParameterStruct params) +{ + typedef itk::Image ImageType; + typedef itk::Image MaskType; + + typename MaskType::Pointer maskImage = MaskType::New(); + mitk::CastToItkImage(mask, maskImage); + + // + // Calculate the Volume of Voxel (Maximum to the 3th order) + // + double voxelVolume = 1; + for (unsigned int i = 0; i < std::min(3, VImageDimension); ++i) + voxelVolume *= itkImage->GetSpacing()[i]; + + // + // Calculate the Hypervolume of Voxel + // + double voxelSpace = 1; + for (unsigned int i = 0; i < VImageDimension; ++i) + voxelSpace *= itkImage->GetSpacing()[i]; + + unsigned int numberOfBins = params.quantifier->GetBins(); + std::vector histogram; + histogram.resize(numberOfBins, 0); + + + double minimum = std::numeric_limits::max(); + double maximum = std::numeric_limits::lowest(); + double absoluteMinimum = std::numeric_limits::max(); + double absoluteMaximum = std::numeric_limits::lowest(); + double sum = 0; + double sumTwo= 0; + double sumThree = 0; + unsigned int numberOfVoxels = 0; + + itk::ImageRegionIterator imageIter(itkImage, itkImage->GetLargestPossibleRegion()); + itk::ImageRegionIterator maskIter(maskImage, maskImage->GetLargestPossibleRegion()); + + while (!imageIter.IsAtEnd()) + { + double value = imageIter.Get(); + + absoluteMinimum = std::min(minimum, value); + absoluteMaximum = std::max(maximum, value); + if (maskIter.Get() > 0) + { + minimum = std::min(minimum, value); + maximum = std::max(maximum, value); + + sum += value; + sumTwo += value * value; + sumThree += value * value*value; + + histogram[params.quantifier->IntensityToIndex(value)] += 1; + + ++numberOfVoxels; + } + ++maskIter; + ++imageIter; + } + + // + // Histogram based calculations + // + unsigned int passedValues = 0; + double doubleNoOfVoxes = numberOfVoxels; + double median = 0; + double lastIntensityWithValues = params.quantifier->IndexToMeanIntensity(0); + std::size_t modeIdx = 0; + + double entropy = 0; + double uniformity = 0; + + std::vector percentiles; + percentiles.resize(20, 0); + + for (std::size_t idx = 0; idx < histogram.size(); ++idx) + { + unsigned int actualValues = histogram[idx]; + + for (std::size_t percentileIdx = 0; percentileIdx < percentiles.size(); ++percentileIdx) + { + double threshold = doubleNoOfVoxes * (percentileIdx + 1) *1.0 / (percentiles.size()); + if ((passedValues < threshold) & ((passedValues + actualValues) >= threshold)) + { + // Lower Bound + if (passedValues == std::floor(threshold)) + { + percentiles[percentileIdx] = 0.5*(lastIntensityWithValues + params.quantifier->IndexToMeanIntensity(idx)); + } + else + { + percentiles[percentileIdx] = params.quantifier->IndexToMeanIntensity(idx); + } + } + } + + if ((passedValues < doubleNoOfVoxes * 0.5) & ((passedValues + actualValues) >= doubleNoOfVoxes * 0.5)) + { + // Lower Bound + if (passedValues == std::floor(doubleNoOfVoxes * 0.5)) + { + median = 0.5*(lastIntensityWithValues + params.quantifier->IndexToMeanIntensity(idx)); + } + else + { + median = params.quantifier->IndexToMeanIntensity(idx); + } + } + + if (actualValues > histogram[modeIdx]) + { + modeIdx = idx; + } + + if (actualValues > 0) + { + lastIntensityWithValues = params.quantifier->IndexToMeanIntensity(idx); + + double currentProbability = actualValues / (1.0 *numberOfVoxels); + uniformity += currentProbability * currentProbability; + entropy += currentProbability * std::log(currentProbability) / std::log(2); + } + passedValues += actualValues; + } + double p10 = percentiles[1]; + double p25idx = params.quantifier->IntensityToIndex(percentiles[4]); + double p75idx = params.quantifier->IntensityToIndex(percentiles[14]); + double p90 = percentiles[17]; + + double mean = sum / (numberOfVoxels); + double variance = sumTwo / (numberOfVoxels) - (mean*mean); + double energy = sumTwo; + double rootMeanSquare = std::sqrt(sumTwo / numberOfVoxels); + + double sumAbsoluteDistanceToMean = 0; + double sumAbsoluteDistanceToMedian = 0; + double sumRobust = 0; + double sumRobustSquare = 0; + double sumRobustAbsolulteDistanceToMean = 0; + double sumValueMinusMean = 0; + double sumValueMinusMeanThree = 0; + double sumValueMinusMeanFour = 0; + unsigned int numberOfRobustVoxel = 0; + + + maskIter.GoToBegin(); + imageIter.GoToBegin(); + while (!imageIter.IsAtEnd()) + { + if (maskIter.Get() > 0) + { + double value = imageIter.Get(); + double valueMinusMean = value - mean; + + sumAbsoluteDistanceToMean += std::abs(valueMinusMean); + sumAbsoluteDistanceToMedian += std::abs(value - median); + sumValueMinusMean += valueMinusMean; + sumValueMinusMeanThree += valueMinusMean * valueMinusMean * valueMinusMean; + sumValueMinusMeanFour += valueMinusMean * valueMinusMean * valueMinusMean * valueMinusMean; + + if ((p10 <= value) & (value <= p90)) + { + sumRobust += value; + sumRobustSquare += value * value; + ++numberOfRobustVoxel; + } + } + ++maskIter; + ++imageIter; + } + double robustMean = sumRobust / numberOfRobustVoxel; + double robustVariance = sumRobustSquare / numberOfRobustVoxel - (robustMean * robustMean); + + maskIter.GoToBegin(); + imageIter.GoToBegin(); + while (!imageIter.IsAtEnd()) + { + if (maskIter.Get() > 0) + { + double value = imageIter.Get(); + + if ((p10 <= value) & (value <= p90)) + { + sumRobustAbsolulteDistanceToMean += std::abs(value - robustMean); + } + } + ++maskIter; + ++imageIter; + } + + + + double meanAbsoluteDeviation = sumAbsoluteDistanceToMean / numberOfVoxels; + double medianAbsoluteDeviation = sumAbsoluteDistanceToMedian / numberOfVoxels; + double robustMeanAbsoluteDeviation = sumRobustAbsolulteDistanceToMean / numberOfRobustVoxel; + double skewness = sumValueMinusMeanThree / numberOfVoxels / variance / std::sqrt(variance); + double kurtosis = sumValueMinusMeanFour / numberOfVoxels / variance / variance; + double interquantileRange = p75idx - p25idx; + double coefficientOfVariation = std::sqrt(variance) / mean; + double quantileCoefficientOfDispersion = (p75idx - p25idx) / (p75idx + p25idx + 2); + double coveredImageRange = (maximum - minimum)/ (absoluteMaximum - absoluteMinimum) ; + + featureList.push_back(std::make_pair(params.prefix + "Mean", mean)); + featureList.push_back(std::make_pair(params.prefix + "Variance", variance)); + featureList.push_back(std::make_pair(params.prefix + "Skewness", skewness)); + featureList.push_back(std::make_pair(params.prefix + "Excess kurtosis", kurtosis-3)); + featureList.push_back(std::make_pair(params.prefix + "Median", median)); + featureList.push_back(std::make_pair(params.prefix + "Minimum", minimum)); + featureList.push_back(std::make_pair(params.prefix + "05th Percentile", percentiles[0])); + featureList.push_back(std::make_pair(params.prefix + "10th Percentile", percentiles[1])); + featureList.push_back(std::make_pair(params.prefix + "15th Percentile", percentiles[2])); + featureList.push_back(std::make_pair(params.prefix + "20th Percentile", percentiles[3])); + featureList.push_back(std::make_pair(params.prefix + "25th Percentile", percentiles[4])); + featureList.push_back(std::make_pair(params.prefix + "30th Percentile", percentiles[5])); + featureList.push_back(std::make_pair(params.prefix + "35th Percentile", percentiles[6])); + featureList.push_back(std::make_pair(params.prefix + "40th Percentile", percentiles[7])); + featureList.push_back(std::make_pair(params.prefix + "45th Percentile", percentiles[8])); + featureList.push_back(std::make_pair(params.prefix + "50th Percentile", percentiles[9])); + featureList.push_back(std::make_pair(params.prefix + "55th Percentile", percentiles[10])); + featureList.push_back(std::make_pair(params.prefix + "60th Percentile", percentiles[11])); + featureList.push_back(std::make_pair(params.prefix + "65th Percentile", percentiles[12])); + featureList.push_back(std::make_pair(params.prefix + "70th Percentile", percentiles[13])); + featureList.push_back(std::make_pair(params.prefix + "75th Percentile", percentiles[14])); + featureList.push_back(std::make_pair(params.prefix + "80th Percentile", percentiles[15])); + featureList.push_back(std::make_pair(params.prefix + "85th Percentile", percentiles[16])); + featureList.push_back(std::make_pair(params.prefix + "90th Percentile", percentiles[17])); + featureList.push_back(std::make_pair(params.prefix + "95th Percentile", percentiles[18])); + featureList.push_back(std::make_pair(params.prefix + "Maximum", maximum)); + featureList.push_back(std::make_pair(params.prefix + "Interquantile range", interquantileRange)); + featureList.push_back(std::make_pair(params.prefix + "Range", maximum-minimum)); + featureList.push_back(std::make_pair(params.prefix + "Mean absolute deviation", meanAbsoluteDeviation)); + featureList.push_back(std::make_pair(params.prefix + "Robust mean absolute deviation", robustMeanAbsoluteDeviation)); + featureList.push_back(std::make_pair(params.prefix + "Median absolute deviation", medianAbsoluteDeviation)); + featureList.push_back(std::make_pair(params.prefix + "Coefficient of variation", coefficientOfVariation)); + featureList.push_back(std::make_pair(params.prefix + "Quantile coefficient of dispersion", quantileCoefficientOfDispersion)); + featureList.push_back(std::make_pair(params.prefix + "Energy", energy)); + featureList.push_back(std::make_pair(params.prefix + "Root mean square", rootMeanSquare)); + + featureList.push_back(std::make_pair(params.prefix + "Standard Deviation", std::sqrt(variance))); + featureList.push_back(std::make_pair(params.prefix + "Kurtosis", kurtosis)); + featureList.push_back(std::make_pair(params.prefix + "Robust mean", robustMean)); + featureList.push_back(std::make_pair(params.prefix + "Robust variance", robustVariance)); + featureList.push_back(std::make_pair(params.prefix + "Covered image intensity range", coveredImageRange)); + featureList.push_back(std::make_pair(params.prefix + "Mode index", modeIdx)); + featureList.push_back(std::make_pair(params.prefix + "Mode value", params.quantifier->IndexToMeanIntensity(modeIdx))); + featureList.push_back(std::make_pair(params.prefix + "Mode probability", histogram[modeIdx] / (1.0*numberOfVoxels))); + featureList.push_back(std::make_pair(params.prefix + "Entropy", entropy)); + featureList.push_back(std::make_pair(params.prefix + "Uniformtiy", uniformity)); + featureList.push_back(std::make_pair(params.prefix + "Number of voxels", numberOfVoxels)); + featureList.push_back(std::make_pair(params.prefix + "Sum of voxels", sum)); + featureList.push_back(std::make_pair(params.prefix + "Voxel space", voxelSpace)); + featureList.push_back(std::make_pair(params.prefix + "Voxel volume", voxelVolume)); + featureList.push_back(std::make_pair(params.prefix + "Image Dimension", VImageDimension)); + + return; +} + +mitk::GIFFirstOrderNumericStatistics::GIFFirstOrderNumericStatistics() +{ + SetShortName("fon"); + SetLongName("first-order-numeric"); + SetFeatureClassName("First Order Numeric"); +} + +mitk::GIFFirstOrderNumericStatistics::FeatureListType mitk::GIFFirstOrderNumericStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) +{ + InitializeQuantifier(image, mask); + FeatureListType featureList; + + FirstOrderNumericParameterStruct params; + + params.quantifier = GetQuantifier(); + params.MinimumIntensity = GetQuantifier()->GetMinimum(); + params.MaximumIntensity = GetQuantifier()->GetMaximum(); + params.Bins = GetQuantifier()->GetBins(); + params.prefix = FeatureDescriptionPrefix(); + AccessByItk_3(image, CalculateFirstOrderStatistics, mask, featureList, params); + + return featureList; +} + +mitk::GIFFirstOrderNumericStatistics::FeatureNameListType mitk::GIFFirstOrderNumericStatistics::GetFeatureNames() +{ + FeatureNameListType featureList; + return featureList; +} + + +void mitk::GIFFirstOrderNumericStatistics::AddArguments(mitkCommandLineParser &parser) +{ + std::string name = GetOptionPrefix(); + + parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use First Order Statistic (Numeric)", "calculates First Order Statistic (Numeric)", us::Any()); + AddQuantifierArguments(parser); +} + +void +mitk::GIFFirstOrderNumericStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) +{ + auto parsedArgs = GetParameter(); + if (parsedArgs.count(GetLongName())) + { + InitializeQuantifierFromParameters(feature, maskNoNAN); + MITK_INFO << "Start calculating first order features ...."; + auto localResults = this->CalculateFeatures(feature, maskNoNAN); + featureList.insert(featureList.end(), localResults.begin(), localResults.end()); + MITK_INFO << "Finished calculating first order features...."; + } +} + +std::string mitk::GIFFirstOrderNumericStatistics::GetCurrentFeatureEncoding() +{ + return QuantifierParameterString(); +} \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp index 827b67b4ef..29cf808810 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFImageDescriptionFeatures.cpp @@ -1,177 +1,177 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include // MITK #include #include #include // ITK #include #include #include // STL #include template static void CalculateFirstOrderStatistics(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFImageDescriptionFeatures::FeatureListType & featureList, std::string prefix) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::MinimumMaximumImageCalculator MinMaxComputerType; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); unsigned int imageDimensionX = itkImage->GetLargestPossibleRegion().GetSize()[0]; unsigned int imageDimensionY = itkImage->GetLargestPossibleRegion().GetSize()[1]; unsigned int imageDimensionZ = itkImage->GetLargestPossibleRegion().GetSize()[2]; double imageVoxelSpacingX = itkImage->GetSpacing()[0]; double imageVoxelSpacingY = itkImage->GetSpacing()[1]; double imageVoxelSpacingZ = itkImage->GetSpacing()[2]; typename MinMaxComputerType::Pointer minMaxComputer = MinMaxComputerType::New(); minMaxComputer->SetImage(itkImage); minMaxComputer->Compute(); double imageMinimum = minMaxComputer->GetMinimum(); double imageMaximum = minMaxComputer->GetMaximum(); unsigned int maskDimensionX = maskImage->GetLargestPossibleRegion().GetSize()[0]; unsigned int maskDimensionY = maskImage->GetLargestPossibleRegion().GetSize()[1]; unsigned int maskDimensionZ = maskImage->GetLargestPossibleRegion().GetSize()[2]; double maskVoxelSpacingX = maskImage->GetSpacing()[0]; double maskVoxelSpacingY = maskImage->GetSpacing()[1]; double maskVoxelSpacingZ = maskImage->GetSpacing()[2]; unsigned int voxelCount = 0; unsigned int maskVoxelCount = 0; double maskMinimum = imageMaximum; double maskMaximum = imageMinimum; double imageMean = 0; double maskMean = 0; - unsigned int maskMinimumX = maskDimensionX; - unsigned int maskMaximumX = 0; - unsigned int maskMinimumY = maskDimensionY; - unsigned int maskMaximumY = 0; - unsigned int maskMinimumZ = maskDimensionZ; - unsigned int maskMaximumZ = 0; + int maskMinimumX = maskDimensionX; + int maskMaximumX = 0; + int maskMinimumY = maskDimensionY; + int maskMaximumY = 0; + int maskMinimumZ = maskDimensionZ; + int maskMaximumZ = 0; itk::ImageRegionConstIteratorWithIndex imIter(itkImage, itkImage->GetLargestPossibleRegion()); itk::ImageRegionConstIteratorWithIndex maIter(maskImage, maskImage->GetLargestPossibleRegion()); while (!imIter.IsAtEnd()) { auto pixelValue = imIter.Get(); if (maIter.Get() > 0) { ++maskVoxelCount; maskMean += pixelValue; maskMinimum = (maskMinimum > pixelValue) ? pixelValue : maskMinimum; maskMaximum = (maskMaximum < pixelValue) ? pixelValue : maskMaximum; maskMinimumX = (maskMinimumX > imIter.GetIndex()[0]) ? imIter.GetIndex()[0] : maskMinimumX; maskMaximumX = (maskMaximumX < imIter.GetIndex()[0]) ? imIter.GetIndex()[0] : maskMaximumX; maskMinimumY = (maskMinimumY > imIter.GetIndex()[1]) ? imIter.GetIndex()[1] : maskMinimumY; maskMaximumY = (maskMaximumY < imIter.GetIndex()[1]) ? imIter.GetIndex()[1] : maskMaximumY; maskMinimumZ = (maskMinimumZ > imIter.GetIndex()[2]) ? imIter.GetIndex()[2] : maskMinimumZ; maskMaximumZ = (maskMaximumZ < imIter.GetIndex()[2]) ? imIter.GetIndex()[2] : maskMaximumZ; } ++voxelCount; imageMean += pixelValue; ++imIter; ++maIter; } imageMean /= voxelCount; maskMean /= maskVoxelCount; featureList.push_back(std::make_pair(prefix + "Image Dimension X", imageDimensionX)); featureList.push_back(std::make_pair(prefix + "Image Dimension Y", imageDimensionY)); featureList.push_back(std::make_pair(prefix + "Image Dimension Z", imageDimensionZ)); featureList.push_back(std::make_pair(prefix + "Image Spacing X", imageVoxelSpacingX)); featureList.push_back(std::make_pair(prefix + "Image Spacing Y", imageVoxelSpacingY)); featureList.push_back(std::make_pair(prefix + "Image Spacing Z", imageVoxelSpacingZ)); featureList.push_back(std::make_pair(prefix + "Image Mean intensity", imageMean)); featureList.push_back(std::make_pair(prefix + "Image Minimum intensity", imageMinimum)); featureList.push_back(std::make_pair(prefix + "Image Maximum intensity", imageMaximum)); featureList.push_back(std::make_pair(prefix + "Mask Dimension X", maskDimensionX)); featureList.push_back(std::make_pair(prefix + "Mask Dimension Y", maskDimensionY)); featureList.push_back(std::make_pair(prefix + "Mask Dimension Z", maskDimensionZ)); featureList.push_back(std::make_pair(prefix + "Mask bounding box X", maskMaximumX - maskMinimumX + 1)); featureList.push_back(std::make_pair(prefix + "Mask bounding box Y", maskMaximumY - maskMinimumY + 1)); featureList.push_back(std::make_pair(prefix + "Mask bounding box Z", maskMaximumZ - maskMinimumZ + 1)); featureList.push_back(std::make_pair(prefix + "Mask Spacing X", maskVoxelSpacingX)); featureList.push_back(std::make_pair(prefix + "Mask Spacing Y", maskVoxelSpacingY)); featureList.push_back(std::make_pair(prefix + "Mask Spacing Z", maskVoxelSpacingZ)); featureList.push_back(std::make_pair(prefix + "Mask Voxel Count", maskVoxelCount)); featureList.push_back(std::make_pair(prefix + "Mask Mean intensity", maskMean)); featureList.push_back(std::make_pair(prefix + "Mask Minimum intensity", maskMinimum)); featureList.push_back(std::make_pair(prefix + "Mask Maximum intensity", maskMaximum)); } mitk::GIFImageDescriptionFeatures::GIFImageDescriptionFeatures() { SetShortName("id"); SetLongName("image-diagnostic"); SetFeatureClassName("Diagnostic"); } mitk::GIFImageDescriptionFeatures::FeatureListType mitk::GIFImageDescriptionFeatures::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; AccessByItk_3(image, CalculateFirstOrderStatistics, mask, featureList, FeatureDescriptionPrefix()); return featureList; } mitk::GIFImageDescriptionFeatures::FeatureNameListType mitk::GIFImageDescriptionFeatures::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFImageDescriptionFeatures::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Image Description", "calculates image description features", us::Any()); } void mitk::GIFImageDescriptionFeatures::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &, const Image::Pointer &maskNoNAN, FeatureListType &featureList) { auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { MITK_INFO << "Start calculating image description features...."; auto localResults = this->CalculateFeatures(feature, maskNoNAN); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating image description features...."; } } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp index d29b4a9e0e..a531a1043d 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFIntensityVolumeHistogramFeatures.cpp @@ -1,173 +1,173 @@ /*=================================================================== 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 // MITK #include #include #include #include // ITK #include #include // STL #include struct GIFIntensityVolumeHistogramFeaturesParameters { mitk::IntensityQuantifier::Pointer quantifier; std::string prefix; }; template static void CalculateIntensityPeak(itk::Image* itkImage, mitk::Image::Pointer mask, GIFIntensityVolumeHistogramFeaturesParameters params, mitk::GIFIntensityVolumeHistogramFeatures::FeatureListType & featureList) { typedef itk::Image ImageType; typedef itk::Image MaskType; typename MaskType::Pointer itkMask = MaskType::New(); mitk::CastToItkImage(mask, itkMask); mitk::IntensityQuantifier::Pointer quantifier = params.quantifier; std::string prefix = params.prefix; itk::ImageRegionConstIterator iter(itkImage, itkImage->GetLargestPossibleRegion()); itk::ImageRegionConstIterator iterMask(itkMask, itkMask->GetLargestPossibleRegion()); MITK_INFO << "Quantification: " << quantifier->GetMinimum() << " to " << quantifier->GetMaximum() << " with " << quantifier->GetBins()<< " bins"; iter.GoToBegin(); iterMask.GoToBegin(); std::vector hist; hist.resize(quantifier->GetBins() , 0); int count = 0; while (!iter.IsAtEnd()) { if (iterMask.Get() > 0) { double value = iter.Get(); //std::size_t index = std::floor((value - minimum) / (maximum - minimum) * (bins-1)); std::size_t index = quantifier->IntensityToIndex(value); ++count; hist[index] += 1.0;// / count; } ++iterMask; ++iter; } bool notFoundIntenstiy010 = true; bool notFoundIntenstiy090 = true; double intensity010 = -1; double intensity090 = -1; double fraction = 0; double auc = 0; bool firstRound = true; for (int i = quantifier->GetBins()-1; i >= 0; --i) { hist[i] /= count; hist[i] += fraction; fraction = hist[i]; if (!firstRound) { auc += 0.5 * (hist[i] + hist[i+1]) / (quantifier->GetBins()-1); } firstRound = false; if (notFoundIntenstiy010 && fraction > 0.1) { intensity010 = quantifier->IndexToMeanIntensity(i + 1); notFoundIntenstiy010 = false; } if (notFoundIntenstiy090 && fraction > 0.9) { intensity090 = quantifier->IndexToMeanIntensity(i + 1); notFoundIntenstiy090 = false; } } unsigned int index010 = std::ceil(quantifier->GetBins() * 0.1); unsigned int index090 = std::floor(quantifier->GetBins() * 0.9); - featureList.push_back(std::make_pair(prefix + "Volume fration at 0.10 intensity", hist[index010])); - featureList.push_back(std::make_pair(prefix + "Volume fration at 0.90 intensity", hist[index090])); + featureList.push_back(std::make_pair(prefix + "Volume fraction at 0.10 intensity", hist[index010])); + featureList.push_back(std::make_pair(prefix + "Volume fraction at 0.90 intensity", hist[index090])); featureList.push_back(std::make_pair(prefix + "Intensity at 0.10 volume", intensity010)); featureList.push_back(std::make_pair(prefix + "Intensity at 0.90 volume", intensity090)); - featureList.push_back(std::make_pair(prefix + "Difference volume fration at 0.10 and 0.90 intensity", std::abs(hist[index010] - hist[index090]))); + featureList.push_back(std::make_pair(prefix + "Difference volume fraction at 0.10 and 0.90 intensity", std::abs(hist[index010] - hist[index090]))); featureList.push_back(std::make_pair(prefix + "Difference intensity at 0.10 and 0.90 volume", std::abs(intensity090 - intensity010))); featureList.push_back(std::make_pair(prefix + "Area under IVH curve", auc)); //featureList.push_back(std::make_pair("Local Intensity Global Intensity Peak", globalPeakValue)); } mitk::GIFIntensityVolumeHistogramFeatures::GIFIntensityVolumeHistogramFeatures() { SetLongName("intensity-volume-histogram"); SetShortName("ivoh"); SetFeatureClassName("Intensity Volume Histogram"); } mitk::GIFIntensityVolumeHistogramFeatures::FeatureListType mitk::GIFIntensityVolumeHistogramFeatures::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { InitializeQuantifier(image, mask, 1000); FeatureListType featureList; GIFIntensityVolumeHistogramFeaturesParameters params; params.quantifier = GetQuantifier(); params.prefix = FeatureDescriptionPrefix(); AccessByItk_3(image, CalculateIntensityPeak, mask, params, featureList); return featureList; } mitk::GIFIntensityVolumeHistogramFeatures::FeatureNameListType mitk::GIFIntensityVolumeHistogramFeatures::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFIntensityVolumeHistogramFeatures::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Local Intensity", "calculates local intensity based features", us::Any()); AddQuantifierArguments(parser); } void mitk::GIFIntensityVolumeHistogramFeatures::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &, FeatureListType &featureList) { InitializeQuantifierFromParameters(feature, mask, 1000); auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { MITK_INFO << "Start calculating local intensity features ...."; auto localResults = this->CalculateFeatures(feature, mask); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating local intensity features...."; } } std::string mitk::GIFIntensityVolumeHistogramFeatures::GetCurrentFeatureEncoding() { return QuantifierParameterString(); } diff --git a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp index 7353fd353a..cd26bcfddb 100644 --- a/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp +++ b/Modules/Classification/CLUtilities/src/GlobalImageFeatures/mitkGIFVolumetricStatistics.cpp @@ -1,460 +1,460 @@ /*=================================================================== 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 // MITK #include #include #include #include #include // ITK #include #include // VTK #include #include #include #include #include #include // STL #include template void CalculateVolumeStatistic(itk::Image* itkImage, mitk::Image::Pointer mask, mitk::GIFVolumetricStatistics::FeatureListType & featureList, std::string prefix) { typedef itk::Image ImageType; typedef itk::Image MaskType; typedef itk::LabelStatisticsImageFilter FilterType; typename MaskType::Pointer maskImage = MaskType::New(); mitk::CastToItkImage(mask, maskImage); typename FilterType::Pointer labelStatisticsImageFilter = FilterType::New(); labelStatisticsImageFilter->SetInput( itkImage ); labelStatisticsImageFilter->SetLabelInput(maskImage); labelStatisticsImageFilter->Update(); double volume = labelStatisticsImageFilter->GetCount(1); double voxelVolume = 1; for (int i = 0; i < (int)(VImageDimension); ++i) { volume *= itkImage->GetSpacing()[i]; voxelVolume *= itkImage->GetSpacing()[i]; } featureList.push_back(std::make_pair(prefix + "Voxel Volume", voxelVolume)); featureList.push_back(std::make_pair(prefix + "Volume (voxel based)", volume)); } template void CalculateLargestDiameter(itk::Image* mask, mitk::Image::Pointer valueImage, mitk::GIFVolumetricStatistics::FeatureListType & featureList, std::string prefix) { typedef itk::Image ValueImageType; typename ValueImageType::Pointer itkValueImage = ValueImageType::New(); mitk::CastToItkImage(valueImage, itkValueImage); typedef itk::Image ImageType; typedef typename ImageType::PointType PointType; typename ImageType::SizeType radius; for (int i=0; i < (int)VImageDimension; ++i) radius[i] = 1; itk::NeighborhoodIterator iterator(radius, mask, mask->GetRequestedRegion()); itk::NeighborhoodIterator valueIter(radius, itkValueImage, itkValueImage->GetRequestedRegion()); std::vector borderPoints; unsigned int maskDimensionX = mask->GetLargestPossibleRegion().GetSize()[0]; unsigned int maskDimensionY = mask->GetLargestPossibleRegion().GetSize()[1]; unsigned int maskDimensionZ = mask->GetLargestPossibleRegion().GetSize()[2]; double maskVoxelSpacingX = mask->GetSpacing()[0]; double maskVoxelSpacingY = mask->GetSpacing()[1]; double maskVoxelSpacingZ = mask->GetSpacing()[2]; - unsigned int maskMinimumX = maskDimensionX; - unsigned int maskMaximumX = 0; - unsigned int maskMinimumY = maskDimensionY; - unsigned int maskMaximumY = 0; - unsigned int maskMinimumZ = maskDimensionZ; - unsigned int maskMaximumZ = 0; + int maskMinimumX = maskDimensionX; + int maskMaximumX = 0; + int maskMinimumY = maskDimensionY; + int maskMaximumY = 0; + int maskMinimumZ = maskDimensionZ; + int maskMaximumZ = 0; // // Calculate surface in different directions // double surface = 0; std::vector directionSurface; for (int i = 0; i < (int)(iterator.Size()); ++i) { auto offset = iterator.GetOffset(i); double deltaS = 1; int nonZeros = 0; for (unsigned int j = 0; j < VImageDimension; ++j) { if (offset[j] != 0 && nonZeros == 0) { for (unsigned int k = 0; k < VImageDimension; ++k) { if (k != j) deltaS *= mask->GetSpacing()[k]; } nonZeros++; } else if (offset[j] != 0) { deltaS = 0; } } if (nonZeros < 1) deltaS = 0; directionSurface.push_back(deltaS); } // // Prepare calulation of Centre of mass shift // PointType normalCenter(0); PointType normalCenterUncorrected(0); PointType weightedCenter(0); PointType currentPoint; int numberOfPoints = 0; int numberOfPointsUncorrected = 0; double sumOfPoints = 0; while(!iterator.IsAtEnd()) { if (iterator.GetCenterPixel() == 0) { ++iterator; ++valueIter; continue; } maskMinimumX = (maskMinimumX > iterator.GetIndex()[0]) ? iterator.GetIndex()[0] : maskMinimumX; maskMaximumX = (maskMaximumX < iterator.GetIndex()[0]) ? iterator.GetIndex()[0] : maskMaximumX; maskMinimumY = (maskMinimumY > iterator.GetIndex()[1]) ? iterator.GetIndex()[1] : maskMinimumY; maskMaximumY = (maskMaximumY < iterator.GetIndex()[1]) ? iterator.GetIndex()[1] : maskMaximumY; maskMinimumZ = (maskMinimumZ > iterator.GetIndex()[2]) ? iterator.GetIndex()[2] : maskMinimumZ; maskMaximumZ = (maskMaximumZ < iterator.GetIndex()[2]) ? iterator.GetIndex()[2] : maskMaximumZ; mask->TransformIndexToPhysicalPoint(iterator.GetIndex(), currentPoint); normalCenterUncorrected += currentPoint.GetVectorFromOrigin(); ++numberOfPointsUncorrected; double intensityValue = valueIter.GetCenterPixel(); if (intensityValue == intensityValue) { normalCenter += currentPoint.GetVectorFromOrigin(); weightedCenter += currentPoint.GetVectorFromOrigin() * intensityValue; sumOfPoints += intensityValue; ++numberOfPoints; } bool border = false; for (int i = 0; i < (int)(iterator.Size()); ++i) { if (iterator.GetPixel(i) == 0 || ( ! iterator.IndexInBounds(i))) { border = true; surface += directionSurface[i]; //break; } } if (border) { auto centerIndex = iterator.GetIndex(); PointType centerPoint; mask->TransformIndexToPhysicalPoint(centerIndex, centerPoint ); borderPoints.push_back(centerPoint); } ++iterator; ++valueIter; } auto normalCenterVector = normalCenter.GetVectorFromOrigin() / numberOfPoints; auto normalCenterVectorUncorrected = normalCenter.GetVectorFromOrigin() / numberOfPointsUncorrected; auto weightedCenterVector = weightedCenter.GetVectorFromOrigin() / sumOfPoints; auto differenceOfCentersUncorrected = (normalCenterVectorUncorrected - weightedCenterVector).GetNorm(); auto differenceOfCenters = (normalCenterVector - weightedCenterVector).GetNorm(); double longestDiameter = 0; unsigned long numberOfBorderPoints = borderPoints.size(); for (int i = 0; i < (int)numberOfBorderPoints; ++i) { auto point = borderPoints[i]; for (int j = i; j < (int)numberOfBorderPoints; ++j) { double newDiameter=point.EuclideanDistanceTo(borderPoints[j]); if (newDiameter > longestDiameter) longestDiameter = newDiameter; } } double boundingBoxVolume = maskVoxelSpacingX* (maskMaximumX - maskMinimumX) * maskVoxelSpacingY* (maskMaximumY - maskMinimumY) * maskVoxelSpacingZ* (maskMaximumZ - maskMinimumZ); featureList.push_back(std::make_pair(prefix + "Maximum 3D diameter", longestDiameter)); featureList.push_back(std::make_pair(prefix + "Surface (voxel based)", surface)); featureList.push_back(std::make_pair(prefix + "Centre of mass shift", differenceOfCenters)); featureList.push_back(std::make_pair(prefix + "Centre of mass shift (uncorrected)", differenceOfCentersUncorrected)); featureList.push_back(std::make_pair(prefix + "Bounding Box Volume", boundingBoxVolume)); } mitk::GIFVolumetricStatistics::GIFVolumetricStatistics() { SetLongName("volume"); SetShortName("vol"); SetFeatureClassName("Volumetric Features"); } mitk::GIFVolumetricStatistics::FeatureListType mitk::GIFVolumetricStatistics::CalculateFeatures(const Image::Pointer & image, const Image::Pointer &mask) { FeatureListType featureList; if (image->GetDimension() < 3) { return featureList; } AccessByItk_3(image, CalculateVolumeStatistic, mask, featureList, FeatureDescriptionPrefix()); AccessByItk_3(mask, CalculateLargestDiameter, image, featureList, FeatureDescriptionPrefix()); vtkSmartPointer mesher = vtkSmartPointer::New(); vtkSmartPointer stats = vtkSmartPointer::New(); mesher->SetInputData(mask->GetVtkImageData()); mesher->SetValue(0, 0.5); stats->SetInputConnection(mesher->GetOutputPort()); stats->Update(); double pi = vnl_math::pi; double meshVolume = stats->GetVolume(); double meshSurf = stats->GetSurfaceArea(); double pixelVolume = featureList[1].second; double pixelSurface = featureList[3].second; MITK_INFO << "Surface: " << pixelSurface << " Volume: " << pixelVolume; double compactness1 = pixelVolume / (std::sqrt(pi) * std::pow(meshSurf, 2.0 / 3.0)); double compactness1Pixel = pixelVolume / (std::sqrt(pi) * std::pow(pixelSurface, 2.0 / 3.0)); //This is the definition used by Aertz. However, due to 2/3 this feature is not demensionless. Use compactness3 instead. double compactness2 = 36 * pi*pixelVolume*pixelVolume / meshSurf / meshSurf / meshSurf; double compactness2Pixel = 36 * pi*pixelVolume*pixelVolume / pixelSurface / pixelSurface / pixelSurface; double compactness3 = pixelVolume / (std::sqrt(pi) * std::pow(meshSurf, 3.0 / 2.0)); double compactness3Pixel = pixelVolume / (std::sqrt(pi) * std::pow(pixelSurface, 3.0 / 2.0)); double sphericity = std::pow(pi, 1 / 3.0) *std::pow(6 * pixelVolume, 2.0 / 3.0) / meshSurf; double sphericityPixel = std::pow(pi, 1 / 3.0) *std::pow(6 * pixelVolume, 2.0 / 3.0) / pixelSurface; double surfaceToVolume = meshSurf / meshVolume; double surfaceToVolumePixel = pixelSurface / pixelVolume; double sphericalDisproportion = meshSurf / 4 / pi / std::pow(3.0 / 4.0 / pi * pixelVolume, 2.0 / 3.0); double sphericalDisproportionPixel = pixelSurface / 4 / pi / std::pow(3.0 / 4.0 / pi * pixelVolume, 2.0 / 3.0); double asphericity = std::pow(1.0/compactness2, (1.0 / 3.0)) - 1; double asphericityPixel = std::pow(1.0/compactness2Pixel, (1.0 / 3.0)) - 1; //Calculate center of mass shift int xx = mask->GetDimensions()[0]; int yy = mask->GetDimensions()[1]; int zz = mask->GetDimensions()[2]; double xd = mask->GetGeometry()->GetSpacing()[0]; double yd = mask->GetGeometry()->GetSpacing()[1]; double zd = mask->GetGeometry()->GetSpacing()[2]; vtkSmartPointer dataset1Arr = vtkSmartPointer::New(); vtkSmartPointer dataset2Arr = vtkSmartPointer::New(); vtkSmartPointer dataset3Arr = vtkSmartPointer::New(); dataset1Arr->SetNumberOfComponents(1); dataset2Arr->SetNumberOfComponents(1); dataset3Arr->SetNumberOfComponents(1); dataset1Arr->SetName("M1"); dataset2Arr->SetName("M2"); dataset3Arr->SetName("M3"); vtkSmartPointer dataset1ArrU = vtkSmartPointer::New(); vtkSmartPointer dataset2ArrU = vtkSmartPointer::New(); vtkSmartPointer dataset3ArrU = vtkSmartPointer::New(); dataset1ArrU->SetNumberOfComponents(1); dataset2ArrU->SetNumberOfComponents(1); dataset3ArrU->SetNumberOfComponents(1); dataset1ArrU->SetName("M1"); dataset2ArrU->SetName("M2"); dataset3ArrU->SetName("M3"); for (int x = 0; x < xx; x++) { for (int y = 0; y < yy; y++) { for (int z = 0; z < zz; z++) { itk::Image::IndexType index; index[0] = x; index[1] = y; index[2] = z; mitk::ScalarType pxImage; mitk::ScalarType pxMask; mitkPixelTypeMultiplex5( mitk::FastSinglePixelAccess, image->GetChannelDescriptor().GetPixelType(), image, image->GetVolumeData(), index, pxImage, 0); mitkPixelTypeMultiplex5( mitk::FastSinglePixelAccess, mask->GetChannelDescriptor().GetPixelType(), mask, mask->GetVolumeData(), index, pxMask, 0); //Check if voxel is contained in segmentation if (pxMask > 0) { dataset1ArrU->InsertNextValue(x*xd); dataset2ArrU->InsertNextValue(y*yd); dataset3ArrU->InsertNextValue(z*zd); if (pxImage == pxImage) { dataset1Arr->InsertNextValue(x*xd); dataset2Arr->InsertNextValue(y*yd); dataset3Arr->InsertNextValue(z*zd); } } } } } vtkSmartPointer datasetTable = vtkSmartPointer::New(); datasetTable->AddColumn(dataset1Arr); datasetTable->AddColumn(dataset2Arr); datasetTable->AddColumn(dataset3Arr); vtkSmartPointer datasetTableU = vtkSmartPointer::New(); datasetTableU->AddColumn(dataset1ArrU); datasetTableU->AddColumn(dataset2ArrU); datasetTableU->AddColumn(dataset3ArrU); vtkSmartPointer pcaStatistics = vtkSmartPointer::New(); pcaStatistics->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA, datasetTable); pcaStatistics->SetColumnStatus("M1", 1); pcaStatistics->SetColumnStatus("M2", 1); pcaStatistics->SetColumnStatus("M3", 1); pcaStatistics->RequestSelectedColumns(); pcaStatistics->SetDeriveOption(true); pcaStatistics->Update(); vtkSmartPointer eigenvalues = vtkSmartPointer::New(); pcaStatistics->GetEigenvalues(eigenvalues); pcaStatistics->SetInputData(vtkStatisticsAlgorithm::INPUT_DATA, datasetTableU); pcaStatistics->Update(); vtkSmartPointer eigenvaluesU = vtkSmartPointer::New(); pcaStatistics->GetEigenvalues(eigenvaluesU); std::vector eigen_val(3); std::vector eigen_valUC(3); eigen_val[2] = eigenvalues->GetValue(0); eigen_val[1] = eigenvalues->GetValue(1); eigen_val[0] = eigenvalues->GetValue(2); eigen_valUC[2] = eigenvaluesU->GetValue(0); eigen_valUC[1] = eigenvaluesU->GetValue(1); eigen_valUC[0] = eigenvaluesU->GetValue(2); double major = 4*sqrt(eigen_val[2]); double minor = 4*sqrt(eigen_val[1]); double least = 4*sqrt(eigen_val[0]); double elongation = (major == 0) ? 0 : sqrt(eigen_val[1] / eigen_val[2]); double flatness = (major == 0) ? 0 : sqrt(eigen_val[0] / eigen_val[2]); double majorUC = 4*sqrt(eigen_valUC[2]); double minorUC = 4*sqrt(eigen_valUC[1]); double leastUC = 4*sqrt(eigen_valUC[0]); double elongationUC = majorUC == 0 ? 0 : sqrt(eigen_valUC[1] / eigen_valUC[2]); double flatnessUC = majorUC == 0 ? 0 : sqrt(eigen_valUC[0] / eigen_valUC[2]); std::string prefix = FeatureDescriptionPrefix(); featureList.push_back(std::make_pair(prefix + "Volume (mesh based)",meshVolume)); featureList.push_back(std::make_pair(prefix + "Surface (mesh based)",meshSurf)); featureList.push_back(std::make_pair(prefix + "Surface to volume ratio (mesh based)",surfaceToVolume)); featureList.push_back(std::make_pair(prefix + "Sphericity (mesh based)",sphericity)); featureList.push_back(std::make_pair(prefix + "Asphericity (mesh based)", asphericity)); featureList.push_back(std::make_pair(prefix + "Compactness 1 (mesh based)", compactness3)); featureList.push_back(std::make_pair(prefix + "Compactness 1 old (mesh based)" ,compactness1)); featureList.push_back(std::make_pair(prefix + "Compactness 2 (mesh based)",compactness2)); featureList.push_back(std::make_pair(prefix + "Spherical disproportion (mesh based)", sphericalDisproportion)); featureList.push_back(std::make_pair(prefix + "Surface to volume ratio (voxel based)", surfaceToVolumePixel)); featureList.push_back(std::make_pair(prefix + "Sphericity (voxel based)", sphericityPixel)); featureList.push_back(std::make_pair(prefix + "Asphericity (voxel based)", asphericityPixel)); featureList.push_back(std::make_pair(prefix + "Compactness 1 (voxel based)", compactness3Pixel)); featureList.push_back(std::make_pair(prefix + "Compactness 1 old (voxel based)", compactness1Pixel)); featureList.push_back(std::make_pair(prefix + "Compactness 2 (voxel based)", compactness2Pixel)); featureList.push_back(std::make_pair(prefix + "Spherical disproportion (voxel based)", sphericalDisproportionPixel)); featureList.push_back(std::make_pair(prefix + "PCA Major axis length",major)); featureList.push_back(std::make_pair(prefix + "PCA Minor axis length",minor)); featureList.push_back(std::make_pair(prefix + "PCA Least axis length",least)); featureList.push_back(std::make_pair(prefix + "PCA Elongation",elongation)); featureList.push_back(std::make_pair(prefix + "PCA Flatness",flatness)); featureList.push_back(std::make_pair(prefix + "PCA Major axis length (uncorrected)", majorUC)); featureList.push_back(std::make_pair(prefix + "PCA Minor axis length (uncorrected)", minorUC)); featureList.push_back(std::make_pair(prefix + "PCA Least axis length (uncorrected)", leastUC)); featureList.push_back(std::make_pair(prefix + "PCA Elongation (uncorrected)", elongationUC)); featureList.push_back(std::make_pair(prefix + "PCA Flatness (uncorrected)", flatnessUC)); return featureList; } mitk::GIFVolumetricStatistics::FeatureNameListType mitk::GIFVolumetricStatistics::GetFeatureNames() { FeatureNameListType featureList; return featureList; } void mitk::GIFVolumetricStatistics::AddArguments(mitkCommandLineParser &parser) { std::string name = GetOptionPrefix(); parser.addArgument(GetLongName(), name, mitkCommandLineParser::Bool, "Use Volume-Statistic", "calculates volume based features", us::Any()); } void mitk::GIFVolumetricStatistics::CalculateFeaturesUsingParameters(const Image::Pointer & feature, const Image::Pointer &mask, const Image::Pointer &, FeatureListType &featureList) { auto parsedArgs = GetParameter(); if (parsedArgs.count(GetLongName())) { MITK_INFO << "Start calculating Volumetric Features::...."; auto localResults = this->CalculateFeatures(feature, mask); featureList.insert(featureList.end(), localResults.begin(), localResults.end()); MITK_INFO << "Finished calculating volumetric features...."; } } diff --git a/Modules/Classification/CLUtilities/test/files.cmake b/Modules/Classification/CLUtilities/test/files.cmake index b0f32b97fe..579c0e0670 100644 --- a/Modules/Classification/CLUtilities/test/files.cmake +++ b/Modules/Classification/CLUtilities/test/files.cmake @@ -1,14 +1,18 @@ set(MODULE_TESTS + mitkGIFCooc2Test mitkGIFCurvatureStatisticTest mitkGIFFirstOrderHistogramStatisticsTest + mitkGIFFirstOrderNumericStatisticsTest + mitkGIFFirstOrderStatisticsTest mitkGIFGreyLevelDistanceZoneTest mitkGIFGreyLevelSizeZoneTest mitkGIFImageDescriptionFeaturesTest + mitkGIFIntensityVolumeHistogramTest mitkGIFLocalIntensityTest mitkGIFNeighbourhoodGreyToneDifferenceFeaturesTest mitkGIFNeighbouringGreyLevelDependenceFeatureTest mitkGIFVolumetricDensityStatisticsTest mitkGIFVolumetricStatisticsTest #mitkSmoothedClassProbabilitesTest.cpp #mitkGlobalFeaturesTest.cpp ) diff --git a/Modules/Classification/CLUtilities/test/mitkGIFCooc2Test.cpp b/Modules/Classification/CLUtilities/test/mitkGIFCooc2Test.cpp new file mode 100644 index 0000000000..ef4dcd4254 --- /dev/null +++ b/Modules/Classification/CLUtilities/test/mitkGIFCooc2Test.cpp @@ -0,0 +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 +#include +#include "mitkIOUtil.h" +#include + +#include + +class mitkGIFCooc2TestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkGIFCooc2TestSuite); + + MITK_TEST(ImageDescription_PhantomTest_3D); + MITK_TEST(ImageDescription_PhantomTest_2D); + + CPPUNIT_TEST_SUITE_END(); + +private: + mitk::Image::Pointer m_IBSI_Phantom_Image_Small; + mitk::Image::Pointer m_IBSI_Phantom_Image_Large; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; + +public: + + void setUp(void) override + { + m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); + m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); + m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); + m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); + } + + void ImageDescription_PhantomTest_3D() + { + mitk::GIFCooccurenceMatrix2::Pointer featureCalculator = mitk::GIFCooccurenceMatrix2::New(); + + featureCalculator->SetUseBinsize(true); + featureCalculator->SetBinsize(1.0); + featureCalculator->SetUseMinimumIntensity(true); + featureCalculator->SetUseMaximumIntensity(true); + featureCalculator->SetMinimumIntensity(0.5); + featureCalculator->SetMaximumIntensity(6.5); + + auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); + + std::map results; + for (auto valuePair : featureList) + { + MITK_INFO << valuePair.first << " : " << valuePair.second; + results[valuePair.first] = valuePair.second; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 18 features.", std::size_t(93), featureList.size()); + + // These values are obtained with IBSI (3D Comb) + // Standard accuracy is 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Joint Maximum with Large IBSI Phantom Image", 0.509, results["Co-occurenced Based Features::Overall Joint Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Joint Average with Large IBSI Phantom Image", 2.149, results["Co-occurenced Based Features::Overall Joint Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Joint Variance with Large IBSI Phantom Image", 3.132, results["Co-occurenced Based Features::Overall Joint Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Joint Entropy with Large IBSI Phantom Image", 2.574, results["Co-occurenced Based Features::Overall Joint Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Difference Average with Large IBSI Phantom Image", 1.379, results["Co-occurenced Based Features::Overall Difference Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Difference Variance with Large IBSI Phantom Image", 3.215, results["Co-occurenced Based Features::Overall Difference Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Difference Entropy with Large IBSI Phantom Image", 1.641, results["Co-occurenced Based Features::Overall Difference Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Sum Average with Large IBSI Phantom Image", 4.298, results["Co-occurenced Based Features::Overall Sum Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Sum Variance with Large IBSI Phantom Image", 7.412, results["Co-occurenced Based Features::Overall Sum Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Sum Entropy with Large IBSI Phantom Image", 2.110, results["Co-occurenced Based Features::Overall Sum Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Angular Second Moment with Large IBSI Phantom Image", 0.291, results["Co-occurenced Based Features::Overall Angular Second Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Contrast with Large IBSI Phantom Image", 5.118, results["Co-occurenced Based Features::Overall Contrast"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Dissimilarity with Large IBSI Phantom Image", 1.380, results["Co-occurenced Based Features::Overall Dissimilarity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Difference with Large IBSI Phantom Image", 0.688, results["Co-occurenced Based Features::Overall Inverse Difference"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Difference Normalized with Large IBSI Phantom Image", 0.856, results["Co-occurenced Based Features::Overall Inverse Difference Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Difference Moment with Large IBSI Phantom Image", 0.631, results["Co-occurenced Based Features::Overall Inverse Difference Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Difference Moment Normalized with Large IBSI Phantom Image", 0.902, results["Co-occurenced Based Features::Overall Inverse Difference Moment Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Inverse Variance with Large IBSI Phantom Image", 0.057, results["Co-occurenced Based Features::Overall Inverse Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Correlation with Large IBSI Phantom Image", 0.183, results["Co-occurenced Based Features::Overall Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Autocorrelation with Large IBSI Phantom Image", 5.192, results["Co-occurenced Based Features::Overall Autocorrelation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Cluster Tendency with Large IBSI Phantom Image", 7.412, results["Co-occurenced Based Features::Overall Cluster Tendency"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Cluster Shade with Large IBSI Phantom Image", 17.419, results["Co-occurenced Based Features::Overall Cluster Shade"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Cluster Prominence with Large IBSI Phantom Image", 147.464, results["Co-occurenced Based Features::Overall Cluster Prominence"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall First Measure of Information Correlation with Large IBSI Phantom Image", -0.0288, results["Co-occurenced Based Features::Overall First Measure of Information Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Second Measure of Information Correlation with Large IBSI Phantom Image", 0.269, results["Co-occurenced Based Features::Overall Second Measure of Information Correlation"], 0.001); + + // These values are obtained by manually running the tool + // Values might be wrong. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Row Maximum with Large IBSI Phantom Image", 0.679, results["Co-occurenced Based Features::Overall Row Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Row Average with Large IBSI Phantom Image", 2.149, results["Co-occurenced Based Features::Overall Row Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Row Variance with Large IBSI Phantom Image", 3.132, results["Co-occurenced Based Features::Overall Row Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Row Entropy with Large IBSI Phantom Image", 1.306, results["Co-occurenced Based Features::Overall Row Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall First Row-Column Entropy with Large IBSI Phantom Image", 2.611, results["Co-occurenced Based Features::Overall First Row-Column Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Overall Second Row-Column Entropy with Large IBSI Phantom Image", 2.611, results["Co-occurenced Based Features::Overall Second Row-Column Entropy"], 0.001); + + + + + // These values are obtained with IBSI (3D Avg) + // Standard accuracy is 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Joint Maximum with Large IBSI Phantom Image", 0.503, results["Co-occurenced Based Features::Mean Joint Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Joint Average with Large IBSI Phantom Image", 2.143, results["Co-occurenced Based Features::Mean Joint Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Joint Variance with Large IBSI Phantom Image", 3.099, results["Co-occurenced Based Features::Mean Joint Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Joint Entropy with Large IBSI Phantom Image", 2.399, results["Co-occurenced Based Features::Mean Joint Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Difference Average with Large IBSI Phantom Image", 1.431, results["Co-occurenced Based Features::Mean Difference Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Difference Variance with Large IBSI Phantom Image", 3.056, results["Co-occurenced Based Features::Mean Difference Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Difference Entropy with Large IBSI Phantom Image", 1.563, results["Co-occurenced Based Features::Mean Difference Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Sum Average with Large IBSI Phantom Image", 4.2859, results["Co-occurenced Based Features::Mean Sum Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Sum Variance with Large IBSI Phantom Image", 7.072, results["Co-occurenced Based Features::Mean Sum Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Sum Entropy with Large IBSI Phantom Image", 1.9226, results["Co-occurenced Based Features::Mean Sum Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Angular Second Moment with Large IBSI Phantom Image", 0.303, results["Co-occurenced Based Features::Mean Angular Second Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Contrast with Large IBSI Phantom Image", 5.3245, results["Co-occurenced Based Features::Mean Contrast"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Dissimilarity with Large IBSI Phantom Image", 1.431, results["Co-occurenced Based Features::Mean Dissimilarity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Difference with Large IBSI Phantom Image", 0.6766, results["Co-occurenced Based Features::Mean Inverse Difference"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Difference Normalized with Large IBSI Phantom Image", 0.8506, results["Co-occurenced Based Features::Mean Inverse Difference Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Difference Moment with Large IBSI Phantom Image", 0.6177, results["Co-occurenced Based Features::Mean Inverse Difference Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Difference Moment Normalized with Large IBSI Phantom Image", 0.8984, results["Co-occurenced Based Features::Mean Inverse Difference Moment Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Inverse Variance with Large IBSI Phantom Image", 0.0604, results["Co-occurenced Based Features::Mean Inverse Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Correlation with Large IBSI Phantom Image", 0.157, results["Co-occurenced Based Features::Mean Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Autocorrelation with Large IBSI Phantom Image", 5.05544, results["Co-occurenced Based Features::Mean Autocorrelation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Cluster Tendency with Large IBSI Phantom Image", 7.0728, results["Co-occurenced Based Features::Mean Cluster Tendency"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Cluster Shade with Large IBSI Phantom Image", 16.6441, results["Co-occurenced Based Features::Mean Cluster Shade"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Cluster Prominence with Large IBSI Phantom Image", 144.703, results["Co-occurenced Based Features::Mean Cluster Prominence"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean First Measure of Information Correlation with Large IBSI Phantom Image", -0.15684, results["Co-occurenced Based Features::Mean First Measure of Information Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Second Measure of Information Correlation with Large IBSI Phantom Image", 0.519588, results["Co-occurenced Based Features::Mean Second Measure of Information Correlation"], 0.001); + + // These values are obtained by manually running the tool + // Values might be wrong. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Row Maximum with Large IBSI Phantom Image", 0.6808, results["Co-occurenced Based Features::Mean Row Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Row Average with Large IBSI Phantom Image", 2.143, results["Co-occurenced Based Features::Mean Row Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Row Variance with Large IBSI Phantom Image", 3.0993, results["Co-occurenced Based Features::Mean Row Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Row Entropy with Large IBSI Phantom Image", 1.29699, results["Co-occurenced Based Features::Mean Row Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean First Row-Column Entropy with Large IBSI Phantom Image", 2.5939, results["Co-occurenced Based Features::Mean First Row-Column Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Co-occurenced Based Features::Mean Second Row-Column Entropy with Large IBSI Phantom Image", 2.5939, results["Co-occurenced Based Features::Mean Second Row-Column Entropy"], 0.001); + } + + void ImageDescription_PhantomTest_2D() + { + mitk::GIFCooccurenceMatrix2::Pointer featureCalculator = mitk::GIFCooccurenceMatrix2::New(); + + featureCalculator->SetUseBinsize(true); + featureCalculator->SetBinsize(1.0); + featureCalculator->SetUseMinimumIntensity(true); + featureCalculator->SetUseMaximumIntensity(true); + featureCalculator->SetMinimumIntensity(0.5); + featureCalculator->SetMaximumIntensity(6.5); + + auto featureList = featureCalculator->CalculateFeaturesSlicewise(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large, 2); + + std::map results; + for (auto valuePair : featureList) + { + MITK_INFO << valuePair.first << " : " << valuePair.second; + results[valuePair.first] = valuePair.second; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 558 features.", std::size_t(558), featureList.size()); + + // These values are obtained with IBSI + // Standard accuracy is 0.01 + // These values are obtained with IBSI (2D Comb) + // Standard accuracy is 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Joint Maximum with Large IBSI Phantom Image", 0.512, results["SliceWise Mean Co-occurenced Based Features::Overall Joint Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Joint Average with Large IBSI Phantom Image", 2.143, results["SliceWise Mean Co-occurenced Based Features::Overall Joint Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Joint Variance with Large IBSI Phantom Image", 2.7115, results["SliceWise Mean Co-occurenced Based Features::Overall Joint Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Joint Entropy with Large IBSI Phantom Image", 2.2383, results["SliceWise Mean Co-occurenced Based Features::Overall Joint Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Difference Average with Large IBSI Phantom Image", 1.3990, results["SliceWise Mean Co-occurenced Based Features::Overall Difference Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Difference Variance with Large IBSI Phantom Image", 3.06426, results["SliceWise Mean Co-occurenced Based Features::Overall Difference Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Difference Entropy with Large IBSI Phantom Image", 1.49262, results["SliceWise Mean Co-occurenced Based Features::Overall Difference Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Sum Average with Large IBSI Phantom Image", 4.28686, results["SliceWise Mean Co-occurenced Based Features::Overall Sum Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Sum Variance with Large IBSI Phantom Image", 5.65615, results["SliceWise Mean Co-occurenced Based Features::Overall Sum Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Sum Entropy with Large IBSI Phantom Image", 1.79494, results["SliceWise Mean Co-occurenced Based Features::Overall Sum Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Angular Second Moment with Large IBSI Phantom Image", 0.351678, results["SliceWise Mean Co-occurenced Based Features::Overall Angular Second Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Contrast with Large IBSI Phantom Image", 5.19019, results["SliceWise Mean Co-occurenced Based Features::Overall Contrast"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Dissimilarity with Large IBSI Phantom Image", 1.3990, results["SliceWise Mean Co-occurenced Based Features::Overall Dissimilarity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference with Large IBSI Phantom Image", 0.683294, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Normalized with Large IBSI Phantom Image", 0.8538, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Moment with Large IBSI Phantom Image", 0.625003, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Moment Normalized with Large IBSI Phantom Image", 0.90088, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Difference Moment Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Inverse Variance with Large IBSI Phantom Image", 0.055286, results["SliceWise Mean Co-occurenced Based Features::Overall Inverse Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Correlation with Large IBSI Phantom Image", 0.0173072, results["SliceWise Mean Co-occurenced Based Features::Overall Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Autocorrelation with Large IBSI Phantom Image", 5.13953, results["SliceWise Mean Co-occurenced Based Features::Overall Autocorrelation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Cluster Tendency with Large IBSI Phantom Image", 5.6561, results["SliceWise Mean Co-occurenced Based Features::Overall Cluster Tendency"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Cluster Shade with Large IBSI Phantom Image", 6.97661, results["SliceWise Mean Co-occurenced Based Features::Overall Cluster Shade"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Cluster Prominence with Large IBSI Phantom Image", 80.3855, results["SliceWise Mean Co-occurenced Based Features::Overall Cluster Prominence"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall First Measure of Information Correlation with Large IBSI Phantom Image", -0.0340891, results["SliceWise Mean Co-occurenced Based Features::Overall First Measure of Information Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Second Measure of Information Correlation with Large IBSI Phantom Image", 0.2625, results["SliceWise Mean Co-occurenced Based Features::Overall Second Measure of Information Correlation"], 0.001); + + // These values are obtained by manually running the tool + // Values might be wrong. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Row Maximum with Large IBSI Phantom Image", 0.682689, results["SliceWise Mean Co-occurenced Based Features::Overall Row Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Row Average with Large IBSI Phantom Image", 2.14343, results["SliceWise Mean Co-occurenced Based Features::Overall Row Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Row Variance with Large IBSI Phantom Image", 2.71158, results["SliceWise Mean Co-occurenced Based Features::Overall Row Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Row Entropy with Large IBSI Phantom Image", 1.13773, results["SliceWise Mean Co-occurenced Based Features::Overall Row Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall First Row-Column Entropy with Large IBSI Phantom Image", 2.27545, results["SliceWise Mean Co-occurenced Based Features::Overall First Row-Column Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Overall Second Row-Column Entropy with Large IBSI Phantom Image", 2.27545, results["SliceWise Mean Co-occurenced Based Features::Overall Second Row-Column Entropy"], 0.001); + + + + + // These values are obtained with IBSI (2D Avg) + // Standard accuracy is 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Joint Maximum with Large IBSI Phantom Image", 0.5188, results["SliceWise Mean Co-occurenced Based Features::Mean Joint Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Joint Average with Large IBSI Phantom Image", 2.14242, results["SliceWise Mean Co-occurenced Based Features::Mean Joint Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Joint Variance with Large IBSI Phantom Image", 2.6877, results["SliceWise Mean Co-occurenced Based Features::Mean Joint Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Joint Entropy with Large IBSI Phantom Image", 2.04966, results["SliceWise Mean Co-occurenced Based Features::Mean Joint Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Difference Average with Large IBSI Phantom Image", 1.42247, results["SliceWise Mean Co-occurenced Based Features::Mean Difference Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Difference Variance with Large IBSI Phantom Image", 2.90159, results["SliceWise Mean Co-occurenced Based Features::Mean Difference Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Difference Entropy with Large IBSI Phantom Image", 1.39615, results["SliceWise Mean Co-occurenced Based Features::Mean Difference Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Sum Average with Large IBSI Phantom Image", 4.28484, results["SliceWise Mean Co-occurenced Based Features::Mean Sum Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Sum Variance with Large IBSI Phantom Image", 5.47293, results["SliceWise Mean Co-occurenced Based Features::Mean Sum Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Sum Entropy with Large IBSI Phantom Image", 1.60319, results["SliceWise Mean Co-occurenced Based Features::Mean Sum Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Angular Second Moment with Large IBSI Phantom Image", 0.367529, results["SliceWise Mean Co-occurenced Based Features::Mean Angular Second Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Contrast with Large IBSI Phantom Image", 5.27785, results["SliceWise Mean Co-occurenced Based Features::Mean Contrast"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Dissimilarity with Large IBSI Phantom Image", 1.42247, results["SliceWise Mean Co-occurenced Based Features::Mean Dissimilarity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference with Large IBSI Phantom Image", 0.677949, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Normalized with Large IBSI Phantom Image", 0.851399, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Moment with Large IBSI Phantom Image", 0.618737, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Moment"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Moment Normalized with Large IBSI Phantom Image", 0.899219, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Difference Moment Normalized"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Inverse Variance with Large IBSI Phantom Image", 0.0566983, results["SliceWise Mean Co-occurenced Based Features::Mean Inverse Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Correlation with Large IBSI Phantom Image", -.012107, results["SliceWise Mean Co-occurenced Based Features::Mean Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Autocorrelation with Large IBSI Phantom Image", 5.09437, results["SliceWise Mean Co-occurenced Based Features::Mean Autocorrelation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Cluster Tendency with Large IBSI Phantom Image", 5.47293, results["SliceWise Mean Co-occurenced Based Features::Mean Cluster Tendency"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Cluster Shade with Large IBSI Phantom Image", 6.99782, results["SliceWise Mean Co-occurenced Based Features::Mean Cluster Shade"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Cluster Prominence with Large IBSI Phantom Image", 79.1126, results["SliceWise Mean Co-occurenced Based Features::Mean Cluster Prominence"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean First Measure of Information Correlation with Large IBSI Phantom Image", -0.15512, results["SliceWise Mean Co-occurenced Based Features::Mean First Measure of Information Correlation"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Second Measure of Information Correlation with Large IBSI Phantom Image", 0.487457, results["SliceWise Mean Co-occurenced Based Features::Mean Second Measure of Information Correlation"], 0.001); + + // These values are obtained by manually running the tool + // Values might be wrong. + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Row Maximum with Large IBSI Phantom Image", 0.689717, results["SliceWise Mean Co-occurenced Based Features::Mean Row Maximum"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Row Average with Large IBSI Phantom Image", 2.14242, results["SliceWise Mean Co-occurenced Based Features::Mean Row Average"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Row Variance with Large IBSI Phantom Image", 2.6877, results["SliceWise Mean Co-occurenced Based Features::Mean Row Variance"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Row Entropy with Large IBSI Phantom Image", 1.1238, results["SliceWise Mean Co-occurenced Based Features::Mean Row Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean First Row-Column Entropy with Large IBSI Phantom Image", 2.24761, results["SliceWise Mean Co-occurenced Based Features::Mean First Row-Column Entropy"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Co-occurenced Based Features::Mean Second Row-Column Entropy with Large IBSI Phantom Image", 2.24761, results["SliceWise Mean Co-occurenced Based Features::Mean Second Row-Column Entropy"], 0.001); + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkGIFCooc2 ) \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderNumericStatisticsTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderNumericStatisticsTest.cpp new file mode 100644 index 0000000000..31bac39039 --- /dev/null +++ b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderNumericStatisticsTest.cpp @@ -0,0 +1,113 @@ +/*=================================================================== + +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 "mitkIOUtil.h" +#include + +#include + +class mitkGIFFirstOrderNumericStatisticsTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkGIFFirstOrderNumericStatisticsTestSuite); + + MITK_TEST(ImageDescription_PhantomTest); + + CPPUNIT_TEST_SUITE_END(); + +private: + mitk::Image::Pointer m_IBSI_Phantom_Image_Small; + mitk::Image::Pointer m_IBSI_Phantom_Image_Large; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; + +public: + + void setUp(void) override + { + m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); + m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); + m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); + m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); + } + + void ImageDescription_PhantomTest() + { + mitk::GIFFirstOrderNumericStatistics::Pointer featureCalculator = mitk::GIFFirstOrderNumericStatistics::New(); + + featureCalculator->SetUseBinsize(true); + featureCalculator->SetBinsize(1.0); + featureCalculator->SetUseMinimumIntensity(true); + featureCalculator->SetUseMaximumIntensity(true); + featureCalculator->SetMinimumIntensity(0.5); + featureCalculator->SetMaximumIntensity(6.5); + + auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); + + std::map results; + for (auto valuePair : featureList) + { + MITK_INFO << valuePair.first << " : " << valuePair.second; + results[valuePair.first] = valuePair.second; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 50 features.", std::size_t(50), featureList.size()); + + // These values are obtained by a run of the filter. + // The might be wrong! + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mean with Large IBSI Phantom Image", 2.15, results["First Order Numeric::Mean"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Variance with Large IBSI Phantom Image", 3.05, results["First Order Numeric::Variance"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Skewness with Large IBSI Phantom Image", 1.08, results["First Order Numeric::Skewness"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Excess kurtosis with Large IBSI Phantom Image", -0.355, results["First Order Numeric::Excess kurtosis"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Median with Large IBSI Phantom Image", 1, results["First Order Numeric::Median"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Minimum with Large IBSI Phantom Image", 1, results["First Order Numeric::Minimum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::10th Percentile with Large IBSI Phantom Image", 1, results["First Order Numeric::10th Percentile"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::90th Percentile with Large IBSI Phantom Image", 4, results["First Order Numeric::90th Percentile"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Maximum with Large IBSI Phantom Image", 6, results["First Order Numeric::Maximum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Interquantile range with Large IBSI Phantom Image", 3, results["First Order Numeric::Interquantile range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Range with Large IBSI Phantom Image", 5, results["First Order Numeric::Range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mean absolute deviation with Large IBSI Phantom Image", 1.55, results["First Order Numeric::Mean absolute deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Robust mean absolute deviation with Large IBSI Phantom Image", 1.11, results["First Order Numeric::Robust mean absolute deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Median absolute deviation with Large IBSI Phantom Image", 1.15, results["First Order Numeric::Median absolute deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Coefficient of variation with Large IBSI Phantom Image", 0.812, results["First Order Numeric::Coefficient of variation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Quantile coefficient of dispersion with Large IBSI Phantom Image", 0.6, results["First Order Numeric::Quantile coefficient of dispersion"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Energy with Large IBSI Phantom Image", 567, results["First Order Numeric::Energy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Root mean square with Large IBSI Phantom Image", 2.77, results["First Order Numeric::Root mean square"], 0.01); + + + // These values are taken from the IBSI Initiative to ensure compatibility + // The values are given with an accuracy of 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Standard Deviation with Large IBSI Phantom Image", 1.74513, results["First Order Numeric::Standard Deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Kurtosis with Large IBSI Phantom Image", 2.64538, results["First Order Numeric::Kurtosis"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Robust mean with Large IBSI Phantom Image", 1.74627, results["First Order Numeric::Robust mean"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Robust variance with Large IBSI Phantom Image", 1.65204, results["First Order Numeric::Robust variance"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Covered image intensity range with Large IBSI Phantom Image", 0.83333, results["First Order Numeric::Covered image intensity range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mode index with Large IBSI Phantom Image",0 , results["First Order Numeric::Mode index"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mode value with Large IBSI Phantom Image", 1, results["First Order Numeric::Mode value"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Mode probability with Large IBSI Phantom Image", 0.675676, results["First Order Numeric::Mode probability"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Entropy with Large IBSI Phantom Image", -1.26561, results["First Order Numeric::Entropy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Uniformtiy with Large IBSI Phantom Image", 0.512418, results["First Order Numeric::Uniformtiy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Number of voxels with Large IBSI Phantom Image", 74 , results["First Order Numeric::Number of voxels"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Sum of voxels with Large IBSI Phantom Image", 159, results["First Order Numeric::Sum of voxels"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Voxel space with Large IBSI Phantom Image", 8, results["First Order Numeric::Voxel space"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Voxel volume with Large IBSI Phantom Image", 8, results["First Order Numeric::Voxel volume"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order Numeric::Image Dimension with Large IBSI Phantom Image", 3, results["First Order Numeric::Image Dimension"], 0.01); + + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkGIFFirstOrderNumericStatistics ) \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderStatisticsTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderStatisticsTest.cpp new file mode 100644 index 0000000000..d6af72b9a8 --- /dev/null +++ b/Modules/Classification/CLUtilities/test/mitkGIFFirstOrderStatisticsTest.cpp @@ -0,0 +1,112 @@ +/*=================================================================== + +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 "mitkIOUtil.h" +#include + +#include + +class mitkGIFFirstOrderStatisticsTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE(mitkGIFFirstOrderStatisticsTestSuite); + + MITK_TEST(ImageDescription_PhantomTest); + + CPPUNIT_TEST_SUITE_END(); + +private: + mitk::Image::Pointer m_IBSI_Phantom_Image_Small; + mitk::Image::Pointer m_IBSI_Phantom_Image_Large; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; + +public: + + void setUp(void) override + { + m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); + m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); + m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); + m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); + } + + void ImageDescription_PhantomTest() + { + mitk::GIFFirstOrderStatistics::Pointer featureCalculator = mitk::GIFFirstOrderStatistics::New(); + + featureCalculator->SetUseBinsize(true); + featureCalculator->SetBinsize(1); + featureCalculator->SetUseMinimumIntensity(true); + featureCalculator->SetUseMaximumIntensity(true); + featureCalculator->SetMinimumIntensity(0.5); + featureCalculator->SetMaximumIntensity(6.5); + + auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); + + std::map results; + for (auto valuePair : featureList) + { + MITK_INFO << valuePair.first << " : " << valuePair.second; + results[valuePair.first] = valuePair.second; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 50 features.", std::size_t(50), featureList.size()); + + // These values are obtained by a run of the filter. + // The might be wrong! + + + // These values are taken from the IBSI Initiative to ensure compatibility + // The values are given with an accuracy of 0.01 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mean with Large IBSI Phantom Image", 2.15, results["First Order::Mean"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Unbiased Variance with Large IBSI Phantom Image", 3.09, results["First Order::Unbiased Variance"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Biased Variance with Large IBSI Phantom Image", 3.05, results["First Order::Biased Variance"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Skewness with Large IBSI Phantom Image", 1.08, results["First Order::Skewness"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Kurtosis with Large IBSI Phantom Image", 2.65, results["First Order::Kurtosis"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Median with Large IBSI Phantom Image", 1, results["First Order::Median"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Minimum with Large IBSI Phantom Image", 1, results["First Order::Minimum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Maximum with Large IBSI Phantom Image", 6, results["First Order::Maximum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Range with Large IBSI Phantom Image", 5, results["First Order::Range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mean Absolute Deviation with Large IBSI Phantom Image", 1.55, results["First Order::Mean Absolute Deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Robust Mean Absolute Deviation with Large IBSI Phantom Image", 1.11, results["First Order::Robust Mean Absolute Deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Median Absolute Deviation with Large IBSI Phantom Image", 1.15, results["First Order::Median Absolute Deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Coefficient of variation with Large IBSI Phantom Image", 0.812, results["First Order::Coefficient Of Variation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Quantile coefficient of dispersion with Large IBSI Phantom Image", 0.625, results["First Order::Quantile Coefficient Of Dispersion"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Energy with Large IBSI Phantom Image", 567, results["First Order::Energy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Root mean square with Large IBSI Phantom Image", 2.77, results["First Order::Root Mean Square"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Entropy with Large IBSI Phantom Image", 1.26561, results["First Order::Entropy"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Excess Kurtosis with Large IBSI Phantom Image", -0.35462, results["First Order::Excess Kurtosis"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Covered image intensity range with Large IBSI Phantom Image", 0.5555555, results["First Order::Covered Image Intensity Range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Sum of voxels with Large IBSI Phantom Image", 159, results["First Order::Sum"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mode with Large IBSI Phantom Image", 1, results["First Order::Mode"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Mode Probability with Large IBSI Phantom Image", 50, results["First Order::Mode Probability"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Unbiased Standard deviation with Large IBSI Phantom Image", 1.757, results["First Order::Unbiased Standard deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Biased Standard deviation with Large IBSI Phantom Image", 1.74627, results["First Order::Biased Standard deviation"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Robust mean with Large IBSI Phantom Image", 1.74627, results["First Order::Robust Mean"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Number Of Voxels with Large IBSI Phantom Image", 74, results["First Order::Number Of Voxels"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::10th Percentile with Large IBSI Phantom Image", 0.648, results["First Order::10th Percentile"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::90th Percentile with Large IBSI Phantom Image", 4.475, results["First Order::90th Percentile"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Interquantile Range with Large IBSI Phantom Image", 2.91125, results["First Order::Interquartile Range"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Voxel Space with Large IBSI Phantom Image", 8, results["First Order::Voxel Space"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Voxel Volume with Large IBSI Phantom Image", 8, results["First Order::Voxel Volume"], 0.01); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("First Order::Image Dimension with Large IBSI Phantom Image", 3, results["First Order::Image Dimension"], 0.01); + + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkGIFFirstOrderStatistics ) \ No newline at end of file diff --git a/Modules/Classification/CLUtilities/test/mitkGIFIntensityVolumeHistogramTest.cpp b/Modules/Classification/CLUtilities/test/mitkGIFIntensityVolumeHistogramTest.cpp new file mode 100644 index 0000000000..b0a0eebfa0 --- /dev/null +++ b/Modules/Classification/CLUtilities/test/mitkGIFIntensityVolumeHistogramTest.cpp @@ -0,0 +1,159 @@ +/*=================================================================== + +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 "mitkIOUtil.h" +#include + +#include + +class mitkGIFIntensityVolumeHistogramTestSuite : public mitk::TestFixture +{ + CPPUNIT_TEST_SUITE( mitkGIFIntensityVolumeHistogramTestSuite); + + MITK_TEST(ImageDescription_PhantomTest_Large); + MITK_TEST(ImageDescription_PhantomTest_Small); + MITK_TEST(ImageDescription_PhantomTest_2D); + + CPPUNIT_TEST_SUITE_END(); + +private: + mitk::Image::Pointer m_IBSI_Phantom_Image_Small; + mitk::Image::Pointer m_IBSI_Phantom_Image_Large; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Small; + mitk::Image::Pointer m_IBSI_Phantom_Mask_Large; + +public: + + void setUp(void) override + { + m_IBSI_Phantom_Image_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Small.nrrd")); + m_IBSI_Phantom_Image_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Image_Large.nrrd")); + m_IBSI_Phantom_Mask_Small = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Small.nrrd")); + m_IBSI_Phantom_Mask_Large = mitk::IOUtil::Load(GetTestDataFilePath("Radiomics/IBSI_Phantom_Mask_Large.nrrd")); + } + + void ImageDescription_PhantomTest_Large() + { + mitk::GIFIntensityVolumeHistogramFeatures::Pointer featureCalculator = mitk::GIFIntensityVolumeHistogramFeatures::New(); + + featureCalculator->SetUseBinsize(true); + featureCalculator->SetBinsize(1.0); + featureCalculator->SetUseMinimumIntensity(true); + featureCalculator->SetUseMaximumIntensity(true); + featureCalculator->SetMinimumIntensity(0.5); + featureCalculator->SetMaximumIntensity(6.5); + + auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large); + + std::map results; + for (auto valuePair : featureList) + { + MITK_INFO << valuePair.first << " : " << valuePair.second; + results[valuePair.first] = valuePair.second; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 7 features.", std::size_t(7), featureList.size()); + + + // These values are obtained in cooperation with IBSI + // Reported with an accuracy of 0.1 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Volume fraction at 0.10 intensity with Large IBSI Phantom Image", 0.3243, results["Intensity Volume Histogram::Volume fraction at 0.10 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Volume fraction at 0.90 intensity with Large IBSI Phantom Image", 0.09459, results["Intensity Volume Histogram::Volume fraction at 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Intensity at 0.10 volume with Large IBSI Phantom Image", 5, results["Intensity Volume Histogram::Intensity at 0.10 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Intensity at 0.90 volume with Large IBSI Phantom Image", 2, results["Intensity Volume Histogram::Intensity at 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity with Large IBSI Phantom Image", 0.22973, results["Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume with Large IBSI Phantom Image", 3, results["Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Area under IVH curve with Large IBSI Phantom Image", 0.32027, results["Intensity Volume Histogram::Area under IVH curve"], 0.001); + } + + void ImageDescription_PhantomTest_Small() + { + mitk::GIFIntensityVolumeHistogramFeatures::Pointer featureCalculator = mitk::GIFIntensityVolumeHistogramFeatures::New(); + + featureCalculator->SetUseBinsize(true); + featureCalculator->SetBinsize(1.0); + featureCalculator->SetUseMinimumIntensity(true); + featureCalculator->SetUseMaximumIntensity(true); + featureCalculator->SetMinimumIntensity(0.5); + featureCalculator->SetMaximumIntensity(6.5); + + auto featureList = featureCalculator->CalculateFeatures(m_IBSI_Phantom_Image_Small, m_IBSI_Phantom_Mask_Small); + + std::map results; + for (auto valuePair : featureList) + { + MITK_INFO << valuePair.first << " : " << valuePair.second; + results[valuePair.first] = valuePair.second; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 7 features.", std::size_t(7), featureList.size()); + + + // These values are obtained in cooperation with IBSI + // Reported with an accuracy of 0.1 + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Volume fraction at 0.10 intensity with Large IBSI Phantom Image", 0.3243, results["Intensity Volume Histogram::Volume fraction at 0.10 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Volume fraction at 0.90 intensity with Large IBSI Phantom Image", 0.09459, results["Intensity Volume Histogram::Volume fraction at 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Intensity at 0.10 volume with Large IBSI Phantom Image", 5, results["Intensity Volume Histogram::Intensity at 0.10 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Intensity at 0.90 volume with Large IBSI Phantom Image", 2, results["Intensity Volume Histogram::Intensity at 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity with Large IBSI Phantom Image", 0.22973, results["Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume with Large IBSI Phantom Image", 3, results["Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("Intensity Volume Histogram::Area under IVH curve with Large IBSI Phantom Image", 0.32027, results["Intensity Volume Histogram::Area under IVH curve"], 0.001); + } + + void ImageDescription_PhantomTest_2D() + { + mitk::GIFIntensityVolumeHistogramFeatures::Pointer featureCalculator = mitk::GIFIntensityVolumeHistogramFeatures::New(); + + featureCalculator->SetUseBinsize(true); + featureCalculator->SetBinsize(1.0); + featureCalculator->SetUseMinimumIntensity(true); + featureCalculator->SetUseMaximumIntensity(true); + featureCalculator->SetMinimumIntensity(0.5); + featureCalculator->SetMaximumIntensity(6.5); + + auto featureList = featureCalculator->CalculateFeaturesSlicewise(m_IBSI_Phantom_Image_Large, m_IBSI_Phantom_Mask_Large, 2); + + std::map results; + for (auto valuePair : featureList) + { + MITK_INFO << valuePair.first << " : " << valuePair.second; + results[valuePair.first] = valuePair.second; + } + CPPUNIT_ASSERT_EQUAL_MESSAGE("Image Diagnostics should calculate 42 features.", std::size_t(42), featureList.size()); + + + // These values are obtained by calculating on the features + // Could be wrong! + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Volume fraction at 0.10 intensity with Large IBSI Phantom Image", 0.31539, results["SliceWise Mean Intensity Volume Histogram::Volume fraction at 0.10 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Volume fraction at 0.90 intensity with Large IBSI Phantom Image", 0.0924106, results["SliceWise Mean Intensity Volume Histogram::Volume fraction at 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Intensity at 0.10 volume with Large IBSI Phantom Image", 6, results["SliceWise Mean Intensity Volume Histogram::Intensity at 0.10 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Intensity at 0.90 volume with Large IBSI Phantom Image", 2, results["SliceWise Mean Intensity Volume Histogram::Intensity at 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity with Large IBSI Phantom Image", 0.222979, results["SliceWise Mean Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume with Large IBSI Phantom Image", 4, results["SliceWise Mean Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Mean Intensity Volume Histogram::Area under IVH curve with Large IBSI Phantom Image", 0.314325, results["SliceWise Mean Intensity Volume Histogram::Area under IVH curve"], 0.001); + + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Volume fraction at 0.10 intensity with Large IBSI Phantom Image", 0.0248178, results["SliceWise Var. Intensity Volume Histogram::Volume fraction at 0.10 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Volume fraction at 0.90 intensity with Large IBSI Phantom Image", 0.00149203, results["SliceWise Var. Intensity Volume Histogram::Volume fraction at 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Intensity at 0.10 volume with Large IBSI Phantom Image", 1, results["SliceWise Var. Intensity Volume Histogram::Intensity at 0.10 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Intensity at 0.90 volume with Large IBSI Phantom Image", 0, results["SliceWise Var. Intensity Volume Histogram::Intensity at 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity with Large IBSI Phantom Image", 0.01414, results["SliceWise Var. Intensity Volume Histogram::Difference volume fraction at 0.10 and 0.90 intensity"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume with Large IBSI Phantom Image", 1, results["SliceWise Var. Intensity Volume Histogram::Difference intensity at 0.10 and 0.90 volume"], 0.001); + CPPUNIT_ASSERT_DOUBLES_EQUAL_MESSAGE("SliceWise Var. Intensity Volume Histogram::Area under IVH curve with Large IBSI Phantom Image", 0.0110923, results["SliceWise Var. Intensity Volume Histogram::Area under IVH curve"], 0.001); + } + +}; + +MITK_TEST_SUITE_REGISTRATION(mitkGIFIntensityVolumeHistogram) \ No newline at end of file diff --git a/Modules/Core/CMakeLists.txt b/Modules/Core/CMakeLists.txt index 54a5c9c8e1..0fcc604b38 100644 --- a/Modules/Core/CMakeLists.txt +++ b/Modules/Core/CMakeLists.txt @@ -1,75 +1,65 @@ set(TOOL_CPPS "") # temporary suppress warnings in the following files until image accessors are fully integrated. set_source_files_properties( src/DataManagement/mitkImage.cpp COMPILE_FLAGS -DMITK_NO_DEPRECATED_WARNINGS ) set_source_files_properties( src/Controllers/mitkSliceNavigationController.cpp COMPILE_FLAGS -DMITK_NO_DEPRECATED_WARNINGS ) MITK_CREATE_MODULE( INCLUDE_DIRS PUBLIC ${MITK_BINARY_DIR} PRIVATE src/Algorithms src/Controllers src/DataManagement src/Interactions src/IO src/Rendering ${OPENGL_INCLUDE_DIR} DEPENDS PUBLIC mbilog CppMicroServices PACKAGE_DEPENDS PRIVATE tinyxml OpenGL PUBLIC ITK|ITKTransform+ITKImageGrid+ITKImageFeature+ITKIOImageBase+ITKIOHDF5+ITKIOLSM+ITKIOMRC+ITKIOBioRad+ITKIOGE+ITKIOStimulate+ITKIOBruker+ITKIOMINC # We privately use/link all ITK modules in order to support all IO, Transform, etc. # factories from ITK which are registered "automatically" via a factory manager. PRIVATE ITK PUBLIC VTK|vtkFiltersTexture+vtkFiltersParallel+vtkImagingStencil+vtkImagingMath+vtkInteractionStyle+vtkRenderingOpenGL2+vtkRenderingContextOpenGL2+vtkRenderingVolumeOpenGL2+vtkRenderingFreeType+vtkRenderingLabel+vtkInteractionWidgets+vtkIOGeometry+vtkIOXML PUBLIC Boost SUBPROJECTS MITK-Core # Do not automatically create CppMicroServices initialization code. # Because the VTK 6 "auto-init" functionality injects file-local static # initialization code in every cpp file which includes a VTK header, # static initialization order becomes an issue again. For the Mitk # core library, we need to ensure that the VTK static initialization stuff # happens before the CppMicroServices initialization, since the latter # might already use VTK code which needs to access VTK object factories. # Hence, CppMicroServices initialization code is placed manually within # the mitkCoreActivator.cpp file. NO_INIT ) if(NOT TARGET ${MODULE_TARGET}) message(SEND_ERROR "Core target ${MODULE_TARGET} does not exist") endif() function(_itk_create_factory_register_manager) # In MITK_ITK_Config.cmake, we do *not* include ITK_USE_FILE, which # prevents multiple registrations/unregistrations of ITK IO factories # during library loading/unloading (of MITK libraries). However, we need # "one" place where the IO factories are registered at # least once. This could be the application executable, but every executable would # need to take care of that itself. Instead, we allow the auto registration in the # Mitk Core library. set(NO_DIRECTORY_SCOPED_ITK_COMPILE_DEFINITION 1) find_package(ITK) include(${ITK_USE_FILE}) if(NOT ITK_NO_IO_FACTORY_REGISTER_MANAGER) # We manually add the define which will be of target scope. MITK # patches ITK_USE_FILE to remove the directory scoped compile # definition since it would be propagated to other targets in the # same directory scope but these targets might want to *not* # use the ITK factory manager stuff. target_compile_definitions(${MODULE_TARGET} PRIVATE ITK_IO_FACTORY_REGISTER_MANAGER) endif() endfunction() _itk_create_factory_register_manager() -# this is needed for libraries which link to Mitk and need -# symbols from explicitly instantiated templates -if(MINGW) - get_target_property(_mitkCore_MINGW_linkflags ${MODULE_TARGET} LINK_FLAGS) - if(NOT _mitkCore_MINGW_linkflags) - set(_mitkCore_MINGW_linkflags "") - endif(NOT _mitkCore_MINGW_linkflags) - set_target_properties(${MODULE_TARGET} PROPERTIES LINK_FLAGS "${_mitkCore_MINGW_linkflags} -Wl,--export-all-symbols") -endif(MINGW) - -if(MSVC_IDE OR MSVC_VERSION OR MINGW) +if(MSVC_IDE OR MSVC_VERSION) target_link_libraries(${MODULE_TARGET} PRIVATE psapi.lib) -endif(MSVC_IDE OR MSVC_VERSION OR MINGW) +endif() add_subdirectory(TestingHelper) add_subdirectory(test) diff --git a/Modules/Core/include/mitkImageDataItem.h b/Modules/Core/include/mitkImageDataItem.h index 02780abe89..6f06aa77fa 100644 --- a/Modules/Core/include/mitkImageDataItem.h +++ b/Modules/Core/include/mitkImageDataItem.h @@ -1,167 +1,167 @@ /*=================================================================== 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 IMAGEDATAITEM_H #define IMAGEDATAITEM_H #include "mitkCommon.h" #include //#include //#include "mitkPixelType.h" #include "mitkImageDescriptor.h" //#include "mitkImageVtkAccessor.h" class vtkImageData; namespace mitk { class PixelType; class ImageVtkReadAccessor; class ImageVtkWriteAccessor; class Image; //##Documentation //## @brief Internal class for managing references on sub-images //## //## ImageDataItem is a container for image data which is used internal in //## mitk::Image to handle the communication between the different data types for images //## used in MITK (ipPicDescriptor, mitk::Image, vtkImageData). Common for these image data //## types is the actual image data, but they differ in representation of pixel type etc. //## The class is also used to convert ipPic images to vtkImageData. //## //## The class is mainly used to extract sub-images inside of mitk::Image, like single slices etc. //## It should not be used outside of this. //## //## @param manageMemory Determines if image data is removed while destruction of ImageDataItem or not. //## @ingroup Data class MITKCORE_EXPORT ImageDataItem : public itk::LightObject { friend class ImageAccessorBase; friend class ImageWriteAccessor; friend class ImageReadAccessor; template friend class ImagePixelAccessor; friend class Image; // template // friend class ImageToItk; public: typedef itk::SmartPointer ImagePointer; typedef itk::SmartPointer ImageConstPointer; mitkClassMacroItkParent(ImageDataItem, itk::LightObject); itkCloneMacro(ImageDataItem); itk::LightObject::Pointer InternalClone() const override; ImageDataItem(const ImageDataItem &aParent, const mitk::ImageDescriptor::Pointer desc, int timestep, unsigned int dimension, void *data = nullptr, bool manageMemory = false, size_t offset = 0); ~ImageDataItem() override; ImageDataItem(const mitk::ImageDescriptor::Pointer desc, int timestep, void *data, bool manageMemory); ImageDataItem(const mitk::PixelType &type, int timestep, unsigned int dimension, unsigned int *dimensions, void *data, bool manageMemory); ImageDataItem(const ImageDataItem &other); /** \deprecatedSince{2012_09} Please use image accessors instead: See Doxygen/Related-Pages/Concepts/Image. This method can be replaced by ImageWriteAccessor::GetData() or ImageReadAccessor::GetData() */ DEPRECATED(void *GetData() const) { return m_Data; } bool IsComplete() const { return m_IsComplete; } void SetComplete(bool complete) { m_IsComplete = complete; } int GetOffset() const { return m_Offset; } PixelType GetPixelType() const { return *m_PixelType; } void SetTimestep(int t) { m_Timestep = t; } void SetManageMemory(bool b) { m_ManageMemory = b; } int GetDimension() const { return m_Dimension; } int GetDimension(int i) const { int returnValue = 0; // return the true size if dimension available if (i < (int)m_Dimension) returnValue = m_Dimensions[i]; return returnValue; } ImageDataItem::ConstPointer GetParent() const { return m_Parent; } /** * @brief GetVtkImageAccessor Returns a vtkImageDataItem, if none is present, a new one is constructed by the * ConstructVtkImageData method. * Due to historical development of MITK and VTK, the vtkImage origin is explicitly set * to * (0, 0, 0) for 3D images. * See bug 5050 for detailed information. * @return Pointer of type ImageVtkReadAccessor */ ImageVtkReadAccessor *GetVtkImageAccessor(ImageConstPointer) const; ImageVtkWriteAccessor *GetVtkImageAccessor(ImagePointer); // Returns if image data should be deleted on destruction of ImageDataItem. bool GetManageMemory() const { return m_ManageMemory; } virtual void ConstructVtkImageData(ImageConstPointer) const; - unsigned long GetSize() const { return m_Size; } + size_t GetSize() const { return m_Size; } virtual void Modified() const; protected: unsigned char *m_Data; PixelType *m_PixelType; bool m_ManageMemory; mutable vtkImageData *m_VtkImageData; mutable ImageVtkReadAccessor *m_VtkImageReadAccessor; ImageVtkWriteAccessor *m_VtkImageWriteAccessor; int m_Offset; bool m_IsComplete; - unsigned long m_Size; + size_t m_Size; private: void ComputeItemSize(const unsigned int *dimensions, unsigned int dimension); ImageDataItem::ConstPointer m_Parent; unsigned int m_Dimension; unsigned int m_Dimensions[MAX_IMAGE_DIMENSIONS]; int m_Timestep; }; } // namespace mitk #endif /* IMAGEDATAITEM_H */ diff --git a/Modules/Core/include/mitkLexicalCast.h b/Modules/Core/include/mitkLexicalCast.h new file mode 100644 index 0000000000..65829242a5 --- /dev/null +++ b/Modules/Core/include/mitkLexicalCast.h @@ -0,0 +1,75 @@ +/*=================================================================== + +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 mitkLexicalCast_h +#define mitkLexicalCast_h + +#include + +namespace mitk +{ + template + inline Target lexical_cast(const std::string &arg) + { + Target result = Target(); + + // Let Boost try to do the lexical cast, which will most probably succeed! + if (!boost::conversion::detail::try_lexical_convert(arg, result)) + { + // Fallback to our own conversion using std::istringstream. This happens with + // Apple LLVM version 9.1.0 (clang-902.0.39.1) on darwin17.5.0 and very small + // floating point numbers like 0.2225e-307. + std::istringstream stream(arg); + stream.exceptions(std::ios::badbit); + + try + { + stream.unsetf(std::ios::skipws); + stream.precision(boost::detail::lcast_get_precision()); + stream >> result; + } + catch (const std::ios_base::failure &) + { + boost::conversion::detail::throw_bad_cast(); + } + } + + return result; + } +} + +namespace boost +{ + template <> + inline float lexical_cast(const std::string &arg) + { + return mitk::lexical_cast(arg); + } + + template <> + inline double lexical_cast(const std::string &arg) + { + return mitk::lexical_cast(arg); + } + + template <> + inline long double lexical_cast(const std::string &arg) + { + return mitk::lexical_cast(arg); + } +} + +#endif diff --git a/Modules/Core/src/DataManagement/mitkMemoryUtilities.cpp b/Modules/Core/src/DataManagement/mitkMemoryUtilities.cpp index 845b6ca7c7..50444e5b5a 100755 --- a/Modules/Core/src/DataManagement/mitkMemoryUtilities.cpp +++ b/Modules/Core/src/DataManagement/mitkMemoryUtilities.cpp @@ -1,119 +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. ===================================================================*/ #include "mitkMemoryUtilities.h" #include -#if _MSC_VER || __MINGW32__ +#if _MSC_VER #include #include #elif defined(__APPLE__) #include #include #include #include #else #include #include #endif /** * Returns the memory usage of the current process in bytes. * On linux, this refers to the virtual memory allocated by * the process (the VIRT column in top). * On windows, this refery to the size in bytes of the working * set pages (the "Speicherauslastung" column in the task manager). */ size_t mitk::MemoryUtilities::GetProcessMemoryUsage() { -#if _MSC_VER || __MINGW32__ +#if _MSC_VER size_t size = 0; DWORD pid = GetCurrentProcessId(); PROCESS_MEMORY_COUNTERS pmc; HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, pid); if (hProcess == nullptr) return 0; if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc))) { size = pmc.WorkingSetSize; } CloseHandle(hProcess); return size; #elif defined(__APPLE__) struct task_basic_info t_info; mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT; task_info(current_task(), TASK_BASIC_INFO, (task_info_t)&t_info, &t_info_count); size_t size = t_info.virtual_size; return size; #else int size, res, shared, text, sharedLibs, stack, dirtyPages; if (!ReadStatmFromProcFS(&size, &res, &shared, &text, &sharedLibs, &stack, &dirtyPages)) return (size_t)size * getpagesize(); else return 0; #endif return 0; } /** * Returns the total size of phyiscal memory in bytes */ size_t mitk::MemoryUtilities::GetTotalSizeOfPhysicalRam() { -#if _MSC_VER || __MINGW32__ +#if _MSC_VER MEMORYSTATUSEX statex; statex.dwLength = sizeof(statex); GlobalMemoryStatusEx(&statex); return (size_t)statex.ullTotalPhys; #elif defined(__APPLE__) int mib[2]; int64_t physical_memory; mib[0] = CTL_HW; mib[1] = HW_MEMSIZE; size_t length = sizeof(int64_t); sysctl(mib, 2, &physical_memory, &length, nullptr, 0); return physical_memory; #else struct sysinfo info; if (!sysinfo(&info)) return info.totalram * info.mem_unit; else return 0; #endif } #ifndef _MSC_VER #ifndef __APPLE__ int mitk::MemoryUtilities::ReadStatmFromProcFS( int *size, int *res, int *shared, int *text, int *sharedLibs, int *stack, int *dirtyPages) { int ret = 0; FILE *f; f = fopen("/proc/self/statm", "r"); if (f) { size_t ignored = fscanf(f, "%d %d %d %d %d %d %d", size, res, shared, text, sharedLibs, stack, dirtyPages); ++ignored; fclose(f); } else { ret = -1; } return ret; } #endif #endif diff --git a/Modules/Core/src/IO/mitkGeometry3DToXML.cpp b/Modules/Core/src/IO/mitkGeometry3DToXML.cpp index 379441bb22..d0019ebddf 100644 --- a/Modules/Core/src/IO/mitkGeometry3DToXML.cpp +++ b/Modules/Core/src/IO/mitkGeometry3DToXML.cpp @@ -1,240 +1,240 @@ /*=================================================================== 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 "mitkGeometry3DToXML.h" -#include +#include #include TiXmlElement *mitk::Geometry3DToXML::ToXML(const Geometry3D *geom3D) { assert(geom3D); // really serialize const AffineTransform3D *transform = geom3D->GetIndexToWorldTransform(); // get transform parameters that would need to be serialized AffineTransform3D::MatrixType matrix = transform->GetMatrix(); AffineTransform3D::OffsetType offset = transform->GetOffset(); bool isImageGeometry = geom3D->GetImageGeometry(); BaseGeometry::BoundsArrayType bounds = geom3D->GetBounds(); // create XML file // construct XML tree describing the geometry auto *geomElem = new TiXmlElement("Geometry3D"); geomElem->SetAttribute("ImageGeometry", isImageGeometry ? "true" : "false"); geomElem->SetAttribute("FrameOfReferenceID", geom3D->GetFrameOfReferenceID()); // coefficients are matrix[row][column]! auto *matrixElem = new TiXmlElement("IndexToWorld"); matrixElem->SetAttribute("type", "Matrix3x3"); matrixElem->SetAttribute("m_0_0", boost::lexical_cast(matrix[0][0])); matrixElem->SetAttribute("m_0_1", boost::lexical_cast(matrix[0][1])); matrixElem->SetAttribute("m_0_2", boost::lexical_cast(matrix[0][2])); matrixElem->SetAttribute("m_1_0", boost::lexical_cast(matrix[1][0])); matrixElem->SetAttribute("m_1_1", boost::lexical_cast(matrix[1][1])); matrixElem->SetAttribute("m_1_2", boost::lexical_cast(matrix[1][2])); matrixElem->SetAttribute("m_2_0", boost::lexical_cast(matrix[2][0])); matrixElem->SetAttribute("m_2_1", boost::lexical_cast(matrix[2][1])); matrixElem->SetAttribute("m_2_2", boost::lexical_cast(matrix[2][2])); geomElem->LinkEndChild(matrixElem); auto *offsetElem = new TiXmlElement("Offset"); offsetElem->SetAttribute("type", "Vector3D"); offsetElem->SetAttribute("x", boost::lexical_cast(offset[0])); offsetElem->SetAttribute("y", boost::lexical_cast(offset[1])); offsetElem->SetAttribute("z", boost::lexical_cast(offset[2])); geomElem->LinkEndChild(offsetElem); auto *boundsElem = new TiXmlElement("Bounds"); auto *boundsMinElem = new TiXmlElement("Min"); boundsMinElem->SetAttribute("type", "Vector3D"); boundsMinElem->SetAttribute("x", boost::lexical_cast(bounds[0])); boundsMinElem->SetAttribute("y", boost::lexical_cast(bounds[2])); boundsMinElem->SetAttribute("z", boost::lexical_cast(bounds[4])); boundsElem->LinkEndChild(boundsMinElem); auto *boundsMaxElem = new TiXmlElement("Max"); boundsMaxElem->SetAttribute("type", "Vector3D"); boundsMaxElem->SetAttribute("x", boost::lexical_cast(bounds[1])); boundsMaxElem->SetAttribute("y", boost::lexical_cast(bounds[3])); boundsMaxElem->SetAttribute("z", boost::lexical_cast(bounds[5])); boundsElem->LinkEndChild(boundsMaxElem); geomElem->LinkEndChild(boundsElem); return geomElem; } mitk::Geometry3D::Pointer mitk::Geometry3DToXML::FromXML(TiXmlElement *geometryElement) { if (!geometryElement) { MITK_ERROR << "Cannot deserialize Geometry3D from nullptr."; return nullptr; } AffineTransform3D::MatrixType matrix; AffineTransform3D::OffsetType offset; bool isImageGeometry(false); unsigned int frameOfReferenceID(0); BaseGeometry::BoundsArrayType bounds; if (TIXML_SUCCESS != geometryElement->QueryUnsignedAttribute("FrameOfReferenceID", &frameOfReferenceID)) { MITK_WARN << "Missing FrameOfReference for Geometry3D."; } if (TIXML_SUCCESS != geometryElement->QueryBoolAttribute("ImageGeometry", &isImageGeometry)) { MITK_WARN << "Missing bool ImageGeometry for Geometry3D."; } // matrix if (TiXmlElement *matrixElem = geometryElement->FirstChildElement("IndexToWorld")->ToElement()) { bool matrixComplete = true; for (unsigned int r = 0; r < 3; ++r) { for (unsigned int c = 0; c < 3; ++c) { std::stringstream element_namer; element_namer << "m_" << r << "_" << c; std::string string_value; if (TIXML_SUCCESS == matrixElem->QueryStringAttribute(element_namer.str().c_str(), &string_value)) { try { matrix[r][c] = boost::lexical_cast(string_value); } catch (boost::bad_lexical_cast &e) { MITK_ERROR << "Could not parse '" << string_value << "' as number: " << e.what(); return nullptr; } } else { matrixComplete = false; } } } if (!matrixComplete) { MITK_ERROR << "Could not parse all Geometry3D matrix coefficients!"; return nullptr; } } else { MITK_ERROR << "Parse error: expected Matrix3x3 child below Geometry3D node"; return nullptr; } // offset if (TiXmlElement *offsetElem = geometryElement->FirstChildElement("Offset")->ToElement()) { bool vectorComplete = true; std::string offset_string[3]; vectorComplete &= TIXML_SUCCESS == offsetElem->QueryStringAttribute("x", &offset_string[0]); vectorComplete &= TIXML_SUCCESS == offsetElem->QueryStringAttribute("y", &offset_string[1]); vectorComplete &= TIXML_SUCCESS == offsetElem->QueryStringAttribute("z", &offset_string[2]); if (!vectorComplete) { MITK_ERROR << "Could not parse complete Geometry3D offset!"; return nullptr; } for (unsigned int d = 0; d < 3; ++d) try { offset[d] = boost::lexical_cast(offset_string[d]); } catch (boost::bad_lexical_cast &e) { MITK_ERROR << "Could not parse '" << offset_string[d] << "' as number: " << e.what(); return nullptr; } } else { MITK_ERROR << "Parse error: expected Offset3D child below Geometry3D node"; return nullptr; } // bounds if (TiXmlElement *boundsElem = geometryElement->FirstChildElement("Bounds")->ToElement()) { bool vectorsComplete(true); std::string bounds_string[6]; if (TiXmlElement *minElem = boundsElem->FirstChildElement("Min")->ToElement()) { vectorsComplete &= TIXML_SUCCESS == minElem->QueryStringAttribute("x", &bounds_string[0]); vectorsComplete &= TIXML_SUCCESS == minElem->QueryStringAttribute("y", &bounds_string[2]); vectorsComplete &= TIXML_SUCCESS == minElem->QueryStringAttribute("z", &bounds_string[4]); } else { vectorsComplete = false; } if (TiXmlElement *maxElem = boundsElem->FirstChildElement("Max")->ToElement()) { vectorsComplete &= TIXML_SUCCESS == maxElem->QueryStringAttribute("x", &bounds_string[1]); vectorsComplete &= TIXML_SUCCESS == maxElem->QueryStringAttribute("y", &bounds_string[3]); vectorsComplete &= TIXML_SUCCESS == maxElem->QueryStringAttribute("z", &bounds_string[5]); } else { vectorsComplete = false; } if (!vectorsComplete) { MITK_ERROR << "Could not parse complete Geometry3D bounds!"; return nullptr; } for (unsigned int d = 0; d < 6; ++d) try { bounds[d] = boost::lexical_cast(bounds_string[d]); } catch (boost::bad_lexical_cast &e) { MITK_ERROR << "Could not parse '" << bounds_string[d] << "' as number: " << e.what(); return nullptr; } } // build GeometryData from matrix/offset AffineTransform3D::Pointer newTransform = AffineTransform3D::New(); newTransform->SetMatrix(matrix); newTransform->SetOffset(offset); Geometry3D::Pointer newGeometry = Geometry3D::New(); newGeometry->SetFrameOfReferenceID(frameOfReferenceID); newGeometry->SetImageGeometry(isImageGeometry); newGeometry->SetIndexToWorldTransform(newTransform); newGeometry->SetBounds(bounds); return newGeometry; } diff --git a/Modules/Core/src/IO/mitkProportionalTimeGeometryToXML.cpp b/Modules/Core/src/IO/mitkProportionalTimeGeometryToXML.cpp index 58594fe397..8925d6245c 100644 --- a/Modules/Core/src/IO/mitkProportionalTimeGeometryToXML.cpp +++ b/Modules/Core/src/IO/mitkProportionalTimeGeometryToXML.cpp @@ -1,166 +1,166 @@ /*=================================================================== 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 "mitkProportionalTimeGeometryToXML.h" #include "mitkGeometry3DToXML.h" #include -#include +#include TiXmlElement *mitk::ProportionalTimeGeometryToXML::ToXML(const ProportionalTimeGeometry *timeGeom) { assert(timeGeom); auto *timeGeomElem = new TiXmlElement("ProportionalTimeGeometry"); timeGeomElem->SetAttribute("NumberOfTimeSteps", timeGeom->CountTimeSteps()); // TinyXML cannot serialize infinity (default value for time step) // So we guard this value and the first time point against serialization problems // by not writing them. The reader can then tell that absence of those values // means "keep the default values" if (timeGeom->GetFirstTimePoint() != -std::numeric_limits::max()) timeGeomElem->SetAttribute("FirstTimePoint", boost::lexical_cast(timeGeom->GetFirstTimePoint())); if (timeGeom->GetStepDuration() != std::numeric_limits::infinity()) timeGeomElem->SetAttribute("StepDuration", boost::lexical_cast(timeGeom->GetStepDuration())); for (TimeStepType t = 0; t < timeGeom->CountTimeSteps(); ++t) { // add a node for the geometry of each time step const Geometry3D *geom3D(nullptr); if ((geom3D = dynamic_cast(timeGeom->GetGeometryForTimeStep(t).GetPointer()))) { TiXmlElement *geom3DElement = Geometry3DToXML::ToXML(geom3D); geom3DElement->SetAttribute("TimeStep", t); // mark order for us timeGeomElem->LinkEndChild(geom3DElement); } else { MITK_WARN << "Serializing a ProportionalTimeGeometry that contains something other than Geometry3D!" << " (in time step " << t << ")" << " File will miss information!"; } } return timeGeomElem; } mitk::ProportionalTimeGeometry::Pointer mitk::ProportionalTimeGeometryToXML::FromXML(TiXmlElement *timeGeometryElement) { if (!timeGeometryElement) { MITK_ERROR << "Cannot deserialize ProportionalTimeGeometry from nullptr."; return nullptr; } int numberOfTimeSteps = 0; if (TIXML_SUCCESS != timeGeometryElement->QueryIntAttribute("NumberOfTimeSteps", &numberOfTimeSteps)) { MITK_WARN << " found without NumberOfTimeSteps attribute. Counting..."; } // might be missing! TimePointType firstTimePoint; std::string firstTimePoint_s; TimePointType stepDuration; std::string stepDuration_s; try { if (TIXML_SUCCESS == timeGeometryElement->QueryStringAttribute("FirstTimePoint", &firstTimePoint_s)) { firstTimePoint = boost::lexical_cast(firstTimePoint_s); } else { firstTimePoint = -std::numeric_limits::max(); } if (TIXML_SUCCESS == timeGeometryElement->QueryStringAttribute("StepDuration", &stepDuration_s)) { stepDuration = boost::lexical_cast(stepDuration_s); } else { stepDuration = std::numeric_limits::infinity(); } } catch (boost::bad_lexical_cast &e) { MITK_ERROR << "Could not parse string as number: " << e.what(); return nullptr; } // list of all geometries with their time steps std::multimap allReadGeometries; int indexForUnlabeledTimeStep(-1); for (TiXmlElement *currentElement = timeGeometryElement->FirstChildElement(); currentElement != nullptr; currentElement = currentElement->NextSiblingElement()) { // different geometries could have been inside a ProportionalTimeGeometry. // By now, we only support Geometry3D std::string tagName = currentElement->Value(); if (tagName == "Geometry3D") { Geometry3D::Pointer restoredGeometry = Geometry3DToXML::FromXML(currentElement); if (restoredGeometry.IsNotNull()) { int timeStep(-1); if (TIXML_SUCCESS != currentElement->QueryIntAttribute("TimeStep", &timeStep)) { timeStep = indexForUnlabeledTimeStep--; // decrement index for next one MITK_WARN << "Found without 'TimeStep' attribute in . No guarantees " "on order anymore."; } if (allReadGeometries.count(static_cast(timeStep)) > 0) { MITK_WARN << "Found tags with identical 'TimeStep' attribute in . No " "guarantees on order anymore."; } allReadGeometries.insert(std::make_pair(static_cast(timeStep), restoredGeometry.GetPointer())); } } else { MITK_WARN << "Found unsupported tag <" << tagName << "> inside . Ignoring."; } } // now add all BaseGeometries that were read to a new instance // of ProportionalTimeGeometry ProportionalTimeGeometry::Pointer newTimeGeometry = ProportionalTimeGeometry::New(); newTimeGeometry->SetFirstTimePoint(firstTimePoint); newTimeGeometry->SetStepDuration(stepDuration); newTimeGeometry->ReserveSpaceForGeometries(allReadGeometries.size()); TimeStepType t(0); for (auto entry : allReadGeometries) { // We add items with newly assigned time steps. // This avoids great confusion when a file contains // bogus numbers. newTimeGeometry->SetTimeStepGeometry(entry.second, t++); } // Need to re-calculate global bounding box. // This is neither stored in a file, nor done by SetTimeStepGeometry newTimeGeometry->UpdateBoundingBox(); return newTimeGeometry; } diff --git a/Modules/Core/src/Rendering/mitkVtkPropRenderer.cpp b/Modules/Core/src/Rendering/mitkVtkPropRenderer.cpp index 4b3274ac0f..391c28b73c 100644 --- a/Modules/Core/src/Rendering/mitkVtkPropRenderer.cpp +++ b/Modules/Core/src/Rendering/mitkVtkPropRenderer.cpp @@ -1,680 +1,682 @@ /*=================================================================== 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 "mitkVtkPropRenderer.h" // MAPPERS #include "mitkCameraController.h" #include "mitkImageVtkMapper2D.h" #include "mitkMapper.h" #include "mitkPlaneGeometryDataVtkMapper3D.h" #include "mitkVtkMapper.h" #include #include #include #include #include #include #include #include #include #include // VTK #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include mitk::VtkPropRenderer::VtkPropRenderer(const char *name, vtkRenderWindow *renWin, mitk::RenderingManager *rm, mitk::BaseRenderer::RenderingMode::Type renderingMode) : BaseRenderer(name, renWin, rm, renderingMode), m_CameraInitializedForMapperID(0) { didCount = false; m_WorldPointPicker = vtkWorldPointPicker::New(); m_PointPicker = vtkPointPicker::New(); m_PointPicker->SetTolerance(0.0025); m_CellPicker = vtkCellPicker::New(); m_CellPicker->SetTolerance(0.0025); mitk::PlaneGeometryDataVtkMapper3D::Pointer geometryMapper = mitk::PlaneGeometryDataVtkMapper3D::New(); m_CurrentWorldPlaneGeometryMapper = geometryMapper; m_CurrentWorldPlaneGeometryNode->SetMapper(2, geometryMapper); m_LightKit = vtkLightKit::New(); m_LightKit->AddLightsToRenderer(m_VtkRenderer); m_PickingMode = WorldPointPicking; m_TextRenderer = vtkRenderer::New(); m_TextRenderer->SetRenderWindow(renWin); m_TextRenderer->SetInteractive(0); m_TextRenderer->SetErase(0); } /*! \brief Destructs the VtkPropRenderer. */ mitk::VtkPropRenderer::~VtkPropRenderer() { // Workaround for GLDisplayList Bug { m_MapperID = 0; checkState(); } if (m_LightKit != nullptr) m_LightKit->Delete(); if (m_VtkRenderer != nullptr) { m_CameraController = nullptr; m_VtkRenderer->Delete(); m_VtkRenderer = nullptr; } else m_CameraController = nullptr; if (m_WorldPointPicker != nullptr) m_WorldPointPicker->Delete(); if (m_PointPicker != nullptr) m_PointPicker->Delete(); if (m_CellPicker != nullptr) m_CellPicker->Delete(); if (m_TextRenderer != nullptr) m_TextRenderer->Delete(); } void mitk::VtkPropRenderer::SetDataStorage(mitk::DataStorage *storage) { if (storage == nullptr || storage == m_DataStorage) return; BaseRenderer::SetDataStorage(storage); static_cast(m_CurrentWorldPlaneGeometryMapper.GetPointer()) ->SetDataStorageForTexture(m_DataStorage.GetPointer()); // Compute the geometry from the current data tree bounds and set it as world geometry this->SetWorldGeometryToDataStorageBounds(); } bool mitk::VtkPropRenderer::SetWorldGeometryToDataStorageBounds() { if (m_DataStorage.IsNull()) return false; // initialize world geometry auto geometry = m_DataStorage->ComputeVisibleBoundingGeometry3D(nullptr, "includeInBoundingBox"); if (geometry.IsNull()) return false; this->SetWorldTimeGeometry(geometry); this->GetVtkRenderer()->ResetCamera(); this->GetCameraController()->Fit(); this->Modified(); return true; } /*! \brief Called by the vtkMitkRenderProp in order to start MITK rendering process. */ int mitk::VtkPropRenderer::Render(mitk::VtkPropRenderer::RenderType type) { // Do we have objects to render? if (this->GetEmptyWorldGeometry()) return 0; if (m_DataStorage.IsNull()) return 0; // Update mappers and prepare mapper queue if (type == VtkPropRenderer::Opaque) this->PrepareMapperQueue(); // go through the generated list and let the sorted mappers paint for (auto it = m_MappersMap.cbegin(); it != m_MappersMap.cend(); it++) { Mapper *mapper = (*it).second; mapper->MitkRender(this, type); } // Render text if (type == VtkPropRenderer::Overlay) { if (m_TextCollection.size() > 0) { m_TextRenderer->SetViewport(this->GetVtkRenderer()->GetViewport()); for (auto it = m_TextCollection.begin(); it != m_TextCollection.end(); ++it) m_TextRenderer->AddViewProp((*it).second); m_TextRenderer->Render(); } } return 1; } /*! \brief PrepareMapperQueue iterates the datatree PrepareMapperQueue iterates the datatree in order to find mappers which shall be rendered. Also, it sortes the mappers wrt to their layer. */ void mitk::VtkPropRenderer::PrepareMapperQueue() { // variable for counting LOD-enabled mappers m_NumberOfVisibleLODEnabledMappers = 0; // Do we have to update the mappers ? if (m_LastUpdateTime < GetMTime() || m_LastUpdateTime < this->GetCurrentWorldPlaneGeometry()->GetMTime()) { Update(); } else if (m_MapperID >= 1 && m_MapperID < 6) Update(); // remove all text properties before mappers will add new ones m_TextRenderer->RemoveAllViewProps(); for (unsigned int i = 0; i < m_TextCollection.size(); i++) { m_TextCollection[i]->Delete(); } m_TextCollection.clear(); // clear priority_queue m_MappersMap.clear(); int mapperNo = 0; // DataStorage if (m_DataStorage.IsNull()) return; DataStorage::SetOfObjects::ConstPointer allObjects = m_DataStorage->GetAll(); for (DataStorage::SetOfObjects::ConstIterator it = allObjects->Begin(); it != allObjects->End(); ++it) { const DataNode::Pointer node = it->Value(); if (node.IsNull()) continue; const mitk::Mapper::Pointer mapper = node->GetMapper(m_MapperID); if (mapper.IsNull()) continue; bool visible = true; node->GetVisibility(visible, this, "visible"); // The information about LOD-enabled mappers is required by RenderingManager if (mapper->IsLODEnabled(this) && visible) { ++m_NumberOfVisibleLODEnabledMappers; } // mapper without a layer property get layer number 1 int layer = 1; node->GetIntProperty("layer", layer, this); int nr = (layer << 16) + mapperNo; m_MappersMap.insert(std::pair(nr, mapper)); mapperNo++; } } void mitk::VtkPropRenderer::Update(mitk::DataNode *datatreenode) { if (datatreenode != nullptr) { mitk::Mapper::Pointer mapper = datatreenode->GetMapper(m_MapperID); if (mapper.IsNotNull()) { if (GetCurrentWorldPlaneGeometry()->IsValid()) { mapper->Update(this); { auto *vtkmapper = dynamic_cast(mapper.GetPointer()); if (vtkmapper != nullptr) { vtkmapper->UpdateVtkTransform(this); } } } } } } void mitk::VtkPropRenderer::Update() { if (m_DataStorage.IsNull()) return; mitk::DataStorage::SetOfObjects::ConstPointer all = m_DataStorage->GetAll(); for (mitk::DataStorage::SetOfObjects::ConstIterator it = all->Begin(); it != all->End(); ++it) Update(it->Value()); Modified(); m_LastUpdateTime = GetMTime(); } /*! \brief This method is called from the two Constructors */ void mitk::VtkPropRenderer::InitRenderer(vtkRenderWindow *renderWindow) { BaseRenderer::InitRenderer(renderWindow); vtkCallbackCommand *renderCallbackCommand = vtkCallbackCommand::New(); renderCallbackCommand->SetCallback(VtkPropRenderer::RenderingCallback); renderWindow->GetInteractor()->AddObserver(vtkCommand::RenderEvent, renderCallbackCommand); renderCallbackCommand->Delete(); if (renderWindow == nullptr) { m_InitNeeded = false; m_ResizeNeeded = false; return; } m_InitNeeded = true; m_ResizeNeeded = true; m_LastUpdateTime = 0; } void mitk::VtkPropRenderer::RenderingCallback(vtkObject *caller, unsigned long, void *, void *) { auto *renderWindowInteractor = dynamic_cast(caller); if (!renderWindowInteractor) return; mitk::BaseRenderer *renderer = mitk::BaseRenderer::GetInstance(renderWindowInteractor->GetRenderWindow()); if (renderer) renderer->RequestUpdate(); } /*! \brief Resize the OpenGL Window */ void mitk::VtkPropRenderer::Resize(int w, int h) { BaseRenderer::Resize(w, h); m_RenderingManager->RequestUpdate(this->GetRenderWindow()); } void mitk::VtkPropRenderer::InitSize(int w, int h) { m_RenderWindow->SetSize(w, h); Superclass::InitSize(w, h); Modified(); Update(); if (m_VtkRenderer != nullptr) { int w = vtkObject::GetGlobalWarningDisplay(); vtkObject::GlobalWarningDisplayOff(); m_VtkRenderer->ResetCamera(); vtkObject::SetGlobalWarningDisplay(w); } this->GetCameraController()->Fit(); } int mitk::VtkPropRenderer::WriteSimpleText( std::string text, double posX, double posY, double color1, double color2, double color3, float opacity) { this->GetVtkRenderer()->ViewToDisplay(); if (!text.empty()) { Point2D p; vtkTextActor *textActor = vtkTextActor::New(); textActor->SetDisplayPosition(posX, posY); textActor->SetInput(text.c_str()); textActor->SetTextScaleModeToNone(); textActor->GetTextProperty()->SetColor(color1, color2, color3); // TODO: Read color from node property textActor->GetTextProperty()->SetOpacity(opacity); int text_id = m_TextCollection.size(); m_TextCollection.insert(TextMapType::value_type(text_id, textActor)); return text_id; } else { return -1; } } void mitk::VtkPropRenderer::SetMapperID(const MapperSlotId mapperId) { if (m_MapperID != mapperId) Superclass::SetMapperID(mapperId); // Workaround for GL Displaylist Bug checkState(); } /*! \brief Activates the current renderwindow. */ void mitk::VtkPropRenderer::MakeCurrent() { if (m_RenderWindow != nullptr) m_RenderWindow->MakeCurrent(); } void mitk::VtkPropRenderer::PickWorldPoint(const mitk::Point2D &displayPoint, mitk::Point3D &worldPoint) const { if (this->GetRenderWindow()->GetNeverRendered() != 0) return; // somebody called picking before we ever rendered; cannot have enough information yet switch (m_PickingMode) { case (WorldPointPicking): { m_WorldPointPicker->Pick(displayPoint[0], displayPoint[1], 0, m_VtkRenderer); vtk2itk(m_WorldPointPicker->GetPickPosition(), worldPoint); break; } case (PointPicking): { m_PointPicker->Pick(displayPoint[0], displayPoint[1], 0, m_VtkRenderer); vtk2itk(m_PointPicker->GetPickPosition(), worldPoint); break; } case (CellPicking): { m_CellPicker->Pick(displayPoint[0], displayPoint[1], 0, m_VtkRenderer); vtk2itk(m_CellPicker->GetPickPosition(), worldPoint); break; } } // todo: is this picking in 2D renderwindows? // Superclass::PickWorldPoint(displayPoint, worldPoint); } mitk::DataNode *mitk::VtkPropRenderer::PickObject(const Point2D &displayPosition, Point3D &worldPosition) const { m_CellPicker->InitializePickList(); // Iterate over all DataStorage objects to determine all vtkProps intended // for picking DataStorage::SetOfObjects::ConstPointer allObjects = m_DataStorage->GetAll(); for (DataStorage::SetOfObjects::ConstIterator it = allObjects->Begin(); it != allObjects->End(); ++it) { const DataNode *node = it->Value(); if (node == nullptr) continue; bool pickable = false; node->GetBoolProperty("pickable", pickable); if (!pickable) continue; auto *mapper = dynamic_cast(node->GetMapper(m_MapperID)); if (mapper == nullptr) continue; vtkProp *prop = mapper->GetVtkProp((mitk::BaseRenderer *)this); if (prop == nullptr) continue; m_CellPicker->AddPickList(prop); } // Do the picking and retrieve the picked vtkProp (if any) m_CellPicker->PickFromListOn(); m_CellPicker->Pick(displayPosition[0], displayPosition[1], 0.0, m_VtkRenderer); m_CellPicker->PickFromListOff(); vtk2itk(m_CellPicker->GetPickPosition(), worldPosition); vtkProp *prop = m_CellPicker->GetViewProp(); if (prop == nullptr) { return nullptr; } // Iterate over all DataStorage objects to determine if the retrieved // vtkProp is owned by any associated mapper. for (DataStorage::SetOfObjects::ConstIterator it = allObjects->Begin(); it != allObjects->End(); ++it) { DataNode::Pointer node = it->Value(); if (node.IsNull()) continue; mitk::Mapper *mapper = node->GetMapper(m_MapperID); if (mapper == nullptr) continue; auto *vtkmapper = dynamic_cast(mapper); if (vtkmapper) { // if vtk-based, then ... if (vtkmapper->HasVtkProp(prop, const_cast(this))) { return node; } } } return nullptr; } // todo: is this 2D renderwindow picking? // return Superclass::PickObject( displayPosition, worldPosition ); vtkTextProperty *mitk::VtkPropRenderer::GetTextLabelProperty(int text_id) { return this->m_TextCollection[text_id]->GetTextProperty(); } void mitk::VtkPropRenderer::InitPathTraversal() { if (m_DataStorage.IsNotNull()) { this->UpdatePaths(); this->m_Paths->InitTraversal(); } } void mitk::VtkPropRenderer::UpdatePaths() { if (m_DataStorage.IsNull()) { return; } if (GetMTime() > m_PathTime || (m_Paths != nullptr && m_Paths->GetMTime() > m_PathTime)) { // Create the list to hold all the paths m_Paths = vtkSmartPointer::New(); DataStorage::SetOfObjects::ConstPointer objects = m_DataStorage->GetAll(); for (auto iter = objects->begin(); iter != objects->end(); ++iter) { vtkSmartPointer onePath = vtkSmartPointer::New(); Mapper *mapper = (*iter)->GetMapper(BaseRenderer::Standard3D); if (mapper) { auto *vtkmapper = dynamic_cast(mapper); + + if (nullptr != vtkmapper) { vtkProp *prop = vtkmapper->GetVtkProp(this); if (prop && prop->GetVisibility()) { // add to assembly path onePath->AddNode(prop, prop->GetMatrix()); m_Paths->AddItem(onePath); } } } } m_PathTime.Modified(); } } int mitk::VtkPropRenderer::GetNumberOfPaths() { UpdatePaths(); return m_Paths->GetNumberOfItems(); } vtkAssemblyPath *mitk::VtkPropRenderer::GetNextPath() { return m_Paths ? m_Paths->GetNextItem() : nullptr; } void mitk::VtkPropRenderer::ReleaseGraphicsResources(vtkWindow * /*renWin*/) { if (m_DataStorage.IsNull()) return; DataStorage::SetOfObjects::ConstPointer allObjects = m_DataStorage->GetAll(); for (auto iter = allObjects->begin(); iter != allObjects->end(); ++iter) { DataNode::Pointer node = *iter; if (node.IsNull()) continue; Mapper *mapper = node->GetMapper(m_MapperID); if (mapper) { auto *vtkmapper = dynamic_cast(mapper); if (vtkmapper) vtkmapper->ReleaseGraphicsResources(this); } } } const vtkWorldPointPicker *mitk::VtkPropRenderer::GetWorldPointPicker() const { return m_WorldPointPicker; } const vtkPointPicker *mitk::VtkPropRenderer::GetPointPicker() const { return m_PointPicker; } const vtkCellPicker *mitk::VtkPropRenderer::GetCellPicker() const { return m_CellPicker; } mitk::VtkPropRenderer::MappersMapType mitk::VtkPropRenderer::GetMappersMap() const { return m_MappersMap; } // Workaround for GL Displaylist bug static int glWorkAroundGlobalCount = 0; bool mitk::VtkPropRenderer::useImmediateModeRendering() { return glWorkAroundGlobalCount > 1; } void mitk::VtkPropRenderer::checkState() { if (m_MapperID == Standard3D) { if (!didCount) { didCount = true; glWorkAroundGlobalCount++; if (glWorkAroundGlobalCount == 2) { MITK_INFO << "Multiple 3D Renderwindows active...: turning Immediate Rendering ON for legacy mappers"; // vtkMapper::GlobalImmediateModeRenderingOn(); } } } else { if (didCount) { didCount = false; glWorkAroundGlobalCount--; if (glWorkAroundGlobalCount == 1) { MITK_INFO << "Single 3D Renderwindow active...: turning Immediate Rendering OFF for legacy mappers"; // vtkMapper::GlobalImmediateModeRenderingOff(); } } } } //### Contains all methods which are neceassry before each VTK Render() call void mitk::VtkPropRenderer::PrepareRender() { if (this->GetMapperID() != m_CameraInitializedForMapperID) { Initialize2DvtkCamera(); // Set parallel projection etc. } GetCameraController()->AdjustCameraToPlane(); } bool mitk::VtkPropRenderer::Initialize2DvtkCamera() { if (this->GetMapperID() == Standard3D) { // activate parallel projection for 2D this->GetVtkRenderer()->GetActiveCamera()->SetParallelProjection(false); vtkSmartPointer style = vtkSmartPointer::New(); this->GetRenderWindow()->GetInteractor()->SetInteractorStyle(style); this->GetRenderWindow()->GetInteractor()->EnableRenderOff(); m_CameraInitializedForMapperID = Standard3D; } else if (this->GetMapperID() == Standard2D) { // activate parallel projection for 2D this->GetVtkRenderer()->GetActiveCamera()->SetParallelProjection(true); // turn the light out in the scene in order to render correct grey values. // TODO Implement a property for light in the 2D render windows (in another method) this->GetVtkRenderer()->RemoveAllLights(); vtkSmartPointer style = vtkSmartPointer::New(); this->GetRenderWindow()->GetInteractor()->SetInteractorStyle(style); this->GetRenderWindow()->GetInteractor()->EnableRenderOff(); m_CameraInitializedForMapperID = Standard2D; } return true; } diff --git a/Modules/Core/test/DirectOverlayTest.cpp b/Modules/Core/test/DirectOverlayTest.cpp index efd216fe9e..620160f593 100644 --- a/Modules/Core/test/DirectOverlayTest.cpp +++ b/Modules/Core/test/DirectOverlayTest.cpp @@ -1,237 +1,237 @@ #include #include #include #include #include #include #include #include #include #include -//#include +//#include class DirectOverlayTestClass { public: template static void InternalThreshold(const itk::Image *image, mitk::Image::Pointer &output, const double th[]) { typedef itk::Image InputImageType; typedef itk::Image OutputImageType; typedef itk::BinaryThresholdImageFilter BinaryThresholdFilterType; typename BinaryThresholdFilterType::Pointer thresholder = BinaryThresholdFilterType::New(); thresholder->SetInput(image); thresholder->SetLowerThreshold(th[0]); thresholder->SetUpperThreshold(th[1]); thresholder->SetInsideValue(255); thresholder->SetOutsideValue(0); thresholder->Update(); output = mitk::ImportItkImage(thresholder->GetOutput()); // mitk::IOUtil::Save( output, "/tmp/out.nii" ); std::cout << "extra line"; } template static void InternalThreshold2(const itk::Image *image, itk::Image::Pointer &output, const double th[]) { typedef itk::Image InputImageType; typedef itk::Image OutputImageType; typedef itk::BinaryThresholdImageFilter BinaryThresholdFilterType; typename BinaryThresholdFilterType::Pointer thresholder = BinaryThresholdFilterType::New(); thresholder->SetInput(image); thresholder->SetLowerThreshold(th[0]); thresholder->SetUpperThreshold(th[1]); thresholder->SetInsideValue(255); thresholder->SetOutsideValue(0); thresholder->Update(); output = thresholder->GetOutput(); } static void TestOverlay(mitk::Image::Pointer original, mitk::Image::Pointer truth, const double lower, const double upper) { mitk::Image::Pointer overlayImage; const double th[] = {lower, upper}; typedef itk::Image ImageType; ImageType::Pointer itkOverlayImage = ImageType::New(); AccessByItk_2(original, InternalThreshold, overlayImage, th); /* AccessFixedDimensionByItk_2( original, InternalThreshold2, 3, itkOverlayImage, th ); overlayImage = mitk::ImportItkImage( itkOverlayImage ); */ // mitk::IOUtil::Save(truth, "/tmp/truth_TestOverlay.nii"); try { // mitk::Image::Pointer temp = overlayImage; mitk::IOUtil::Save(overlayImage, "/tmp/overlayImage_TestOverlay.nrrd"); } catch (const itk::ExceptionObject &e) { MITK_ERROR << "Save image: exception : " << e.what(); } typedef itk::Image InputImageType; InputImageType::Pointer overlayItk; try { mitk::CastToItkImage(overlayImage, overlayItk); } catch (const mitk::Exception &e) { MITK_ERROR << "(CAST) Catched exception while creating accessor " << e.what(); // MITK_TEST_FAILED_MSG("Exception for ouverlay image"); } /* typedef itk::ImageFileWriter< InputImageType > WriterType; WriterType::Pointer writer = WriterType::New(); writer->SetFileName("/tmp/overlayITK_TestOverlay.nii"); writer->SetInput(overlayItk); writer->Update(); */ InputImageType::Pointer truthItk; mitk::CastToItkImage(truth, truthItk); bool difference = false; /* try { typedef unsigned int TPixel; itk::ImageRegionConstIteratorWithIndex< InputImageType > iter( truthItk, truthItk->GetLargestPossibleRegion() ); iter.GoToBegin(); mitk::ImagePixelReadAccessor< TPixel, 3 > readAccessor( overlayImage, overlayImage->GetVolumeData(0), mitk::ImageAccessorBase::ExceptionIfLocked ); while( !iter.IsAtEnd() ) { TPixel ref = iter.Get(); TPixel val = readAccessor.GetPixelByIndex( iter.GetIndex() ); difference |= ( ref != val ); //if( difference ) //{ std::cout << iter.GetIndex() << ":" << ref << " ? " << val << "\n"; //} ++iter; } } catch( const mitk::Exception &e) { MITK_ERROR << "Catched exception while creating accessor "<< e.what(); //MITK_TEST_FAILED_MSG("Exception for ouverlay image"); } */ /* typedef itk::Testing::ComparisonImageFilter ComparisonImageFilterType; ComparisonImageFilterType::Pointer comp = ComparisonImageFilterType::New(); comp->SetValidInput(truthItk); comp->SetTestInput(overlayItk); try { comp->Update(); } catch( const itk::ExceptionObject& e) { MITK_ERROR << "ITK Exception: " << e.what(); } */ typedef unsigned int TPixel; itk::ImageRegionConstIteratorWithIndex iter(truthItk, truthItk->GetLargestPossibleRegion()); itk::ImageRegionConstIteratorWithIndex iter2(overlayItk, overlayItk->GetLargestPossibleRegion()); iter.GoToBegin(); unsigned int counter = 0; while (!iter.IsAtEnd() && !iter2.IsAtEnd()) { TPixel ref = iter.Get(); TPixel val = iter2.Get(); if (ref != val) { counter++; // std::cout << iter.GetIndex() << ":" << ref << " ? " << val << "\n"; } ++iter; ++iter2; } std::cout << "Differs in " << counter << "voxels" << std::endl; MITK_TEST_CONDITION_REQUIRED( // comp->GetNumberOfPixelsWithDifferences() == 0, counter == 0, "Comparing overlay with ground truth") } static void TestDirectOverlay(char *in, char *gt, const int lower, const int upper) { mitk::Image::Pointer original = mitk::IOUtil::Load(in); mitk::Image::Pointer truth = mitk::IOUtil::Load(gt); if (original.IsNotNull() && original->GetDimension() == 3 && truth.IsNotNull() && truth->GetDimension() == 3 && upper > lower) { TestOverlay(original, truth, lower, upper); } else { MITK_TEST_FAILED_MSG(<< "Invalid parameters"); } } }; int DirectOverlayTest(int argc, char *argv[]) { MITK_TEST_BEGIN("DirectOverlay") MITK_TEST_CONDITION_REQUIRED(argc >= 5, "File to load has been specified on the command line"); unsigned int lower = 0, upper = 0; try { sscanf(argv[3], "%u", &lower); sscanf(argv[4], "%u", &upper); // lower = boost::lexical_cast(argv[3]); // upper = boost::lexical_cast(argv[4]); MITK_INFO << "Got values: " << lower << " : " << upper; } catch (std::exception &e) { MITK_TEST_FAILED_MSG(<< e.what()); } DirectOverlayTestClass::TestDirectOverlay(argv[1], argv[2], lower, upper); MITK_TEST_END() } diff --git a/Modules/Core/test/mitkFloatToStringTest.cpp b/Modules/Core/test/mitkFloatToStringTest.cpp index 027bd48aa7..bbb53654eb 100644 --- a/Modules/Core/test/mitkFloatToStringTest.cpp +++ b/Modules/Core/test/mitkFloatToStringTest.cpp @@ -1,146 +1,146 @@ /*=================================================================== 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 "mitkTestFixture.h" #include "mitkTestingMacros.h" -#include +#include #include "mitkEqual.h" #include #include "mitkLog.h" #include #include //! //! Verifies boost::lexical for MITK's serialization purposes //! //! Verifies: //! - special numbers behavior: //! - infinity converted to "inf", parsed from "inf" or "infinity" (case-independent) //! - not-a-number converted to "nan", parsed from "nan" (case-independent) //! - Default round-trip conversion double-to-string-to-double compares equal given //! the MITK default epsilon value (mitk::Equal) //! class mitkFloatToStringTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkFloatToStringTestSuite); MITK_TEST(ConfirmStringValues); MITK_TEST(ConfirmStringValues); MITK_TEST(TestConversions); MITK_TEST(TestConversions); CPPUNIT_TEST_SUITE_END(); public: template void ConfirmNumberToString(DATATYPE number, const std::string &s) { CPPUNIT_ASSERT_EQUAL(boost::lexical_cast(number), s); } template void ConfirmStringToNumber(const std::string &s, DATATYPE number) { CPPUNIT_ASSERT_EQUAL(number, boost::lexical_cast(s)); } template void ConfirmStringValues() { // we want to make sure that the following strings will be accepted and returned // by our conversion functions. This must not change in the future to ensure compatibility auto nan = boost::lexical_cast("nan"); CPPUNIT_ASSERT_MESSAGE("nan==nan must be false", !(nan == nan)); nan = boost::lexical_cast("NAN"); CPPUNIT_ASSERT_MESSAGE("NAN==NAN must be false", !(nan == nan)); std::string s_nan = boost::lexical_cast(nan); CPPUNIT_ASSERT_EQUAL(std::string("nan"), s_nan); ConfirmStringToNumber("inf", std::numeric_limits::infinity()); ConfirmStringToNumber("INF", std::numeric_limits::infinity()); ConfirmStringToNumber("infinity", std::numeric_limits::infinity()); ConfirmStringToNumber("INFINITY", std::numeric_limits::infinity()); ConfirmStringToNumber("-inf", -std::numeric_limits::infinity()); ConfirmStringToNumber("-INF", -std::numeric_limits::infinity()); ConfirmStringToNumber("-infinity", -std::numeric_limits::infinity()); ConfirmStringToNumber("-INFINITY", -std::numeric_limits::infinity()); ConfirmNumberToString(std::numeric_limits::infinity(), "inf"); ConfirmNumberToString(-std::numeric_limits::infinity(), "-inf"); } template void CheckRoundTrip(DATATYPE number, DATATYPE tolerance) { std::string s = boost::lexical_cast(number); auto number2 = boost::lexical_cast(s); CPPUNIT_ASSERT_MESSAGE(std::string("Must not parse string ") + s + " as NaN", number2 == number2); if (tolerance == 0) { CPPUNIT_ASSERT_EQUAL(number, number2); } else // mitk::Equal cannot take 0 as tolerance { CPPUNIT_ASSERT(mitk::Equal(number, number2, tolerance)); } } template void CheckRoundTrip(const std::string &input) { auto number = boost::lexical_cast(input); std::string result = boost::lexical_cast(number); // There are normal imprecisions when converting to string // We do only compare if the numeric values match "close enough" auto number2 = boost::lexical_cast(result); CPPUNIT_ASSERT(mitk::Equal(number, number2)); } template void TestConversions() { // we cannot test the NaN roundtrip because nan == nan will never be true CheckRoundTrip(std::numeric_limits::infinity(), 0.0); CheckRoundTrip(-std::numeric_limits::infinity(), 0.0); CheckRoundTrip(std::numeric_limits::denorm_min(), mitk::eps); CheckRoundTrip(std::numeric_limits::epsilon(), mitk::eps); CheckRoundTrip(std::numeric_limits::lowest(), mitk::eps); CheckRoundTrip(std::numeric_limits::min(), mitk::eps); CheckRoundTrip(std::numeric_limits::max(), mitk::eps); CheckRoundTrip(sqrt(2), mitk::eps); CheckRoundTrip(0.000000042, mitk::eps); CheckRoundTrip(422345678.2345678, mitk::eps); CheckRoundTrip(0.0, 0); CheckRoundTrip(-0.0, 0); CheckRoundTrip("1"); CheckRoundTrip("1.1"); CheckRoundTrip("1.12121212"); CheckRoundTrip("1.1e-2"); } }; // class MITK_TEST_SUITE_REGISTRATION(mitkFloatToString) diff --git a/Modules/Core/test/mitkImageDataItemTest.cpp b/Modules/Core/test/mitkImageDataItemTest.cpp index b332e9eca7..c17d46b8a7 100644 --- a/Modules/Core/test/mitkImageDataItemTest.cpp +++ b/Modules/Core/test/mitkImageDataItemTest.cpp @@ -1,32 +1,74 @@ /*=================================================================== 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 "mitkImage.h" -#include "mitkImageDataItem.h" +#include -#include -int mitkImageDataItemTest(int /*argc*/, char * /*argv*/ []) +#include "mitkTestFixture.h" +#include "mitkTestingMacros.h" + +#include + +#include +#include +#include + +class mitkImageDataItemTestSuite : public mitk::TestFixture { - auto pixels = new unsigned long[100]; - void *data = pixels; + CPPUNIT_TEST_SUITE(mitkImageDataItemTestSuite); + MITK_TEST(TestAccessOnHugeImage); + CPPUNIT_TEST_SUITE_END(); + +private: + mitk::Image::Pointer m_Image; + +public: + void setUp() override + { + m_Image = mitk::Image::New(); + mitk::PixelType pixelType = mitk::MakeScalarPixelType(); + + std::array dimensions = {{ 1700, 1700, 1700 }}; + m_Image->Initialize(pixelType, 3, dimensions.data()); + } + + void TestAccessOnHugeImage() + { + CPPUNIT_ASSERT(m_Image.IsNotNull()); + + try + { + mitk::ImagePixelWriteAccessor writeAccess(m_Image.GetPointer(), m_Image->GetVolumeData()); + + auto* voxelStart = writeAccess.GetData(); + size_t imageSize = 1; + for (unsigned int i = 0; i < m_Image->GetDimension(); i++) + imageSize *= m_Image->GetDimension(i); + + auto* voxelEnd = voxelStart + imageSize; - std::cout << "Testing pseudo-type independent deleting: "; - delete[](unsigned char *) data; - std::cout << "[PASSED]" << std::endl; + CPPUNIT_ASSERT(writeAccess.GetData() != nullptr); + auto* accessCheck = voxelEnd - 1; + *accessCheck = 1; + } + catch (const itk::MemoryAllocationError& e) + { + MITK_ERROR << e.what(); + exit(77); + } + } +}; - std::cout << "[TEST DONE]" << std::endl; - return EXIT_SUCCESS; -} +MITK_TEST_SUITE_REGISTRATION(mitkImageDataItem) diff --git a/Modules/CppMicroServices/CMakeLists.txt b/Modules/CppMicroServices/CMakeLists.txt index 85168a4a52..afcc73d72e 100644 --- a/Modules/CppMicroServices/CMakeLists.txt +++ b/Modules/CppMicroServices/CMakeLists.txt @@ -1,450 +1,443 @@ project(CppMicroServices) set(${PROJECT_NAME}_MAJOR_VERSION 2) set(${PROJECT_NAME}_MINOR_VERSION 99) set(${PROJECT_NAME}_PATCH_VERSION 0) set(${PROJECT_NAME}_VERSION ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION}) cmake_minimum_required(VERSION 2.8) cmake_policy(VERSION 2.8) cmake_policy(SET CMP0017 NEW) #----------------------------------------------------------------------------- # Update CMake module path #------------------------------------------------------------------------------ set(US_CMAKE_DIR ${PROJECT_SOURCE_DIR}/cmake) set(CMAKE_MODULE_PATH ${US_CMAKE_DIR} ${CMAKE_MODULE_PATH} ) #----------------------------------------------------------------------------- # CMake function(s) and macro(s) #----------------------------------------------------------------------------- include(CMakeParseArguments) include(CMakePackageConfigHelpers) include(CheckCXXSourceCompiles) include(usFunctionAddResources) include(usFunctionEmbedResources) include(usFunctionGetResourceSource) include(usFunctionCheckResourceLinking) include(usFunctionCheckCompilerFlags) include(usFunctionGetGccVersion) include(usFunctionGenerateModuleInit) include(usMacroCreateModule) if(US_BUILD_TESTING) include(usFunctionCompileSnippets) endif() #----------------------------------------------------------------------------- # Init output directories #----------------------------------------------------------------------------- set(US_ARCHIVE_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(US_LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/lib") set(US_RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/bin") foreach(_type ARCHIVE LIBRARY RUNTIME) if(NOT CMAKE_${_type}_OUTPUT_DIRECTORY) set(CMAKE_${_type}_OUTPUT_DIRECTORY ${US_${_type}_OUTPUT_DIRECTORY}) endif() endforeach() #----------------------------------------------------------------------------- # Set a default build type if none was specified #----------------------------------------------------------------------------- if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) message(STATUS "Setting build type to 'Debug' as none was specified.") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Choose the type of build." FORCE) # Set the possible values of build type for cmake-gui set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") endif() #----------------------------------------------------------------------------- # CMake options #----------------------------------------------------------------------------- function(us_cache_var _var_name _var_default _var_type _var_help) set(_advanced 0) set(_force) foreach(_argn ${ARGN}) if(_argn STREQUAL ADVANCED) set(_advanced 1) elseif(_argn STREQUAL FORCE) set(_force FORCE) endif() endforeach() if(US_IS_EMBEDDED) if(NOT DEFINED ${_var_name} OR _force) set(${_var_name} ${_var_default} PARENT_SCOPE) endif() else() set(${_var_name} ${_var_default} CACHE ${_var_type} "${_var_help}" ${_force}) if(_advanced) mark_as_advanced(${_var_name}) endif() endif() endfunction() # Determine if we are being build inside a larger project if(NOT DEFINED US_IS_EMBEDDED) if(CMAKE_PROJECT_NAME STREQUAL PROJECT_NAME) set(US_IS_EMBEDDED 0) else() set(US_IS_EMBEDDED 1) endif() endif() # Determine the name of the install component for "SDK" artifacts. # The default is "sdk" if(NOT DEFINED US_SDK_INSTALL_COMPONENT) set(US_SDK_INSTALL_COMPONENT COMPONENT sdk) elseif(US_SDK_INSTALL_COMPONENT) set(US_SDK_INSTALL_COMPONENT COMPONENT ${US_SDK_INSTALL_COMPONENT}) endif() us_cache_var(US_ENABLE_AUTOLOADING_SUPPORT OFF BOOL "Enable module auto-loading support") us_cache_var(US_ENABLE_THREADING_SUPPORT OFF BOOL "Enable threading support") us_cache_var(US_ENABLE_DEBUG_OUTPUT OFF BOOL "Enable debug messages" ADVANCED) us_cache_var(US_BUILD_SHARED_LIBS ON BOOL "Build shared libraries") us_cache_var(US_BUILD_TESTING OFF BOOL "Build tests") us_cache_var(US_BUILD_EXAMPLES OFF BOOL "Build example projects") if(US_BUILD_TESTING) enable_testing() endif() if(WIN32 AND NOT CYGWIN) set(default_runtime_install_dir bin/) set(default_library_install_dir bin/) set(default_archive_install_dir lib/) set(default_header_install_dir include/) set(default_auxiliary_install_dir share/) else() set(default_runtime_install_dir bin/) set(default_library_install_dir lib/${PROJECT_NAME}) set(default_archive_install_dir lib/${PROJECT_NAME}) set(default_header_install_dir include/${PROJECT_NAME}) set(default_auxiliary_install_dir share/${PROJECT_NAME}) endif() us_cache_var(RUNTIME_INSTALL_DIR ${default_runtime_install_dir} STRING "Relative install location for binaries" ADVANCED) us_cache_var(LIBRARY_INSTALL_DIR ${default_library_install_dir} STRING "Relative install location for libraries" ADVANCED) us_cache_var(ARCHIVE_INSTALL_DIR ${default_archive_install_dir} STRING "Relative install location for archives" ADVANCED) us_cache_var(HEADER_INSTALL_DIR ${default_header_install_dir} STRING "Relative install location for headers" ADVANCED) us_cache_var(AUXILIARY_INSTALL_DIR ${default_auxiliary_install_dir} STRING "Relative install location for auxiliary files" ADVANCED) set(AUXILIARY_CMAKE_INSTALL_DIR ${AUXILIARY_INSTALL_DIR}/cmake) us_cache_var(US_NAMESPACE "us" STRING "The namespace for the C++ Micro Services symbols") set(BUILD_SHARED_LIBS ${US_BUILD_SHARED_LIBS}) set(US_MODULE_INIT_TEMPLATE "${US_CMAKE_DIR}/usModuleInit.cpp" CACHE INTERNAL "The module initialization template code") set(US_RESOURCE_RC_TEMPLATE "${US_CMAKE_DIR}/us_resources.rc.in" CACHE INTERNAL "The Windows RC resource template") set(US_CMAKE_RESOURCE_DEPENDENCIES_CPP "${US_CMAKE_DIR}/usCMakeResourceDependencies.cpp" CACHE INTERNAL "The dummy resource dependencies code") #----------------------------------------------------------------------------- # US C/CXX Flags #----------------------------------------------------------------------------- if(US_IS_EMBEDDED) set(CMAKE_C_FLAGS) set(CMAKE_C_FLAGS_RELEASE) set(CMAKE_C_FLAGS_DEBUG) set(CMAKE_CXX_FLAGS) set(CMAKE_CXX_FLAGS_RELEASE) set(CMAKE_CXX_FLAGS_DEBUG) set(CMAKE_LINK_FLAGS) set(CMAKE_LINK_FLAGS_RELEASE) set(CMAKE_LINK_FLAGS_DEBUG) endif() # Set C++ compiler flags if(NOT MSVC) foreach(_cxxflag -Werror -Wall -Wextra -Wpointer-arith -Winvalid-pch -Wcast-align -Wwrite-strings -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast -Wstrict-null-sentinel -Wsign-promo -fdiagnostics-show-option) usFunctionCheckCompilerFlags(${_cxxflag} US_CXX_FLAGS) endforeach() endif() set(US_HAVE_VISIBILITY_ATTRIBUTE 0) usFunctionCheckCompilerFlags("-fvisibility=hidden -fvisibility-inlines-hidden" _have_visibility) if(_have_visibility) set(US_HAVE_VISIBILITY_ATTRIBUTE 1) endif() if(CMAKE_COMPILER_IS_GNUCXX) usFunctionGetGccVersion(${CMAKE_CXX_COMPILER} GCC_VERSION) if(${GCC_VERSION} VERSION_LESS "4.0.0") message(FATAL_ERROR "gcc version ${GCC_VERSION} not supported. Please use gcc >= 4.") endif() # With older versions of gcc the flag -fstack-protector-all requires an extra dependency to libssp.so. # If the gcc version is lower than 4.4.0 and the build type is Release let's not include the flag. if(${GCC_VERSION} VERSION_GREATER "4.4.0" OR (CMAKE_BUILD_TYPE STREQUAL "Debug" AND ${GCC_VERSION} VERSION_LESS "4.4.0")) usFunctionCheckCompilerFlags("-fstack-protector-all" US_CXX_FLAGS) endif() - if(MINGW) - # suppress warnings about auto imported symbols - set(US_CXX_FLAGS "-Wl,--enable-auto-import ${US_CXX_FLAGS}") - # we need to define a Windows version - set(US_CXX_FLAGS "-D_WIN32_WINNT=0x0500 ${US_CXX_FLAGS}") + # Enable visibility support (only for gcc >= 4.5) + # We only support hidden visibility with gcc for now. + # + # Clang has troubles with correctly marking template declarations and explicit template + # instantiations as exported across shared library boundaries. Specifically, comparing + # type_info objects from STL types does not work (used in us::Any::Type() == typeid(std::string)) + # which could be related to the default visibility of STL types declared in libstdc++ and/or libc++ + # but also to using RTLD_LOCAL or RTLD_GLOBAL when loading shared libraries via dlopen(). + # + # See http://comments.gmane.org/gmane.comp.compilers.clang.scm/50028 + # and http://llvm.org/bugs/show_bug.cgi?id=10113 + # + if(_have_visibility AND NOT ${GCC_VERSION} VERSION_LESS "4.5") + set(US_CXX_FLAGS "${US_CXX_FLAGS} ${_have_visibility}") else() - # Enable visibility support (only for gcc >= 4.5) - # We only support hidden visibility with gcc for now. - # - # Clang has troubles with correctly marking template declarations and explicit template - # instantiations as exported across shared library boundaries. Specifically, comparing - # type_info objects from STL types does not work (used in us::Any::Type() == typeid(std::string)) - # which could be related to the default visibility of STL types declared in libstdc++ and/or libc++ - # but also to using RTLD_LOCAL or RTLD_GLOBAL when loading shared libraries via dlopen(). - # - # See http://comments.gmane.org/gmane.comp.compilers.clang.scm/50028 - # and http://llvm.org/bugs/show_bug.cgi?id=10113 - # - if(_have_visibility AND NOT ${GCC_VERSION} VERSION_LESS "4.5") - set(US_CXX_FLAGS "${US_CXX_FLAGS} ${_have_visibility}") - else() - set(US_GCC_RTTI_WORKAROUND_NEEDED 1) - endif() + set(US_GCC_RTTI_WORKAROUND_NEEDED 1) endif() usFunctionCheckCompilerFlags("-O1 -D_FORTIFY_SOURCE=2" _fortify_source_flag) if(_fortify_source_flag) set(US_CXX_FLAGS_RELEASE "${US_CXX_FLAGS_RELEASE} -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2") endif() endif() if(MSVC) set(US_CXX_FLAGS "/MP /WX /wd4180 /wd4996 /wd4251 /wd4503 ${US_CXX_FLAGS}") endif() set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${US_CXX_FLAGS}") set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${US_CXX_FLAGS_RELEASE}") set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${US_C_FLAGS}") set(CMAKE_C_FLAGS_REALEASE "${CMAKE_C_FLAGS_RELEASE} ${US_C_FLAGS_RELEASE}") #----------------------------------------------------------------------------- # US Link Flags #----------------------------------------------------------------------------- set(US_LINK_FLAGS ) if(CMAKE_COMPILER_IS_GNUCXX AND NOT APPLE) foreach(_linkflag -Wl,--no-undefined) set(_add_flag) usFunctionCheckCompilerFlags("${_linkflag}" _add_flag) if(_add_flag) set(US_LINK_FLAGS "${US_LINK_FLAGS} ${_linkflag}") endif() endforeach() endif() usFunctionCheckResourceLinking() #----------------------------------------------------------------------------- # US Header Checks #----------------------------------------------------------------------------- include(CheckIncludeFileCXX) include(CheckCXXSourceCompiles) CHECK_INCLUDE_FILE_CXX(cxxabi.h US_HAVE_CXXABI_H) CHECK_INCLUDE_FILE_CXX(stdint.h US_HAVE_STDINT_H) CHECK_INCLUDE_FILE_CXX(tr1/unordered_map US_HAVE_TR1_UNORDERED_MAP_H) CHECK_INCLUDE_FILE_CXX(tr1/unordered_set US_HAVE_TR1_UNORDERED_SET_H) CHECK_INCLUDE_FILE_CXX(tr1/functional US_HAVE_TR1_FUNCTIONAL_H) CHECK_INCLUDE_FILE_CXX(unordered_map US_HAVE_UNORDERED_MAP_H) CHECK_INCLUDE_FILE_CXX(unordered_set US_HAVE_UNORDERED_SET_H) CHECK_INCLUDE_FILE_CXX(functional US_HAVE_FUNCTIONAL_H) if(US_HAVE_UNORDERED_MAP_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_map m; return 0; }" US_HAVE_TR1_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_map m; return 0; }" US_HAVE_STD_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::hash(); return 0; }" US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::hash(); return 0; }" US_HAVE_STD_HASH) if(US_HAVE_STD_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_CLASS) elseif(US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_CLASS) endif() elseif(US_HAVE_TR1_UNORDERED_MAP_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_map m; return 0; }" US_HAVE_TR1_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_map m; return 0; }" US_HAVE_STD_UNORDERED_MAP) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::hash(); return 0; }" US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::hash(); return 0; }" US_HAVE_STD_HASH) if(US_HAVE_STD_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::hash; }; int main() { return 0; }" US_HAVE_STD_HASH_CLASS) elseif(US_HAVE_TR1_HASH) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend struct std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_STRUCT) CHECK_CXX_SOURCE_COMPILES("#include \nstruct A { friend class std::tr1::hash; }; int main() { return 0; }" US_HAVE_TR1_HASH_CLASS) endif() else() message(SEND_ERROR "The header file \"unordered_map\" is not available.") endif() if(NOT (US_HAVE_TR1_UNORDERED_MAP OR US_HAVE_STD_UNORDERED_MAP)) message(SEND_ERROR "The \"unordered_map\" type is not available.") endif() if(US_HAVE_UNORDERED_SET_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_set s; return 0; }" US_HAVE_TR1_UNORDERED_SET) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_set s; return 0; }" US_HAVE_STD_UNORDERED_SET) elseif(US_HAVE_TR1_UNORDERED_SET_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::unordered_set s; return 0; }" US_HAVE_TR1_UNORDERED_SET) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::unordered_set s; return 0; }" US_HAVE_STD_UNORDERED_SET) else() message(SEND_ERROR "The header file \"unordered_set\" is not available.") endif() if(NOT (US_HAVE_TR1_UNORDERED_SET OR US_HAVE_STD_UNORDERED_SET)) message(SEND_ERROR "The \"unordered_set\" type is not available.") endif() if(NOT (US_HAVE_FUNCTIONAL_H OR US_HAVE_TR1_FUNCTIONAL_H)) message(SEND_ERROR "The header file \"functional\" is not available.") endif() if(US_HAVE_FUNCTIONAL_H) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::function f(main); return 0; }" US_HAVE_TR1_FUNCTION) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::function f(main); return 0; }" US_HAVE_STD_FUNCTION) endif() if((NOT (US_HAVE_STD_FUNCTION OR US_HAVE_TR1_FUNCTION)) AND US_HAVE_TR1_FUNCTIONAL_H) unset(US_HAVE_TR1_FUNCTION CACHE) unset(US_HAVE_STD_FUNCTION CACHE) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::tr1::function f(main); return 0; }" US_HAVE_TR1_FUNCTION) CHECK_CXX_SOURCE_COMPILES("#include \nint main() { std::function f(main); return 0; }" US_HAVE_STD_FUNCTION) endif() if(NOT (US_HAVE_STD_FUNCTION OR US_HAVE_TR1_FUNCTION)) message(SEND_ERROR "The \"function\" type is not available.") endif() #----------------------------------------------------------------------------- # Source directory #----------------------------------------------------------------------------- set(US_INCLUDE_DIRS ${PROJECT_SOURCE_DIR}/third_party ${PROJECT_BINARY_DIR}/include) # Configure CppMicroServicesConfig.cmake for the build tree. # The file is used in sub-directories. set(PACKAGE_CONFIG_INCLUDE_DIR ${US_INCLUDE_DIRS}) set(PACKAGE_CONFIG_RUNTIME_DIR ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}) set(PACKAGE_CONFIG_CMAKE_DIR ${US_CMAKE_DIR}) set(US_RCC_EXECUTABLE_NAME usResourceCompiler CACHE INTERNAL "The target name of the usResourceCompiler executable.") configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in ${PROJECT_BINARY_DIR}/${PROJECT_NAME}Config.cmake @ONLY ) set(us_global_config_h_file "${PROJECT_BINARY_DIR}/include/usGlobalConfig.h") configure_file(${US_CMAKE_DIR}/usGlobalConfig.h.in ${us_global_config_h_file}) include_directories(${US_INCLUDE_DIRS}) add_subdirectory(tools) add_subdirectory(core) #----------------------------------------------------------------------------- # Documentation #----------------------------------------------------------------------------- add_subdirectory(doc) #----------------------------------------------------------------------------- # Last configuration and install steps #----------------------------------------------------------------------------- # Version information configure_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}ConfigVersion.cmake.in ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake @ONLY ) export(TARGETS ${US_RCC_EXECUTABLE_NAME} FILE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Targets.cmake) if(NOT US_NO_INSTALL) install(EXPORT ${PROJECT_NAME}Targets FILE ${PROJECT_NAME}Targets.cmake DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR}) set(_install_cmake_scripts ${US_MODULE_INIT_TEMPLATE} ${US_CMAKE_RESOURCE_DEPENDENCIES_CPP} ${US_CMAKE_DIR}/usFunctionGenerateModuleInit.cmake ${US_CMAKE_DIR}/usFunctionAddResources.cmake ${US_CMAKE_DIR}/usFunctionEmbedResources.cmake ${US_CMAKE_DIR}/usFunctionGetResourceSource.cmake ${US_CMAKE_DIR}/usFunctionCheckResourceLinking.cmake ${US_CMAKE_DIR}/usFunctionCheckCompilerFlags.cmake ) install(FILES ${_install_cmake_scripts} DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR}) install(FILES ${us_global_config_h_file} DESTINATION ${HEADER_INSTALL_DIR}) # Configure CppMicroServicesConfig.cmake for the install tree set(CONFIG_INCLUDE_DIR ${HEADER_INSTALL_DIR}) set(CONFIG_RUNTIME_DIR ${RUNTIME_INSTALL_DIR}) set(CONFIG_CMAKE_DIR ${AUXILIARY_CMAKE_INSTALL_DIR}) configure_package_config_file( ${CMAKE_CURRENT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in ${PROJECT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake INSTALL_DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR} PATH_VARS CONFIG_INCLUDE_DIR CONFIG_RUNTIME_DIR CONFIG_CMAKE_DIR NO_SET_AND_CHECK_MACRO NO_CHECK_REQUIRED_COMPONENTS_MACRO ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/${PROJECT_NAME}Config.cmake ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake DESTINATION ${AUXILIARY_CMAKE_INSTALL_DIR} ${US_SDK_INSTALL_COMPONENT} ) endif() diff --git a/Modules/CppMicroServices/cmake/usCTestScript_custom.cmake b/Modules/CppMicroServices/cmake/usCTestScript_custom.cmake index 9b95df48b6..afe87f1f1e 100644 --- a/Modules/CppMicroServices/cmake/usCTestScript_custom.cmake +++ b/Modules/CppMicroServices/cmake/usCTestScript_custom.cmake @@ -1,38 +1,38 @@ find_program(CTEST_COVERAGE_COMMAND NAMES gcov) find_program(CTEST_MEMORYCHECK_COMMAND NAMES valgrind) find_program(CTEST_GIT_COMMAND NAMES git) set(CTEST_SITE "bigeye") if(WIN32) set(CTEST_DASHBOARD_ROOT "C:/tmp/us") else() set(CTEST_DASHBOARD_ROOT "/tmp/us") set(CTEST_BUILD_FLAGS "-j") #set(CTEST_COMPILER "gcc-4.5") endif() set(CTEST_CONFIGURATION_TYPE Release) set(CTEST_BUILD_CONFIGURATION Release) set(CTEST_PARALLEL_LEVEL 4) set(US_TEST_SHARED 1) set(US_TEST_STATIC 1) set(US_SOURCE_DIR "${CMAKE_CURRENT_LIST_DIR}/../") set(US_BUILD_CONFIGURATION ) foreach(i RANGE 7) list(APPEND US_BUILD_CONFIGURATION ${i}) endforeach() -if(WIN32 AND NOT MINGW) +if(WIN32) set(US_CMAKE_GENERATOR "Visual Studio 9 2008" "Visual Studio 10" "Visual Studio 11" ) endif() include(${US_SOURCE_DIR}/cmake/usCTestScript.cmake) diff --git a/Modules/DICOMReader/include/mitkDICOMTagPath.h b/Modules/DICOMReader/include/mitkDICOMTagPath.h index c877341417..e5bd3e6464 100644 --- a/Modules/DICOMReader/include/mitkDICOMTagPath.h +++ b/Modules/DICOMReader/include/mitkDICOMTagPath.h @@ -1,180 +1,180 @@ /*=================================================================== 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 mitkDICOMTagPath_h #define mitkDICOMTagPath_h #include #include #include namespace mitk { /** @brief Class is used to identify (nested) attributes in a DICOM dataset. * In contrast to the class DICOMTag, which only specifies one specific tag, * the tag path can identify nested attributes (like items in a DICOM sequence). * In addition you may also specify wildcards for the selection index or * complete elements of the path. * @remark If you want to keep the DICOMTagPath compatible to the dcmtk search path * format, you may *not* use element wild cards (this IsExplicit() or HasItemSelectionWildcardsOnly() * must return true). */ class MITKDICOMREADER_EXPORT DICOMTagPath { public: typedef int ItemSelectionIndex; struct MITKDICOMREADER_EXPORT NodeInfo { enum class NodeType { Invalid = 0, //*< Node is non existant or invalid. Element, //*< Selects an specific element given the node name. SequenceSelection, //*< Selects an specific item in a sequence of items and has a item selector ("[n]"). AnySelection, //*< Selects all items of a specific element ("[*]"). AnyElement, //*< Selects any element/item. Node name is wildcarded ("*"); item selection as well implictily. }; NodeType type; DICOMTag tag; ItemSelectionIndex selection; NodeInfo(); NodeInfo(const DICOMTag& tag, NodeType type = NodeType::Element, ItemSelectionIndex index = 0); bool Matches(const NodeInfo& right) const; bool operator == (const NodeInfo& right) const; }; typedef std::vector NodeInfoVectorType; typedef NodeInfoVectorType::size_type PathIndexType; /** Returns if the DICOMTagPath is empty.*/ bool IsEmpty() const; /** Returns if the path is explicit (has no wildcards).*/ bool IsExplicit() const; /** Returns if the path has any nodes with item selection wild cards ([*]).*/ bool HasItemSelectionWildcardsOnly() const; /** Number of path nodes the DICOMTagPath contains.*/ PathIndexType Size() const; /** Adds a new node to the end of the path. \param [in] newNode Reference to the node that should be added. \return Returns the index of the newly added node.*/ PathIndexType AddNode(const NodeInfo& newNode); /** Function returns the node info of a path node specified by the index * within the DICOMTagPath. * \pre Passed index must not be out of bound. * \param [in] index Index of the node whose info should be retrieved. * \return Info of the specified path node. If the index is out of bound an InvalidPathNode exception will be thrown.*/ const NodeInfo& GetNode(const PathIndexType& index) const; /** Function returns the node info of a path node specified by the index * within the DICOMTagPath. * \pre Passed index must not be out of bound. * \param [in] index Index of the node whose info should be retrieved. * \return Info of the specified path node. If the index is out of bound an InvalidPathNode exception will be thrown.*/ NodeInfo& GetNode(const PathIndexType& index); /** Function returns the node info of the first path node within the DICOMTagPath. * \pre DICOMTagPath must not be empty. * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ NodeInfo& GetFirstNode(); /** Function returns the node info of the first path node within the DICOMTagPath. * \pre DICOMTagPath must not be empty. * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ const NodeInfo& GetFirstNode() const; /** Function returns the node info of the last path node within the DICOMTagPath. * \pre DICOMTagPath must not be empty. * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ NodeInfo& GetLastNode(); /** Function returns the node info of the last path node within the DICOMTagPath. * \pre DICOMTagPath must not be empty. * \return Info of the first path node. If the path is empty, an InvalidPathNode exception will be thrown.*/ const NodeInfo& GetLastNode() const; const NodeInfoVectorType& GetNodes() const; std::string ToStr() const; DICOMTagPath& FromStr(const std::string& pathStr); /**Compares two DICOMTagPaths for real equality. So its a string compare of their string conversion*/ bool operator == (const DICOMTagPath& path) const; /**Operation equals like comparing the ToStr() results with operator <.*/ bool operator < (const DICOMTagPath& right) const; /**Checks if to DICOMTagPathes are specify the same node. Hence all wildcards will be processed.\n * E.G.: "item1/child1/grandChild2" == ".//item1//grandChild2" is true. * \remark If you want to check if to pathes are "truely" equal and not only equal in terms of * pointing to the same node, use the member function Equals()*/ bool Equals(const DICOMTagPath& path) const; DICOMTagPath& operator = (const DICOMTagPath& path); DICOMTagPath& AddAnyElement(); DICOMTagPath& AddElement(unsigned int group, unsigned int element); DICOMTagPath& AddAnySelection(unsigned int group, unsigned int element); DICOMTagPath& AddSelection(unsigned int group, unsigned int element, ItemSelectionIndex index); DICOMTagPath(); DICOMTagPath(const DICOMTagPath& path); DICOMTagPath(const DICOMTag& tag); explicit DICOMTagPath(unsigned int group, unsigned int element); - ~DICOMTagPath(); + virtual ~DICOMTagPath(); virtual void Reset(); protected: NodeInfoVectorType m_NodeInfos; static bool DICOMTagPathesMatch(const DICOMTagPath& left, const DICOMTagPath& right); }; typedef std::vector DICOMTagPathList; MITKDICOMREADER_EXPORT std::ostream& operator<<(std::ostream& os, const DICOMTagPath& path); MITKDICOMREADER_EXPORT std::string DICOMTagPathToPropertyRegEx(const DICOMTagPath& tagPath); MITKDICOMREADER_EXPORT std::string DICOMTagPathToPersistenceKeyRegEx(const DICOMTagPath& tagPath); MITKDICOMREADER_EXPORT std::string DICOMTagPathToPersistenceKeyTemplate(const DICOMTagPath& tagPath); MITKDICOMREADER_EXPORT std::string DICOMTagPathToPersistenceNameTemplate(const DICOMTagPath& tagPath); /** Converts a passed path into a search string for the DCMTK DcmPathProcessor. @pre tagPath must be an explicit (DICOMTagPath::IsExplicit()) path or must only contain selection wild cards (DICOMTagPath::HasItemSelectionWildcardsOnly()).*/ MITKDICOMREADER_EXPORT std::string DICOMTagPathToDCMTKSearchPath(const DICOMTagPath& tagPath); /** Converts the passed property name into a tag path. If the property name cannot be converted into a valid path, the returned path is empty.*/ MITKDICOMREADER_EXPORT DICOMTagPath PropertyNameToDICOMTagPath(const std::string& propertyName); /** returns the correct property name for a given DICOMTagPath instance. */ MITKDICOMREADER_EXPORT std::string DICOMTagPathToPropertyName(const DICOMTagPath& tagPath); } #endif diff --git a/Modules/DICOMReader/src/legacy/mitkDicomSR_ImageBlockDescriptor.cpp b/Modules/DICOMReader/src/legacy/mitkDicomSR_ImageBlockDescriptor.cpp index 6ef0bf1d74..6f12bb6f2f 100644 --- a/Modules/DICOMReader/src/legacy/mitkDicomSR_ImageBlockDescriptor.cpp +++ b/Modules/DICOMReader/src/legacy/mitkDicomSR_ImageBlockDescriptor.cpp @@ -1,197 +1,197 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include namespace mitk { DicomSeriesReader::ImageBlockDescriptor::ImageBlockDescriptor() : m_HasGantryTiltCorrected(false), m_HasMultipleTimePoints(false), m_IsMultiFrameImage(false) { } DicomSeriesReader::ImageBlockDescriptor::~ImageBlockDescriptor() { // nothing } DicomSeriesReader::ImageBlockDescriptor::ImageBlockDescriptor(const StringContainer &files) : m_HasGantryTiltCorrected(false), m_HasMultipleTimePoints(false), m_IsMultiFrameImage(false) { m_Filenames = files; } void DicomSeriesReader::ImageBlockDescriptor::AddFile(const std::string &filename) { m_Filenames.push_back(filename); } void DicomSeriesReader::ImageBlockDescriptor::AddFiles(const StringContainer &files) { m_Filenames.insert(m_Filenames.end(), files.begin(), files.end()); } DicomSeriesReader::StringContainer DicomSeriesReader::ImageBlockDescriptor::GetFilenames() const { return m_Filenames; } std::string DicomSeriesReader::ImageBlockDescriptor::GetImageBlockUID() const { return m_ImageBlockUID; } std::string DicomSeriesReader::ImageBlockDescriptor::GetSeriesInstanceUID() const { return m_SeriesInstanceUID; } std::string DicomSeriesReader::ImageBlockDescriptor::GetModality() const { return m_Modality; } std::string DicomSeriesReader::ImageBlockDescriptor::GetSOPClassUIDAsString() const { gdcm::UIDs uidKnowledge; uidKnowledge.SetFromUID(m_SOPClassUID.c_str()); return uidKnowledge.GetName(); } std::string DicomSeriesReader::ImageBlockDescriptor::GetSOPClassUID() const { return m_SOPClassUID; } bool DicomSeriesReader::ImageBlockDescriptor::IsMultiFrameImage() const { return m_IsMultiFrameImage; } DicomSeriesReader::ReaderImplementationLevel DicomSeriesReader::ImageBlockDescriptor::GetReaderImplementationLevel() const { if (this->IsMultiFrameImage()) return ReaderImplementationLevel_Unsupported; gdcm::UIDs uidKnowledge; uidKnowledge.SetFromUID(m_SOPClassUID.c_str()); - gdcm::UIDs::TSType uid = uidKnowledge; + gdcm::UIDs::TSName uid = static_cast((gdcm::UIDs::TSType)uidKnowledge); switch (uid) { case gdcm::UIDs::CTImageStorage: case gdcm::UIDs::MRImageStorage: case gdcm::UIDs::PositronEmissionTomographyImageStorage: case gdcm::UIDs::ComputedRadiographyImageStorage: case gdcm::UIDs::DigitalXRayImageStorageForPresentation: case gdcm::UIDs::DigitalXRayImageStorageForProcessing: return ReaderImplementationLevel_Supported; case gdcm::UIDs::NuclearMedicineImageStorage: return ReaderImplementationLevel_PartlySupported; case gdcm::UIDs::SecondaryCaptureImageStorage: return ReaderImplementationLevel_Implemented; default: return ReaderImplementationLevel_Unsupported; } } bool DicomSeriesReader::ImageBlockDescriptor::HasGantryTiltCorrected() const { return m_HasGantryTiltCorrected; } /* PS defined IPS defined PS==IPS 0 0 --> UNKNOWN spacing, loader will invent 0 1 --> spacing as at detector surface 1 0 --> spacing as in patient 1 1 0 --> detector surface spacing CORRECTED for geometrical magnifications: spacing as in patient 1 1 1 --> detector surface spacing NOT corrected for geometrical magnifications: spacing as at detector */ DicomSeriesReader::PixelSpacingInterpretation DicomSeriesReader::ImageBlockDescriptor::GetPixelSpacingType() const { if (m_PixelSpacing.empty()) { if (m_ImagerPixelSpacing.empty()) { return PixelSpacingInterpretation_SpacingUnknown; } else { return PixelSpacingInterpretation_SpacingAtDetector; } } else // Pixel Spacing defined { if (m_ImagerPixelSpacing.empty()) { return PixelSpacingInterpretation_SpacingInPatient; } else if (m_PixelSpacing != m_ImagerPixelSpacing) { return PixelSpacingInterpretation_SpacingInPatient; } else { return PixelSpacingInterpretation_SpacingAtDetector; } } } bool DicomSeriesReader::ImageBlockDescriptor::PixelSpacingRelatesToPatient() const { return GetPixelSpacingType() == PixelSpacingInterpretation_SpacingInPatient; } bool DicomSeriesReader::ImageBlockDescriptor::PixelSpacingRelatesToDetector() const { return GetPixelSpacingType() == PixelSpacingInterpretation_SpacingAtDetector; } bool DicomSeriesReader::ImageBlockDescriptor::PixelSpacingIsUnknown() const { return GetPixelSpacingType() == PixelSpacingInterpretation_SpacingUnknown; } void DicomSeriesReader::ImageBlockDescriptor::SetPixelSpacingInformation(const std::string &pixelSpacing, const std::string &imagerPixelSpacing) { m_PixelSpacing = pixelSpacing; m_ImagerPixelSpacing = imagerPixelSpacing; } void DicomSeriesReader::ImageBlockDescriptor::GetDesiredMITKImagePixelSpacing(ScalarType &spacingX, ScalarType &spacingY) const { // preference for "in patient" pixel spacing if (!DICOMStringToSpacing(m_PixelSpacing, spacingX, spacingY)) { // fallback to "on detector" spacing if (!DICOMStringToSpacing(m_ImagerPixelSpacing, spacingX, spacingY)) { // last resort: invent something spacingX = spacingY = 1.0; } } } bool DicomSeriesReader::ImageBlockDescriptor::HasMultipleTimePoints() const { return m_HasMultipleTimePoints; } void DicomSeriesReader::ImageBlockDescriptor::SetImageBlockUID(const std::string &uid) { m_ImageBlockUID = uid; } void DicomSeriesReader::ImageBlockDescriptor::SetSeriesInstanceUID(const std::string &uid) { m_SeriesInstanceUID = uid; } void DicomSeriesReader::ImageBlockDescriptor::SetModality(const std::string &modality) { m_Modality = modality; } void DicomSeriesReader::ImageBlockDescriptor::SetNumberOfFrames(const std::string &numberOfFrames) { m_IsMultiFrameImage = !numberOfFrames.empty(); } void DicomSeriesReader::ImageBlockDescriptor::SetSOPClassUID(const std::string &sopClassUID) { m_SOPClassUID = sopClassUID; } void DicomSeriesReader::ImageBlockDescriptor::SetHasGantryTiltCorrected(bool on) { m_HasGantryTiltCorrected = on; } void DicomSeriesReader::ImageBlockDescriptor::SetHasMultipleTimePoints(bool on) { m_HasMultipleTimePoints = on; } } // end namespace mitk diff --git a/Modules/DICOMReader/src/mitkDICOMITKSeriesGDCMReader.cpp b/Modules/DICOMReader/src/mitkDICOMITKSeriesGDCMReader.cpp index 857610edfc..a12a611e50 100644 --- a/Modules/DICOMReader/src/mitkDICOMITKSeriesGDCMReader.cpp +++ b/Modules/DICOMReader/src/mitkDICOMITKSeriesGDCMReader.cpp @@ -1,622 +1,622 @@ /*=================================================================== 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. ===================================================================*/ //#define MBILOG_ENABLE_DEBUG #define ENABLE_TIMING #include #include #include "mitkDICOMITKSeriesGDCMReader.h" #include "mitkITKDICOMSeriesReaderHelper.h" #include "mitkGantryTiltInformation.h" #include "mitkDICOMTagBasedSorter.h" #include "mitkDICOMGDCMTagScanner.h" itk::MutexLock::Pointer mitk::DICOMITKSeriesGDCMReader::s_LocaleMutex = itk::MutexLock::New(); mitk::DICOMITKSeriesGDCMReader::DICOMITKSeriesGDCMReader( unsigned int decimalPlacesForOrientation, bool simpleVolumeImport ) : DICOMFileReader() , m_FixTiltByShearing(m_DefaultFixTiltByShearing) , m_SimpleVolumeReading( simpleVolumeImport ) , m_DecimalPlacesForOrientation( decimalPlacesForOrientation ) , m_ExternalCache(false) { this->EnsureMandatorySortersArePresent( decimalPlacesForOrientation, simpleVolumeImport ); } mitk::DICOMITKSeriesGDCMReader::DICOMITKSeriesGDCMReader( const DICOMITKSeriesGDCMReader& other ) : DICOMFileReader( other ) , m_FixTiltByShearing( other.m_FixTiltByShearing) , m_SortingResultInProgress( other.m_SortingResultInProgress ) , m_Sorter( other.m_Sorter ) , m_EquiDistantBlocksSorter( other.m_EquiDistantBlocksSorter->Clone() ) , m_NormalDirectionConsistencySorter( other.m_NormalDirectionConsistencySorter->Clone() ) , m_ReplacedCLocales( other.m_ReplacedCLocales ) , m_ReplacedCinLocales( other.m_ReplacedCinLocales ) , m_DecimalPlacesForOrientation( other.m_DecimalPlacesForOrientation ) , m_TagCache( other.m_TagCache ) , m_ExternalCache(other.m_ExternalCache) { } mitk::DICOMITKSeriesGDCMReader::~DICOMITKSeriesGDCMReader() { } mitk::DICOMITKSeriesGDCMReader& mitk::DICOMITKSeriesGDCMReader:: operator=( const DICOMITKSeriesGDCMReader& other ) { if ( this != &other ) { DICOMFileReader::operator =( other ); this->m_FixTiltByShearing = other.m_FixTiltByShearing; this->m_SortingResultInProgress = other.m_SortingResultInProgress; this->m_Sorter = other.m_Sorter; // TODO should clone the list items this->m_EquiDistantBlocksSorter = other.m_EquiDistantBlocksSorter->Clone(); this->m_NormalDirectionConsistencySorter = other.m_NormalDirectionConsistencySorter->Clone(); this->m_ReplacedCLocales = other.m_ReplacedCLocales; this->m_ReplacedCinLocales = other.m_ReplacedCinLocales; this->m_DecimalPlacesForOrientation = other.m_DecimalPlacesForOrientation; this->m_TagCache = other.m_TagCache; } return *this; } bool mitk::DICOMITKSeriesGDCMReader::operator==( const DICOMFileReader& other ) const { if ( const auto* otherSelf = dynamic_cast( &other ) ) { if ( this->m_FixTiltByShearing == otherSelf->m_FixTiltByShearing && *( this->m_EquiDistantBlocksSorter ) == *( otherSelf->m_EquiDistantBlocksSorter ) && ( fabs( this->m_DecimalPlacesForOrientation - otherSelf->m_DecimalPlacesForOrientation ) < eps ) ) { // test sorters for equality if ( this->m_Sorter.size() != otherSelf->m_Sorter.size() ) return false; auto mySorterIter = this->m_Sorter.cbegin(); auto oSorterIter = otherSelf->m_Sorter.cbegin(); for ( ; mySorterIter != this->m_Sorter.cend() && oSorterIter != otherSelf->m_Sorter.cend(); ++mySorterIter, ++oSorterIter ) { if ( !( **mySorterIter == **oSorterIter ) ) return false; // this sorter differs } // nothing differs ==> all is equal return true; } else { return false; } } else { return false; } } void mitk::DICOMITKSeriesGDCMReader::SetFixTiltByShearing( bool on ) { this->Modified(); m_FixTiltByShearing = on; } bool mitk::DICOMITKSeriesGDCMReader::GetFixTiltByShearing() const { return m_FixTiltByShearing; } void mitk::DICOMITKSeriesGDCMReader::SetAcceptTwoSlicesGroups( bool accept ) const { this->Modified(); m_EquiDistantBlocksSorter->SetAcceptTwoSlicesGroups( accept ); } bool mitk::DICOMITKSeriesGDCMReader::GetAcceptTwoSlicesGroups() const { return m_EquiDistantBlocksSorter->GetAcceptTwoSlicesGroups(); } void mitk::DICOMITKSeriesGDCMReader::InternalPrintConfiguration( std::ostream& os ) const { unsigned int sortIndex( 1 ); for ( auto sorterIter = m_Sorter.cbegin(); sorterIter != m_Sorter.cend(); ++sortIndex, ++sorterIter ) { os << "Sorting step " << sortIndex << ":" << std::endl; ( *sorterIter )->PrintConfiguration( os, " " ); } os << "Sorting step " << sortIndex << ":" << std::endl; m_EquiDistantBlocksSorter->PrintConfiguration( os, " " ); } std::string mitk::DICOMITKSeriesGDCMReader::GetActiveLocale() { return setlocale( LC_NUMERIC, nullptr ); } void mitk::DICOMITKSeriesGDCMReader::PushLocale() const { s_LocaleMutex->Lock(); std::string currentCLocale = setlocale( LC_NUMERIC, nullptr ); m_ReplacedCLocales.push( currentCLocale ); setlocale( LC_NUMERIC, "C" ); std::locale currentCinLocale( std::cin.getloc() ); m_ReplacedCinLocales.push( currentCinLocale ); std::locale l( "C" ); std::cin.imbue( l ); s_LocaleMutex->Unlock(); } void mitk::DICOMITKSeriesGDCMReader::PopLocale() const { s_LocaleMutex->Lock(); if ( !m_ReplacedCLocales.empty() ) { setlocale( LC_NUMERIC, m_ReplacedCLocales.top().c_str() ); m_ReplacedCLocales.pop(); } else { MITK_WARN << "Mismatched PopLocale on DICOMITKSeriesGDCMReader."; } if ( !m_ReplacedCinLocales.empty() ) { std::cin.imbue( m_ReplacedCinLocales.top() ); m_ReplacedCinLocales.pop(); } else { MITK_WARN << "Mismatched PopLocale on DICOMITKSeriesGDCMReader."; } s_LocaleMutex->Unlock(); } mitk::DICOMITKSeriesGDCMReader::SortingBlockList mitk::DICOMITKSeriesGDCMReader::Condense3DBlocks( SortingBlockList& input ) { return input; // to be implemented differently by sub-classes } #if defined( MBILOG_ENABLE_DEBUG ) || defined( ENABLE_TIMING ) #define timeStart( part ) timer.Start( part ); #define timeStop( part ) timer.Stop( part ); #else #define timeStart( part ) #define timeStop( part ) #endif void mitk::DICOMITKSeriesGDCMReader::AnalyzeInputFiles() { itk::TimeProbesCollectorBase timer; timeStart( "Reset" ); this->ClearOutputs(); timeStop( "Reset" ); // prepare initial sorting (== list of input files) const StringList inputFilenames = this->GetInputFiles(); timeStart( "Check input for DCM" ); if ( inputFilenames.empty() || !this->CanHandleFile( inputFilenames.front() ) // first || !this->CanHandleFile( inputFilenames.back() ) // last || !this->CanHandleFile( inputFilenames[inputFilenames.size() / 2] ) // roughly central file ) { // TODO a read-as-many-as-possible fallback could be implemented here MITK_DEBUG << "Reader unable to process files.."; return; } timeStop( "Check input for DCM" ); // scan files for sorting-relevant tags if ( m_TagCache.IsNull() || ( m_TagCache->GetMTime()GetMTime() && !m_ExternalCache )) { timeStart( "Tag scanning" ); DICOMGDCMTagScanner::Pointer filescanner = DICOMGDCMTagScanner::New(); filescanner->SetInputFiles( inputFilenames ); filescanner->AddTagPaths( this->GetTagsOfInterest() ); PushLocale(); filescanner->Scan(); PopLocale(); m_TagCache = filescanner->GetScanCache(); // keep alive and make accessible to sub-classes timeStop("Tag scanning"); } else { // ensure that the tag cache contains our required tags AND files and has scanned! } m_SortingResultInProgress.clear(); m_SortingResultInProgress.push_back(m_TagCache->GetFrameInfoList()); // sort and split blocks as configured timeStart( "Sorting frames" ); unsigned int sorterIndex = 0; for ( auto sorterIter = m_Sorter.cbegin(); sorterIter != m_Sorter.cend(); ++sorterIndex, ++sorterIter ) { std::stringstream ss; ss << "Sorting step " << sorterIndex; timeStart( ss.str().c_str() ); m_SortingResultInProgress = this->InternalExecuteSortingStep( sorterIndex, *sorterIter, m_SortingResultInProgress ); timeStop( ss.str().c_str() ); } if ( !m_SimpleVolumeReading ) { // a last extra-sorting step: ensure equidistant slices timeStart( "EquiDistantBlocksSorter" ); m_SortingResultInProgress = this->InternalExecuteSortingStep( sorterIndex++, m_EquiDistantBlocksSorter.GetPointer(), m_SortingResultInProgress ); timeStop( "EquiDistantBlocksSorter" ); } timeStop( "Sorting frames" ); timeStart( "Condensing 3D blocks" ); m_SortingResultInProgress = this->Condense3DBlocks( m_SortingResultInProgress ); timeStop( "Condensing 3D blocks" ); // provide final result as output timeStart( "Output" ); unsigned int o = this->GetNumberOfOutputs(); this->SetNumberOfOutputs( o + m_SortingResultInProgress.size() ); // Condense3DBlocks may already have added outputs! for ( auto blockIter = m_SortingResultInProgress.cbegin(); blockIter != m_SortingResultInProgress.cend(); ++o, ++blockIter ) { const DICOMDatasetAccessingImageFrameList& gdcmFrameInfoList = *blockIter; assert( !gdcmFrameInfoList.empty() ); // reverse frames if necessary // update tilt information from absolute last sorting const DICOMDatasetList datasetList = ConvertToDICOMDatasetList( gdcmFrameInfoList ); m_NormalDirectionConsistencySorter->SetInput( datasetList ); m_NormalDirectionConsistencySorter->Sort(); const DICOMDatasetAccessingImageFrameList sortedGdcmInfoFrameList = ConvertToDICOMDatasetAccessingImageFrameList( m_NormalDirectionConsistencySorter->GetOutput( 0 ) ); const GantryTiltInformation& tiltInfo = m_NormalDirectionConsistencySorter->GetTiltInformation(); // set frame list for current block const DICOMImageFrameList frameList = ConvertToDICOMImageFrameList( sortedGdcmInfoFrameList ); assert( !frameList.empty() ); DICOMImageBlockDescriptor block; block.SetTagCache( this->GetTagCache() ); // important: this must be before SetImageFrameList(), because // SetImageFrameList will trigger reading of lots of interesting // tags! block.SetAdditionalTagsOfInterest( GetAdditionalTagsOfInterest() ); block.SetTagLookupTableToPropertyFunctor( GetTagLookupTableToPropertyFunctor() ); block.SetImageFrameList( frameList ); block.SetTiltInformation( tiltInfo ); block.SetReaderImplementationLevel( this->GetReaderImplementationLevel( block.GetSOPClassUID() ) ); this->SetOutput( o, block ); } timeStop( "Output" ); #if defined( MBILOG_ENABLE_DEBUG ) || defined( ENABLE_TIMING ) std::cout << "---------------------------------------------------------------" << std::endl; timer.Report( std::cout ); std::cout << "---------------------------------------------------------------" << std::endl; #endif } mitk::DICOMITKSeriesGDCMReader::SortingBlockList mitk::DICOMITKSeriesGDCMReader::InternalExecuteSortingStep( unsigned int sortingStepIndex, const DICOMDatasetSorter::Pointer& sorter, const SortingBlockList& input ) { SortingBlockList nextStepSorting; // we should not modify our input list while processing it std::stringstream ss; ss << "Sorting step " << sortingStepIndex << " '"; #if defined( MBILOG_ENABLE_DEBUG ) sorter->PrintConfiguration( ss ); #endif ss << "'"; nextStepSorting.clear(); MITK_DEBUG << "================================================================================"; MITK_DEBUG << "DICOMITKSeriesGDCMReader: " << ss.str() << ": " << input.size() << " groups input"; unsigned int groupIndex = 0; for ( auto blockIter = input.cbegin(); blockIter != input.cend(); ++groupIndex, ++blockIter ) { const DICOMDatasetAccessingImageFrameList& gdcmInfoFrameList = *blockIter; const DICOMDatasetList datasetList = ConvertToDICOMDatasetList( gdcmInfoFrameList ); #if defined( MBILOG_ENABLE_DEBUG ) MITK_DEBUG << "--------------------------------------------------------------------------------"; MITK_DEBUG << "DICOMITKSeriesGDCMReader: " << ss.str() << ", dataset group " << groupIndex << " (" << datasetList.size() << " datasets): "; for ( auto oi = datasetList.cbegin(); oi != datasetList.cend(); ++oi ) { MITK_DEBUG << " INPUT : " << ( *oi )->GetFilenameIfAvailable(); } #endif sorter->SetInput( datasetList ); sorter->Sort(); unsigned int numberOfResultingBlocks = sorter->GetNumberOfOutputs(); for ( unsigned int b = 0; b < numberOfResultingBlocks; ++b ) { const DICOMDatasetList blockResult = sorter->GetOutput( b ); for ( auto oi = blockResult.cbegin(); oi != blockResult.cend(); ++oi ) { MITK_DEBUG << " OUTPUT(" << b << ") :" << ( *oi )->GetFilenameIfAvailable(); } DICOMDatasetAccessingImageFrameList sortedGdcmInfoFrameList = ConvertToDICOMDatasetAccessingImageFrameList( blockResult ); nextStepSorting.push_back( sortedGdcmInfoFrameList ); } } return nextStepSorting; } mitk::ReaderImplementationLevel mitk::DICOMITKSeriesGDCMReader::GetReaderImplementationLevel( const std::string sopClassUID ) { if ( sopClassUID.empty() ) { return SOPClassUnknown; } gdcm::UIDs uidKnowledge; uidKnowledge.SetFromUID( sopClassUID.c_str() ); - gdcm::UIDs::TSType gdcmType = uidKnowledge; + gdcm::UIDs::TSName gdcmType = static_cast((gdcm::UIDs::TSType)uidKnowledge); switch ( gdcmType ) { case gdcm::UIDs::CTImageStorage: case gdcm::UIDs::MRImageStorage: case gdcm::UIDs::PositronEmissionTomographyImageStorage: case gdcm::UIDs::ComputedRadiographyImageStorage: case gdcm::UIDs::DigitalXRayImageStorageForPresentation: case gdcm::UIDs::DigitalXRayImageStorageForProcessing: return SOPClassSupported; case gdcm::UIDs::NuclearMedicineImageStorage: return SOPClassPartlySupported; case gdcm::UIDs::SecondaryCaptureImageStorage: return SOPClassImplemented; default: return SOPClassUnsupported; } } // void AllocateOutputImages(); bool mitk::DICOMITKSeriesGDCMReader::LoadImages() { bool success = true; unsigned int numberOfOutputs = this->GetNumberOfOutputs(); for ( unsigned int o = 0; o < numberOfOutputs; ++o ) { success &= this->LoadMitkImageForOutput( o ); } return success; } bool mitk::DICOMITKSeriesGDCMReader::LoadMitkImageForImageBlockDescriptor( DICOMImageBlockDescriptor& block ) const { PushLocale(); const DICOMImageFrameList& frames = block.GetImageFrameList(); const GantryTiltInformation tiltInfo = block.GetTiltInformation(); bool hasTilt = tiltInfo.IsRegularGantryTilt(); ITKDICOMSeriesReaderHelper::StringContainer filenames; filenames.reserve( frames.size() ); for ( auto frameIter = frames.cbegin(); frameIter != frames.cend(); ++frameIter ) { filenames.push_back( ( *frameIter )->Filename ); } mitk::ITKDICOMSeriesReaderHelper helper; bool success( true ); try { mitk::Image::Pointer mitkImage = helper.Load( filenames, m_FixTiltByShearing && hasTilt, tiltInfo ); block.SetMitkImage( mitkImage ); } catch ( const std::exception& e ) { success = false; MITK_ERROR << "Exception during image loading: " << e.what(); } PopLocale(); return success; } bool mitk::DICOMITKSeriesGDCMReader::LoadMitkImageForOutput( unsigned int o ) { DICOMImageBlockDescriptor& block = this->InternalGetOutput( o ); return this->LoadMitkImageForImageBlockDescriptor( block ); } bool mitk::DICOMITKSeriesGDCMReader::CanHandleFile( const std::string& filename ) { return ITKDICOMSeriesReaderHelper::CanHandleFile( filename ); } void mitk::DICOMITKSeriesGDCMReader::AddSortingElement( DICOMDatasetSorter* sorter, bool atFront ) { assert( sorter ); if ( atFront ) { m_Sorter.push_front( sorter ); } else { m_Sorter.push_back( sorter ); } this->Modified(); } mitk::DICOMITKSeriesGDCMReader::ConstSorterList mitk::DICOMITKSeriesGDCMReader::GetFreelyConfiguredSortingElements() const { std::list result; unsigned int sortIndex( 0 ); for ( auto sorterIter = m_Sorter.begin(); sorterIter != m_Sorter.end(); ++sortIndex, ++sorterIter ) { if ( sortIndex > 0 ) // ignore first element (see EnsureMandatorySortersArePresent) { result.push_back( ( *sorterIter ).GetPointer() ); } } return result; } void mitk::DICOMITKSeriesGDCMReader::EnsureMandatorySortersArePresent( unsigned int decimalPlacesForOrientation, bool simpleVolumeImport ) { DICOMTagBasedSorter::Pointer splitter = DICOMTagBasedSorter::New(); splitter->AddDistinguishingTag( DICOMTag(0x0028, 0x0010) ); // Number of Rows splitter->AddDistinguishingTag( DICOMTag(0x0028, 0x0011) ); // Number of Columns splitter->AddDistinguishingTag( DICOMTag(0x0028, 0x0030) ); // Pixel Spacing splitter->AddDistinguishingTag( DICOMTag(0x0018, 0x1164) ); // Imager Pixel Spacing splitter->AddDistinguishingTag( DICOMTag(0x0020, 0x0037), new mitk::DICOMTagBasedSorter::CutDecimalPlaces(decimalPlacesForOrientation) ); // Image Orientation (Patient) splitter->AddDistinguishingTag( DICOMTag(0x0018, 0x0050) ); // Slice Thickness if ( !simpleVolumeImport ) { std::cout << "Simple volume reading: ignoring number of frames" << std::endl; splitter->AddDistinguishingTag( DICOMTag(0x0028, 0x0008) ); // Number of Frames } this->AddSortingElement( splitter, true ); // true = at front if ( m_EquiDistantBlocksSorter.IsNull() ) { m_EquiDistantBlocksSorter = mitk::EquiDistantBlocksSorter::New(); } m_EquiDistantBlocksSorter->SetAcceptTilt( m_FixTiltByShearing ); if ( m_NormalDirectionConsistencySorter.IsNull() ) { m_NormalDirectionConsistencySorter = mitk::NormalDirectionConsistencySorter::New(); } } void mitk::DICOMITKSeriesGDCMReader::SetToleratedOriginOffsetToAdaptive( double fractionOfInterSliceDistance ) const { assert( m_EquiDistantBlocksSorter.IsNotNull() ); m_EquiDistantBlocksSorter->SetToleratedOriginOffsetToAdaptive( fractionOfInterSliceDistance ); this->Modified(); } void mitk::DICOMITKSeriesGDCMReader::SetToleratedOriginOffset( double millimeters ) const { assert( m_EquiDistantBlocksSorter.IsNotNull() ); m_EquiDistantBlocksSorter->SetToleratedOriginOffset( millimeters ); this->Modified(); } double mitk::DICOMITKSeriesGDCMReader::GetToleratedOriginError() const { assert( m_EquiDistantBlocksSorter.IsNotNull() ); return m_EquiDistantBlocksSorter->GetToleratedOriginOffset(); } bool mitk::DICOMITKSeriesGDCMReader::IsToleratedOriginOffsetAbsolute() const { assert( m_EquiDistantBlocksSorter.IsNotNull() ); return m_EquiDistantBlocksSorter->IsToleratedOriginOffsetAbsolute(); } double mitk::DICOMITKSeriesGDCMReader::GetDecimalPlacesForOrientation() const { return m_DecimalPlacesForOrientation; } mitk::DICOMTagCache::Pointer mitk::DICOMITKSeriesGDCMReader::GetTagCache() const { return m_TagCache; } void mitk::DICOMITKSeriesGDCMReader::SetTagCache( const DICOMTagCache::Pointer& tagCache ) { m_TagCache = tagCache; m_ExternalCache = tagCache.IsNotNull(); } mitk::DICOMTagPathList mitk::DICOMITKSeriesGDCMReader::GetTagsOfInterest() const { DICOMTagPathList completeList; // check all configured sorters for ( auto sorterIter = m_Sorter.cbegin(); sorterIter != m_Sorter.cend(); ++sorterIter ) { assert( sorterIter->IsNotNull() ); const DICOMTagList tags = ( *sorterIter )->GetTagsOfInterest(); completeList.insert( completeList.end(), tags.cbegin(), tags.cend() ); } // check our own forced sorters DICOMTagList tags = m_EquiDistantBlocksSorter->GetTagsOfInterest(); completeList.insert( completeList.end(), tags.cbegin(), tags.cend() ); tags = m_NormalDirectionConsistencySorter->GetTagsOfInterest(); completeList.insert( completeList.end(), tags.cbegin(), tags.cend() ); // add the tags for DICOMImageBlockDescriptor tags = DICOMImageBlockDescriptor::GetTagsOfInterest(); completeList.insert( completeList.end(), tags.cbegin(), tags.cend() ); const AdditionalTagsMapType tagList = GetAdditionalTagsOfInterest(); for ( auto iter = tagList.cbegin(); iter != tagList.cend(); ++iter ) { completeList.push_back( iter->first ) ; } return completeList; } diff --git a/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.cpp b/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.cpp index 74b935d036..3b75360031 100644 --- a/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.cpp +++ b/Modules/DicomRT/autoload/IO/mitkRTDoseReaderService.cpp @@ -1,172 +1,172 @@ /*=================================================================== 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 "mitkRTDoseReaderService.h" -#include +#include #include #include #include #include #include #include #include #include "mitkDICOMDCMTKTagScanner.h" #include "mitkDicomRTIOMimeTypes.h" #include #include "dcmtk/dcmrt/drtdose.h" #include #include namespace mitk { RTDoseReaderService::RTDoseReaderService() : AbstractFileReader(CustomMimeType(mitk::DicomRTIOMimeTypes::DICOMRT_DOSE_MIMETYPE_NAME()), mitk::DicomRTIOMimeTypes::DICOMRT_DOSE_MIMETYPE_DESCRIPTION()) { m_FileReaderServiceReg = RegisterService(); } RTDoseReaderService::RTDoseReaderService(const RTDoseReaderService& other) : mitk::AbstractFileReader(other) { } RTDoseReaderService::~RTDoseReaderService() {} template void RTDoseReaderService::MultiplyGridScaling(itk::Image* image, float gridscale) { typedef itk::Image OutputImageType; typedef itk::Image InputImageType; typedef itk::CastImageFilter CastFilterType; typedef itk::ShiftScaleImageFilter ScaleFilterType; typename CastFilterType::Pointer castFilter = CastFilterType::New(); typename ScaleFilterType::Pointer scaleFilter = ScaleFilterType::New(); castFilter->SetInput(image); scaleFilter->SetInput(castFilter->GetOutput()); scaleFilter->SetScale(gridscale); scaleFilter->Update(); typename OutputImageType::Pointer scaledOutput = scaleFilter->GetOutput(); this->scaledDoseImage = mitk::Image::New(); mitk::CastToMitkImage(scaledOutput, this->scaledDoseImage); } std::vector > RTDoseReaderService::Read() { std::vector > result; mitk::IDICOMTagsOfInterest* toiSrv = GetDicomTagsOfInterestService(); auto tagsOfInterest = toiSrv->GetTagsOfInterest(); DICOMTagPathList tagsOfInterestList; for (const auto& tag : tagsOfInterest) { tagsOfInterestList.push_back(tag.first); } std::string location = GetInputLocation(); mitk::DICOMFileReaderSelector::Pointer selector = mitk::DICOMFileReaderSelector::New(); selector->LoadBuiltIn3DConfigs(); selector->SetInputFiles({ location }); mitk::DICOMFileReader::Pointer reader = selector->GetFirstReaderWithMinimumNumberOfOutputImages(); reader->SetAdditionalTagsOfInterest(toiSrv->GetTagsOfInterest()); reader->SetInputFiles({ location }); reader->AnalyzeInputFiles(); reader->LoadImages(); if (reader->GetNumberOfOutputs() == 0) { MITK_ERROR << "Could not determine a DICOM reader for this file" << std::endl; return result; } mitk::DICOMDCMTKTagScanner::Pointer scanner = mitk::DICOMDCMTKTagScanner::New(); scanner->SetInputFiles({ location }); scanner->AddTagPaths(tagsOfInterestList); scanner->Scan(); mitk::DICOMDatasetAccessingImageFrameList frames = scanner->GetFrameInfoList(); if (frames.empty()) { MITK_ERROR << "Error reading the RTDOSE file" << std::endl; return result; } const mitk::DICOMImageBlockDescriptor& desc = reader->GetOutput(0); mitk::Image::Pointer originalImage = desc.GetMitkImage(); if (originalImage.IsNull()) { MITK_ERROR << "Error reading the RTDOSE file in mitk::DicomFileReader" << std::endl; return result; } DcmFileFormat fileformat; OFCondition outp = fileformat.loadFile(location.c_str(), EXS_Unknown); if (outp.bad()) { MITK_ERROR << "Error reading the RTDOSE file in DCMTK" << std::endl; return result; } DcmDataset *dataset = fileformat.getDataset(); DRTDoseIOD doseObject; OFCondition DCMTKresult = doseObject.read(*dataset); if (DCMTKresult.bad()) { MITK_ERROR << "Error reading the RTDOSE file in DCMTK" << std::endl; return result; } auto findingsGridScaling = frames.front()->GetTagValueAsString(DICOMTagPath(0x3004, 0x000e)); //(0x3004, 0x000e) is grid scaling double gridScaling; if (findingsGridScaling.empty()) { MITK_ERROR << "Could not find DoseGridScaling tag" << std::endl; return result; } else { gridScaling = boost::lexical_cast(findingsGridScaling.front().value); } AccessByItk_1(originalImage, MultiplyGridScaling, gridScaling); auto statistics = this->scaledDoseImage->GetStatistics(); double maxDose = statistics->GetScalarValueMax(); this->scaledDoseImage->SetPropertyList(originalImage->GetPropertyList()); this->scaledDoseImage->SetProperty(mitk::RTConstants::PRESCRIBED_DOSE_PROPERTY_NAME.c_str(), mitk::GenericProperty::New(0.8*maxDose)); auto findings = ExtractPathsOfInterest(tagsOfInterestList, frames); SetProperties(this->scaledDoseImage, findings); result.push_back(this->scaledDoseImage.GetPointer()); return result; } RTDoseReaderService* RTDoseReaderService::Clone() const { return new RTDoseReaderService(*this); } } diff --git a/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkNrrdTensorImageReader.cpp b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkNrrdTensorImageReader.cpp index f1315466d6..c6449ec8c0 100644 --- a/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkNrrdTensorImageReader.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/autoload/IO/mitkNrrdTensorImageReader.cpp @@ -1,428 +1,428 @@ /*=================================================================== 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 "mitkNrrdTensorImageReader.h" #include #include "mitkDiffusionCoreIOMimeTypes.h" #include "itkImageFileReader.h" #include "itkImageRegionIterator.h" #include "itkMetaDataObject.h" #include "itkNrrdImageIO.h" #include #include "mitkITKImageImport.h" #include "mitkImageDataItem.h" #include #include -#include +#include namespace mitk { NrrdTensorImageReader::NrrdTensorImageReader(const NrrdTensorImageReader& other) : mitk::AbstractFileReader(other) { } NrrdTensorImageReader::NrrdTensorImageReader() : mitk::AbstractFileReader( CustomMimeType( mitk::DiffusionCoreIOMimeTypes::DTI_MIMETYPE() ), mitk::DiffusionCoreIOMimeTypes::DTI_MIMETYPE_DESCRIPTION() ) { m_ServiceReg = this->RegisterService(); } NrrdTensorImageReader::~NrrdTensorImageReader() { } std::vector > NrrdTensorImageReader::Read() { std::vector > result; std::string location = GetInputLocation(); if ( location == "") { throw itk::ImageFileReaderException(__FILE__, __LINE__, "Sorry, the filename is empty!"); } else { try { mitk::LocaleSwitch localeSwitch("C"); try { std::string fname3 = mitk::IOUtil::GetTempPath()+"/temp_dti.nii.gz"; int c = 0; while( itksys::SystemTools::FileExists(fname3) ) { fname3 = mitk::IOUtil::GetTempPath()+"/temp_dti_" + boost::lexical_cast(c) + ".nii.gz"; ++c; } itksys::SystemTools::CopyAFile(location.c_str(), fname3.c_str()); typedef itk::VectorImage ImageType; itk::NiftiImageIO::Pointer io = itk::NiftiImageIO::New(); typedef itk::ImageFileReader FileReaderType; FileReaderType::Pointer reader = FileReaderType::New(); reader->SetImageIO(io); reader->SetFileName(fname3); reader->Update(); ImageType::Pointer img = reader->GetOutput(); TensorImage::ItkTensorImageType::Pointer vecImg = TensorImage::ItkTensorImageType::New(); vecImg->SetSpacing( img->GetSpacing() ); // Set the image spacing vecImg->SetOrigin( img->GetOrigin() ); // Set the image origin vecImg->SetDirection( img->GetDirection() ); // Set the image direction vecImg->SetRegions( img->GetLargestPossibleRegion()); vecImg->Allocate(); itk::ImageRegionIterator ot (vecImg, vecImg->GetLargestPossibleRegion() ); ot.GoToBegin(); itk::ImageRegionIterator it (img, img->GetLargestPossibleRegion() ); it.GoToBegin(); typedef ImageType::PixelType VarPixType; typedef TensorImage::PixelType FixPixType; int numComponents = img->GetNumberOfComponentsPerPixel(); if (numComponents==6) { MITK_INFO << "Trying to load dti as 6-comp nifti ..."; while (!it.IsAtEnd()) { VarPixType vec = it.Get(); FixPixType fixVec(vec.GetDataPointer()); TensorImage::PixelType tensor; tensor.SetElement(0, vec.GetElement(0)); tensor.SetElement(1, vec.GetElement(1)); tensor.SetElement(2, vec.GetElement(2)); tensor.SetElement(3, vec.GetElement(3)); tensor.SetElement(4, vec.GetElement(4)); tensor.SetElement(5, vec.GetElement(5)); fixVec = tensor; ot.Set(fixVec); ++ot; ++it; } } else if(numComponents==9) { MITK_INFO << "Trying to load dti as 9-comp nifti ..."; while (!it.IsAtEnd()) { VarPixType vec = it.Get(); TensorImage::PixelType tensor; tensor.SetElement(0, vec.GetElement(0)); tensor.SetElement(1, vec.GetElement(1)); tensor.SetElement(2, vec.GetElement(2)); tensor.SetElement(3, vec.GetElement(4)); tensor.SetElement(4, vec.GetElement(5)); tensor.SetElement(5, vec.GetElement(8)); FixPixType fixVec(tensor); ot.Set(fixVec); ++ot; ++it; } } else if (numComponents==1) { MITK_INFO << "Trying to load dti as 4D nifti ..."; typedef itk::Image ImageType; typedef itk::ImageFileReader FileReaderType; FileReaderType::Pointer reader = FileReaderType::New(); reader->SetImageIO(io); reader->SetFileName(fname3); reader->Update(); ImageType::Pointer img = reader->GetOutput(); itk::Size<4> size = img->GetLargestPossibleRegion().GetSize(); while (!ot.IsAtEnd()) { TensorImage::PixelType tensor; ImageType::IndexType idx; idx[0] = ot.GetIndex()[0]; idx[1] = ot.GetIndex()[1]; idx[2] = ot.GetIndex()[2]; if (size[3]==6) { for (unsigned int te=0; teGetPixel(idx)); } } else if (size[3]==9) { idx[3] = 0; tensor.SetElement(0, img->GetPixel(idx)); idx[3] = 1; tensor.SetElement(1, img->GetPixel(idx)); idx[3] = 2; tensor.SetElement(2, img->GetPixel(idx)); idx[3] = 4; tensor.SetElement(3, img->GetPixel(idx)); idx[3] = 5; tensor.SetElement(4, img->GetPixel(idx)); idx[3] = 8; tensor.SetElement(5, img->GetPixel(idx)); } else throw itk::ImageFileReaderException(__FILE__, __LINE__, "Unknown number of components for DTI file. Should be 6 or 9!"); FixPixType fixVec(tensor); ot.Set(fixVec); ++ot; } } OutputType::Pointer resultImage = OutputType::New(); resultImage->InitializeByItk( vecImg.GetPointer() ); resultImage->SetVolume( vecImg->GetBufferPointer() ); result.push_back( resultImage.GetPointer() ); } catch(...) { MITK_INFO << "Trying to load dti as nrrd ..."; typedef itk::VectorImage ImageType; itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); typedef itk::ImageFileReader FileReaderType; FileReaderType::Pointer reader = FileReaderType::New(); reader->SetImageIO(io); reader->SetFileName(location); reader->Update(); ImageType::Pointer img = reader->GetOutput(); TensorImage::ItkTensorImageType::Pointer vecImg = TensorImage::ItkTensorImageType::New(); vecImg->SetSpacing( img->GetSpacing() ); // Set the image spacing vecImg->SetOrigin( img->GetOrigin() ); // Set the image origin vecImg->SetDirection( img->GetDirection() ); // Set the image direction vecImg->SetRegions( img->GetLargestPossibleRegion()); vecImg->Allocate(); itk::ImageRegionIterator ot (vecImg, vecImg->GetLargestPossibleRegion() ); ot.GoToBegin(); itk::ImageRegionIterator it (img, img->GetLargestPossibleRegion() ); it.GoToBegin(); typedef ImageType::PixelType VarPixType; typedef TensorImage::PixelType FixPixType; int numComponents = img->GetNumberOfComponentsPerPixel(); itk::MetaDataDictionary imgMetaDictionary = img->GetMetaDataDictionary(); std::vector imgMetaKeys = imgMetaDictionary.GetKeys(); std::vector::const_iterator itKey = imgMetaKeys.begin(); std::string metaString; bool readFrame = false; double xx, xy, xz, yx, yy, yz, zx, zy, zz; MeasurementFrameType measFrame; measFrame.SetIdentity(); MeasurementFrameType measFrameTransp; measFrameTransp.SetIdentity(); for (; itKey != imgMetaKeys.end(); itKey ++) { itk::ExposeMetaData (imgMetaDictionary, *itKey, metaString); if (itKey->find("measurement frame") != std::string::npos) { sscanf(metaString.c_str(), " ( %lf , %lf , %lf ) ( %lf , %lf , %lf ) ( %lf , %lf , %lf ) \n", &xx, &xy, &xz, &yx, &yy, &yz, &zx, &zy, &zz); if (xx>10e-10 || xy>10e-10 || xz>10e-10 || yx>10e-10 || yy>10e-10 || yz>10e-10 || zx>10e-10 || zy>10e-10 || zz>10e-10 ) { readFrame = true; measFrame(0,0) = xx; measFrame(0,1) = xy; measFrame(0,2) = xz; measFrame(1,0) = yx; measFrame(1,1) = yy; measFrame(1,2) = yz; measFrame(2,0) = zx; measFrame(2,1) = zy; measFrame(2,2) = zz; measFrameTransp = measFrame.GetTranspose(); } } } if (numComponents==6) { while (!it.IsAtEnd()) { // T'=RTR' VarPixType vec = it.Get(); FixPixType fixVec(vec.GetDataPointer()); if(readFrame) { TensorImage::PixelType tensor; tensor.SetElement(0, vec.GetElement(0)); tensor.SetElement(1, vec.GetElement(1)); tensor.SetElement(2, vec.GetElement(2)); tensor.SetElement(3, vec.GetElement(3)); tensor.SetElement(4, vec.GetElement(4)); tensor.SetElement(5, vec.GetElement(5)); tensor = ConvertMatrixTypeToFixedArrayType(tensor.PreMultiply(measFrame)); tensor = ConvertMatrixTypeToFixedArrayType(tensor.PostMultiply(measFrameTransp)); fixVec = tensor; } ot.Set(fixVec); ++ot; ++it; } } else if(numComponents==9) { while (!it.IsAtEnd()) { VarPixType vec = it.Get(); TensorImage::PixelType tensor; tensor.SetElement(0, vec.GetElement(0)); tensor.SetElement(1, vec.GetElement(1)); tensor.SetElement(2, vec.GetElement(2)); tensor.SetElement(3, vec.GetElement(4)); tensor.SetElement(4, vec.GetElement(5)); tensor.SetElement(5, vec.GetElement(8)); if(readFrame) { tensor = ConvertMatrixTypeToFixedArrayType(tensor.PreMultiply(measFrame)); tensor = ConvertMatrixTypeToFixedArrayType(tensor.PostMultiply(measFrameTransp)); } FixPixType fixVec(tensor); ot.Set(fixVec); ++ot; ++it; } } else if (numComponents==1) { typedef itk::Image ImageType; itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); typedef itk::ImageFileReader FileReaderType; FileReaderType::Pointer reader = FileReaderType::New(); reader->SetImageIO(io); reader->SetFileName(location); reader->Update(); ImageType::Pointer img = reader->GetOutput(); itk::Size<4> size = img->GetLargestPossibleRegion().GetSize(); while (!ot.IsAtEnd()) { TensorImage::PixelType tensor; ImageType::IndexType idx; idx[0] = ot.GetIndex()[0]; idx[1] = ot.GetIndex()[1]; idx[2] = ot.GetIndex()[2]; if (size[3]==6) { for (unsigned int te=0; teGetPixel(idx)); } } else if (size[3]==9) { idx[3] = 0; tensor.SetElement(0, img->GetPixel(idx)); idx[3] = 1; tensor.SetElement(1, img->GetPixel(idx)); idx[3] = 2; tensor.SetElement(2, img->GetPixel(idx)); idx[3] = 4; tensor.SetElement(3, img->GetPixel(idx)); idx[3] = 5; tensor.SetElement(4, img->GetPixel(idx)); idx[3] = 8; tensor.SetElement(5, img->GetPixel(idx)); } else throw itk::ImageFileReaderException(__FILE__, __LINE__, "Unknown number of komponents for DTI file. Should be 6 or 9!"); if(readFrame) { tensor = ConvertMatrixTypeToFixedArrayType(tensor.PreMultiply(measFrame)); tensor = ConvertMatrixTypeToFixedArrayType(tensor.PostMultiply(measFrameTransp)); } FixPixType fixVec(tensor); ot.Set(fixVec); ++ot; } } else { throw itk::ImageFileReaderException(__FILE__, __LINE__, "Image has wrong number of pixel components!"); } OutputType::Pointer resultImage = OutputType::New(); resultImage->InitializeByItk( vecImg.GetPointer() ); resultImage->SetVolume( vecImg->GetBufferPointer() ); result.push_back( resultImage.GetPointer() ); } } catch(std::exception& e) { throw itk::ImageFileReaderException(__FILE__, __LINE__, e.what()); } catch(...) { throw itk::ImageFileReaderException(__FILE__, __LINE__, "Sorry, an error occurred while reading the requested DTI file!"); } } return result; } TensorImage::PixelType NrrdTensorImageReader ::ConvertMatrixTypeToFixedArrayType(const TensorImage::PixelType::Superclass::MatrixType & matrix) { /* | 0 1 2 | * | X 3 4 | * | X X 5 | */ TensorImage::PixelType arr; arr.SetElement(0,matrix(0,0)); arr.SetElement(1,matrix(0,1)); arr.SetElement(2,matrix(0,2)); arr.SetElement(3,matrix(1,3)); arr.SetElement(4,matrix(1,4)); arr.SetElement(5,matrix(2,5)); return arr; } } //namespace MITK mitk::NrrdTensorImageReader* mitk::NrrdTensorImageReader::Clone() const { return new NrrdTensorImageReader(*this); } diff --git a/Modules/DiffusionImaging/DiffusionCore/cmdapps/ResampleGradients.cpp b/Modules/DiffusionImaging/DiffusionCore/cmdapps/ResampleGradients.cpp index c87ecf2b02..74b85c1966 100644 --- a/Modules/DiffusionImaging/DiffusionCore/cmdapps/ResampleGradients.cpp +++ b/Modules/DiffusionImaging/DiffusionCore/cmdapps/ResampleGradients.cpp @@ -1,243 +1,243 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include "mitkCommandLineParser.h" -#include +#include #include #include #include #include #include // itk includes #include // mitk includes #include #include "itkDWIVoxelFunctor.h" #include typedef short DiffusionPixelType; typedef itk::VectorImage< short, 3 > ItkDwiType; // itk includes #include "itkTimeProbe.h" #include "itkB0ImageExtractionImageFilter.h" #include "itkB0ImageExtractionToSeparateImageFilter.h" #include "itkBrainMaskExtractionImageFilter.h" #include "itkCastImageFilter.h" #include "itkVectorContainer.h" #include #include #include #include #include #include // Multishell includes #include // Multishell Functors #include #include #include #include // mitk includes #include "mitkProgressBar.h" #include "mitkStatusBar.h" #include "mitkNodePredicateDataType.h" #include "mitkProperties.h" #include "mitkVtkResliceInterpolationProperty.h" #include "mitkLookupTable.h" #include "mitkLookupTableProperty.h" #include "mitkTransferFunction.h" #include "mitkTransferFunctionProperty.h" //#include "mitkDataNodeObject.h" #include "mitkOdfNormalizationMethodProperty.h" #include "mitkOdfScaleByProperty.h" #include #include #include #include #include //#include //#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkPreferenceListReaderOptionsFunctor.h" mitk::Image::Pointer DoReduceGradientDirections(mitk::Image::Pointer image, double BValue, unsigned int numOfGradientsToKeep) { bool isDiffusionImage( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage(image) ); if ( !isDiffusionImage ) { std::cout << "Image is not a Diffusion Weighted Image" << std::endl; //return; } typedef itk::ElectrostaticRepulsionDiffusionGradientReductionFilter FilterType; typedef mitk::BValueMapProperty::BValueMap BValueMap; BValueMap shellSlectionMap; BValueMap originalShellMap = static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::BVALUEMAPPROPERTYNAME.c_str()).GetPointer() ) ->GetBValueMap(); std::vector newNumGradientDirections; //Keeps 1 b0 gradient double B0Value = 0; shellSlectionMap[B0Value] = originalShellMap[B0Value]; unsigned int num = 1; newNumGradientDirections.push_back(num); //BValue = 1000; shellSlectionMap[BValue] = originalShellMap[BValue]; //numOfGradientsToKeep = 32; newNumGradientDirections.push_back(numOfGradientsToKeep); if (newNumGradientDirections.empty()) { std::cout << "newNumGradientDirections is empty" << std::endl; //return; } itk::DwiGradientLengthCorrectionFilter::GradientDirectionContainerType::Pointer gradientContainer = static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer(); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); std::cout << "1" << std::endl; FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetOriginalGradientDirections(gradientContainer); filter->SetNumGradientDirections(newNumGradientDirections); filter->SetOriginalBValueMap(originalShellMap); filter->SetShellSelectionBValueMap(shellSlectionMap); filter->Update(); std::cout << "2" << std::endl; if( filter->GetOutput() == nullptr) { std::cout << "filter get output is nullptr" << std::endl; } mitk::Image::Pointer newImage = mitk::GrabItkImageMemory( filter->GetOutput() ); mitk::DiffusionPropertyHelper::CopyProperties(image, newImage, true); newImage->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( filter->GetGradientDirections() ) ); mitk::DiffusionPropertyHelper propertyHelper( newImage ); propertyHelper.InitializeImage(); //needed? return newImage; } /*! \brief Resample gradients of input DWI image. */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Resample Gradients"); parser.setCategory("Preprocessing Tools"); parser.setDescription("Resample gradients of input DWI image. You can select one b-value shell and the number of gradients within this shell you want to have. It will also keep one b0 image."); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", mitkCommandLineParser::String, "Input:", "input image", us::Any(), false); parser.addArgument("output", "o", mitkCommandLineParser::String, "Output:", "output image", us::Any(), false); parser.addArgument("bValue", "b", mitkCommandLineParser::Float, "b-value:", "float", 1000, false); parser.addArgument("nrOfGradients", "n", mitkCommandLineParser::Int, "Nr of gradients:", "integer", 32, false); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string inFileName = us::any_cast(parsedArgs["input"]); std::string outFileName = us::any_cast(parsedArgs["output"]); double bValue = us::any_cast(parsedArgs["bValue"]); unsigned int nrOfGradients = us::any_cast(parsedArgs["nrOfGradients"]); try { mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({ "Diffusion Weighted Images" }, {}); mitk::Image::Pointer mitkImage = mitk::IOUtil::Load(inFileName, &functor); mitk::Image::Pointer newImage = DoReduceGradientDirections(mitkImage, bValue, nrOfGradients); //mitk::IOUtil::Save(newImage, outFileName); //save as dwi image mitk::IOUtil::Save(newImage, "application/vnd.mitk.nii.gz", outFileName); //save as nifti image } 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/include/Algorithms/Reconstruction/itkOrientationDistributionFunction.txx b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Reconstruction/itkOrientationDistributionFunction.txx index dc9107f3b9..c50bf289c1 100644 --- a/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Reconstruction/itkOrientationDistributionFunction.txx +++ b/Modules/DiffusionImaging/DiffusionCore/include/Algorithms/Reconstruction/itkOrientationDistributionFunction.txx @@ -1,1367 +1,1366 @@ /*=================================================================== 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 _itkOrientationDistributionFunction_txx #define _itkOrientationDistributionFunction_txx #include #include #include #include #include #include #include "itkPointShell.h" #ifdef _MSC_VER #if _MSC_VER <= 1700 #define fmin(a,b) ((a<=b)?(a):(b)) #define fmax(a,b) ((a>=b)?(a):(b)) #define isnan(c) (c!=c) #endif #endif #include #include #include #include #include #include namespace itk { template vtkPolyData* itk::OrientationDistributionFunction::m_BaseMesh = nullptr; template double itk::OrientationDistributionFunction::m_MaxChordLength = -1.0; template vnl_matrix_fixed* itk::OrientationDistributionFunction::m_Directions = itk::PointShell >::DistributePointShell(); template std::vector< std::vector* >* itk::OrientationDistributionFunction::m_NeighborIdxs = nullptr; template std::vector< std::vector* >* itk::OrientationDistributionFunction::m_AngularRangeIdxs = nullptr; template std::vector* itk::OrientationDistributionFunction::m_HalfSphereIdxs = nullptr; template itk::SimpleFastMutexLock itk::OrientationDistributionFunction::m_MutexBaseMesh; template itk::SimpleFastMutexLock itk::OrientationDistributionFunction::m_MutexHalfSphereIdxs; template itk::SimpleFastMutexLock itk::OrientationDistributionFunction::m_MutexNeighbors; template itk::SimpleFastMutexLock itk::OrientationDistributionFunction::m_MutexAngularRange; /** * Assignment Operator */ template OrientationDistributionFunction& OrientationDistributionFunction ::operator= (const Self& r) { BaseArray::operator=(r); return *this; } /** * Assignment Operator from a scalar constant */ template OrientationDistributionFunction& OrientationDistributionFunction ::operator= (const ComponentType & r) { BaseArray::operator=(&r); return *this; } /** * Assigment from a plain array */ template OrientationDistributionFunction& OrientationDistributionFunction ::operator= (const ComponentArrayType r ) { BaseArray::operator=(r); return *this; } /** * Returns a temporary copy of a vector */ template OrientationDistributionFunction OrientationDistributionFunction ::operator+(const Self & r) const { Self result; for( unsigned int i=0; i OrientationDistributionFunction OrientationDistributionFunction ::operator-(const Self & r) const { Self result; for( unsigned int i=0; i const OrientationDistributionFunction & OrientationDistributionFunction ::operator+=(const Self & r) { for( unsigned int i=0; i const OrientationDistributionFunction & OrientationDistributionFunction ::operator-=(const Self & r) { for( unsigned int i=0; i const OrientationDistributionFunction & OrientationDistributionFunction ::operator*=(const RealValueType & r) { for( unsigned int i=0; i const OrientationDistributionFunction & OrientationDistributionFunction ::operator/=(const RealValueType & r) { for( unsigned int i=0; i OrientationDistributionFunction OrientationDistributionFunction ::operator*(const RealValueType & r) const { Self result; for( unsigned int i=0; i OrientationDistributionFunction OrientationDistributionFunction ::operator/(const RealValueType & r) const { Self result; for( unsigned int i=0; i const typename OrientationDistributionFunction::ValueType & OrientationDistributionFunction ::operator()(unsigned int row, unsigned int col) const { unsigned int k; if( row < col ) { k = row * InternalDimension + col - row * ( row + 1 ) / 2; } else { k = col * InternalDimension + row - col * ( col + 1 ) / 2; } if( k >= InternalDimension ) { k = 0; } return (*this)[k]; } /** * Matrix notation access to elements */ template typename OrientationDistributionFunction::ValueType & OrientationDistributionFunction ::operator()(unsigned int row, unsigned int col) { unsigned int k; if( row < col ) { k = row * InternalDimension + col - row * ( row + 1 ) / 2; } else { k = col * InternalDimension + row - col * ( col + 1 ) / 2; } if( k >= InternalDimension ) { k = 0; } return (*this)[k]; } /** * Set the Tensor to an Identity. * Set ones in the diagonal and zeroes every where else. */ template void OrientationDistributionFunction ::SetIsotropic() { this->Fill(NumericTraits< T >::One / NOdfDirections); } /** * InitFromTensor() */ template void OrientationDistributionFunction ::InitFromTensor(itk::DiffusionTensor3D tensor) { m_EigenAnalysisCalculated = false; for(unsigned int i=0; i void OrientationDistributionFunction:: InitFromEllipsoid( itk::DiffusionTensor3D tensor ) { m_EigenAnalysisCalculated = false; FixedArray nulltensor; nulltensor.Fill(0.0); if( tensor == nulltensor ) { for ( unsigned int it=0; it < NOdfDirections; ++it ){ (*this)[it] = (T)0; } MITK_DEBUG << "OrientationDistributionFunction<" << typeid(T).name() << ", " << NOdfDirections << ">::InitFromEllipsoid(" << typeid(tensor).name() << ") encountered a nulltensor as dti input point and ignorend it."; return; } tensor.ComputeEigenAnalysis( m_EigenValues, this->m_EigenVectors ); // gives normalized eigenvectors as lines i.e. rows. m_EigenAnalysisCalculated = true; double a = m_EigenValues[0]; // those eigenvalues are the 3 |axes of the ellipsoid|, double b = m_EigenValues[1]; // ComputeEigenAnalysis gives eigenValues in ascending < order per default, double c = m_EigenValues[2]; // therefor the third eigenVector is the main direction of diffusion. if( a <= 0.0 || b <= 0.0 || c <= 0.0 ) { for ( unsigned int it=0; it < NOdfDirections; ++it ){ (*this)[it] = (T)0; } MITK_DEBUG << "OrientationDistributionFunction<" << typeid(T).name() << ", " << NOdfDirections << ">::InitFromEllipsoid(" << typeid(tensor).name() << ") encountered an eigenvalue <= 0 and ignored this input point."; return; } // check magnitude and scale towards 1 to minimize numerical condition kappa: #ifdef _MSC_VER #if _MSC_VER <= 1700 int exponent_a = floor(std::log(a)/std::log(2)); int exponent_b = floor(std::log(b)/std::log(2)); int exponent_c = floor(std::log(c)/std::log(2)); #else int exponent_a = std::ilogb(a); int exponent_b = std::ilogb(b); int exponent_c = std::ilogb(c); #endif #else int exponent_a = std::ilogb(a); int exponent_b = std::ilogb(b); int exponent_c = std::ilogb(c); #endif T min_exponent= fmin(exponent_a, fmin(exponent_b, exponent_c) ); T max_exponent= fmax(exponent_c, fmax(exponent_b, exponent_a) ); int scale_exponent = floor(0.5 * (min_exponent + max_exponent)); double scaling = pow(2, scale_exponent); a= a/scaling; b= b/scaling; c= c/scaling; vnl_matrix_fixed eigenBase; // for change of base system. for (int row = 0 ; row < 3; ++row) // Transposing because ComputeEigenAnalysis(,) gave us _row_ vectors. { for (int col = 0; col < 3; ++col) { eigenBase(row, col) = this->m_EigenVectors(col, row); } } eigenBase= vnl_inverse(eigenBase); // Assuming canonical orthonormal system x=[1;0;0];y=[0;1;0];z=[0;0;1] for original DT. eigenBase.assert_finite(); #ifndef NDEBUG double kappa=1.0; { // calculate numerical condition kappa= ||f(x)-f(x~)|| approximately: double gxaa = pow( a, -2.0); double gybb = pow( b, -2.0); double gzcc = pow( c, -2.0); kappa = sqrt( pow( a, 2.0)+ pow( b, 2.0)+ pow( c, 2.0) + 1 ) / (gxaa + gybb + gzcc) * sqrt( pow( a, -6.0)+ pow( b, -6.0)+ pow( c, -6.0) + pow( a, -4.0)+ pow( b, -4.0)+ pow( c, -4.0) ); MITK_DEBUG <<"kappa= "<< kappa << ", eigenvalues= [" << a <<", "<< b <<", "<< c <<"], eigenbase= [" < g( (*m_Directions)(0,i), (*m_Directions)(1,i), (*m_Directions)(2,i) ); g = eigenBase*g; // passive change of base system of g. g = g.normalize(); // unit vectors necessary. (*this)[i] = scaling / sqrt( (g[0]/a)*(g[0]/a) + (g[1]/b)*(g[1]/b) + (g[2]/c)*(g[2]/c) ); #ifndef NDEBUG { // boundary check for numerical stability, assuming sigma=6, ||f(x~)-f~(x~)|| <= eps*kappa*sigma. T min_ev= fmin(a, fmin(b, c) ); T max_ev= fmax(c, fmax(b, a) ); double eps= std::numeric_limits::epsilon(); assert( scaling*min_ev <= ((*this)[i] + eps*kappa*6.0) ); // we should be between smallest and assert( (*this)[i] <= (scaling*max_ev + eps*kappa*6.0) ); // biggest eigenvalue. } #endif if ( (*this)[i] < T(0) || (*this)[i] > T(1) || std::isnan((*this)[i]) ) // P∈[0;1] sanity check. { // C: NaN != NaN, C++11: isnan((*this)[i]). MITK_DEBUG << "OrientationDistributionFunction<" << typeid(T).name() << ", " << NOdfDirections << ">::InitFromEllipsoid(" << typeid(tensor).name() << ") encountered a probability value out of range [0;1] and set it to zero: (*this)[" << i <<"]= " << (*this)[i]; (*this)[i] = T(0); } } } /** * L2-Normalization */ template void OrientationDistributionFunction ::L2Normalize() { T sum = 0; for( unsigned int i=0; i void OrientationDistributionFunction ::Normalize() { T sum = 0; for( unsigned int i=0; i0) { for( unsigned int i=0; i OrientationDistributionFunction OrientationDistributionFunction ::MinMaxNormalize() const { T max = NumericTraits::NonpositiveMin(); T min = NumericTraits::max(); for( unsigned int i=0; i max ? (*this)[i] : max; min = (*this)[i] < min ? (*this)[i] : min; } Self retval; for( unsigned int i=0; i OrientationDistributionFunction OrientationDistributionFunction ::MaxNormalize() const { T max = NumericTraits::NonpositiveMin(); for( unsigned int i=0; i max ? (*this)[i] : max; } Self retval; for( unsigned int i=0; i T OrientationDistributionFunction ::GetMaxValue() const { T max = NumericTraits::NonpositiveMin(); for( unsigned int i=0; i= max ) { max = (*this)[i]; } } return max; } template T OrientationDistributionFunction ::GetMinValue() const { T min = NumericTraits::max(); for( unsigned int i=0; i= min ) { min = (*this)[i]; } } return min; } template T OrientationDistributionFunction ::GetMeanValue() const { T sum = 0; for( unsigned int i=0; i double OrientationDistributionFunction ::GetMaxChordLength() { if(m_MaxChordLength<0.0) { ComputeBaseMesh(); double max_dist = -1; vtkPoints* points = m_BaseMesh->GetPoints(); for(int i=0; iGetPoint(i,p); std::vector neighbors = GetNeighbors(i); for(std::size_t j=0; jGetPoint(neighbors[j],n); double d = sqrt( (p[0]-n[0])*(p[0]-n[0]) + (p[1]-n[1])*(p[1]-n[1]) + (p[2]-n[2])*(p[2]-n[2])); max_dist = d>max_dist ? d : max_dist; } } m_MaxChordLength = max_dist; } return m_MaxChordLength; } template void OrientationDistributionFunction ::ComputeBaseMesh() { m_MutexBaseMesh.Lock(); if(m_BaseMesh == nullptr) { vtkPoints* points = vtkPoints::New(); for(unsigned int j=0; jInsertNextPoint(az,elev,r); } vtkPolyData* polydata = vtkPolyData::New(); polydata->SetPoints( points ); vtkDelaunay2D *delaunay = vtkDelaunay2D::New(); delaunay->SetInputData( polydata ); delaunay->Update(); vtkCellArray* vtkpolys = delaunay->GetOutput()->GetPolys(); vtkCellArray* vtknewpolys = vtkCellArray::New(); vtkIdType npts; vtkIdType *pts; while(vtkpolys->GetNextCell(npts,pts)) { bool insert = true; for(int i=0; iGetPoint(pts[i]); double az = tmpPoint[0]; double elev = tmpPoint[1]; if((std::abs(az)>itk::Math::pi-0.5) || (std::abs(elev)>itk::Math::pi/2-0.5)) insert = false; } if(insert) vtknewpolys->InsertNextCell(npts, pts); } vtkPoints* points2 = vtkPoints::New(); for(unsigned int j=0; jInsertNextPoint(az,elev,r); } vtkPolyData* polydata2 = vtkPolyData::New(); polydata2->SetPoints( points2 ); vtkDelaunay2D *delaunay2 = vtkDelaunay2D::New(); delaunay2->SetInputData( polydata2 ); delaunay2->Update(); vtkpolys = delaunay2->GetOutput()->GetPolys(); while(vtkpolys->GetNextCell(npts,pts)) { bool insert = true; for(int i=0; iGetPoint(pts[i]); double az = tmpPoint[0]; double elev = tmpPoint[1]; if((std::abs(az)>itk::Math::pi-0.5) || (std::abs(elev)>itk::Math::pi/2-0.5)) insert = false; } if(insert) vtknewpolys->InsertNextCell(npts, pts); } polydata->SetPolys(vtknewpolys); for (unsigned int p = 0; p < NOdfDirections; p++) { points->SetPoint(p,m_Directions->get_column(p).data_block()); } polydata->SetPoints( points ); m_BaseMesh = polydata; } m_MutexBaseMesh.Unlock(); } /** * Extract the index of the principal diffusion direction */ template int OrientationDistributionFunction::GetPrincipalDiffusionDirectionIndex() const { T max = NumericTraits::NonpositiveMin(); int maxidx = -1; for( unsigned int i=0; i= max ) { max = (*this)[i]; maxidx = i; } } return maxidx; } /** * Extract the principal diffusion direction */ template vnl_vector_fixed OrientationDistributionFunction::GetPrincipalDiffusionDirection() const { if (m_EigenAnalysisCalculated) { vnl_vector_fixed vec; vec[0] = this->m_EigenVectors(2,0); vec[1] = this->m_EigenVectors(2,1); vec[2] = this->m_EigenVectors(2,2); vec.normalize(); return vec; } else { int idx = GetPrincipalDiffusionDirectionIndex(); if (idx>0 && idx<(int)NOdfDirections) return OrientationDistributionFunction::GetDirection(idx); vnl_vector_fixed vec; vec.fill(0); return vec; } } template std::vector OrientationDistributionFunction ::GetNeighbors(int idx) { ComputeBaseMesh(); m_MutexNeighbors.Lock(); if(m_NeighborIdxs == nullptr) { m_NeighborIdxs = new std::vector< std::vector* >(); vtkCellArray* polys = m_BaseMesh->GetPolys(); for(unsigned int i=0; i(); polys->InitTraversal(); vtkIdType npts; vtkIdType *pts; while(polys->GetNextCell(npts,pts)) { if( pts[0] == i ) { idxs->push_back(pts[1]); idxs->push_back(pts[2]); } else if( pts[1] == i ) { idxs->push_back(pts[0]); idxs->push_back(pts[2]); } else if( pts[2] == i ) { idxs->push_back(pts[0]); idxs->push_back(pts[1]); } } std::sort(idxs->begin(), idxs->end()); std::vector< int >::iterator endLocation; endLocation = std::unique( idxs->begin(), idxs->end() ); idxs->erase(endLocation, idxs->end()); m_NeighborIdxs->push_back(idxs); } } m_MutexNeighbors.Unlock(); return *m_NeighborIdxs->at(idx); } /** * Extract the n-th diffusion direction */ template int OrientationDistributionFunction ::GetNthDiffusionDirection(int n, vnl_vector_fixed rndVec) const { if( n == 0 ) return GetPrincipalDiffusionDirectionIndex(); m_MutexHalfSphereIdxs.Lock(); if( !m_HalfSphereIdxs ) { m_HalfSphereIdxs = new std::vector(); for( unsigned int i=0; iget_column(i),rndVec) > 0.0) { m_HalfSphereIdxs->push_back(i); } } } m_MutexHalfSphereIdxs.Unlock(); // collect indices of directions // that are local maxima std::vector localMaxima; std::vector::iterator it; for( it=m_HalfSphereIdxs->begin(); it!=m_HalfSphereIdxs->end(); it++) { std::vector nbs = GetNeighbors(*it); std::vector::iterator it2; bool max = true; for(it2 = nbs.begin(); it2 != nbs.end(); it2++) { if((*this)[*it2] > (*this)[*it]) { max = false; break; } } if(max) localMaxima.push_back(*it); } // delete n highest local maxima from list // and return remaining highest int maxidx = -1; - std::vector::iterator itMax; for( int i=0; i<=n; i++ ) { maxidx = -1; T max = NumericTraits::NonpositiveMin(); for(it = localMaxima.begin(); it != localMaxima.end(); it++) { if((*this)[*it]>max) { max = (*this)[*it]; maxidx = *it; } } it = find(localMaxima.begin(), localMaxima.end(), maxidx); if(it!=localMaxima.end()) localMaxima.erase(it); } return maxidx; } template < typename TComponent, unsigned int NOdfDirections > vnl_vector_fixed itk::OrientationDistributionFunction ::GetDirection( int i ) { return m_Directions->get_column(i); } /** * Interpolate a position between sampled directions */ template T OrientationDistributionFunction ::GetInterpolatedComponent(vnl_vector_fixed dir, InterpolationMethods method) const { ComputeBaseMesh(); double retval = -1.0; switch(method) { case ODF_NEAREST_NEIGHBOR_INTERP: { vtkPoints* points = m_BaseMesh->GetPoints(); double current_min = NumericTraits::max(); int current_min_idx = -1; for(int i=0; i P(points->GetPoint(i)); double dist = (dir-P).two_norm(); current_min_idx = distGetNthComponent(current_min_idx); break; } case ODF_TRILINEAR_BARYCENTRIC_INTERP: { double maxChordLength = GetMaxChordLength(); vtkCellArray* polys = m_BaseMesh->GetPolys(); vtkPoints* points = m_BaseMesh->GetPoints(); vtkIdType npts; vtkIdType *pts; double current_min = NumericTraits::max(); polys->InitTraversal(); while(polys->GetNextCell(npts,pts)) { vnl_vector_fixed A(points->GetPoint(pts[0])); vnl_vector_fixed B(points->GetPoint(pts[1])); vnl_vector_fixed C(points->GetPoint(pts[2])); vnl_vector_fixed d1; d1.put(0,(dir-A).two_norm()); d1.put(1,(dir-B).two_norm()); d1.put(2,(dir-C).two_norm()); double maxval = d1.max_value(); if(maxval>maxChordLength) { continue; } // Compute vectors vnl_vector_fixed v0 = C - A; vnl_vector_fixed v1 = B - A; // Project direction to plane ABC vnl_vector_fixed v6 = dir; vnl_vector_fixed cross = vnl_cross_3d(v0, v1); cross = cross.normalize(); vtkPlane::ProjectPoint(v6.data_block(),A.data_block(),cross.data_block(),v6.data_block()); v6 = v6-A; // Calculate barycentric coords vnl_matrix_fixed mat; mat.set_column(0, v0); mat.set_column(1, v1); vnl_matrix_inverse inv(mat); vnl_matrix_fixed inver = inv.pinverse(); vnl_vector uv = inv.pinverse()*v6; // Check if point is in triangle double eps = 0.01; if( (uv(0) >= 0-eps) && (uv(1) >= 0-eps) && (uv(0) + uv(1) <= 1+eps) ) { // check if minimum angle is the max so far if(d1.two_norm() < current_min) { current_min = d1.two_norm(); vnl_vector barycentricCoords(3); barycentricCoords[2] = uv[0]<0 ? 0 : (uv[0]>1?1:uv[0]); barycentricCoords[1] = uv[1]<0 ? 0 : (uv[1]>1?1:uv[1]); barycentricCoords[0] = 1-(barycentricCoords[1]+barycentricCoords[2]); retval = barycentricCoords[0]*this->GetNthComponent(pts[0]) + barycentricCoords[1]*this->GetNthComponent(pts[1]) + barycentricCoords[2]*this->GetNthComponent(pts[2]); } } } break; } case ODF_SPHERICAL_GAUSSIAN_BASIS_FUNCTIONS: { double maxChordLength = GetMaxChordLength(); double sigma = asin(maxChordLength/2); // this is the contribution of each kernel to each sampling point on the // equator vnl_vector contrib; contrib.set_size(NOdfDirections); vtkPoints* points = m_BaseMesh->GetPoints(); double sum = 0; for(int i=0; i P(points->GetPoint(i)); double stv = dir[0]*P[0] + dir[1]*P[1] + dir[2]*P[2]; stv = (stv<-1.0) ? -1.0 : ( (stv>1.0) ? 1.0 : stv); double x = acos(stv); contrib[i] = (1.0/(sigma*sqrt(2.0*itk::Math::pi))) *exp((-x*x)/(2*sigma*sigma)); sum += contrib[i]; } retval = 0; for(int i=0; iGetNthComponent(i); } break; } } if(retval==-1) { std::cout << "Interpolation failed" << std::endl; return 0; } return retval; } /** * Calculate Generalized Fractional Anisotropy */ template T OrientationDistributionFunction ::GetGeneralizedFractionalAnisotropy() const { double mean = 0; double std = 0; double rms = 0; for( unsigned int i=0; i T itk::OrientationDistributionFunction ::GetGeneralizedGFA( int k, int p ) const { double mean = 0; double std = 0; double rms = 0; double max = NumericTraits::NonpositiveMin(); for( unsigned int i=0; i max ? val : max; } max = pow(max,(double)p); mean /= N; for( unsigned int i=0; i0) { rms += pow(val,(double)(p*k)); } } std /= N - 1; std = sqrt(std); if(k>0) { rms /= N; rms = pow(rms,(double)(1.0/k)); } else if(k<0) // lim k->inf gives us the maximum { rms = max; } else // k==0 undefined, we define zeros root from 1 as 1 { rms = 1; } if(rms == 0) { return 0; } else { return (T)(std/rms); } } /** * Calculate Nematic Order Parameter */ template < typename T, unsigned int N > T itk::OrientationDistributionFunction ::GetNematicOrderParameter() const { // not yet implemented return 0; } /** * Calculate StdDev by MaxValue */ template < typename T, unsigned int N > T itk::OrientationDistributionFunction ::GetStdDevByMaxValue() const { double mean = 0; double std = 0; T max = NumericTraits::NonpositiveMin(); for( unsigned int i=0; i max ? (*this)[i] : max; } mean /= InternalDimension; for( unsigned int i=0; i T itk::OrientationDistributionFunction ::GetPrincipleCurvature(double alphaMinDegree, double alphaMaxDegree, int invert) const { // following loop only performed once // (computing indices of each angular range) m_MutexAngularRange.Lock(); if(m_AngularRangeIdxs == nullptr) { m_AngularRangeIdxs = new std::vector< std::vector* >(); for(unsigned int i=0; i pDir = GetDirection(i); auto idxs = new std::vector(); for(unsigned int j=0; j cDir = GetDirection(j); double angle = ( 180 / itk::Math::pi ) * acos( dot_product(pDir, cDir) ); if( (angle < alphaMaxDegree) && (angle > alphaMinDegree) ) { idxs->push_back(j); } } m_AngularRangeIdxs->push_back(idxs); } } m_MutexAngularRange.Unlock(); // find the maximum (or minimum) direction (remember index and value) T mode; int pIdx = -1; if(invert == 0) { pIdx = GetPrincipalDiffusionDirectionIndex(); mode = (*this)[pIdx]; } else { mode = NumericTraits::max(); for( unsigned int i=0; i nbs = GetNeighbors(pIdx); //////std::vector modeAndNeighborVals; //////modeAndNeighborVals.push_back(mode); //////int numNeighbors = nbs.size(); //////for(int i=0; i odfValuesInAngularRange; int numInRange = m_AngularRangeIdxs->at(pIdx)->size(); for(int i=0; iat(pIdx))[i] ]); } // sort them by value std::sort( odfValuesInAngularRange.begin(), odfValuesInAngularRange.end() ); // median of angular range T median = odfValuesInAngularRange[floor(quantile*(double)numInRange+0.5)]; // compute and return final value if(mode > median) { return mode/median - 1.0; } else { return median/mode - 1.0; } } /** * Calculate Normalized Entropy */ template < typename T, unsigned int N > T itk::OrientationDistributionFunction ::GetNormalizedEntropy() const { double mean = 0; for( unsigned int i=0; i OrientationDistributionFunction OrientationDistributionFunction ::PreMultiply( const MatrixType & m ) const { Self result; typedef typename NumericTraits::AccumulateType AccumulateType; for(unsigned int r=0; r::ZeroValue(); for(unsigned int t=0; t( sum ); } } return result; } /** * Post-multiply the Tensor by a Matrix */ template OrientationDistributionFunction OrientationDistributionFunction ::PostMultiply( const MatrixType & m ) const { Self result; typedef typename NumericTraits::AccumulateType AccumulateType; for(unsigned int r=0; r::ZeroValue(); for(unsigned int t=0; t( sum ); } } return result; } /** * Print content to an ostream */ template std::ostream & operator<<(std::ostream& os,const OrientationDistributionFunction & c ) { for(unsigned int i=0; i::PrintType>(c[i]) << " "; } return os; } /** * Read content from an istream */ template std::istream & operator>>(std::istream& is, OrientationDistributionFunction & dt ) { for(unsigned int i=0; i < dt.GetNumberOfComponents(); i++) { is >> dt[i]; } return is; } } // end namespace itk #endif diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleDicomReader.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleDicomReader.cpp index 17e0a7e30d..07d33c1ca0 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleDicomReader.cpp +++ b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleDicomReader.cpp @@ -1,180 +1,180 @@ /*=================================================================== 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 "mitkFiberBundleDicomReader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkDiffusionIOMimeTypes.h" #include -#include +#include #include "dcmtk/config/osconfig.h" /* make sure OS specific configuration is included first */ #include "dcmtk/dcmtract/trctractographyresults.h" #include "dcmtk/dcmtract/trctrack.h" mitk::FiberBundleDicomReader::FiberBundleDicomReader() : mitk::AbstractFileReader( mitk::DiffusionIOMimeTypes::FIBERBUNDLE_DICOM_MIMETYPE_NAME(), "DICOM Fiber Bundle Reader" ) { m_ServiceReg = this->RegisterService(); } mitk::FiberBundleDicomReader::FiberBundleDicomReader(const FiberBundleDicomReader &other) :mitk::AbstractFileReader(other) { } mitk::FiberBundleDicomReader * mitk::FiberBundleDicomReader::Clone() const { return new FiberBundleDicomReader(*this); } std::vector > mitk::FiberBundleDicomReader::Read() { std::vector > output_fibs; try { const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, nullptr ); setlocale(LC_ALL, locale.c_str()); std::string filename = this->GetInputLocation(); OFCondition result; TrcTractographyResults *trc = nullptr; result = TrcTractographyResults::loadFile(filename.c_str(), trc); if (result.bad()) mitkThrow() << "Unable to load tractography dicom file: " << result.text(); OFString val = "-"; trc->getPatient().getPatientName(val); MITK_INFO << "Patient Name: " << val; val = "-"; trc->getStudy().getStudyInstanceUID(val); MITK_INFO << "Study : " << val; val = "-"; trc->getSeries().getSeriesInstanceUID(val); MITK_INFO << "Series : " << val; val = "-"; trc->getSOPCommon().getSOPInstanceUID(val); MITK_INFO << "Instance : " << val; val = "-"; MITK_INFO << "-------------------------------------------------------------------------"; size_t numTrackSets = trc->getNumberOfTrackSets(); OFVector& sets = trc->getTrackSets(); for (size_t ts = 0; ts < numTrackSets; ts++) { size_t numTracks = sets[ts]->getNumberOfTracks(); MITK_INFO << " Track Set #" << ts << ": " << numTracks << " Tracks, " << sets[ts]->getNumberOfTrackSetStatistics() << " Track Set Statistics, " << sets[ts]->getNumberOfTrackStatistics() << " Track Statistics, " << sets[ts]->getNumberOfMeasurements() << " Measurements "; vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); for (size_t t = 0; t < numTracks; t++) { vtkSmartPointer container = vtkSmartPointer::New(); TrcTrack* track = sets[ts]->getTracks()[t]; const Float32* vals = nullptr; size_t numPoints = track->getTrackData(vals); for (size_t v = 0; v < numPoints; ++v) { vtkIdType id = vtkNewPoints->InsertNextPoint(vals[v*3],vals[v*3+1],vals[v*3+2]); container->GetPointIds()->InsertNextId(id); } vtkNewCells->InsertNextCell(container); } vtkSmartPointer fiberPolyData = vtkSmartPointer::New(); fiberPolyData->SetPoints(vtkNewPoints); fiberPolyData->SetLines(vtkNewCells); // // transform polydata from RAS (MRtrix) to LPS (MITK) // mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); // vtkSmartPointer< vtkMatrix4x4 > 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(fiberPolyData); // transformFilter->SetTransform(geometry->GetVtkTransform()); // transformFilter->Update(); FiberBundle::Pointer fib = FiberBundle::New(fiberPolyData); CodeSequenceMacro* algoCode = sets[ts]->getTrackingAlgorithmIdentification().at(0); val = "-"; algoCode->getCodeValue(val); fib->GetPropertyList()->SetStringProperty("DICOM.algo_code.value",val.c_str()); val = "-"; algoCode->getCodeMeaning(val); fib->GetPropertyList()->SetStringProperty("DICOM.algo_code.meaning",val.c_str()); CodeSequenceMacro modelCode = sets[ts]->getDiffusionModelCode(); val = "-"; modelCode.getCodeValue(val); fib->GetPropertyList()->SetStringProperty("DICOM.model_code.value",val.c_str()); val = "-"; modelCode.getCodeMeaning(val); fib->GetPropertyList()->SetStringProperty("DICOM.model_code.meaning",val.c_str()); CodeWithModifiers anatomy = sets[ts]->getTrackSetAnatomy(); val = "-"; anatomy.getCodeValue(val); fib->GetPropertyList()->SetStringProperty("DICOM.anatomy.value",val.c_str()); val = "-"; anatomy.getCodeMeaning(val); fib->GetPropertyList()->SetStringProperty("DICOM.anatomy.meaning",val.c_str()); val = "-"; trc->getPatient().getPatientID(val); fib->GetPropertyList()->SetStringProperty("DICOM.patient_id",val.c_str()); val = "-"; trc->getPatient().getPatientName(val); fib->GetPropertyList()->SetStringProperty("DICOM.patient_name",val.c_str()); val = "-"; trc->getStudy().getStudyInstanceUID(val); fib->GetPropertyList()->SetStringProperty("DICOM.study_instance_uid",val.c_str()); val = "-"; trc->getSeries().getSeriesInstanceUID(val); fib->GetPropertyList()->SetStringProperty("DICOM.series_instance_uid",val.c_str()); val = "-"; trc->getSOPCommon().getSOPInstanceUID(val); fib->GetPropertyList()->SetStringProperty("DICOM.sop_instance_uid",val.c_str()); val = "-"; trc->getSOPCommon().getSOPClassUID(val); fib->GetPropertyList()->SetStringProperty("DICOM.sop_class_uid",val.c_str()); val = "-"; trc->getFrameOfReference().getFrameOfReferenceUID(val); fib->GetPropertyList()->SetStringProperty("DICOM.frame_of_reference_uid",val.c_str()); output_fibs.push_back(fib.GetPointer()); MITK_INFO << "Fiber bundle read"; } delete trc; setlocale(LC_ALL, currLocale.c_str()); return output_fibs; } catch(...) { throw; } return output_fibs; } diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTckReader.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTckReader.cpp index cc326c9b2c..2c427b9039 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTckReader.cpp +++ b/Modules/DiffusionImaging/DiffusionIO/mitkFiberBundleTckReader.cpp @@ -1,164 +1,164 @@ /*=================================================================== 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 "mitkFiberBundleTckReader.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "mitkDiffusionIOMimeTypes.h" #include -#include +#include mitk::FiberBundleTckReader::FiberBundleTckReader() : mitk::AbstractFileReader( mitk::DiffusionIOMimeTypes::FIBERBUNDLE_TCK_MIMETYPE_NAME(), "tck Fiber Bundle Reader (MRtrix format)" ) { m_ServiceReg = this->RegisterService(); } mitk::FiberBundleTckReader::FiberBundleTckReader(const FiberBundleTckReader &other) :mitk::AbstractFileReader(other) { } mitk::FiberBundleTckReader * mitk::FiberBundleTckReader::Clone() const { return new FiberBundleTckReader(*this); } std::vector > mitk::FiberBundleTckReader::Read() { std::vector > result; try { const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, nullptr ); setlocale(LC_ALL, locale.c_str()); std::string filename = this->GetInputLocation(); std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename); ext = itksys::SystemTools::LowerCase(ext); if (ext==".tck") { MITK_INFO << "Loading tractogram (MRtrix format): " << itksys::SystemTools::GetFilenameName(filename); std::FILE* filePointer = std::fopen(filename.c_str(),"r+b"); std::string header = ""; bool header_end = false; int count = 0; while (!header_end) { char c; count += std::fread(&c, 1, 1, filePointer); header += c; if (header.size() >= 3 && header.compare(header.size() - 3, 3, "END") == 0) header_end = true; } MITK_INFO << "TCK Header:"; MITK_INFO << header; int header_size = -1; try { std::string delimiter = "file: . "; size_t pos = 0; pos = header.find(delimiter); header.erase(0, pos + delimiter.length()); pos = header.find("\n"); header_size = boost::lexical_cast(header.substr(0, pos)); } catch(...) { } if (header_size==-1) mitkThrow() << "Could not parse header size from " << filename; std::fseek ( filePointer , header_size , SEEK_SET ); vtkSmartPointer vtkNewPoints = vtkSmartPointer::New(); vtkSmartPointer vtkNewCells = vtkSmartPointer::New(); vtkSmartPointer container = vtkSmartPointer::New(); float tmp[3]; count = 1; int fiber_length = 0; while (std::fread((char*)tmp, 1, 12, filePointer)==12) { if (std::isinf(tmp[0]) || std::isinf(tmp[1]) || std::isinf(tmp[1])) break; else if (std::isnan(tmp[0]) || std::isnan(tmp[1]) || std::isnan(tmp[2])) { count++; fiber_length = 0; vtkNewCells->InsertNextCell(container); container = vtkSmartPointer::New(); } else { fiber_length++; vtkIdType id = vtkNewPoints->InsertNextPoint(tmp); container->GetPointIds()->InsertNextId(id); } } vtkSmartPointer fiberPolyData = vtkSmartPointer::New(); fiberPolyData->SetPoints(vtkNewPoints); fiberPolyData->SetLines(vtkNewCells); // transform polydata from RAS (MRtrix) to LPS (MITK) mitk::Geometry3D::Pointer geometry = mitk::Geometry3D::New(); vtkSmartPointer< vtkMatrix4x4 > 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(fiberPolyData); transformFilter->SetTransform(geometry->GetVtkTransform()); transformFilter->Update(); FiberBundle::Pointer fib = FiberBundle::New(transformFilter->GetOutput()); result.push_back(fib.GetPointer()); } setlocale(LC_ALL, currLocale.c_str()); MITK_INFO << "Fiber bundle read"; return result; } catch(...) { throw; } return result; } diff --git a/Modules/DiffusionImaging/DiffusionIO/mitkPlanarFigureCompositeReader.cpp b/Modules/DiffusionImaging/DiffusionIO/mitkPlanarFigureCompositeReader.cpp index fd4ea8063d..e2710e3e85 100644 --- a/Modules/DiffusionImaging/DiffusionIO/mitkPlanarFigureCompositeReader.cpp +++ b/Modules/DiffusionImaging/DiffusionIO/mitkPlanarFigureCompositeReader.cpp @@ -1,100 +1,100 @@ /*=================================================================== 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 "mitkPlanarFigureCompositeReader.h" #include #include #include #include #include #include #include "mitkDiffusionIOMimeTypes.h" #include #define RAPIDXML_NO_EXCEPTIONS #include #include -#include +#include #include mitk::PlanarFigureCompositeReader::PlanarFigureCompositeReader() : mitk::AbstractFileReader( mitk::DiffusionIOMimeTypes::PLANARFIGURECOMPOSITE_MIMETYPE(), "Planar Figure Composite Reader" ) { m_ServiceReg = this->RegisterService(); } mitk::PlanarFigureCompositeReader::PlanarFigureCompositeReader(const PlanarFigureCompositeReader &other) :mitk::AbstractFileReader(other) { } mitk::PlanarFigureCompositeReader * mitk::PlanarFigureCompositeReader::Clone() const { return new PlanarFigureCompositeReader(*this); } std::vector > mitk::PlanarFigureCompositeReader::Read() { std::vector > result; try { const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, nullptr ); setlocale(LC_ALL, locale.c_str()); std::string filename = this->GetInputLocation(); std::string ext = itksys::SystemTools::GetFilenameLastExtension(filename); ext = itksys::SystemTools::LowerCase(ext); boost::property_tree::ptree tree; boost::property_tree::xml_parser::read_xml(filename, tree); int comptype = tree.get("comptype"); mitk::PlanarFigureComposite::Pointer pfc = mitk::PlanarFigureComposite::New(); switch(comptype) { case 0: pfc->setOperationType(mitk::PlanarFigureComposite::AND); MITK_INFO << "loading AND composition"; break; case 1: pfc->setOperationType(mitk::PlanarFigureComposite::OR); MITK_INFO << "loading OR composition"; break; case 2: pfc->setOperationType(mitk::PlanarFigureComposite::NOT); MITK_INFO << "loading NOT composition"; break; default: MITK_ERROR << filename << " contains no valid composition type!"; } std::vector > result; result.push_back(pfc.GetPointer()); setlocale(LC_ALL, currLocale.c_str()); return result; } catch(...) { throw; } return result; } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp index d31b7d25c2..413e4215b3 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkGibbsTrackingFilter.cpp @@ -1,515 +1,515 @@ /*=================================================================== 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 "itkGibbsTrackingFilter.h" // MITK #include #include #include #include #include //#include #include #include // ITK #include #include #include // MISC #include // #include #include #include -#include +#include #include namespace itk{ template< class ItkOdfImageType > GibbsTrackingFilter< ItkOdfImageType >::GibbsTrackingFilter(): m_StartTemperature(0.1), m_EndTemperature(0.001), m_Iterations(1e9), m_CurrentIteration(0.0), m_CurrentStep(0), m_ParticleWeight(0), m_ParticleWidth(0), m_ParticleLength(0), m_ConnectionPotential(10), m_InexBalance(0), m_ParticlePotential(0.2), m_MinFiberLength(10), m_AbortTracking(false), m_NumAcceptedFibers(0), m_BuildFibers(false), m_ProposalAcceptance(0), m_CurvatureThreshold(0.7), m_DuplicateImage(true), m_NumParticles(0), m_NumConnections(0), m_RandomSeed(-1), m_LoadParameterFile(""), m_LutPath(""), m_IsInValidState(true) { } template< class ItkOdfImageType > GibbsTrackingFilter< ItkOdfImageType >::~GibbsTrackingFilter() { } // fill output fiber bundle datastructure template< class ItkOdfImageType > typename GibbsTrackingFilter< ItkOdfImageType >::FiberPolyDataType GibbsTrackingFilter< ItkOdfImageType >::GetFiberBundle() { if (!m_AbortTracking) { m_BuildFibers = true; while (m_BuildFibers){} } return m_FiberPolyData; } template< class ItkOdfImageType > void GibbsTrackingFilter< ItkOdfImageType > ::EstimateParticleWeight() { MITK_INFO << "GibbsTrackingFilter: estimating particle weight"; float minSpacing; if(m_OdfImage->GetSpacing()[0]GetSpacing()[1] && m_OdfImage->GetSpacing()[0]GetSpacing()[2]) minSpacing = m_OdfImage->GetSpacing()[0]; else if (m_OdfImage->GetSpacing()[1] < m_OdfImage->GetSpacing()[2]) minSpacing = m_OdfImage->GetSpacing()[1]; else minSpacing = m_OdfImage->GetSpacing()[2]; float m_ParticleLength = 1.5*minSpacing; float m_ParticleWidth = 0.5*minSpacing; // seed random generators Statistics::MersenneTwisterRandomVariateGenerator::Pointer randGen = Statistics::MersenneTwisterRandomVariateGenerator::New(); if (m_RandomSeed>-1) randGen->SetSeed(m_RandomSeed); else randGen->SetSeed(); // instantiate all necessary components SphereInterpolator* interpolator = new SphereInterpolator(m_LutPath); // handle lookup table not found cases if( !interpolator->IsInValidState() ) { m_IsInValidState = false; m_AbortTracking = true; m_BuildFibers = false; mitkThrow() << "Unable to load lookup tables."; } ParticleGrid* particleGrid = new ParticleGrid(m_MaskImage, m_ParticleLength, m_ParticleGridCellCapacity); GibbsEnergyComputer* encomp = new GibbsEnergyComputer(m_OdfImage, m_MaskImage, particleGrid, interpolator, randGen); // EnergyComputer* encomp = new EnergyComputer(m_OdfImage, m_MaskImage, particleGrid, interpolator, randGen); MetropolisHastingsSampler* sampler = new MetropolisHastingsSampler(particleGrid, encomp, randGen, m_CurvatureThreshold); float alpha = log(m_EndTemperature/m_StartTemperature); m_ParticleWeight = 0.01; int ppv = 0; // main loop int neededParts = 3000; while (ppvSetParameters(m_ParticleWeight,m_ParticleWidth,m_ConnectionPotential*m_ParticleLength*m_ParticleLength,m_CurvatureThreshold,m_InexBalance,m_ParticlePotential); for( int step = 0; step < 10; step++ ) { // update temperatur for simulated annealing process float temperature = m_StartTemperature * exp(alpha*(((1.0)*step)/((1.0)*10))); sampler->SetTemperature(temperature); for (unsigned long i=0; i<10000; i++) sampler->MakeProposal(); } ppv = particleGrid->m_NumParticles; particleGrid->ResetGrid(); } delete sampler; delete encomp; delete particleGrid; delete interpolator; MITK_INFO << "GibbsTrackingFilter: finished estimating particle weight"; } // perform global tracking template< class ItkOdfImageType > void GibbsTrackingFilter< ItkOdfImageType >::GenerateData() { TimeProbe preClock; preClock.Start(); // check if input is Odf or tensor image and generate Odf if necessary if (m_OdfImage.IsNull() && m_TensorImage.IsNotNull()) { TensorImageToOdfImageFilter::Pointer filter = TensorImageToOdfImageFilter::New(); filter->SetInput( m_TensorImage ); filter->Update(); m_OdfImage = filter->GetOutput(); } else if (m_DuplicateImage) // generate local working copy of Odf image (if not disabled) { typedef itk::ImageDuplicator< ItkOdfImageType > DuplicateFilterType; typename DuplicateFilterType::Pointer duplicator = DuplicateFilterType::New(); duplicator->SetInputImage( m_OdfImage ); duplicator->Update(); m_OdfImage = duplicator->GetOutput(); } // perform mean subtraction on odfs typedef ImageRegionIterator< ItkOdfImageType > InputIteratorType; InputIteratorType it(m_OdfImage, m_OdfImage->GetLargestPossibleRegion() ); it.GoToBegin(); while (!it.IsAtEnd()) { itk::OrientationDistributionFunction odf(it.Get().GetDataPointer()); float mean = odf.GetMeanValue(); odf -= mean; it.Set(odf.GetDataPointer()); ++it; } // check if mask image is given if it needs resampling PrepareMaskImage(); // load parameter file LoadParameters(); // prepare parameters float minSpacing; if(m_OdfImage->GetSpacing()[0]GetSpacing()[1] && m_OdfImage->GetSpacing()[0]GetSpacing()[2]) minSpacing = m_OdfImage->GetSpacing()[0]; else if (m_OdfImage->GetSpacing()[1] < m_OdfImage->GetSpacing()[2]) minSpacing = m_OdfImage->GetSpacing()[1]; else minSpacing = m_OdfImage->GetSpacing()[2]; if(m_ParticleLength == 0) m_ParticleLength = 1.5*minSpacing; if(m_ParticleWidth == 0) m_ParticleWidth = 0.5*minSpacing; if(m_ParticleWeight == 0) EstimateParticleWeight(); float alpha = log(m_EndTemperature/m_StartTemperature); if (m_CurvatureThreshold < mitk::eps) m_CurvatureThreshold = 0; // seed random generators Statistics::MersenneTwisterRandomVariateGenerator::Pointer randGen = Statistics::MersenneTwisterRandomVariateGenerator::New(); if (m_RandomSeed>-1) randGen->SetSeed(m_RandomSeed); else randGen->SetSeed(); // load sphere interpolator to evaluate the ODFs SphereInterpolator* interpolator = new SphereInterpolator(m_LutPath); // handle lookup table not found cases if( !interpolator->IsInValidState() ) { m_IsInValidState = false; m_AbortTracking = true; m_BuildFibers = false; mitkThrow() << "Unable to load lookup tables."; } // initialize the actual tracking components (ParticleGrid, Metropolis Hastings Sampler and Energy Computer) ParticleGrid* particleGrid; GibbsEnergyComputer* encomp; MetropolisHastingsSampler* sampler; try{ particleGrid = new ParticleGrid(m_MaskImage, m_ParticleLength, m_ParticleGridCellCapacity); encomp = new GibbsEnergyComputer(m_OdfImage, m_MaskImage, particleGrid, interpolator, randGen); encomp->SetParameters(m_ParticleWeight,m_ParticleWidth,m_ConnectionPotential*m_ParticleLength*m_ParticleLength,m_CurvatureThreshold,m_InexBalance,m_ParticlePotential); sampler = new MetropolisHastingsSampler(particleGrid, encomp, randGen, m_CurvatureThreshold); } catch(...) { MITK_ERROR << "Particle grid allocation failed. Not enough memory? Try to increase the particle length."; m_IsInValidState = false; m_AbortTracking = true; m_BuildFibers = false; return; } MITK_INFO << "----------------------------------------"; MITK_INFO << "Iterations: " << m_Iterations; MITK_INFO << "Particle length: " << m_ParticleLength; MITK_INFO << "Particle width: " << m_ParticleWidth; MITK_INFO << "Particle weight: " << m_ParticleWeight; MITK_INFO << "Start temperature: " << m_StartTemperature; MITK_INFO << "End temperature: " << m_EndTemperature; MITK_INFO << "In/Ex balance: " << m_InexBalance; MITK_INFO << "Min. fiber length: " << m_MinFiberLength; MITK_INFO << "Curvature threshold: " << m_CurvatureThreshold; MITK_INFO << "Random seed: " << m_RandomSeed; MITK_INFO << "----------------------------------------"; // main loop preClock.Stop(); TimeProbe clock; clock.Start(); m_NumAcceptedFibers = 0; m_CurrentIteration = 0; bool just_built_fibers = false; boost::progress_display disp(m_Iterations); if (!m_AbortTracking) while (m_CurrentIterationSetTemperature(temperature); sampler->MakeProposal(); m_ProposalAcceptance = (float)sampler->GetNumAcceptedProposals()/m_CurrentIteration; m_NumParticles = particleGrid->m_NumParticles; m_NumConnections = particleGrid->m_NumConnections; if (m_AbortTracking) break; if (m_BuildFibers) { FiberBuilder fiberBuilder(particleGrid, m_MaskImage); m_FiberPolyData = fiberBuilder.iterate(m_MinFiberLength); m_NumAcceptedFibers = m_FiberPolyData->GetNumberOfLines(); m_BuildFibers = false; just_built_fibers = true; } } if (!just_built_fibers) { FiberBuilder fiberBuilder(particleGrid, m_MaskImage); m_FiberPolyData = fiberBuilder.iterate(m_MinFiberLength); m_NumAcceptedFibers = m_FiberPolyData->GetNumberOfLines(); } clock.Stop(); delete sampler; delete encomp; delete interpolator; delete particleGrid; m_AbortTracking = true; m_BuildFibers = false; int h = clock.GetTotal()/3600; int m = ((int)clock.GetTotal()%3600)/60; int s = (int)clock.GetTotal()%60; MITK_INFO << "GibbsTrackingFilter: finished gibbs tracking in " << h << "h, " << m << "m and " << s << "s"; m = (int)preClock.GetTotal()/60; s = (int)preClock.GetTotal()%60; MITK_INFO << "GibbsTrackingFilter: preparation of the data took " << m << "m and " << s << "s"; MITK_INFO << "GibbsTrackingFilter: " << m_NumAcceptedFibers << " fibers accepted"; // sampler->PrintProposalTimes(); SaveParameters(); } template< class ItkOdfImageType > void GibbsTrackingFilter< ItkOdfImageType >::PrepareMaskImage() { if(m_MaskImage.IsNull()) { MITK_INFO << "GibbsTrackingFilter: generating default mask image"; m_MaskImage = ItkFloatImageType::New(); m_MaskImage->SetSpacing( m_OdfImage->GetSpacing() ); m_MaskImage->SetOrigin( m_OdfImage->GetOrigin() ); m_MaskImage->SetDirection( m_OdfImage->GetDirection() ); m_MaskImage->SetRegions( m_OdfImage->GetLargestPossibleRegion() ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1.0); } else if ( m_MaskImage->GetLargestPossibleRegion().GetSize()[0]!=m_OdfImage->GetLargestPossibleRegion().GetSize()[0] || m_MaskImage->GetLargestPossibleRegion().GetSize()[1]!=m_OdfImage->GetLargestPossibleRegion().GetSize()[1] || m_MaskImage->GetLargestPossibleRegion().GetSize()[2]!=m_OdfImage->GetLargestPossibleRegion().GetSize()[2] || m_MaskImage->GetSpacing()[0]!=m_OdfImage->GetSpacing()[0] || m_MaskImage->GetSpacing()[1]!=m_OdfImage->GetSpacing()[1] || m_MaskImage->GetSpacing()[2]!=m_OdfImage->GetSpacing()[2] ) { MITK_INFO << "GibbsTrackingFilter: resampling mask image"; typedef itk::ResampleImageFilter< ItkFloatImageType, ItkFloatImageType, float > ResamplerType; ResamplerType::Pointer resampler = ResamplerType::New(); resampler->SetOutputSpacing( m_OdfImage->GetSpacing() ); resampler->SetOutputOrigin( m_OdfImage->GetOrigin() ); resampler->SetOutputDirection( m_OdfImage->GetDirection() ); resampler->SetSize( m_OdfImage->GetLargestPossibleRegion().GetSize() ); resampler->SetInput( m_MaskImage ); resampler->SetDefaultPixelValue(0.0); resampler->Update(); m_MaskImage = resampler->GetOutput(); MITK_INFO << "GibbsTrackingFilter: resampling finished"; } } // load tracking paramters from xml file (.gtp) template< class ItkOdfImageType > bool GibbsTrackingFilter< ItkOdfImageType >::LoadParameters() { m_AbortTracking = true; try { if( m_LoadParameterFile.length()==0 ) { m_AbortTracking = false; return true; } MITK_INFO << "GibbsTrackingFilter: loading parameter file " << m_LoadParameterFile; TiXmlDocument doc( m_LoadParameterFile ); doc.LoadFile(); TiXmlHandle hDoc(&doc); TiXmlElement* pElem; TiXmlHandle hRoot(nullptr); pElem = hDoc.FirstChildElement().Element(); hRoot = TiXmlHandle(pElem); pElem = hRoot.FirstChildElement("parameter_set").Element(); std::string iterations(pElem->Attribute("iterations")); m_Iterations = boost::lexical_cast(iterations); std::string particleLength(pElem->Attribute("particle_length")); m_ParticleLength = boost::lexical_cast(particleLength); std::string particleWidth(pElem->Attribute("particle_width")); m_ParticleWidth = boost::lexical_cast(particleWidth); std::string partWeight(pElem->Attribute("particle_weight")); m_ParticleWeight = boost::lexical_cast(partWeight); std::string startTemp(pElem->Attribute("temp_start")); m_StartTemperature = boost::lexical_cast(startTemp); std::string endTemp(pElem->Attribute("temp_end")); m_EndTemperature = boost::lexical_cast(endTemp); std::string inExBalance(pElem->Attribute("inexbalance")); m_InexBalance = boost::lexical_cast(inExBalance); std::string fiberLength(pElem->Attribute("fiber_length")); m_MinFiberLength = boost::lexical_cast(fiberLength); std::string curvThres(pElem->Attribute("curvature_threshold")); m_CurvatureThreshold = cos(boost::lexical_cast(curvThres)*itk::Math::pi/180); m_AbortTracking = false; MITK_INFO << "GibbsTrackingFilter: parameter file loaded successfully"; return true; } catch(...) { MITK_INFO << "GibbsTrackingFilter: could not load parameter file"; return false; } } // save current tracking paramters to xml file (.gtp) template< class ItkOdfImageType > bool GibbsTrackingFilter< ItkOdfImageType >::SaveParameters() { try { if( m_SaveParameterFile.length()==0 ) { MITK_INFO << "GibbsTrackingFilter: no filename specified to save parameters"; return true; } MITK_INFO << "GibbsTrackingFilter: saving parameter file " << m_SaveParameterFile; TiXmlDocument documentXML; TiXmlDeclaration* declXML = new TiXmlDeclaration( "1.0", "", "" ); documentXML.LinkEndChild( declXML ); TiXmlElement* mainXML = new TiXmlElement("global_tracking_parameter_file"); mainXML->SetAttribute("file_version", "0.1"); documentXML.LinkEndChild(mainXML); TiXmlElement* paramXML = new TiXmlElement("parameter_set"); paramXML->SetAttribute("iterations", boost::lexical_cast(m_Iterations)); paramXML->SetAttribute("particle_length", boost::lexical_cast(m_ParticleLength)); paramXML->SetAttribute("particle_width", boost::lexical_cast(m_ParticleWidth)); paramXML->SetAttribute("particle_weight", boost::lexical_cast(m_ParticleWeight)); paramXML->SetAttribute("temp_start", boost::lexical_cast(m_StartTemperature)); paramXML->SetAttribute("temp_end", boost::lexical_cast(m_EndTemperature)); paramXML->SetAttribute("inexbalance", boost::lexical_cast(m_InexBalance)); paramXML->SetAttribute("fiber_length", boost::lexical_cast(m_MinFiberLength)); paramXML->SetAttribute("curvature_threshold", boost::lexical_cast(m_CurvatureThreshold)); mainXML->LinkEndChild(paramXML); if(!boost::algorithm::ends_with(m_SaveParameterFile, ".gtp")) m_SaveParameterFile.append(".gtp"); documentXML.SaveFile( m_SaveParameterFile ); MITK_INFO << "GibbsTrackingFilter: parameter file saved successfully"; return true; } catch(...) { MITK_INFO << "GibbsTrackingFilter: could not save parameter file"; return false; } } template< class ItkOdfImageType > void GibbsTrackingFilter< ItkOdfImageType >::SetDicomProperties(mitk::FiberBundle::Pointer fib) { std::string model_code_value = "-"; std::string model_code_meaning = "-"; std::string algo_code_value = "sup181_ee03"; std::string algo_code_meaning = "Global"; fib->SetProperty("DICOM.anatomy.value", mitk::StringProperty::New("T-A0095")); fib->SetProperty("DICOM.anatomy.meaning", mitk::StringProperty::New("White matter of brain and spinal cord")); fib->SetProperty("DICOM.algo_code.value", mitk::StringProperty::New(algo_code_value)); fib->SetProperty("DICOM.algo_code.meaning", mitk::StringProperty::New(algo_code_meaning)); fib->SetProperty("DICOM.model_code.value", mitk::StringProperty::New(model_code_value)); fib->SetProperty("DICOM.model_code.meaning", mitk::StringProperty::New(model_code_meaning)); } } diff --git a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.cpp index 4d3adb37d6..4beab1fb73 100644 --- a/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Algorithms/itkStreamlineTrackingFilter.cpp @@ -1,1024 +1,1024 @@ /*=================================================================== 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 "itkStreamlineTrackingFilter.h" #include #include #include #include #include "itkPointShell.h" #include -#include +#include #include #include #include #include #include #include namespace itk { StreamlineTrackingFilter ::StreamlineTrackingFilter() : m_PauseTracking(false) , m_AbortTracking(false) , m_BuildFibersFinished(false) , m_BuildFibersReady(0) , m_FiberPolyData(nullptr) , m_Points(nullptr) , m_Cells(nullptr) , m_StoppingRegions(nullptr) , m_TargetRegions(nullptr) , m_SeedImage(nullptr) , m_MaskImage(nullptr) , m_ExclusionRegions(nullptr) , m_OutputProbabilityMap(nullptr) , m_MinVoxelSize(-1) , m_AngularThresholdDeg(-1) , m_StepSizeVox(-1) , m_SamplingDistanceVox(-1) , m_AngularThreshold(-1) , m_StepSize(0) , m_MaxLength(10000) , m_MinTractLength(20.0) , m_MaxTractLength(400.0) , m_SeedsPerVoxel(1) , m_AvoidStop(true) , m_RandomSampling(false) , m_SamplingDistance(-1) , m_DeflectionMod(1.0) , m_OnlyForwardSamples(true) , m_UseStopVotes(true) , m_NumberOfSamples(30) , m_NumPreviousDirections(1) , m_MaxNumTracts(-1) , m_Verbose(true) , m_LoopCheck(-1) , m_DemoMode(false) , m_Random(true) , m_UseOutputProbabilityMap(false) , m_CurrentTracts(0) , m_Progress(0) , m_StopTracking(false) , m_InterpolateMasks(true) , m_TrialsPerSeed(10) , m_EndpointConstraint(EndpointConstraints::NONE) , m_IntroduceDirectionsFromPrior(true) , m_TrackingPriorAsMask(true) , m_TrackingPriorWeight(1.0) , m_TrackingPriorHandler(nullptr) { this->SetNumberOfRequiredInputs(0); } std::string StreamlineTrackingFilter::GetStatusText() { std::string status = "Seedpoints processed: " + boost::lexical_cast(m_Progress) + "/" + boost::lexical_cast(m_SeedPoints.size()); if (m_SeedPoints.size()>0) status += " (" + boost::lexical_cast(100*m_Progress/m_SeedPoints.size()) + "%)"; if (m_MaxNumTracts>0) status += "\nFibers accepted: " + boost::lexical_cast(m_CurrentTracts) + "/" + boost::lexical_cast(m_MaxNumTracts); else status += "\nFibers accepted: " + boost::lexical_cast(m_CurrentTracts); return status; } void StreamlineTrackingFilter::BeforeTracking() { m_StopTracking = false; m_TrackingHandler->SetRandom(m_Random); m_TrackingHandler->InitForTracking(); m_FiberPolyData = PolyDataType::New(); m_Points = vtkSmartPointer< vtkPoints >::New(); m_Cells = vtkSmartPointer< vtkCellArray >::New(); itk::Vector< double, 3 > imageSpacing = m_TrackingHandler->GetSpacing(); if(imageSpacing[0]SetAngularThreshold(m_AngularThreshold); if (m_TrackingPriorHandler!=nullptr) { m_TrackingPriorHandler->SetRandom(m_Random); m_TrackingPriorHandler->InitForTracking(); m_TrackingPriorHandler->SetAngularThreshold(m_AngularThreshold); } if (m_SamplingDistanceVoxGetNumberOfThreads(); i++) { PolyDataType poly = PolyDataType::New(); m_PolyDataContainer.push_back(poly); } if (m_UseOutputProbabilityMap) { m_OutputProbabilityMap = ItkDoubleImgType::New(); m_OutputProbabilityMap->SetSpacing(imageSpacing); m_OutputProbabilityMap->SetOrigin(m_TrackingHandler->GetOrigin()); m_OutputProbabilityMap->SetDirection(m_TrackingHandler->GetDirection()); m_OutputProbabilityMap->SetRegions(m_TrackingHandler->GetLargestPossibleRegion()); m_OutputProbabilityMap->Allocate(); m_OutputProbabilityMap->FillBuffer(0); } m_MaskInterpolator = itk::LinearInterpolateImageFunction< ItkFloatImgType, float >::New(); m_StopInterpolator = itk::LinearInterpolateImageFunction< ItkFloatImgType, float >::New(); m_SeedInterpolator = itk::LinearInterpolateImageFunction< ItkFloatImgType, float >::New(); m_TargetInterpolator = itk::LinearInterpolateImageFunction< ItkFloatImgType, float >::New(); m_ExclusionInterpolator = itk::LinearInterpolateImageFunction< ItkFloatImgType, float >::New(); if (m_StoppingRegions.IsNull()) { m_StoppingRegions = ItkFloatImgType::New(); m_StoppingRegions->SetSpacing( imageSpacing ); m_StoppingRegions->SetOrigin( m_TrackingHandler->GetOrigin() ); m_StoppingRegions->SetDirection( m_TrackingHandler->GetDirection() ); m_StoppingRegions->SetRegions( m_TrackingHandler->GetLargestPossibleRegion() ); m_StoppingRegions->Allocate(); m_StoppingRegions->FillBuffer(0); } else std::cout << "StreamlineTracking - Using stopping region image" << std::endl; m_StopInterpolator->SetInputImage(m_StoppingRegions); if (m_ExclusionRegions.IsNotNull()) { std::cout << "StreamlineTracking - Using exclusion region image" << std::endl; m_ExclusionInterpolator->SetInputImage(m_ExclusionRegions); } if (m_TargetRegions.IsNull()) { m_TargetImageSet = false; m_TargetRegions = ItkFloatImgType::New(); m_TargetRegions->SetSpacing( imageSpacing ); m_TargetRegions->SetOrigin( m_TrackingHandler->GetOrigin() ); m_TargetRegions->SetDirection( m_TrackingHandler->GetDirection() ); m_TargetRegions->SetRegions( m_TrackingHandler->GetLargestPossibleRegion() ); m_TargetRegions->Allocate(); m_TargetRegions->FillBuffer(1); } else { m_TargetImageSet = true; m_TargetInterpolator->SetInputImage(m_TargetRegions); std::cout << "StreamlineTracking - Using target region image" << std::endl; } if (m_SeedImage.IsNull()) { m_SeedImageSet = false; m_SeedImage = ItkFloatImgType::New(); m_SeedImage->SetSpacing( imageSpacing ); m_SeedImage->SetOrigin( m_TrackingHandler->GetOrigin() ); m_SeedImage->SetDirection( m_TrackingHandler->GetDirection() ); m_SeedImage->SetRegions( m_TrackingHandler->GetLargestPossibleRegion() ); m_SeedImage->Allocate(); m_SeedImage->FillBuffer(1); } else { m_SeedImageSet = true; std::cout << "StreamlineTracking - Using seed image" << std::endl; } m_SeedInterpolator->SetInputImage(m_SeedImage); if (m_MaskImage.IsNull()) { // initialize mask image m_MaskImage = ItkFloatImgType::New(); m_MaskImage->SetSpacing( imageSpacing ); m_MaskImage->SetOrigin( m_TrackingHandler->GetOrigin() ); m_MaskImage->SetDirection( m_TrackingHandler->GetDirection() ); m_MaskImage->SetRegions( m_TrackingHandler->GetLargestPossibleRegion() ); m_MaskImage->Allocate(); m_MaskImage->FillBuffer(1); } else std::cout << "StreamlineTracking - Using mask image" << std::endl; m_MaskInterpolator->SetInputImage(m_MaskImage); // Autosettings for endpoint constraints if (m_EndpointConstraint==EndpointConstraints::NONE && m_TargetImageSet && m_SeedImageSet) { MITK_INFO << "No endpoint constraint chosen but seed and target image set --> setting constraint to EPS_IN_SEED_AND_TARGET"; m_EndpointConstraint = EndpointConstraints::EPS_IN_SEED_AND_TARGET; } else if (m_EndpointConstraint==EndpointConstraints::NONE && m_TargetImageSet) { MITK_INFO << "No endpoint constraint chosen but target image set --> setting constraint to EPS_IN_TARGET"; m_EndpointConstraint = EndpointConstraints::EPS_IN_TARGET; } // Check if endpoint constraints are valid FiberType test_fib; itk::Point p; p.Fill(0); test_fib.push_back(p); test_fib.push_back(p); IsValidFiber(&test_fib); if (m_SeedPoints.empty()) GetSeedPointsFromSeedImage(); m_BuildFibersReady = 0; m_BuildFibersFinished = false; m_Tractogram.clear(); m_SamplingPointset = mitk::PointSet::New(); m_AlternativePointset = mitk::PointSet::New(); m_StopVotePointset = mitk::PointSet::New(); m_StartTime = std::chrono::system_clock::now(); if (m_DemoMode) omp_set_num_threads(1); if (m_TrackingHandler->GetMode()==mitk::TrackingDataHandler::MODE::DETERMINISTIC) std::cout << "StreamlineTracking - Mode: deterministic" << std::endl; else if(m_TrackingHandler->GetMode()==mitk::TrackingDataHandler::MODE::PROBABILISTIC) { std::cout << "StreamlineTracking - Mode: probabilistic" << std::endl; std::cout << "StreamlineTracking - Trials per seed: " << m_TrialsPerSeed << std::endl; } else std::cout << "StreamlineTracking - Mode: ???" << std::endl; if (m_EndpointConstraint==EndpointConstraints::NONE) std::cout << "StreamlineTracking - Endpoint constraint: NONE" << std::endl; else if (m_EndpointConstraint==EndpointConstraints::EPS_IN_TARGET) std::cout << "StreamlineTracking - Endpoint constraint: EPS_IN_TARGET" << std::endl; else if (m_EndpointConstraint==EndpointConstraints::EPS_IN_TARGET_LABELDIFF) std::cout << "StreamlineTracking - Endpoint constraint: EPS_IN_TARGET_LABELDIFF" << std::endl; else if (m_EndpointConstraint==EndpointConstraints::EPS_IN_SEED_AND_TARGET) std::cout << "StreamlineTracking - Endpoint constraint: EPS_IN_SEED_AND_TARGET" << std::endl; else if (m_EndpointConstraint==EndpointConstraints::MIN_ONE_EP_IN_TARGET) std::cout << "StreamlineTracking - Endpoint constraint: MIN_ONE_EP_IN_TARGET" << std::endl; else if (m_EndpointConstraint==EndpointConstraints::ONE_EP_IN_TARGET) std::cout << "StreamlineTracking - Endpoint constraint: ONE_EP_IN_TARGET" << std::endl; else if (m_EndpointConstraint==EndpointConstraints::NO_EP_IN_TARGET) std::cout << "StreamlineTracking - Endpoint constraint: NO_EP_IN_TARGET" << std::endl; std::cout << "StreamlineTracking - Angular threshold: " << m_AngularThreshold << " (" << 180*std::acos( m_AngularThreshold )/itk::Math::pi << "°)" << std::endl; std::cout << "StreamlineTracking - Stepsize: " << m_StepSize << "mm (" << m_StepSize/m_MinVoxelSize << "*vox)" << std::endl; std::cout << "StreamlineTracking - Seeds per voxel: " << m_SeedsPerVoxel << std::endl; std::cout << "StreamlineTracking - Max. tract length: " << m_MaxTractLength << "mm" << std::endl; std::cout << "StreamlineTracking - Min. tract length: " << m_MinTractLength << "mm" << std::endl; std::cout << "StreamlineTracking - Max. num. tracts: " << m_MaxNumTracts << std::endl; std::cout << "StreamlineTracking - Loop check: " << m_LoopCheck << "°" << std::endl; std::cout << "StreamlineTracking - Num. neighborhood samples: " << m_NumberOfSamples << std::endl; std::cout << "StreamlineTracking - Max. sampling distance: " << m_SamplingDistance << "mm (" << m_SamplingDistance/m_MinVoxelSize << "*vox)" << std::endl; std::cout << "StreamlineTracking - Deflection modifier: " << m_DeflectionMod << std::endl; std::cout << "StreamlineTracking - Use stop votes: " << m_UseStopVotes << std::endl; std::cout << "StreamlineTracking - Only frontal samples: " << m_OnlyForwardSamples << std::endl; if (m_TrackingPriorHandler!=nullptr) std::cout << "StreamlineTracking - Using directional prior for tractography (w=" << m_TrackingPriorWeight << ")" << std::endl; if (m_DemoMode) { std::cout << "StreamlineTracking - Running in demo mode"; std::cout << "StreamlineTracking - Starting streamline tracking using 1 thread" << std::endl; } else std::cout << "StreamlineTracking - Starting streamline tracking using " << omp_get_max_threads() << " threads" << std::endl; } void StreamlineTrackingFilter::CalculateNewPosition(itk::Point& pos, vnl_vector_fixed& dir) { pos[0] += dir[0]*m_StepSize; pos[1] += dir[1]*m_StepSize; pos[2] += dir[2]*m_StepSize; } std::vector< vnl_vector_fixed > StreamlineTrackingFilter::CreateDirections(int NPoints) { std::vector< vnl_vector_fixed > pointshell; if (NPoints<2) return pointshell; std::vector< float > theta; theta.resize(NPoints); std::vector< float > phi; phi.resize(NPoints); float C = sqrt(4*itk::Math::pi); phi[0] = 0.0; phi[NPoints-1] = 0.0; for(int i=0; i0 && i d; d[0] = cos(theta[i]) * cos(phi[i]); d[1] = cos(theta[i]) * sin(phi[i]); d[2] = sin(theta[i]); pointshell.push_back(d); } return pointshell; } vnl_vector_fixed StreamlineTrackingFilter::GetNewDirection(const itk::Point &pos, std::deque >& olddirs, itk::Index<3> &oldIndex) { if (m_DemoMode) { m_SamplingPointset->Clear(); m_AlternativePointset->Clear(); m_StopVotePointset->Clear(); } vnl_vector_fixed direction; direction.fill(0); if (mitk::imv::IsInsideMask(pos, m_InterpolateMasks, m_MaskInterpolator) && !mitk::imv::IsInsideMask(pos, m_InterpolateMasks, m_StopInterpolator)) direction = m_TrackingHandler->ProposeDirection(pos, olddirs, oldIndex); // get direction proposal at current streamline position else return direction; int stop_votes = 0; int possible_stop_votes = 0; if (!olddirs.empty()) { vnl_vector_fixed olddir = olddirs.back(); std::vector< vnl_vector_fixed > probeVecs = CreateDirections(m_NumberOfSamples); itk::Point sample_pos; int alternatives = 1; for (unsigned int i=0; i d; bool is_stop_voter = false; if (m_Random && m_RandomSampling) { d[0] = m_TrackingHandler->GetRandDouble(-0.5, 0.5); d[1] = m_TrackingHandler->GetRandDouble(-0.5, 0.5); d[2] = m_TrackingHandler->GetRandDouble(-0.5, 0.5); d.normalize(); d *= m_TrackingHandler->GetRandDouble(0,m_SamplingDistance); } else { d = probeVecs.at(i); float dot = dot_product(d, olddir); if (m_UseStopVotes && dot>0.7) { is_stop_voter = true; possible_stop_votes++; } else if (m_OnlyForwardSamples && dot<0) continue; d *= m_SamplingDistance; } sample_pos[0] = pos[0] + d[0]; sample_pos[1] = pos[1] + d[1]; sample_pos[2] = pos[2] + d[2]; vnl_vector_fixed tempDir; tempDir.fill(0.0); if (mitk::imv::IsInsideMask(sample_pos, m_InterpolateMasks, m_MaskInterpolator)) tempDir = m_TrackingHandler->ProposeDirection(sample_pos, olddirs, oldIndex); // sample neighborhood if (tempDir.magnitude()>mitk::eps) { direction += tempDir; if(m_DemoMode) m_SamplingPointset->InsertPoint(i, sample_pos); } else if (m_AvoidStop && olddir.magnitude()>0.5) // out of white matter { if (is_stop_voter) stop_votes++; if (m_DemoMode) m_StopVotePointset->InsertPoint(i, sample_pos); float dot = dot_product(d, olddir); if (dot >= 0.0) // in front of plane defined by pos and olddir d = -d + 2*dot*olddir; // reflect else d = -d; // invert // look a bit further into the other direction sample_pos[0] = pos[0] + d[0]; sample_pos[1] = pos[1] + d[1]; sample_pos[2] = pos[2] + d[2]; alternatives++; vnl_vector_fixed tempDir; tempDir.fill(0.0); if (mitk::imv::IsInsideMask(sample_pos, m_InterpolateMasks, m_MaskInterpolator)) tempDir = m_TrackingHandler->ProposeDirection(sample_pos, olddirs, oldIndex); // sample neighborhood if (tempDir.magnitude()>mitk::eps) // are we back in the white matter? { direction += d * m_DeflectionMod; // go into the direction of the white matter direction += tempDir; // go into the direction of the white matter direction at this location if(m_DemoMode) m_AlternativePointset->InsertPoint(alternatives, sample_pos); } else { if (m_DemoMode) m_StopVotePointset->InsertPoint(i, sample_pos); } } else { if (m_DemoMode) m_StopVotePointset->InsertPoint(i, sample_pos); if (is_stop_voter) stop_votes++; } } } bool valid = false; if (direction.magnitude()>0.001 && (possible_stop_votes==0 || (float)stop_votes/possible_stop_votes<0.5) ) { direction.normalize(); valid = true; } else direction.fill(0); if (m_TrackingPriorHandler!=nullptr && (m_IntroduceDirectionsFromPrior || valid)) { vnl_vector_fixed prior = m_TrackingPriorHandler->ProposeDirection(pos, olddirs, oldIndex); if (prior.magnitude()>0.001) { prior.normalize(); if (dot_product(prior,direction)<0) prior *= -1; direction = (1.0f-m_TrackingPriorWeight) * direction + m_TrackingPriorWeight * prior; direction.normalize(); } else if (m_TrackingPriorAsMask) direction.fill(0.0); } return direction; } float StreamlineTrackingFilter::FollowStreamline(itk::Point pos, vnl_vector_fixed dir, FiberType* fib, DirectionContainer* container, float tractLength, bool front, bool &exclude) { vnl_vector_fixed zero_dir; zero_dir.fill(0.0); std::deque< vnl_vector_fixed > last_dirs; for (unsigned int i=0; i oldIndex; m_TrackingHandler->WorldToIndex(pos, oldIndex); // get new position CalculateNewPosition(pos, dir); if (m_ExclusionRegions.IsNotNull() && mitk::imv::IsInsideMask(pos, m_InterpolateMasks, m_ExclusionInterpolator)) { exclude = true; return tractLength; } if (m_AbortTracking) return tractLength; // if yes, add new point to streamline dir.normalize(); if (front) { fib->push_front(pos); container->push_front(dir); } else { fib->push_back(pos); container->push_back(dir); } tractLength += m_StepSize; if (m_LoopCheck>=0 && CheckCurvature(container, front)>m_LoopCheck) return tractLength; if (tractLength>m_MaxTractLength) return tractLength; if (m_DemoMode && !m_UseOutputProbabilityMap) // CHECK: warum sind die samplingpunkte der streamline in der visualisierung immer einen schritt voras? { #pragma omp critical { m_BuildFibersReady++; m_Tractogram.push_back(*fib); BuildFibers(true); m_Stop = true; while (m_Stop){ } } } last_dirs.push_back(dir); if (last_dirs.size()>m_NumPreviousDirections) last_dirs.pop_front(); dir = GetNewDirection(pos, last_dirs, oldIndex); while (m_PauseTracking){} if (dir.magnitude()<0.0001) return tractLength; } return tractLength; } float StreamlineTrackingFilter::CheckCurvature(DirectionContainer* fib, bool front) { if (fib->size()<8) return 0; float m_Distance = std::max(m_MinVoxelSize*4, m_StepSize*8); float dist = 0; std::vector< vnl_vector_fixed< float, 3 > > vectors; vnl_vector_fixed< float, 3 > meanV; meanV.fill(0); float dev = 0; if (front) { int c = 0; while(distsize()-1) { dist += m_StepSize; vnl_vector_fixed< float, 3 > v = fib->at(c); if (dot_product(v,meanV)<0) v = -v; vectors.push_back(v); meanV += v; c++; } } else { int c = fib->size()-1; while(dist=0) { dist += m_StepSize; vnl_vector_fixed< float, 3 > v = fib->at(c); if (dot_product(v,meanV)<0) v = -v; vectors.push_back(v); meanV += v; c--; } } meanV.normalize(); for (unsigned int c=0; c1.0) angle = 1.0; dev += acos(angle)*180/itk::Math::pi; } if (vectors.size()>0) dev /= vectors.size(); return dev; } void StreamlineTrackingFilter::SetTrackingPriorHandler(mitk::TrackingDataHandler *TrackingPriorHandler) { m_TrackingPriorHandler = TrackingPriorHandler; } void StreamlineTrackingFilter::GetSeedPointsFromSeedImage() { MITK_INFO << "StreamlineTracking - Calculating seed points."; m_SeedPoints.clear(); typedef ImageRegionConstIterator< ItkFloatImgType > MaskIteratorType; MaskIteratorType sit(m_SeedImage, m_SeedImage->GetLargestPossibleRegion()); sit.GoToBegin(); while (!sit.IsAtEnd()) { if (sit.Value()>0) { ItkFloatImgType::IndexType index = sit.GetIndex(); itk::ContinuousIndex start; start[0] = index[0]; start[1] = index[1]; start[2] = index[2]; itk::Point worldPos; m_SeedImage->TransformContinuousIndexToPhysicalPoint(start, worldPos); if ( mitk::imv::IsInsideMask(worldPos, m_InterpolateMasks, m_MaskInterpolator) ) { m_SeedPoints.push_back(worldPos); for (int s = 1; s < m_SeedsPerVoxel; s++) { start[0] = index[0] + m_TrackingHandler->GetRandDouble(-0.5, 0.5); start[1] = index[1] + m_TrackingHandler->GetRandDouble(-0.5, 0.5); start[2] = index[2] + m_TrackingHandler->GetRandDouble(-0.5, 0.5); itk::Point worldPos; m_SeedImage->TransformContinuousIndexToPhysicalPoint(start, worldPos); m_SeedPoints.push_back(worldPos); } } } ++sit; } } void StreamlineTrackingFilter::GenerateData() { this->BeforeTracking(); if (m_Random) std::random_shuffle(m_SeedPoints.begin(), m_SeedPoints.end()); m_CurrentTracts = 0; int num_seeds = m_SeedPoints.size(); itk::Index<3> zeroIndex; zeroIndex.Fill(0); m_Progress = 0; int i = 0; int print_interval = num_seeds/100; if (print_interval<100) m_Verbose=false; #pragma omp parallel while (i=num_seeds || m_StopTracking) continue; else if (m_Verbose && i%print_interval==0) #pragma omp critical { m_Progress += print_interval; std::cout << " \r"; if (m_MaxNumTracts>0) std::cout << "Tried: " << m_Progress << "/" << num_seeds << " | Accepted: " << m_CurrentTracts << "/" << m_MaxNumTracts << '\r'; else std::cout << "Tried: " << m_Progress << "/" << num_seeds << " | Accepted: " << m_CurrentTracts << '\r'; cout.flush(); } const itk::Point worldPos = m_SeedPoints.at(temp_i); for (unsigned int trials=0; trials dir; dir.fill(0.0); std::deque< vnl_vector_fixed > olddirs; dir = GetNewDirection(worldPos, olddirs, zeroIndex) * 0.5f; bool exclude = false; if (m_ExclusionRegions.IsNotNull() && mitk::imv::IsInsideMask(worldPos, m_InterpolateMasks, m_ExclusionInterpolator)) exclude = true; bool success = false; if (dir.magnitude()>0.0001 && !exclude) { // forward tracking tractLength = FollowStreamline(worldPos, dir, &fib, &direction_container, 0, false, exclude); fib.push_front(worldPos); // backward tracking if (!exclude) tractLength = FollowStreamline(worldPos, -dir, &fib, &direction_container, tractLength, true, exclude); counter = fib.size(); if (tractLength>=m_MinTractLength && counter>=2 && !exclude) { #pragma omp critical if ( IsValidFiber(&fib) ) { if (!m_StopTracking) { if (!m_UseOutputProbabilityMap) m_Tractogram.push_back(fib); else FiberToProbmap(&fib); m_CurrentTracts++; success = true; } if (m_MaxNumTracts > 0 && m_CurrentTracts>=static_cast(m_MaxNumTracts)) { if (!m_StopTracking) { std::cout << " \r"; MITK_INFO << "Reconstructed maximum number of tracts (" << m_CurrentTracts << "). Stopping tractography."; } m_StopTracking = true; } } } } if (success || m_TrackingHandler->GetMode()!=mitk::TrackingDataHandler::PROBABILISTIC) break; // we only try one seed point multiple times if we use a probabilistic tracker and have not found a valid streamline yet }// trials per seed }// seed points this->AfterTracking(); } bool StreamlineTrackingFilter::IsValidFiber(FiberType* fib) { if (m_EndpointConstraint==EndpointConstraints::NONE) { return true; } else if (m_EndpointConstraint==EndpointConstraints::EPS_IN_TARGET) { if (m_TargetImageSet) { if ( mitk::imv::IsInsideMask(fib->front(), m_InterpolateMasks, m_TargetInterpolator) && mitk::imv::IsInsideMask(fib->back(), m_InterpolateMasks, m_TargetInterpolator) ) return true; return false; } else mitkThrow() << "No target image set but endpoint constraint EPS_IN_TARGET chosen!"; } else if (m_EndpointConstraint==EndpointConstraints::EPS_IN_TARGET_LABELDIFF) { if (m_TargetImageSet) { float v1 = mitk::imv::GetImageValue(fib->front(), false, m_TargetInterpolator); float v2 = mitk::imv::GetImageValue(fib->back(), false, m_TargetInterpolator); if ( v1>0.0 && v2>0.0 && v1!=v2 ) return true; return false; } else mitkThrow() << "No target image set but endpoint constraint EPS_IN_TARGET_LABELDIFF chosen!"; } else if (m_EndpointConstraint==EndpointConstraints::EPS_IN_SEED_AND_TARGET) { if (m_TargetImageSet && m_SeedImageSet) { if ( mitk::imv::IsInsideMask(fib->front(), m_InterpolateMasks, m_SeedInterpolator) && mitk::imv::IsInsideMask(fib->back(), m_InterpolateMasks, m_TargetInterpolator) ) return true; if ( mitk::imv::IsInsideMask(fib->back(), m_InterpolateMasks, m_SeedInterpolator) && mitk::imv::IsInsideMask(fib->front(), m_InterpolateMasks, m_TargetInterpolator) ) return true; return false; } else mitkThrow() << "No target or seed image set but endpoint constraint EPS_IN_SEED_AND_TARGET chosen!"; } else if (m_EndpointConstraint==EndpointConstraints::MIN_ONE_EP_IN_TARGET) { if (m_TargetImageSet) { if ( mitk::imv::IsInsideMask(fib->front(), m_InterpolateMasks, m_TargetInterpolator) || mitk::imv::IsInsideMask(fib->back(), m_InterpolateMasks, m_TargetInterpolator) ) return true; return false; } else mitkThrow() << "No target image set but endpoint constraint MIN_ONE_EP_IN_TARGET chosen!"; } else if (m_EndpointConstraint==EndpointConstraints::ONE_EP_IN_TARGET) { if (m_TargetImageSet) { if ( mitk::imv::IsInsideMask(fib->front(), m_InterpolateMasks, m_TargetInterpolator) && !mitk::imv::IsInsideMask(fib->back(), m_InterpolateMasks, m_TargetInterpolator) ) return true; if ( !mitk::imv::IsInsideMask(fib->back(), m_InterpolateMasks, m_TargetInterpolator) && mitk::imv::IsInsideMask(fib->front(), m_InterpolateMasks, m_TargetInterpolator) ) return true; return false; } else mitkThrow() << "No target image set but endpoint constraint ONE_EP_IN_TARGET chosen!"; } else if (m_EndpointConstraint==EndpointConstraints::NO_EP_IN_TARGET) { if (m_TargetImageSet) { if ( mitk::imv::IsInsideMask(fib->front(), m_InterpolateMasks, m_TargetInterpolator) || mitk::imv::IsInsideMask(fib->back(), m_InterpolateMasks, m_TargetInterpolator) ) return false; return true; } else mitkThrow() << "No target image set but endpoint constraint NO_EP_IN_TARGET chosen!"; } return true; } void StreamlineTrackingFilter::FiberToProbmap(FiberType* fib) { ItkDoubleImgType::IndexType last_idx; last_idx.Fill(0); for (auto p : *fib) { ItkDoubleImgType::IndexType idx; m_OutputProbabilityMap->TransformPhysicalPointToIndex(p, idx); if (idx != last_idx) { if (m_OutputProbabilityMap->GetLargestPossibleRegion().IsInside(idx)) m_OutputProbabilityMap->SetPixel(idx, m_OutputProbabilityMap->GetPixel(idx)+1); last_idx = idx; } } } void StreamlineTrackingFilter::BuildFibers(bool check) { if (m_BuildFibersReady::New(); vtkSmartPointer vNewLines = vtkSmartPointer::New(); vtkSmartPointer vNewPoints = vtkSmartPointer::New(); for (unsigned int i=0; i container = vtkSmartPointer::New(); FiberType fib = m_Tractogram.at(i); for (FiberType::iterator it = fib.begin(); it!=fib.end(); ++it) { vtkIdType id = vNewPoints->InsertNextPoint((*it).GetDataPointer()); container->GetPointIds()->InsertNextId(id); } vNewLines->InsertNextCell(container); } if (check) for (int i=0; iSetPoints(vNewPoints); m_FiberPolyData->SetLines(vNewLines); m_BuildFibersFinished = true; } void StreamlineTrackingFilter::AfterTracking() { if (m_Verbose) std::cout << " \r"; if (!m_UseOutputProbabilityMap) { MITK_INFO << "Reconstructed " << m_Tractogram.size() << " fibers."; MITK_INFO << "Generating polydata "; BuildFibers(false); } else { itk::RescaleIntensityImageFilter< ItkDoubleImgType, ItkDoubleImgType >::Pointer filter = itk::RescaleIntensityImageFilter< ItkDoubleImgType, ItkDoubleImgType >::New(); filter->SetInput(m_OutputProbabilityMap); filter->SetOutputMaximum(1.0); filter->SetOutputMinimum(0.0); filter->Update(); m_OutputProbabilityMap = filter->GetOutput(); } MITK_INFO << "done"; m_EndTime = std::chrono::system_clock::now(); std::chrono::hours hh = std::chrono::duration_cast(m_EndTime - m_StartTime); std::chrono::minutes mm = std::chrono::duration_cast(m_EndTime - m_StartTime); std::chrono::seconds ss = std::chrono::duration_cast(m_EndTime - m_StartTime); mm %= 60; ss %= 60; MITK_INFO << "Tracking took " << hh.count() << "h, " << mm.count() << "m and " << ss.count() << "s"; m_SeedPoints.clear(); } void StreamlineTrackingFilter::SetDicomProperties(mitk::FiberBundle::Pointer fib) { std::string model_code_value = "-"; std::string model_code_meaning = "-"; std::string algo_code_value = "-"; std::string algo_code_meaning = "-"; if (m_TrackingHandler->GetMode()==mitk::TrackingDataHandler::DETERMINISTIC && dynamic_cast(m_TrackingHandler) && !m_TrackingHandler->GetInterpolate()) { algo_code_value = "sup181_ee04"; algo_code_meaning = "FACT"; } else if (m_TrackingHandler->GetMode()==mitk::TrackingDataHandler::DETERMINISTIC) { algo_code_value = "sup181_ee01"; algo_code_meaning = "Deterministic"; } else if (m_TrackingHandler->GetMode()==mitk::TrackingDataHandler::PROBABILISTIC) { algo_code_value = "sup181_ee02"; algo_code_meaning = "Probabilistic"; } if (dynamic_cast(m_TrackingHandler) || (dynamic_cast(m_TrackingHandler) && dynamic_cast(m_TrackingHandler)->GetIsOdfFromTensor() ) ) { if ( dynamic_cast(m_TrackingHandler) && dynamic_cast(m_TrackingHandler)->GetNumTensorImages()>1 ) { model_code_value = "sup181_bb02"; model_code_meaning = "Multi Tensor"; } else { model_code_value = "sup181_bb01"; model_code_meaning = "Single Tensor"; } } else if (dynamic_cast*>(m_TrackingHandler) || dynamic_cast*>(m_TrackingHandler)) { model_code_value = "sup181_bb03"; model_code_meaning = "Model Free"; } else if (dynamic_cast(m_TrackingHandler)) { model_code_value = "-"; model_code_meaning = "ODF"; } else if (dynamic_cast(m_TrackingHandler)) { model_code_value = "-"; model_code_meaning = "Peaks"; } fib->SetProperty("DICOM.anatomy.value", mitk::StringProperty::New("T-A0095")); fib->SetProperty("DICOM.anatomy.meaning", mitk::StringProperty::New("White matter of brain and spinal cord")); fib->SetProperty("DICOM.algo_code.value", mitk::StringProperty::New(algo_code_value)); fib->SetProperty("DICOM.algo_code.meaning", mitk::StringProperty::New(algo_code_meaning)); fib->SetProperty("DICOM.model_code.value", mitk::StringProperty::New(model_code_value)); fib->SetProperty("DICOM.model_code.meaning", mitk::StringProperty::New(model_code_meaning)); } } diff --git a/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp b/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp index 28da14ba91..c246971545 100755 --- a/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Fiberfox/itkTractsToDWIImageFilter.cpp @@ -1,1742 +1,1742 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include "itkTractsToDWIImageFilter.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #include namespace itk { template< class PixelType > TractsToDWIImageFilter< PixelType >::TractsToDWIImageFilter() : m_FiberBundle(nullptr) , m_StatusText("") , m_UseConstantRandSeed(false) , m_RandGen(itk::Statistics::MersenneTwisterRandomVariateGenerator::New()) { m_RandGen->SetSeed(); m_DoubleInterpolator = itk::LinearInterpolateImageFunction< ItkDoubleImgType, float >::New(); m_NullDir.Fill(0); } template< class PixelType > TractsToDWIImageFilter< PixelType >::~TractsToDWIImageFilter() { } template< class PixelType > TractsToDWIImageFilter< PixelType >::DoubleDwiType::Pointer TractsToDWIImageFilter< PixelType >:: SimulateKspaceAcquisition( std::vector< DoubleDwiType::Pointer >& compartment_images ) { unsigned int numFiberCompartments = m_Parameters.m_FiberModelList.size(); // create slice object ImageRegion<2> sliceRegion; sliceRegion.SetSize(0, m_WorkingImageRegion.GetSize()[0]); sliceRegion.SetSize(1, m_WorkingImageRegion.GetSize()[1]); Vector< double, 2 > sliceSpacing; sliceSpacing[0] = m_WorkingSpacing[0]; sliceSpacing[1] = m_WorkingSpacing[1]; DoubleDwiType::PixelType nullPix; nullPix.SetSize(compartment_images.at(0)->GetVectorLength()); nullPix.Fill(0.0); auto magnitudeDwiImage = DoubleDwiType::New(); magnitudeDwiImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); magnitudeDwiImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); magnitudeDwiImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); magnitudeDwiImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); magnitudeDwiImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); magnitudeDwiImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); magnitudeDwiImage->SetVectorLength( compartment_images.at(0)->GetVectorLength() ); magnitudeDwiImage->Allocate(); magnitudeDwiImage->FillBuffer(nullPix); m_PhaseImage = DoubleDwiType::New(); m_PhaseImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); m_PhaseImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); m_PhaseImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_PhaseImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_PhaseImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_PhaseImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_PhaseImage->SetVectorLength( compartment_images.at(0)->GetVectorLength() ); m_PhaseImage->Allocate(); m_PhaseImage->FillBuffer(nullPix); m_KspaceImage = DoubleDwiType::New(); m_KspaceImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); m_KspaceImage->SetOrigin( m_Parameters.m_SignalGen.m_ImageOrigin ); m_KspaceImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_KspaceImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_KspaceImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_KspaceImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_KspaceImage->SetVectorLength( m_Parameters.m_SignalGen.m_NumberOfCoils ); m_KspaceImage->Allocate(); m_KspaceImage->FillBuffer(nullPix); std::vector< unsigned int > spikeVolume; for (unsigned int i=0; iGetIntegerVariate()%(compartment_images.at(0)->GetVectorLength())); std::sort (spikeVolume.begin(), spikeVolume.end()); std::reverse (spikeVolume.begin(), spikeVolume.end()); // calculate coil positions double a = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(0)*m_Parameters.m_SignalGen.m_ImageSpacing[0]; double b = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(1)*m_Parameters.m_SignalGen.m_ImageSpacing[1]; double c = m_Parameters.m_SignalGen.m_ImageRegion.GetSize(2)*m_Parameters.m_SignalGen.m_ImageSpacing[2]; double diagonal = sqrt(a*a+b*b)/1000; // image diagonal in m m_CoilPointset = mitk::PointSet::New(); std::vector< itk::Vector > coilPositions; itk::Vector pos; pos.Fill(0.0); pos[1] = -diagonal/2; itk::Vector center; center[0] = a/2-m_Parameters.m_SignalGen.m_ImageSpacing[0]/2; center[1] = b/2-m_Parameters.m_SignalGen.m_ImageSpacing[2]/2; center[2] = c/2-m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; for (int c=0; cInsertPoint(c, pos*1000 + m_Parameters.m_SignalGen.m_ImageOrigin.GetVectorFromOrigin() + center ); double rz = 360.0/m_Parameters.m_SignalGen.m_NumberOfCoils * itk::Math::pi/180; vnl_matrix_fixed< double, 3, 3 > rotZ; rotZ.set_identity(); rotZ[0][0] = cos(rz); rotZ[1][1] = rotZ[0][0]; rotZ[0][1] = -sin(rz); rotZ[1][0] = -rotZ[0][1]; pos.SetVnlVector(rotZ*pos.GetVnlVector()); } PrintToLog("0% 10 20 30 40 50 60 70 80 90 100%", false, true, false); PrintToLog("|----|----|----|----|----|----|----|----|----|----|\n*", false, false, false); unsigned long lastTick = 0; boost::progress_display disp(compartment_images.at(0)->GetVectorLength()*compartment_images.at(0)->GetLargestPossibleRegion().GetSize(2)); #pragma omp parallel for for (int g=0; g<(int)compartment_images.at(0)->GetVectorLength(); g++) { if (this->GetAbortGenerateData()) continue; std::vector< unsigned int > spikeSlice; #pragma omp critical while (!spikeVolume.empty() && (int)spikeVolume.back()==g) { spikeSlice.push_back(m_RandGen->GetIntegerVariate()%compartment_images.at(0)->GetLargestPossibleRegion().GetSize(2)); spikeVolume.pop_back(); } std::sort (spikeSlice.begin(), spikeSlice.end()); std::reverse (spikeSlice.begin(), spikeSlice.end()); for (unsigned int z=0; zGetLargestPossibleRegion().GetSize(2); z++) { std::vector< Float2DImageType::Pointer > compartment_slices; std::vector< float > t2Vector; std::vector< float > t1Vector; for (unsigned int i=0; i* signalModel; if (iSetLargestPossibleRegion( sliceRegion ); slice->SetBufferedRegion( sliceRegion ); slice->SetRequestedRegion( sliceRegion ); slice->SetSpacing(sliceSpacing); slice->Allocate(); slice->FillBuffer(0.0); // extract slice from channel g for (unsigned int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (unsigned int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { Float2DImageType::IndexType index2D; index2D[0]=x; index2D[1]=y; DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; slice->SetPixel(index2D, compartment_images.at(i)->GetPixel(index3D)[g]); } compartment_slices.push_back(slice); t2Vector.push_back(signalModel->GetT2()); t1Vector.push_back(signalModel->GetT1()); } int numSpikes = 0; while (!spikeSlice.empty() && spikeSlice.back()==z) { numSpikes++; spikeSlice.pop_back(); } int spikeCoil = m_RandGen->GetIntegerVariate()%m_Parameters.m_SignalGen.m_NumberOfCoils; if (this->GetAbortGenerateData()) continue; for (int c=0; c::New(); idft->SetCompartmentImages(compartment_slices); idft->SetT2(t2Vector); idft->SetT1(t1Vector); idft->SetUseConstantRandSeed(m_UseConstantRandSeed); idft->SetParameters(&m_Parameters); idft->SetZ((float)z-(float)( compartment_images.at(0)->GetLargestPossibleRegion().GetSize(2) -compartment_images.at(0)->GetLargestPossibleRegion().GetSize(2)%2 ) / 2.0); idft->SetZidx(z); idft->SetCoilPosition(coilPositions.at(c)); idft->SetFiberBundle(m_FiberBundleWorkingCopy); idft->SetTranslation(m_Translations.at(g)); idft->SetRotation(m_Rotations.at(g)); idft->SetDiffusionGradientDirection(m_Parameters.m_SignalGen.GetGradientDirection(g)); if (c==spikeCoil) idft->SetSpikesPerSlice(numSpikes); idft->Update(); #pragma omp critical if (c==spikeCoil && numSpikes>0) { m_SpikeLog += "Volume " + boost::lexical_cast(g) + " Coil " + boost::lexical_cast(c) + "\n"; m_SpikeLog += idft->GetSpikeLog(); } Complex2DImageType::Pointer fSlice; fSlice = idft->GetOutput(); // fourier transform slice Complex2DImageType::Pointer newSlice; auto dft = itk::DftImageFilter< Float2DImageType::PixelType >::New(); dft->SetInput(fSlice); dft->SetParameters(m_Parameters); dft->Update(); newSlice = dft->GetOutput(); // put slice back into channel g for (unsigned int y=0; yGetLargestPossibleRegion().GetSize(1); y++) for (unsigned int x=0; xGetLargestPossibleRegion().GetSize(0); x++) { DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; Complex2DImageType::IndexType index2D; index2D[0]=x; index2D[1]=y; Complex2DImageType::PixelType cPix = newSlice->GetPixel(index2D); double magn = sqrt(cPix.real()*cPix.real()+cPix.imag()*cPix.imag()); double phase = 0; if (cPix.real()!=0) phase = atan( cPix.imag()/cPix.real() ); DoubleDwiType::PixelType real_pix = m_OutputImagesReal.at(c)->GetPixel(index3D); real_pix[g] = cPix.real(); m_OutputImagesReal.at(c)->SetPixel(index3D, real_pix); DoubleDwiType::PixelType imag_pix = m_OutputImagesImag.at(c)->GetPixel(index3D); imag_pix[g] = cPix.imag(); m_OutputImagesImag.at(c)->SetPixel(index3D, imag_pix); DoubleDwiType::PixelType dwiPix = magnitudeDwiImage->GetPixel(index3D); DoubleDwiType::PixelType phasePix = m_PhaseImage->GetPixel(index3D); if (m_Parameters.m_SignalGen.m_NumberOfCoils>1) { dwiPix[g] += magn*magn; phasePix[g] += phase*phase; } else { dwiPix[g] = magn; phasePix[g] = phase; } //#pragma omp critical { magnitudeDwiImage->SetPixel(index3D, dwiPix); m_PhaseImage->SetPixel(index3D, phasePix); // k-space image if (g==0) { DoubleDwiType::PixelType kspacePix = m_KspaceImage->GetPixel(index3D); kspacePix[c] = idft->GetKSpaceImage()->GetPixel(index2D); m_KspaceImage->SetPixel(index3D, kspacePix); } } } } if (m_Parameters.m_SignalGen.m_NumberOfCoils>1) { for (int y=0; y(magnitudeDwiImage->GetLargestPossibleRegion().GetSize(1)); y++) for (int x=0; x(magnitudeDwiImage->GetLargestPossibleRegion().GetSize(0)); x++) { DoubleDwiType::IndexType index3D; index3D[0]=x; index3D[1]=y; index3D[2]=z; DoubleDwiType::PixelType magPix = magnitudeDwiImage->GetPixel(index3D); magPix[g] = sqrt(magPix[g]/m_Parameters.m_SignalGen.m_NumberOfCoils); DoubleDwiType::PixelType phasePix = m_PhaseImage->GetPixel(index3D); phasePix[g] = sqrt(phasePix[g]/m_Parameters.m_SignalGen.m_NumberOfCoils); //#pragma omp critical { magnitudeDwiImage->SetPixel(index3D, magPix); m_PhaseImage->SetPixel(index3D, phasePix); } } } ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); for (unsigned long tick = 0; tick<(newTick-lastTick); tick++) PrintToLog("*", false, false, false); lastTick = newTick; } } PrintToLog("\n", false); return magnitudeDwiImage; } template< class PixelType > TractsToDWIImageFilter< PixelType >::ItkDoubleImgType::Pointer TractsToDWIImageFilter< PixelType >:: NormalizeInsideMask(ItkDoubleImgType::Pointer image) { double max = itk::NumericTraits< double >::min(); double min = itk::NumericTraits< double >::max(); itk::ImageRegionIterator< ItkDoubleImgType > it(image, image->GetLargestPossibleRegion()); while(!it.IsAtEnd()) { if (m_Parameters.m_SignalGen.m_MaskImage.IsNotNull() && m_Parameters.m_SignalGen.m_MaskImage->GetPixel(it.GetIndex())<=0) { it.Set(0.0); ++it; continue; } if (it.Get()>max) max = it.Get(); if (it.Get()::New(); scaler->SetInput(image); scaler->SetShift(-min); scaler->SetScale(1.0/(max-min)); scaler->Update(); return scaler->GetOutput(); } template< class PixelType > void TractsToDWIImageFilter< PixelType >::CheckVolumeFractionImages() { m_UseRelativeNonFiberVolumeFractions = false; // check for fiber volume fraction maps unsigned int fibVolImages = 0; for (std::size_t i=0; iGetVolumeFractionImage().IsNotNull()) { PrintToLog("Using volume fraction map for fiber compartment " + boost::lexical_cast(i+1)); fibVolImages++; } } // check for non-fiber volume fraction maps unsigned int nonfibVolImages = 0; for (std::size_t i=0; iGetVolumeFractionImage().IsNotNull()) { PrintToLog("Using volume fraction map for non-fiber compartment " + boost::lexical_cast(i+1)); nonfibVolImages++; } } // not all fiber compartments are using volume fraction maps // --> non-fiber volume fractions are assumed to be relative to the // non-fiber volume and not absolute voxel-volume fractions. // this means if two non-fiber compartments are used but only one of them // has an associated volume fraction map, the repesctive other volume fraction map // can be determined as inverse (1-val) of the present volume fraction map- if ( fibVolImages::New(); inverter->SetMaximum(1.0); if ( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage().IsNull() && m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage().IsNotNull() ) { // m_Parameters.m_NonFiberModelList[1]->SetVolumeFractionImage( // NormalizeInsideMask( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage() ) ); inverter->SetInput( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage() ); inverter->Update(); m_Parameters.m_NonFiberModelList[0]->SetVolumeFractionImage(inverter->GetOutput()); } else if ( m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage().IsNull() && m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage().IsNotNull() ) { // m_Parameters.m_NonFiberModelList[0]->SetVolumeFractionImage( // NormalizeInsideMask( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage() ) ); inverter->SetInput( m_Parameters.m_NonFiberModelList[0]->GetVolumeFractionImage() ); inverter->Update(); m_Parameters.m_NonFiberModelList[1]->SetVolumeFractionImage(inverter->GetOutput()); } else { itkExceptionMacro("Something went wrong in automatically calculating the missing non-fiber volume fraction image!" " Did you use two non fiber compartments but only one volume fraction image?" " Then it should work and this error is really strange."); } m_UseRelativeNonFiberVolumeFractions = true; nonfibVolImages++; } // Up to two fiber compartments are allowed without volume fraction maps since the volume fractions can then be determined automatically if (m_Parameters.m_FiberModelList.size()>2 && fibVolImages!=m_Parameters.m_FiberModelList.size()) itkExceptionMacro("More than two fiber compartment selected but no corresponding volume fraction maps set!"); // One non-fiber compartment is allowed without volume fraction map since the volume fraction can then be determined automatically if (m_Parameters.m_NonFiberModelList.size()>1 && nonfibVolImages!=m_Parameters.m_NonFiberModelList.size()) itkExceptionMacro("More than one non-fiber compartment selected but no volume fraction maps set!"); if (fibVolImages0) { PrintToLog("Not all fiber compartments are using an associated volume fraction image.\n" "Assuming non-fiber volume fraction images to contain values relative to the" " remaining non-fiber volume, not absolute values."); m_UseRelativeNonFiberVolumeFractions = true; // itk::ImageFileWriter::Pointer wr = itk::ImageFileWriter::New(); // wr->SetInput(m_Parameters.m_NonFiberModelList[1]->GetVolumeFractionImage()); // wr->SetFileName("/local/volumefraction.nrrd"); // wr->Update(); } // initialize the images that store the output volume fraction of each compartment m_VolumeFractions.clear(); for (std::size_t i=0; iSetSpacing( m_WorkingSpacing ); doubleImg->SetOrigin( m_WorkingOrigin ); doubleImg->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); doubleImg->SetLargestPossibleRegion( m_WorkingImageRegion ); doubleImg->SetBufferedRegion( m_WorkingImageRegion ); doubleImg->SetRequestedRegion( m_WorkingImageRegion ); doubleImg->Allocate(); doubleImg->FillBuffer(0); m_VolumeFractions.push_back(doubleImg); } } template< class PixelType > void TractsToDWIImageFilter< PixelType >::InitializeData() { m_Rotations.clear(); m_Translations.clear(); m_MotionLog = ""; m_SpikeLog = ""; // initialize output dwi image m_Parameters.m_SignalGen.m_CroppedRegion = m_Parameters.m_SignalGen.m_ImageRegion; m_Parameters.m_SignalGen.m_CroppedRegion.SetSize( 1, m_Parameters.m_SignalGen.m_CroppedRegion.GetSize(1) *m_Parameters.m_SignalGen.m_CroppingFactor); itk::Point shiftedOrigin = m_Parameters.m_SignalGen.m_ImageOrigin; shiftedOrigin[1] += (m_Parameters.m_SignalGen.m_ImageRegion.GetSize(1) -m_Parameters.m_SignalGen.m_CroppedRegion.GetSize(1))*m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; m_OutputImage = OutputImageType::New(); m_OutputImage->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); m_OutputImage->SetOrigin( shiftedOrigin ); m_OutputImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_OutputImage->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_OutputImage->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_OutputImage->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); m_OutputImage->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); m_OutputImage->Allocate(); typename OutputImageType::PixelType temp; temp.SetSize(m_Parameters.m_SignalGen.GetNumVolumes()); temp.Fill(0.0); m_OutputImage->FillBuffer(temp); // images containing real and imaginary part of the dMRI signal for each coil m_OutputImagesReal.clear(); m_OutputImagesImag.clear(); for (int i=0; iSetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); outputImageReal->SetOrigin( shiftedOrigin ); outputImageReal->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); outputImageReal->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageReal->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageReal->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageReal->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); outputImageReal->Allocate(); outputImageReal->FillBuffer(temp); m_OutputImagesReal.push_back(outputImageReal); typename DoubleDwiType::Pointer outputImageImag = DoubleDwiType::New(); outputImageImag->SetSpacing( m_Parameters.m_SignalGen.m_ImageSpacing ); outputImageImag->SetOrigin( shiftedOrigin ); outputImageImag->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); outputImageImag->SetLargestPossibleRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageImag->SetBufferedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageImag->SetRequestedRegion( m_Parameters.m_SignalGen.m_CroppedRegion ); outputImageImag->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); outputImageImag->Allocate(); outputImageImag->FillBuffer(temp); m_OutputImagesImag.push_back(outputImageImag); } // Apply in-plane upsampling for Gibbs ringing artifact double upsampling = 1; if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging) upsampling = 2; m_WorkingSpacing = m_Parameters.m_SignalGen.m_ImageSpacing; m_WorkingSpacing[0] /= upsampling; m_WorkingSpacing[1] /= upsampling; m_WorkingImageRegion = m_Parameters.m_SignalGen.m_ImageRegion; m_WorkingImageRegion.SetSize(0, m_Parameters.m_SignalGen.m_ImageRegion.GetSize()[0]*upsampling); m_WorkingImageRegion.SetSize(1, m_Parameters.m_SignalGen.m_ImageRegion.GetSize()[1]*upsampling); m_WorkingOrigin = m_Parameters.m_SignalGen.m_ImageOrigin; m_WorkingOrigin[0] -= m_Parameters.m_SignalGen.m_ImageSpacing[0]/2; m_WorkingOrigin[0] += m_WorkingSpacing[0]/2; m_WorkingOrigin[1] -= m_Parameters.m_SignalGen.m_ImageSpacing[1]/2; m_WorkingOrigin[1] += m_WorkingSpacing[1]/2; m_WorkingOrigin[2] -= m_Parameters.m_SignalGen.m_ImageSpacing[2]/2; m_WorkingOrigin[2] += m_WorkingSpacing[2]/2; m_VoxelVolume = m_WorkingSpacing[0]*m_WorkingSpacing[1]*m_WorkingSpacing[2]; // generate double images to store the individual compartment signals m_CompartmentImages.clear(); int numFiberCompartments = m_Parameters.m_FiberModelList.size(); int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size(); for (int i=0; iSetSpacing( m_WorkingSpacing ); doubleDwi->SetOrigin( m_WorkingOrigin ); doubleDwi->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); doubleDwi->SetLargestPossibleRegion( m_WorkingImageRegion ); doubleDwi->SetBufferedRegion( m_WorkingImageRegion ); doubleDwi->SetRequestedRegion( m_WorkingImageRegion ); doubleDwi->SetVectorLength( m_Parameters.m_SignalGen.GetNumVolumes() ); doubleDwi->Allocate(); DoubleDwiType::PixelType pix; pix.SetSize(m_Parameters.m_SignalGen.GetNumVolumes()); pix.Fill(0.0); doubleDwi->FillBuffer(pix); m_CompartmentImages.push_back(doubleDwi); } if (m_FiberBundle.IsNull() && m_InputImage.IsNotNull()) { m_CompartmentImages.clear(); m_Parameters.m_SignalGen.m_DoAddMotion = false; m_Parameters.m_SignalGen.m_DoSimulateRelaxation = false; PrintToLog("Simulating acquisition for input diffusion-weighted image.", false); auto caster = itk::CastImageFilter< OutputImageType, DoubleDwiType >::New(); caster->SetInput(m_InputImage); caster->Update(); if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging) { PrintToLog("Upsampling input diffusion-weighted image for Gibbs ringing simulation.", false); auto resampler = itk::ResampleDwiImageFilter< double >::New(); resampler->SetInput(caster->GetOutput()); itk::Vector< double, 3 > samplingFactor; samplingFactor[0] = upsampling; samplingFactor[1] = upsampling; samplingFactor[2] = 1; resampler->SetSamplingFactor(samplingFactor); resampler->SetInterpolation(itk::ResampleDwiImageFilter< double >::Interpolate_WindowedSinc); resampler->Update(); m_CompartmentImages.push_back(resampler->GetOutput()); } else m_CompartmentImages.push_back(caster->GetOutput()); for (unsigned int g=0; g::New(); rescaler->SetInput(0,m_Parameters.m_SignalGen.m_MaskImage); rescaler->SetOutputMaximum(100); rescaler->SetOutputMinimum(0); rescaler->Update(); // resample mask image auto resampler = itk::ResampleImageFilter::New(); resampler->SetInput(rescaler->GetOutput()); resampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_MaskImage); resampler->SetSize(m_WorkingImageRegion.GetSize()); resampler->SetOutputSpacing(m_WorkingSpacing); resampler->SetOutputOrigin(m_WorkingOrigin); auto nn_interpolator = itk::NearestNeighborInterpolateImageFunction::New(); resampler->SetInterpolator(nn_interpolator); resampler->Update(); m_Parameters.m_SignalGen.m_MaskImage = resampler->GetOutput(); } // resample frequency map if (m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull()) { auto resampler = itk::ResampleImageFilter::New(); resampler->SetInput(m_Parameters.m_SignalGen.m_FrequencyMap); resampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_FrequencyMap); resampler->SetSize(m_WorkingImageRegion.GetSize()); resampler->SetOutputSpacing(m_WorkingSpacing); resampler->SetOutputOrigin(m_WorkingOrigin); auto nn_interpolator = itk::NearestNeighborInterpolateImageFunction::New(); resampler->SetInterpolator(nn_interpolator); resampler->Update(); m_Parameters.m_SignalGen.m_FrequencyMap = resampler->GetOutput(); } } m_MaskImageSet = true; if (m_Parameters.m_SignalGen.m_MaskImage.IsNull()) { // no input tissue mask is set -> create default PrintToLog("No tissue mask set", false); m_Parameters.m_SignalGen.m_MaskImage = ItkUcharImgType::New(); m_Parameters.m_SignalGen.m_MaskImage->SetSpacing( m_WorkingSpacing ); m_Parameters.m_SignalGen.m_MaskImage->SetOrigin( m_WorkingOrigin ); m_Parameters.m_SignalGen.m_MaskImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); m_Parameters.m_SignalGen.m_MaskImage->SetLargestPossibleRegion( m_WorkingImageRegion ); m_Parameters.m_SignalGen.m_MaskImage->SetBufferedRegion( m_WorkingImageRegion ); m_Parameters.m_SignalGen.m_MaskImage->SetRequestedRegion( m_WorkingImageRegion ); m_Parameters.m_SignalGen.m_MaskImage->Allocate(); m_Parameters.m_SignalGen.m_MaskImage->FillBuffer(100); m_MaskImageSet = false; } else { if (m_Parameters.m_SignalGen.m_MaskImage->GetLargestPossibleRegion()!=m_WorkingImageRegion) { itkExceptionMacro("Mask image and specified DWI geometry are not matching!"); } PrintToLog("Using tissue mask", false); } if (m_Parameters.m_SignalGen.m_DoAddMotion) { if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { PrintToLog("Random motion artifacts:", false); PrintToLog("Maximum rotation: +/-" + boost::lexical_cast(m_Parameters.m_SignalGen.m_Rotation) + "°", false); PrintToLog("Maximum translation: +/-" + boost::lexical_cast(m_Parameters.m_SignalGen.m_Translation) + "mm", false); } else { PrintToLog("Linear motion artifacts:", false); PrintToLog("Maximum rotation: " + boost::lexical_cast(m_Parameters.m_SignalGen.m_Rotation) + "°", false); PrintToLog("Maximum translation: " + boost::lexical_cast(m_Parameters.m_SignalGen.m_Translation) + "mm", false); } } if ( m_Parameters.m_SignalGen.m_MotionVolumes.empty() ) { // no motion in first volume m_Parameters.m_SignalGen.m_MotionVolumes.push_back(false); // motion in all other volumes while ( m_Parameters.m_SignalGen.m_MotionVolumes.size() < m_Parameters.m_SignalGen.GetNumVolumes() ) { m_Parameters.m_SignalGen.m_MotionVolumes.push_back(true); } } // we need to know for every volume if there is motion. if this information is missing, then set corresponding fal to false while ( m_Parameters.m_SignalGen.m_MotionVolumes.size()::New(); duplicator->SetInputImage(m_Parameters.m_SignalGen.m_MaskImage); duplicator->Update(); m_TransformedMaskImage = duplicator->GetOutput(); // second upsampling needed for motion artifacts ImageRegion<3> upsampledImageRegion = m_WorkingImageRegion; DoubleVectorType upsampledSpacing = m_WorkingSpacing; upsampledSpacing[0] /= 4; upsampledSpacing[1] /= 4; upsampledSpacing[2] /= 4; upsampledImageRegion.SetSize(0, m_WorkingImageRegion.GetSize()[0]*4); upsampledImageRegion.SetSize(1, m_WorkingImageRegion.GetSize()[1]*4); upsampledImageRegion.SetSize(2, m_WorkingImageRegion.GetSize()[2]*4); itk::Point upsampledOrigin = m_WorkingOrigin; upsampledOrigin[0] -= m_WorkingSpacing[0]/2; upsampledOrigin[0] += upsampledSpacing[0]/2; upsampledOrigin[1] -= m_WorkingSpacing[1]/2; upsampledOrigin[1] += upsampledSpacing[1]/2; upsampledOrigin[2] -= m_WorkingSpacing[2]/2; upsampledOrigin[2] += upsampledSpacing[2]/2; m_UpsampledMaskImage = ItkUcharImgType::New(); auto upsampler = itk::ResampleImageFilter::New(); upsampler->SetInput(m_Parameters.m_SignalGen.m_MaskImage); upsampler->SetOutputParametersFromImage(m_Parameters.m_SignalGen.m_MaskImage); upsampler->SetSize(upsampledImageRegion.GetSize()); upsampler->SetOutputSpacing(upsampledSpacing); upsampler->SetOutputOrigin(upsampledOrigin); auto nn_interpolator = itk::NearestNeighborInterpolateImageFunction::New(); upsampler->SetInterpolator(nn_interpolator); upsampler->Update(); m_UpsampledMaskImage = upsampler->GetOutput(); } template< class PixelType > void TractsToDWIImageFilter< PixelType >::InitializeFiberData() { // resample fiber bundle for sufficient voxel coverage PrintToLog("Resampling fibers ..."); m_SegmentVolume = 0.0001; float minSpacing = 1; if( m_WorkingSpacing[0]GetDeepCopy(); double volumeAccuracy = 10; m_FiberBundleWorkingCopy->ResampleLinear(minSpacing/volumeAccuracy); m_mmRadius = m_Parameters.m_SignalGen.m_AxonRadius/1000; auto caster = itk::CastImageFilter< itk::Image, itk::Image >::New(); caster->SetInput(m_TransformedMaskImage); caster->Update(); vtkSmartPointer weights = m_FiberBundleWorkingCopy->GetFiberWeights(); float mean_weight = 0; for (int i=0; iGetSize(); i++) mean_weight += weights->GetValue(i); mean_weight /= weights->GetSize(); if (mean_weight>0.000001) for (int i=0; iGetSize(); i++) m_FiberBundleWorkingCopy->SetFiberWeight(i, weights->GetValue(i)/mean_weight); else PrintToLog("\nWarning: streamlines have VERY low weights. Average weight: " + boost::lexical_cast(mean_weight) + ". Possible source of calculation errors.", false, true, true); auto density_calculator = itk::TractDensityImageFilter< itk::Image >::New(); density_calculator->SetFiberBundle(m_FiberBundleWorkingCopy); density_calculator->SetInputImage(caster->GetOutput()); density_calculator->SetBinaryOutput(false); density_calculator->SetUseImageGeometry(true); density_calculator->SetDoFiberResampling(false); density_calculator->SetOutputAbsoluteValues(true); density_calculator->SetWorkOnFiberCopy(false); density_calculator->Update(); float max_density = density_calculator->GetMaxDensity(); if (m_mmRadius>0) { m_SegmentVolume = itk::Math::pi*m_mmRadius*m_mmRadius*minSpacing/volumeAccuracy; std::stringstream stream; stream << std::fixed << setprecision(2) << max_density * m_SegmentVolume; std::string s = stream.str(); PrintToLog("\nMax. fiber volume: " + s + "mm².", false, true, true); } else { std::stringstream stream; stream << std::fixed << setprecision(2) << max_density * m_SegmentVolume; std::string s = stream.str(); PrintToLog("\nMax. fiber volume: " + s + "mm² (before rescaling to voxel volume).", false, true, true); } float voxel_volume = m_WorkingSpacing[0]*m_WorkingSpacing[1]*m_WorkingSpacing[2]; float new_seg_vol = voxel_volume/max_density; float new_fib_radius = 1000*std::sqrt(new_seg_vol*volumeAccuracy/(minSpacing*itk::Math::pi)); std::stringstream stream; stream << std::fixed << setprecision(2) << new_fib_radius; std::string s = stream.str(); PrintToLog("\nA full fiber voxel corresponds to a fiber radius of ~" + s + "µm, given the current fiber configuration.", false, true, true); // a second fiber bundle is needed to store the transformed version of the m_FiberBundleWorkingCopy m_FiberBundleTransformed = m_FiberBundleWorkingCopy; } template< class PixelType > bool TractsToDWIImageFilter< PixelType >::PrepareLogFile() { assert( ! m_Logfile.is_open() ); std::string filePath; std::string fileName; // Get directory name: if (m_Parameters.m_Misc.m_OutputPath.size() > 0) { filePath = m_Parameters.m_Misc.m_OutputPath; if( *(--(filePath.cend())) != '/') { filePath.push_back('/'); } } else { filePath = mitk::IOUtil::GetTempPath() + '/'; } // check if directory exists, else use /tmp/: if( itksys::SystemTools::FileIsDirectory( filePath ) ) { while( *(--(filePath.cend())) == '/') { filePath.pop_back(); } filePath = filePath + '/'; } else { filePath = mitk::IOUtil::GetTempPath() + '/'; } // Get file name: if( ! m_Parameters.m_Misc.m_ResultNode->GetName().empty() ) { fileName = m_Parameters.m_Misc.m_ResultNode->GetName(); } else { fileName = ""; } if( ! m_Parameters.m_Misc.m_OutputPrefix.empty() ) { fileName = m_Parameters.m_Misc.m_OutputPrefix + fileName; } else { fileName = "fiberfox"; } // check if file already exists and DO NOT overwrite existing files: std::string NameTest = fileName; int c = 0; while( itksys::SystemTools::FileExists( filePath + '/' + fileName + ".log" ) && c <= std::numeric_limits::max() ) { fileName = NameTest + "_" + boost::lexical_cast(c); ++c; } try { m_Logfile.open( ( filePath + '/' + fileName + ".log" ).c_str() ); } catch (const std::ios_base::failure &fail) { MITK_ERROR << "itkTractsToDWIImageFilter.cpp: Exception " << fail.what() << " while trying to open file" << filePath << '/' << fileName << ".log"; return false; } if ( m_Logfile.is_open() ) { PrintToLog( "Logfile: " + filePath + '/' + fileName + ".log", false ); return true; } else { m_StatusText += "Logfile could not be opened!\n"; MITK_ERROR << "itkTractsToDWIImageFilter.cpp: Logfile could not be opened!"; return false; } } template< class PixelType > void TractsToDWIImageFilter< PixelType >::GenerateData() { // prepare logfile if ( ! PrepareLogFile() ) { this->SetAbortGenerateData( true ); return; } m_TimeProbe.Start(); // check input data if (m_FiberBundle.IsNull() && m_InputImage.IsNull()) itkExceptionMacro("Input fiber bundle and input diffusion-weighted image is nullptr!"); if (m_Parameters.m_FiberModelList.empty() && m_InputImage.IsNull()) itkExceptionMacro("No diffusion model for fiber compartments defined and input diffusion-weighted" " image is nullptr! At least one fiber compartment is necessary to simulate diffusion."); if (m_Parameters.m_NonFiberModelList.empty() && m_InputImage.IsNull()) itkExceptionMacro("No diffusion model for non-fiber compartments defined and input diffusion-weighted" " image is nullptr! At least one non-fiber compartment is necessary to simulate diffusion."); if (m_Parameters.m_SignalGen.m_DoDisablePartialVolume) // no partial volume? remove all but first fiber compartment while (m_Parameters.m_FiberModelList.size()>1) m_Parameters.m_FiberModelList.pop_back(); // int baselineIndex = m_Parameters.m_SignalGen.GetFirstBaselineIndex(); // if (baselineIndex<0) { itkExceptionMacro("No baseline index found!"); } if (!m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition) // No upsampling of input image needed if no k-space simulation is performed m_Parameters.m_SignalGen.m_DoAddGibbsRinging = false; if (m_UseConstantRandSeed) // always generate the same random numbers? m_RandGen->SetSeed(0); else m_RandGen->SetSeed(); InitializeData(); if ( m_FiberBundle.IsNotNull() ) // if no fiber bundle is found, we directly proceed to the k-space acquisition simulation { CheckVolumeFractionImages(); InitializeFiberData(); int numFiberCompartments = m_Parameters.m_FiberModelList.size(); int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size(); double maxVolume = 0; unsigned long lastTick = 0; int signalModelSeed = m_RandGen->GetIntegerVariate(); PrintToLog("\n", false, false); PrintToLog("Generating " + boost::lexical_cast(numFiberCompartments+numNonFiberCompartments) + "-compartment diffusion-weighted signal."); std::vector< int > bVals = m_Parameters.m_SignalGen.GetBvalues(); PrintToLog("b-values: ", false, false, true); for (auto v : bVals) PrintToLog(boost::lexical_cast(v) + " ", false, false, true); PrintToLog("\n", false, false, true); PrintToLog("\n", false, false, true); int numFibers = m_FiberBundleWorkingCopy->GetNumFibers(); boost::progress_display disp(numFibers*m_Parameters.m_SignalGen.GetNumVolumes()); if (m_FiberBundle->GetMeanFiberLength()<5.0) omp_set_num_threads(2); PrintToLog("0% 10 20 30 40 50 60 70 80 90 100%", false, true, false); PrintToLog("|----|----|----|----|----|----|----|----|----|----|\n*", false, false, false); for (unsigned int g=0; gSetSeed(signalModelSeed); for (std::size_t i=0; iSetSeed(signalModelSeed); // storing voxel-wise intra-axonal volume in mm³ auto intraAxonalVolumeImage = ItkDoubleImgType::New(); intraAxonalVolumeImage->SetSpacing( m_WorkingSpacing ); intraAxonalVolumeImage->SetOrigin( m_WorkingOrigin ); intraAxonalVolumeImage->SetDirection( m_Parameters.m_SignalGen.m_ImageDirection ); intraAxonalVolumeImage->SetLargestPossibleRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->SetBufferedRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->SetRequestedRegion( m_WorkingImageRegion ); intraAxonalVolumeImage->Allocate(); intraAxonalVolumeImage->FillBuffer(0); maxVolume = 0; if (this->GetAbortGenerateData()) continue; vtkPolyData* fiberPolyData = m_FiberBundleTransformed->GetFiberPolyData(); // generate fiber signal (if there are any fiber models present) if (!m_Parameters.m_FiberModelList.empty()) { #pragma omp parallel for for( int i=0; iGetAbortGenerateData()) continue; float fiberWeight = m_FiberBundleTransformed->GetFiberWeight(i); int numPoints = -1; std::vector< itk::Vector > points_copy; #pragma omp critical { vtkCell* cell = fiberPolyData->GetCell(i); numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); for (int j=0; jGetPoint(j))); } if (numPoints<2) continue; for( int j=0; jGetAbortGenerateData()) { j=numPoints; continue; } itk::Point vertex = points_copy.at(j); itk::Vector v = points_copy.at(j); itk::Vector dir(3); if (j idx; itk::ContinuousIndex contIndex; m_TransformedMaskImage->TransformPhysicalPointToIndex(vertex, idx); m_TransformedMaskImage->TransformPhysicalPointToContinuousIndex(vertex, contIndex); if (!m_TransformedMaskImage->GetLargestPossibleRegion().IsInside(idx) || m_TransformedMaskImage->GetPixel(idx)<=0) continue; dir.Normalize(); // generate signal for each fiber compartment for (int k=0; kGetPixel(idx); pix[g] += fiberWeight*m_SegmentVolume*m_Parameters.m_FiberModelList[k]->SimulateMeasurement(g, dir); m_CompartmentImages.at(k)->SetPixel(idx, pix); } // update fiber volume image double vol = intraAxonalVolumeImage->GetPixel(idx) + m_SegmentVolume*fiberWeight; intraAxonalVolumeImage->SetPixel(idx, vol); // we assume that the first volume is always unweighted! if (vol>maxVolume) { maxVolume = vol; } } #pragma omp critical { // progress report ++disp; unsigned long newTick = 50*disp.count()/disp.expected_count(); for (unsigned int tick = 0; tick<(newTick-lastTick); ++tick) PrintToLog("*", false, false, false); lastTick = newTick; } } } // axon radius not manually defined --> set fullest voxel (maxVolume) to full fiber voxel double density_correctiony_global = 1.0; if (m_Parameters.m_SignalGen.m_AxonRadius<0.0001) density_correctiony_global = m_VoxelVolume/maxVolume; // generate non-fiber signal ImageRegionIterator it3(m_TransformedMaskImage, m_TransformedMaskImage->GetLargestPossibleRegion()); while(!it3.IsAtEnd()) { if (it3.Get()>0) { DoubleDwiType::IndexType index = it3.GetIndex(); double iAxVolume = intraAxonalVolumeImage->GetPixel(index); // get non-transformed point (remove headmotion tranformation) // this point lives in the volume fraction image space itk::Point volume_fraction_point; if ( m_Parameters.m_SignalGen.m_DoAddMotion && m_Parameters.m_SignalGen.m_MotionVolumes[g] ) volume_fraction_point = GetMovedPoint(index, false); else m_TransformedMaskImage->TransformIndexToPhysicalPoint(index, volume_fraction_point); if (m_Parameters.m_SignalGen.m_DoDisablePartialVolume) { if (iAxVolume>0.0001) // scale fiber compartment to voxel { DoubleDwiType::PixelType pix = m_CompartmentImages.at(0)->GetPixel(index); pix[g] *= m_VoxelVolume/iAxVolume; m_CompartmentImages.at(0)->SetPixel(index, pix); if (g==0) m_VolumeFractions.at(0)->SetPixel(index, 1); } else { DoubleDwiType::PixelType pix = m_CompartmentImages.at(0)->GetPixel(index); pix[g] = 0; m_CompartmentImages.at(0)->SetPixel(index, pix); SimulateExtraAxonalSignal(index, volume_fraction_point, 0, g); } } else { // manually defined axon radius and voxel overflow --> rescale to voxel volume if ( m_Parameters.m_SignalGen.m_AxonRadius>=0.0001 && iAxVolume>m_VoxelVolume ) { for (int i=0; iGetPixel(index); pix[g] *= m_VoxelVolume/iAxVolume; m_CompartmentImages.at(i)->SetPixel(index, pix); } iAxVolume = m_VoxelVolume; } // if volume fraction image is set use it, otherwise use global scaling factor double density_correction_voxel = density_correctiony_global; if ( m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()!=nullptr && iAxVolume>0.0001 ) { m_DoubleInterpolator->SetInputImage(m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()); double volume_fraction = mitk::imv::GetImageValue(volume_fraction_point, true, m_DoubleInterpolator); if (volume_fraction<0) mitkThrow() << "Volume fraction image (index 1) contains negative values (intra-axonal compartment)!"; density_correction_voxel = m_VoxelVolume*volume_fraction/iAxVolume; // remove iAxVolume sclaing and scale to volume_fraction } else if (m_Parameters.m_FiberModelList[0]->GetVolumeFractionImage()!=nullptr) density_correction_voxel = 0.0; // adjust intra-axonal compartment volume by density correction factor DoubleDwiType::PixelType pix = m_CompartmentImages.at(0)->GetPixel(index); pix[g] *= density_correction_voxel; m_CompartmentImages.at(0)->SetPixel(index, pix); // normalize remaining fiber volume fractions (they are rescaled in SimulateExtraAxonalSignal) if (iAxVolume>0.0001) { for (int i=1; iGetPixel(index); pix[g] /= iAxVolume; m_CompartmentImages.at(i)->SetPixel(index, pix); } } else { for (int i=1; iGetPixel(index); pix[g] = 0; m_CompartmentImages.at(i)->SetPixel(index, pix); } } iAxVolume = density_correction_voxel*iAxVolume; // new intra-axonal volume = old intra-axonal volume * correction factor // simulate other compartments SimulateExtraAxonalSignal(index, volume_fraction_point, iAxVolume, g); } } ++it3; } } PrintToLog("\n", false); } if (this->GetAbortGenerateData()) { PrintToLog("\n", false, false); PrintToLog("Simulation aborted"); return; } DoubleDwiType::Pointer doubleOutImage; double signalScale = m_Parameters.m_SignalGen.m_SignalScale; if ( m_Parameters.m_SignalGen.m_SimulateKspaceAcquisition ) // do k-space stuff { PrintToLog("\n", false, false); PrintToLog("Simulating k-space acquisition using " +boost::lexical_cast(m_Parameters.m_SignalGen.m_NumberOfCoils) +" coil(s)"); switch (m_Parameters.m_SignalGen.m_AcquisitionType) { case SignalGenerationParameters::SingleShotEpi: { PrintToLog("Acquisition type: single shot EPI", false); break; } case SignalGenerationParameters::SpinEcho: { PrintToLog("Acquisition type: classic spin echo with cartesian k-space trajectory", false); break; } default: { PrintToLog("Acquisition type: single shot EPI", false); break; } } if (m_Parameters.m_SignalGen.m_NoiseVariance>0 && m_Parameters.m_Misc.m_CheckAddNoiseBox) PrintToLog("Simulating complex Gaussian noise", false); if (m_Parameters.m_SignalGen.m_DoSimulateRelaxation) PrintToLog("Simulating signal relaxation", false); if (m_Parameters.m_SignalGen.m_FrequencyMap.IsNotNull()) PrintToLog("Simulating distortions", false); if (m_Parameters.m_SignalGen.m_DoAddGibbsRinging) PrintToLog("Simulating ringing artifacts", false); if (m_Parameters.m_SignalGen.m_EddyStrength>0) PrintToLog("Simulating eddy currents", false); if (m_Parameters.m_SignalGen.m_Spikes>0) PrintToLog("Simulating spikes", false); if (m_Parameters.m_SignalGen.m_CroppingFactor<1.0) PrintToLog("Simulating aliasing artifacts", false); if (m_Parameters.m_SignalGen.m_KspaceLineOffset>0) PrintToLog("Simulating ghosts", false); doubleOutImage = SimulateKspaceAcquisition(m_CompartmentImages); signalScale = 1; // already scaled in SimulateKspaceAcquisition() } else // don't do k-space stuff, just sum compartments { PrintToLog("Summing compartments"); doubleOutImage = m_CompartmentImages.at(0); for (unsigned int i=1; i::New(); adder->SetInput1(doubleOutImage); adder->SetInput2(m_CompartmentImages.at(i)); adder->Update(); doubleOutImage = adder->GetOutput(); } } if (this->GetAbortGenerateData()) { PrintToLog("\n", false, false); PrintToLog("Simulation aborted"); return; } PrintToLog("Finalizing image"); if (signalScale>1) PrintToLog(" Scaling signal", false); if (m_Parameters.m_NoiseModel) PrintToLog(" Adding noise", false); unsigned int window = 0; unsigned int min = itk::NumericTraits::max(); ImageRegionIterator it4 (m_OutputImage, m_OutputImage->GetLargestPossibleRegion()); DoubleDwiType::PixelType signal; signal.SetSize(m_Parameters.m_SignalGen.GetNumVolumes()); boost::progress_display disp2(m_OutputImage->GetLargestPossibleRegion().GetNumberOfPixels()); PrintToLog("0% 10 20 30 40 50 60 70 80 90 100%", false, true, false); PrintToLog("|----|----|----|----|----|----|----|----|----|----|\n*", false, false, false); int lastTick = 0; while(!it4.IsAtEnd()) { if (this->GetAbortGenerateData()) { PrintToLog("\n", false, false); PrintToLog("Simulation aborted"); return; } ++disp2; unsigned long newTick = 50*disp2.count()/disp2.expected_count(); for (unsigned long tick = 0; tick<(newTick-lastTick); tick++) PrintToLog("*", false, false, false); lastTick = newTick; typename OutputImageType::IndexType index = it4.GetIndex(); signal = doubleOutImage->GetPixel(index)*signalScale; if (m_Parameters.m_NoiseModel) m_Parameters.m_NoiseModel->AddNoise(signal); for (unsigned int i=0; i0) signal[i] = floor(signal[i]+0.5); else signal[i] = ceil(signal[i]-0.5); if ( (!m_Parameters.m_SignalGen.IsBaselineIndex(i) || signal.Size()==1) && signal[i]>window) window = signal[i]; if ( (!m_Parameters.m_SignalGen.IsBaselineIndex(i) || signal.Size()==1) && signal[i]SetNthOutput(0, m_OutputImage); PrintToLog("\n", false); PrintToLog("Finished simulation"); m_TimeProbe.Stop(); if (m_Parameters.m_SignalGen.m_DoAddMotion) { PrintToLog("\nHead motion log:", false); PrintToLog(m_MotionLog, false, false); } if (m_Parameters.m_SignalGen.m_Spikes>0) { PrintToLog("\nSpike log:", false); PrintToLog(m_SpikeLog, false, false); } if (m_Logfile.is_open()) m_Logfile.close(); } template< class PixelType > void TractsToDWIImageFilter< PixelType >::PrintToLog(std::string m, bool addTime, bool linebreak, bool stdOut) { // timestamp if (addTime) { m_Logfile << this->GetTime() << " > "; m_StatusText += this->GetTime() + " > "; if (stdOut) std::cout << this->GetTime() << " > "; } // message if (m_Logfile.is_open()) m_Logfile << m; m_StatusText += m; if (stdOut) std::cout << m; // new line if (linebreak) { if (m_Logfile.is_open()) m_Logfile << "\n"; m_StatusText += "\n"; if (stdOut) std::cout << "\n"; } } template< class PixelType > void TractsToDWIImageFilter< PixelType >::SimulateMotion(int g) { // is motion artifact enabled? // is the current volume g affected by motion? if ( m_Parameters.m_SignalGen.m_DoAddMotion && m_Parameters.m_SignalGen.m_MotionVolumes[g] && g(m_Parameters.m_SignalGen.GetNumVolumes()) ) { if ( m_Parameters.m_SignalGen.m_DoRandomizeMotion ) { // either undo last transform or work on fresh copy of untransformed fibers m_FiberBundleTransformed = m_FiberBundleWorkingCopy->GetDeepCopy(); m_Rotation[0] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[0]*2) -m_Parameters.m_SignalGen.m_Rotation[0]; m_Rotation[1] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[1]*2) -m_Parameters.m_SignalGen.m_Rotation[1]; m_Rotation[2] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Rotation[2]*2) -m_Parameters.m_SignalGen.m_Rotation[2]; m_Translation[0] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[0]*2) -m_Parameters.m_SignalGen.m_Translation[0]; m_Translation[1] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[1]*2) -m_Parameters.m_SignalGen.m_Translation[1]; m_Translation[2] = m_RandGen->GetVariateWithClosedRange(m_Parameters.m_SignalGen.m_Translation[2]*2) -m_Parameters.m_SignalGen.m_Translation[2]; } else { m_Rotation = m_Parameters.m_SignalGen.m_Rotation / m_NumMotionVolumes; m_Translation = m_Parameters.m_SignalGen.m_Translation / m_NumMotionVolumes; m_MotionCounter++; } // move mask image if (m_MaskImageSet) { ImageRegionIterator maskIt(m_UpsampledMaskImage, m_UpsampledMaskImage->GetLargestPossibleRegion()); m_TransformedMaskImage->FillBuffer(0); while(!maskIt.IsAtEnd()) { if (maskIt.Get()<=0) { ++maskIt; continue; } DoubleDwiType::IndexType index = maskIt.GetIndex(); m_TransformedMaskImage->TransformPhysicalPointToIndex(GetMovedPoint(index, true), index); if (m_TransformedMaskImage->GetLargestPossibleRegion().IsInside(index)) m_TransformedMaskImage->SetPixel(index,100); ++maskIt; } } if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { m_Rotations.push_back(m_Rotation); m_Translations.push_back(m_Translation); m_MotionLog += boost::lexical_cast(g) + " rotation: " + boost::lexical_cast(m_Rotation[0]) + "," + boost::lexical_cast(m_Rotation[1]) + "," + boost::lexical_cast(m_Rotation[2]) + ";"; m_MotionLog += " translation: " + boost::lexical_cast(m_Translation[0]) + "," + boost::lexical_cast(m_Translation[1]) + "," + boost::lexical_cast(m_Translation[2]) + "\n"; } else { m_Rotations.push_back(m_Rotation*m_MotionCounter); m_Translations.push_back(m_Translation*m_MotionCounter); m_MotionLog += boost::lexical_cast(g) + " rotation: " + boost::lexical_cast(m_Rotation[0]*m_MotionCounter) + "," + boost::lexical_cast(m_Rotation[1]*m_MotionCounter) + "," + boost::lexical_cast(m_Rotation[2]*m_MotionCounter) + ";"; m_MotionLog += " translation: " + boost::lexical_cast(m_Translation[0]*m_MotionCounter) + "," + boost::lexical_cast(m_Translation[1]*m_MotionCounter) + "," + boost::lexical_cast(m_Translation[2]*m_MotionCounter) + "\n"; } m_FiberBundleTransformed->TransformFibers(m_Rotation[0],m_Rotation[1],m_Rotation[2],m_Translation[0],m_Translation[1],m_Translation[2]); } else { m_Rotation.Fill(0.0); m_Translation.Fill(0.0); m_Rotations.push_back(m_Rotation); m_Translations.push_back(m_Translation); m_MotionLog += boost::lexical_cast(g) + " rotation: " + boost::lexical_cast(m_Rotation[0]) + "," + boost::lexical_cast(m_Rotation[1]) + "," + boost::lexical_cast(m_Rotation[2]) + ";"; m_MotionLog += " translation: " + boost::lexical_cast(m_Translation[0]) + "," + boost::lexical_cast(m_Translation[1]) + "," + boost::lexical_cast(m_Translation[2]) + "\n"; } } template< class PixelType > itk::Point TractsToDWIImageFilter< PixelType >::GetMovedPoint(itk::Index<3>& index, bool forward) { itk::Point transformed_point; if (forward) { m_UpsampledMaskImage->TransformIndexToPhysicalPoint(index, transformed_point); if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { transformed_point = m_FiberBundleWorkingCopy->TransformPoint(transformed_point.GetVnlVector(), m_Rotation[0],m_Rotation[1],m_Rotation[2], m_Translation[0],m_Translation[1],m_Translation[2]); } else { transformed_point = m_FiberBundleWorkingCopy->TransformPoint(transformed_point.GetVnlVector(), m_Rotation[0]*m_MotionCounter,m_Rotation[1]*m_MotionCounter,m_Rotation[2]*m_MotionCounter, m_Translation[0]*m_MotionCounter,m_Translation[1]*m_MotionCounter,m_Translation[2]*m_MotionCounter); } } else { m_TransformedMaskImage->TransformIndexToPhysicalPoint(index, transformed_point); if (m_Parameters.m_SignalGen.m_DoRandomizeMotion) { transformed_point = m_FiberBundleWorkingCopy->TransformPoint( transformed_point.GetVnlVector(), -m_Rotation[0], -m_Rotation[1], -m_Rotation[2], -m_Translation[0], -m_Translation[1], -m_Translation[2] ); } else { transformed_point = m_FiberBundleWorkingCopy->TransformPoint( transformed_point.GetVnlVector(), -m_Rotation[0]*m_MotionCounter, -m_Rotation[1]*m_MotionCounter, -m_Rotation[2]*m_MotionCounter, -m_Translation[0]*m_MotionCounter, -m_Translation[1]*m_MotionCounter, -m_Translation[2]*m_MotionCounter ); } } return transformed_point; } template< class PixelType > void TractsToDWIImageFilter< PixelType >:: SimulateExtraAxonalSignal(ItkUcharImgType::IndexType& index, itk::Point& volume_fraction_point, double intraAxonalVolume, int g) { int numFiberCompartments = m_Parameters.m_FiberModelList.size(); int numNonFiberCompartments = m_Parameters.m_NonFiberModelList.size(); if (m_Parameters.m_SignalGen.m_DoDisablePartialVolume) { // simulate signal for largest non-fiber compartment int max_compartment_index = 0; double max_fraction = 0; if (numNonFiberCompartments>1) { for (int i=0; iSetInputImage(m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()); double compartment_fraction = mitk::imv::GetImageValue(volume_fraction_point, true, m_DoubleInterpolator); if (compartment_fraction<0) mitkThrow() << "Volume fraction image (index " << i << ") contains values less than zero!"; if (compartment_fraction>max_fraction) { max_fraction = compartment_fraction; max_compartment_index = i; } } } DoubleDwiType::Pointer doubleDwi = m_CompartmentImages.at(max_compartment_index+numFiberCompartments); DoubleDwiType::PixelType pix = doubleDwi->GetPixel(index); pix[g] += m_Parameters.m_NonFiberModelList[max_compartment_index]->SimulateMeasurement(g, m_NullDir)*m_VoxelVolume; doubleDwi->SetPixel(index, pix); if (g==0) m_VolumeFractions.at(max_compartment_index+numFiberCompartments)->SetPixel(index, 1); } else { std::vector< double > fractions; if (g==0) m_VolumeFractions.at(0)->SetPixel(index, intraAxonalVolume/m_VoxelVolume); double extraAxonalVolume = m_VoxelVolume-intraAxonalVolume; // non-fiber volume if (extraAxonalVolume<0) { if (extraAxonalVolume<-0.001) MITK_ERROR << "Corrupted intra-axonal signal voxel detected. Fiber volume larger voxel volume! " << m_VoxelVolume << "<" << intraAxonalVolume; extraAxonalVolume = 0; } double interAxonalVolume = 0; if (numFiberCompartments>1) interAxonalVolume = extraAxonalVolume * intraAxonalVolume/m_VoxelVolume; // inter-axonal fraction of non fiber compartment double nonFiberVolume = extraAxonalVolume - interAxonalVolume; // rest of compartment if (nonFiberVolume<0) { if (nonFiberVolume<-0.001) MITK_ERROR << "Corrupted signal voxel detected. Fiber volume larger voxel volume!"; nonFiberVolume = 0; interAxonalVolume = extraAxonalVolume; } double compartmentSum = intraAxonalVolume; fractions.push_back(intraAxonalVolume/m_VoxelVolume); // rescale extra-axonal fiber signal for (int i=1; iGetVolumeFractionImage()!=nullptr) { m_DoubleInterpolator->SetInputImage(m_Parameters.m_FiberModelList[i]->GetVolumeFractionImage()); interAxonalVolume = mitk::imv::GetImageValue(volume_fraction_point, true, m_DoubleInterpolator)*m_VoxelVolume; if (interAxonalVolume<0) mitkThrow() << "Volume fraction image (index " << i+1 << ") contains negative values!"; } DoubleDwiType::PixelType pix = m_CompartmentImages.at(i)->GetPixel(index); pix[g] *= interAxonalVolume; m_CompartmentImages.at(i)->SetPixel(index, pix); compartmentSum += interAxonalVolume; fractions.push_back(interAxonalVolume/m_VoxelVolume); if (g==0) m_VolumeFractions.at(i)->SetPixel(index, interAxonalVolume/m_VoxelVolume); } for (int i=0; iGetVolumeFractionImage()!=nullptr) { m_DoubleInterpolator->SetInputImage(m_Parameters.m_NonFiberModelList[i]->GetVolumeFractionImage()); volume = mitk::imv::GetImageValue(volume_fraction_point, true, m_DoubleInterpolator)*m_VoxelVolume; if (volume<0) mitkThrow() << "Volume fraction image (index " << numFiberCompartments+i+1 << ") contains negative values (non-fiber compartment)!"; if (m_UseRelativeNonFiberVolumeFractions) volume *= nonFiberVolume/m_VoxelVolume; } DoubleDwiType::PixelType pix = m_CompartmentImages.at(i+numFiberCompartments)->GetPixel(index); pix[g] += m_Parameters.m_NonFiberModelList[i]->SimulateMeasurement(g, m_NullDir)*volume; m_CompartmentImages.at(i+numFiberCompartments)->SetPixel(index, pix); compartmentSum += volume; fractions.push_back(volume/m_VoxelVolume); if (g==0) m_VolumeFractions.at(i+numFiberCompartments)->SetPixel(index, volume/m_VoxelVolume); } if (compartmentSum/m_VoxelVolume>1.05) { MITK_ERROR << "Compartments do not sum to 1 in voxel " << index << " (" << compartmentSum/m_VoxelVolume << ")"; for (auto val : fractions) MITK_ERROR << val; } } } template< class PixelType > itk::Point TractsToDWIImageFilter< PixelType >::GetItkPoint(double point[3]) { itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; return itkPoint; } template< class PixelType > itk::Vector TractsToDWIImageFilter< PixelType >::GetItkVector(double point[3]) { itk::Vector itkVector; itkVector[0] = point[0]; itkVector[1] = point[1]; itkVector[2] = point[2]; return itkVector; } template< class PixelType > vnl_vector_fixed TractsToDWIImageFilter< PixelType >::GetVnlVector(double point[3]) { vnl_vector_fixed vnlVector; vnlVector[0] = point[0]; vnlVector[1] = point[1]; vnlVector[2] = point[2]; return vnlVector; } template< class PixelType > vnl_vector_fixed TractsToDWIImageFilter< PixelType >::GetVnlVector(Vector& vector) { vnl_vector_fixed vnlVector; vnlVector[0] = vector[0]; vnlVector[1] = vector[1]; vnlVector[2] = vector[2]; return vnlVector; } template< class PixelType > double TractsToDWIImageFilter< PixelType >::RoundToNearest(double num) { return (num > 0.0) ? floor(num + 0.5) : ceil(num - 0.5); } template< class PixelType > std::string TractsToDWIImageFilter< PixelType >::GetTime() { m_TimeProbe.Stop(); unsigned long total = RoundToNearest(m_TimeProbe.GetTotal()); unsigned long hours = total/3600; unsigned long minutes = (total%3600)/60; unsigned long seconds = total%60; std::string out = ""; out.append(boost::lexical_cast(hours)); out.append(":"); out.append(boost::lexical_cast(minutes)); out.append(":"); out.append(boost::lexical_cast(seconds)); m_TimeProbe.Start(); return out; } } diff --git a/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.cpp b/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.cpp index 6f8d0d5246..98beecf072 100644 --- a/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.cpp +++ b/Modules/DiffusionImaging/FiberTracking/IODataStructures/mitkFiberfoxParameters.cpp @@ -1,985 +1,985 @@ /*=================================================================== 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. ===================================================================*/ #define RAPIDXML_NO_EXCEPTIONS #include -#include +#include #include #include #include #include #include #include mitk::FiberfoxParameters::FiberfoxParameters() : m_NoiseModel(nullptr) { } mitk::FiberfoxParameters::FiberfoxParameters(const mitk::FiberfoxParameters& params) : m_NoiseModel(nullptr) { m_FiberGen = params.m_FiberGen; m_SignalGen = params.m_SignalGen; m_Misc = params.m_Misc; if (params.m_NoiseModel!=nullptr) { if (dynamic_cast*>(params.m_NoiseModel.get())) m_NoiseModel = std::make_shared< mitk::RicianNoiseModel<> >(); else if (dynamic_cast*>(params.m_NoiseModel.get())) m_NoiseModel = std::make_shared< mitk::ChiSquareNoiseModel<> >(); m_NoiseModel->SetNoiseVariance(params.m_NoiseModel->GetNoiseVariance()); } for (unsigned int i=0; i* outModel = nullptr; mitk::DiffusionSignalModel<>* signalModel = nullptr; if (i*>(signalModel)) outModel = new mitk::StickModel<>(dynamic_cast*>(signalModel)); else if (dynamic_cast*>(signalModel)) outModel = new mitk::TensorModel<>(dynamic_cast*>(signalModel)); else if (dynamic_cast*>(signalModel)) outModel = new mitk::RawShModel<>(dynamic_cast*>(signalModel)); else if (dynamic_cast*>(signalModel)) outModel = new mitk::BallModel<>(dynamic_cast*>(signalModel)); else if (dynamic_cast*>(signalModel)) outModel = new mitk::AstroStickModel<>(dynamic_cast*>(signalModel)); else if (dynamic_cast*>(signalModel)) outModel = new mitk::DotModel<>(dynamic_cast*>(signalModel)); if (i theta; theta.set_size(NPoints); vnl_vector phi; phi.set_size(NPoints); double C = sqrt(4*itk::Math::pi); phi(0) = 0.0; phi(NPoints-1) = 0.0; for(int i=0; i0 && i mitk::SignalGenerationParameters::GetBaselineIndices() { std::vector< int > result; for( unsigned int i=0; im_GradientDirections.size(); i++) if (m_GradientDirections.at(i).GetNorm()<0.0001) result.push_back(i); return result; } unsigned int mitk::SignalGenerationParameters::GetFirstBaselineIndex() { for( unsigned int i=0; im_GradientDirections.size(); i++) if (m_GradientDirections.at(i).GetNorm()<0.0001) return i; return -1; } bool mitk::SignalGenerationParameters::IsBaselineIndex(unsigned int idx) { if (m_GradientDirections.size()>idx && m_GradientDirections.at(idx).GetNorm()<0.0001) return true; return false; } unsigned int mitk::SignalGenerationParameters::GetNumWeightedVolumes() { return m_NumGradients; } unsigned int mitk::SignalGenerationParameters::GetNumBaselineVolumes() { return m_NumBaseline; } unsigned int mitk::SignalGenerationParameters::GetNumVolumes() { return m_GradientDirections.size(); } mitk::SignalGenerationParameters::GradientListType mitk::SignalGenerationParameters::GetGradientDirections() { return m_GradientDirections; } mitk::SignalGenerationParameters::GradientType mitk::SignalGenerationParameters::GetGradientDirection(unsigned int i) { return m_GradientDirections.at(i); } void mitk::SignalGenerationParameters::SetNumWeightedVolumes(int numGradients) { m_NumGradients = numGradients; GenerateGradientHalfShell(); } std::vector< int > mitk::SignalGenerationParameters::GetBvalues() { std::vector< int > bVals; for( GradientType g : m_GradientDirections) { float norm = g.GetNorm(); int bVal = std::round(norm*norm*m_Bvalue); if ( std::find(bVals.begin(), bVals.end(), bVal) == bVals.end() ) bVals.push_back(bVal); } return bVals; } double mitk::SignalGenerationParameters::GetBvalue() { return m_Bvalue; } void mitk::SignalGenerationParameters::SetGradienDirections(GradientListType gradientList) { m_GradientDirections = gradientList; m_NumGradients = 0; m_NumBaseline = 0; for( unsigned int i=0; im_GradientDirections.size(); i++) { float norm = m_GradientDirections.at(i).GetNorm(); if (norm>0.0001) m_NumGradients++; else m_NumBaseline++; } } void mitk::SignalGenerationParameters::SetGradienDirections(mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer gradientList) { m_NumGradients = 0; m_NumBaseline = 0; m_GradientDirections.clear(); for( unsigned int i=0; iSize(); i++) { GradientType g; g[0] = gradientList->at(i)[0]; g[1] = gradientList->at(i)[1]; g[2] = gradientList->at(i)[2]; m_GradientDirections.push_back(g); float norm = m_GradientDirections.at(i).GetNorm(); if (norm>0.0001) m_NumGradients++; else m_NumBaseline++; } } void mitk::FiberfoxParameters::SaveParameters(std::string filename) { if(filename.empty()) return; if(".ffp"!=filename.substr(filename.size()-4, 4)) filename += ".ffp"; const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, nullptr ); if ( locale.compare(currLocale)!=0 ) { try { setlocale(LC_ALL, locale.c_str()); } catch(...) { MITK_INFO << "Could not set locale " << locale; } } boost::property_tree::ptree parameters; // fiber generation parameters parameters.put("fiberfox.fibers.distribution", m_FiberGen.m_Distribution); parameters.put("fiberfox.fibers.variance", m_FiberGen.m_Variance); parameters.put("fiberfox.fibers.density", m_FiberGen.m_Density); parameters.put("fiberfox.fibers.spline.sampling", m_FiberGen.m_Sampling); parameters.put("fiberfox.fibers.spline.tension", m_FiberGen.m_Tension); parameters.put("fiberfox.fibers.spline.continuity", m_FiberGen.m_Continuity); parameters.put("fiberfox.fibers.spline.bias", m_FiberGen.m_Bias); parameters.put("fiberfox.fibers.rotation.x", m_FiberGen.m_Rotation[0]); parameters.put("fiberfox.fibers.rotation.y", m_FiberGen.m_Rotation[1]); parameters.put("fiberfox.fibers.rotation.z", m_FiberGen.m_Rotation[2]); parameters.put("fiberfox.fibers.translation.x", m_FiberGen.m_Translation[0]); parameters.put("fiberfox.fibers.translation.y", m_FiberGen.m_Translation[1]); parameters.put("fiberfox.fibers.translation.z", m_FiberGen.m_Translation[2]); parameters.put("fiberfox.fibers.scale.x", m_FiberGen.m_Scale[0]); parameters.put("fiberfox.fibers.scale.y", m_FiberGen.m_Scale[1]); parameters.put("fiberfox.fibers.scale.z", m_FiberGen.m_Scale[2]); // image generation parameters parameters.put("fiberfox.image.basic.size.x", m_SignalGen.m_ImageRegion.GetSize(0)); parameters.put("fiberfox.image.basic.size.y", m_SignalGen.m_ImageRegion.GetSize(1)); parameters.put("fiberfox.image.basic.size.z", m_SignalGen.m_ImageRegion.GetSize(2)); parameters.put("fiberfox.image.basic.spacing.x", m_SignalGen.m_ImageSpacing[0]); parameters.put("fiberfox.image.basic.spacing.y", m_SignalGen.m_ImageSpacing[1]); parameters.put("fiberfox.image.basic.spacing.z", m_SignalGen.m_ImageSpacing[2]); parameters.put("fiberfox.image.basic.origin.x", m_SignalGen.m_ImageOrigin[0]); parameters.put("fiberfox.image.basic.origin.y", m_SignalGen.m_ImageOrigin[1]); parameters.put("fiberfox.image.basic.origin.z", m_SignalGen.m_ImageOrigin[2]); parameters.put("fiberfox.image.basic.direction.1", m_SignalGen.m_ImageDirection[0][0]); parameters.put("fiberfox.image.basic.direction.2", m_SignalGen.m_ImageDirection[0][1]); parameters.put("fiberfox.image.basic.direction.3", m_SignalGen.m_ImageDirection[0][2]); parameters.put("fiberfox.image.basic.direction.4", m_SignalGen.m_ImageDirection[1][0]); parameters.put("fiberfox.image.basic.direction.5", m_SignalGen.m_ImageDirection[1][1]); parameters.put("fiberfox.image.basic.direction.6", m_SignalGen.m_ImageDirection[1][2]); parameters.put("fiberfox.image.basic.direction.7", m_SignalGen.m_ImageDirection[2][0]); parameters.put("fiberfox.image.basic.direction.8", m_SignalGen.m_ImageDirection[2][1]); parameters.put("fiberfox.image.basic.direction.9", m_SignalGen.m_ImageDirection[2][2]); parameters.put("fiberfox.image.basic.numgradients", m_SignalGen.GetNumWeightedVolumes()); for( unsigned int i=0; im_SignalGen.GetNumVolumes(); i++) { parameters.put("fiberfox.image.gradients."+boost::lexical_cast(i)+".x", m_SignalGen.GetGradientDirection(i)[0]); parameters.put("fiberfox.image.gradients."+boost::lexical_cast(i)+".y", m_SignalGen.GetGradientDirection(i)[1]); parameters.put("fiberfox.image.gradients."+boost::lexical_cast(i)+".z", m_SignalGen.GetGradientDirection(i)[2]); } parameters.put("fiberfox.image.acquisitiontype", m_SignalGen.m_AcquisitionType); parameters.put("fiberfox.image.coilsensitivityprofile", m_SignalGen.m_CoilSensitivityProfile); parameters.put("fiberfox.image.numberofcoils", m_SignalGen.m_NumberOfCoils); parameters.put("fiberfox.image.reversephase", m_SignalGen.m_ReversePhase); parameters.put("fiberfox.image.partialfourier", m_SignalGen.m_PartialFourier); parameters.put("fiberfox.image.noisevariance", m_SignalGen.m_NoiseVariance); parameters.put("fiberfox.image.trep", m_SignalGen.m_tRep); parameters.put("fiberfox.image.signalScale", m_SignalGen.m_SignalScale); parameters.put("fiberfox.image.tEcho", m_SignalGen.m_tEcho); parameters.put("fiberfox.image.tLine", m_SignalGen.m_tLine); parameters.put("fiberfox.image.tInhom", m_SignalGen.m_tInhom); parameters.put("fiberfox.image.bvalue", m_SignalGen.m_Bvalue); parameters.put("fiberfox.image.simulatekspace", m_SignalGen.m_SimulateKspaceAcquisition); parameters.put("fiberfox.image.axonRadius", m_SignalGen.m_AxonRadius); parameters.put("fiberfox.image.doSimulateRelaxation", m_SignalGen.m_DoSimulateRelaxation); parameters.put("fiberfox.image.doDisablePartialVolume", m_SignalGen.m_DoDisablePartialVolume); parameters.put("fiberfox.image.artifacts.spikesnum", m_SignalGen.m_Spikes); parameters.put("fiberfox.image.artifacts.spikesscale", m_SignalGen.m_SpikeAmplitude); parameters.put("fiberfox.image.artifacts.kspaceLineOffset", m_SignalGen.m_KspaceLineOffset); parameters.put("fiberfox.image.artifacts.eddyStrength", m_SignalGen.m_EddyStrength); parameters.put("fiberfox.image.artifacts.eddyTau", m_SignalGen.m_Tau); parameters.put("fiberfox.image.artifacts.aliasingfactor", m_SignalGen.m_CroppingFactor); parameters.put("fiberfox.image.artifacts.addringing", m_SignalGen.m_DoAddGibbsRinging); parameters.put("fiberfox.image.artifacts.doAddMotion", m_SignalGen.m_DoAddMotion); parameters.put("fiberfox.image.artifacts.randomMotion", m_SignalGen.m_DoRandomizeMotion); parameters.put("fiberfox.image.artifacts.translation0", m_SignalGen.m_Translation[0]); parameters.put("fiberfox.image.artifacts.translation1", m_SignalGen.m_Translation[1]); parameters.put("fiberfox.image.artifacts.translation2", m_SignalGen.m_Translation[2]); parameters.put("fiberfox.image.artifacts.rotation0", m_SignalGen.m_Rotation[0]); parameters.put("fiberfox.image.artifacts.rotation1", m_SignalGen.m_Rotation[1]); parameters.put("fiberfox.image.artifacts.rotation2", m_SignalGen.m_Rotation[2]); parameters.put("fiberfox.image.artifacts.motionvolumes", m_Misc.m_MotionVolumesBox); parameters.put("fiberfox.image.artifacts.addnoise", m_Misc.m_CheckAddNoiseBox); parameters.put("fiberfox.image.artifacts.addghosts", m_Misc.m_CheckAddGhostsBox); parameters.put("fiberfox.image.artifacts.addaliasing", m_Misc.m_CheckAddAliasingBox); parameters.put("fiberfox.image.artifacts.addspikes", m_Misc.m_CheckAddSpikesBox); parameters.put("fiberfox.image.artifacts.addeddycurrents", m_Misc.m_CheckAddEddyCurrentsBox); parameters.put("fiberfox.image.artifacts.doAddDistortions", m_Misc.m_CheckAddDistortionsBox); parameters.put("fiberfox.image.outputvolumefractions", m_Misc.m_CheckOutputVolumeFractionsBox); parameters.put("fiberfox.image.showadvanced", m_Misc.m_CheckAdvancedSignalOptionsBox); parameters.put("fiberfox.image.signalmodelstring", m_Misc.m_SignalModelString); parameters.put("fiberfox.image.artifactmodelstring", m_Misc.m_ArtifactModelString); parameters.put("fiberfox.image.outpath", m_Misc.m_OutputPath); parameters.put("fiberfox.fibers.realtime", m_Misc.m_CheckRealTimeFibersBox); parameters.put("fiberfox.fibers.showadvanced", m_Misc.m_CheckAdvancedFiberOptionsBox); parameters.put("fiberfox.fibers.constantradius", m_Misc.m_CheckConstantRadiusBox); parameters.put("fiberfox.fibers.includeFiducials", m_Misc.m_CheckIncludeFiducialsBox); if (m_NoiseModel!=nullptr) { parameters.put("fiberfox.image.artifacts.noisevariance", m_NoiseModel->GetNoiseVariance()); if (dynamic_cast*>(m_NoiseModel.get())) parameters.put("fiberfox.image.artifacts.noisetype", "rice"); else if (dynamic_cast*>(m_NoiseModel.get())) parameters.put("fiberfox.image.artifacts.noisetype", "chisquare"); } for (std::size_t i=0; i* signalModel = nullptr; if (i(i)+".type", "fiber"); } else { signalModel = m_NonFiberModelList.at(i-m_FiberModelList.size()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".type", "non-fiber"); } if (dynamic_cast*>(signalModel)) { mitk::StickModel<>* model = dynamic_cast*>(signalModel); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".model", "stick"); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".d", model->GetDiffusivity()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t2", model->GetT2()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t1", model->GetT1()); } else if (dynamic_cast*>(signalModel)) { mitk::TensorModel<>* model = dynamic_cast*>(signalModel); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".model", "tensor"); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".d1", model->GetDiffusivity1()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".d2", model->GetDiffusivity2()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".d3", model->GetDiffusivity3()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t2", model->GetT2()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t1", model->GetT1()); } else if (dynamic_cast*>(signalModel)) { mitk::RawShModel<>* model = dynamic_cast*>(signalModel); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".model", "prototype"); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".minFA", model->GetFaRange().first); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".maxFA", model->GetFaRange().second); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".minADC", model->GetAdcRange().first); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".maxADC", model->GetAdcRange().second); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".maxNumSamples", model->GetMaxNumKernels()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".numSamples", model->GetNumberOfKernels()); int shOrder = model->GetShOrder(); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".numCoeffs", (shOrder*shOrder + shOrder + 2)/2 + shOrder); for (unsigned int j=0; jGetNumberOfKernels(); j++) { vnl_vector< double > coeffs = model->GetCoefficients(j); for (unsigned int k=0; k(i)+".kernels."+boost::lexical_cast(j)+".coeffs."+boost::lexical_cast(k), coeffs[k]); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".kernels."+boost::lexical_cast(j)+".B0", model->GetBaselineSignal(j)); } } else if (dynamic_cast*>(signalModel)) { mitk::BallModel<>* model = dynamic_cast*>(signalModel); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".model", "ball"); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".d", model->GetDiffusivity()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t2", model->GetT2()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t1", model->GetT1()); } else if (dynamic_cast*>(signalModel)) { mitk::AstroStickModel<>* model = dynamic_cast*>(signalModel); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".model", "astrosticks"); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".d", model->GetDiffusivity()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t2", model->GetT2()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t1", model->GetT1()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".randomize", model->GetRandomizeSticks()); } else if (dynamic_cast*>(signalModel)) { mitk::DotModel<>* model = dynamic_cast*>(signalModel); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".model", "dot"); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t2", model->GetT2()); parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".t1", model->GetT1()); } if (signalModel!=nullptr) { parameters.put("fiberfox.image.compartments."+boost::lexical_cast(i)+".ID", signalModel->m_CompartmentId); if (signalModel->GetVolumeFractionImage().IsNotNull()) { try{ itk::ImageFileWriter::Pointer writer = itk::ImageFileWriter::New(); writer->SetFileName(filename+"_VOLUME"+boost::lexical_cast(signalModel->m_CompartmentId)+".nii.gz"); writer->SetInput(signalModel->GetVolumeFractionImage()); writer->Update(); MITK_INFO << "Volume fraction image for compartment "+boost::lexical_cast(signalModel->m_CompartmentId)+" saved."; } catch(...) { } } } } boost::property_tree::xml_writer_settings writerSettings(' ', 2); boost::property_tree::xml_parser::write_xml(filename, parameters, std::locale(), writerSettings); try{ itk::ImageFileWriter::Pointer writer = itk::ImageFileWriter::New(); writer->SetFileName(filename+"_FMAP.nii.gz"); writer->SetInput(m_SignalGen.m_FrequencyMap); writer->Update(); } catch(...) { MITK_INFO << "No frequency map saved."; } try{ itk::ImageFileWriter::Pointer writer = itk::ImageFileWriter::New(); writer->SetFileName(filename+"_MASK.nii.gz"); writer->SetInput(m_SignalGen.m_MaskImage); writer->Update(); } catch(...) { MITK_INFO << "No mask image saved."; } setlocale(LC_ALL, currLocale.c_str()); } template< class ParameterType > ParameterType mitk::FiberfoxParameters::ReadVal(boost::property_tree::ptree::value_type const& v, std::string tag, ParameterType defaultValue, bool essential) { try { return v.second.get(tag); } catch (...) { if (essential) { mitkThrow() << "Parameter file corrupted. Essential tag is missing: '" << tag << "'"; } if (tag!="artifacts.noisetype") { MITK_INFO << "Tag '" << tag << "' not found. Using default value '" << defaultValue << "'."; m_MissingTags += "\n- "; m_MissingTags += tag; } return defaultValue; } } void mitk::FiberfoxParameters::UpdateSignalModels() { for (mitk::DiffusionSignalModel<>* m : m_FiberModelList) { m->SetGradientList(m_SignalGen.m_GradientDirections); m->SetBvalue(m_SignalGen.m_Bvalue); } for (mitk::DiffusionSignalModel<>* m : m_NonFiberModelList) { m->SetGradientList(m_SignalGen.m_GradientDirections); m->SetBvalue(m_SignalGen.m_Bvalue); } } void mitk::FiberfoxParameters::SetNumWeightedVolumes(int numGradients) { m_SignalGen.SetNumWeightedVolumes(numGradients); UpdateSignalModels(); } void mitk::FiberfoxParameters::SetGradienDirections(mitk::SignalGenerationParameters::GradientListType gradientList) { m_SignalGen.SetGradienDirections(gradientList); UpdateSignalModels(); } void mitk::FiberfoxParameters::SetGradienDirections(mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer gradientList) { m_SignalGen.SetGradienDirections(gradientList); UpdateSignalModels(); } void mitk::FiberfoxParameters::SetBvalue(double Bvalue) { m_SignalGen.m_Bvalue = Bvalue; UpdateSignalModels(); } void mitk::FiberfoxParameters::GenerateGradientHalfShell() { m_SignalGen.GenerateGradientHalfShell(); UpdateSignalModels(); } void mitk::FiberfoxParameters::LoadParameters(std::string filename) { m_MissingTags = ""; if(filename.empty()) { return; } const std::string& locale = "C"; const std::string& currLocale = setlocale( LC_ALL, nullptr ); if ( locale.compare(currLocale)!=0 ) { try { setlocale(LC_ALL, locale.c_str()); } catch(...) { MITK_INFO << "Could not set locale " << locale; } } boost::property_tree::ptree parameterTree; boost::property_tree::xml_parser::read_xml( filename, parameterTree ); m_FiberModelList.clear(); m_NonFiberModelList.clear(); if (m_NoiseModel) { m_NoiseModel = nullptr; } BOOST_FOREACH( boost::property_tree::ptree::value_type const& v1, parameterTree.get_child("fiberfox") ) { if( v1.first == "fibers" ) { m_Misc.m_CheckRealTimeFibersBox = ReadVal(v1,"realtime", m_Misc.m_CheckRealTimeFibersBox); m_Misc.m_CheckAdvancedFiberOptionsBox = ReadVal(v1,"showadvanced", m_Misc.m_CheckAdvancedFiberOptionsBox); m_Misc.m_CheckConstantRadiusBox = ReadVal(v1,"constantradius", m_Misc.m_CheckConstantRadiusBox); m_Misc.m_CheckIncludeFiducialsBox = ReadVal(v1,"includeFiducials", m_Misc.m_CheckIncludeFiducialsBox); switch (ReadVal(v1,"distribution", 0)) { case 0: m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_UNIFORM; break; case 1: m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_GAUSSIAN; break; default: m_FiberGen.m_Distribution = FiberGenerationParameters::DISTRIBUTE_UNIFORM; } m_FiberGen.m_Variance = ReadVal(v1,"variance", m_FiberGen.m_Variance); m_FiberGen.m_Density = ReadVal(v1,"density", m_FiberGen.m_Density); m_FiberGen.m_Sampling = ReadVal(v1,"spline.sampling", m_FiberGen.m_Sampling); m_FiberGen.m_Tension = ReadVal(v1,"spline.tension", m_FiberGen.m_Tension); m_FiberGen.m_Continuity = ReadVal(v1,"spline.continuity", m_FiberGen.m_Continuity); m_FiberGen.m_Bias = ReadVal(v1,"spline.bias", m_FiberGen.m_Bias); m_FiberGen.m_Rotation[0] = ReadVal(v1,"rotation.x", m_FiberGen.m_Rotation[0]); m_FiberGen.m_Rotation[1] = ReadVal(v1,"rotation.y", m_FiberGen.m_Rotation[1]); m_FiberGen.m_Rotation[2] = ReadVal(v1,"rotation.z", m_FiberGen.m_Rotation[2]); m_FiberGen.m_Translation[0] = ReadVal(v1,"translation.x", m_FiberGen.m_Translation[0]); m_FiberGen.m_Translation[1] = ReadVal(v1,"translation.y", m_FiberGen.m_Translation[1]); m_FiberGen.m_Translation[2] = ReadVal(v1,"translation.z", m_FiberGen.m_Translation[2]); m_FiberGen.m_Scale[0] = ReadVal(v1,"scale.x", m_FiberGen.m_Scale[0]); m_FiberGen.m_Scale[1] = ReadVal(v1,"scale.y", m_FiberGen.m_Scale[1]); m_FiberGen.m_Scale[2] = ReadVal(v1,"scale.z", m_FiberGen.m_Scale[2]); } else if ( v1.first == "image" ) { m_Misc.m_SignalModelString = ReadVal(v1,"signalmodelstring", m_Misc.m_SignalModelString); m_Misc.m_ArtifactModelString = ReadVal(v1,"artifactmodelstring", m_Misc.m_ArtifactModelString); m_Misc.m_OutputPath = ReadVal(v1,"outpath", m_Misc.m_OutputPath); m_Misc.m_CheckOutputVolumeFractionsBox = ReadVal(v1,"outputvolumefractions", m_Misc.m_CheckOutputVolumeFractionsBox); m_Misc.m_CheckAdvancedSignalOptionsBox = ReadVal(v1,"showadvanced", m_Misc.m_CheckAdvancedSignalOptionsBox); m_Misc.m_CheckAddDistortionsBox = ReadVal(v1,"artifacts.doAddDistortions", m_Misc.m_CheckAddDistortionsBox); m_Misc.m_CheckAddNoiseBox = ReadVal(v1,"artifacts.addnoise", m_Misc.m_CheckAddNoiseBox); m_Misc.m_CheckAddGhostsBox = ReadVal(v1,"artifacts.addghosts", m_Misc.m_CheckAddGhostsBox); m_Misc.m_CheckAddAliasingBox = ReadVal(v1,"artifacts.addaliasing", m_Misc.m_CheckAddAliasingBox); m_Misc.m_CheckAddSpikesBox = ReadVal(v1,"artifacts.addspikes", m_Misc.m_CheckAddSpikesBox); m_Misc.m_CheckAddEddyCurrentsBox = ReadVal(v1,"artifacts.addeddycurrents", m_Misc.m_CheckAddEddyCurrentsBox); m_SignalGen.m_ImageRegion.SetSize(0, ReadVal(v1,"basic.size.x",m_SignalGen.m_ImageRegion.GetSize(0))); m_SignalGen.m_ImageRegion.SetSize(1, ReadVal(v1,"basic.size.y",m_SignalGen.m_ImageRegion.GetSize(1))); m_SignalGen.m_ImageRegion.SetSize(2, ReadVal(v1,"basic.size.z",m_SignalGen.m_ImageRegion.GetSize(2))); m_SignalGen.m_ImageSpacing[0] = ReadVal(v1,"basic.spacing.x",m_SignalGen.m_ImageSpacing[0]); m_SignalGen.m_ImageSpacing[1] = ReadVal(v1,"basic.spacing.y",m_SignalGen.m_ImageSpacing[1]); m_SignalGen.m_ImageSpacing[2] = ReadVal(v1,"basic.spacing.z",m_SignalGen.m_ImageSpacing[2]); m_SignalGen.m_ImageOrigin[0] = ReadVal(v1,"basic.origin.x",m_SignalGen.m_ImageOrigin[0]); m_SignalGen.m_ImageOrigin[1] = ReadVal(v1,"basic.origin.y",m_SignalGen.m_ImageOrigin[1]); m_SignalGen.m_ImageOrigin[2] = ReadVal(v1,"basic.origin.z",m_SignalGen.m_ImageOrigin[2]); m_SignalGen.m_ImageDirection[0][0] = ReadVal(v1,"basic.direction.1",m_SignalGen.m_ImageDirection[0][0]); m_SignalGen.m_ImageDirection[0][1] = ReadVal(v1,"basic.direction.2",m_SignalGen.m_ImageDirection[0][1]); m_SignalGen.m_ImageDirection[0][2] = ReadVal(v1,"basic.direction.3",m_SignalGen.m_ImageDirection[0][2]); m_SignalGen.m_ImageDirection[1][0] = ReadVal(v1,"basic.direction.4",m_SignalGen.m_ImageDirection[1][0]); m_SignalGen.m_ImageDirection[1][1] = ReadVal(v1,"basic.direction.5",m_SignalGen.m_ImageDirection[1][1]); m_SignalGen.m_ImageDirection[1][2] = ReadVal(v1,"basic.direction.6",m_SignalGen.m_ImageDirection[1][2]); m_SignalGen.m_ImageDirection[2][0] = ReadVal(v1,"basic.direction.7",m_SignalGen.m_ImageDirection[2][0]); m_SignalGen.m_ImageDirection[2][1] = ReadVal(v1,"basic.direction.8",m_SignalGen.m_ImageDirection[2][1]); m_SignalGen.m_ImageDirection[2][2] = ReadVal(v1,"basic.direction.9",m_SignalGen.m_ImageDirection[2][2]); m_SignalGen.m_AcquisitionType = (SignalGenerationParameters::AcquisitionType) ReadVal(v1,"acquisitiontype", m_SignalGen.m_AcquisitionType); m_SignalGen.m_CoilSensitivityProfile = (SignalGenerationParameters::CoilSensitivityProfile) ReadVal(v1,"coilsensitivityprofile", m_SignalGen.m_CoilSensitivityProfile); m_SignalGen.m_NumberOfCoils = ReadVal(v1,"numberofcoils", m_SignalGen.m_NumberOfCoils); m_SignalGen.m_ReversePhase = ReadVal(v1,"reversephase", m_SignalGen.m_ReversePhase); m_SignalGen.m_PartialFourier = ReadVal(v1,"partialfourier", m_SignalGen.m_PartialFourier); m_SignalGen.m_NoiseVariance = ReadVal(v1,"noisevariance", m_SignalGen.m_NoiseVariance); m_SignalGen.m_tRep = ReadVal(v1,"trep", m_SignalGen.m_tRep); m_SignalGen.m_SignalScale = ReadVal(v1,"signalScale", m_SignalGen.m_SignalScale); m_SignalGen.m_tEcho = ReadVal(v1,"tEcho", m_SignalGen.m_tEcho); m_SignalGen.m_tLine = ReadVal(v1,"tLine", m_SignalGen.m_tLine); m_SignalGen.m_tInhom = ReadVal(v1,"tInhom", m_SignalGen.m_tInhom); m_SignalGen.m_Bvalue = ReadVal(v1,"bvalue", m_SignalGen.m_Bvalue); m_SignalGen.m_SimulateKspaceAcquisition = ReadVal(v1,"simulatekspace", m_SignalGen.m_SimulateKspaceAcquisition); m_SignalGen.m_AxonRadius = ReadVal(v1,"axonRadius", m_SignalGen.m_AxonRadius); m_SignalGen.m_Spikes = ReadVal(v1,"artifacts.spikesnum", m_SignalGen.m_Spikes); m_SignalGen.m_SpikeAmplitude = ReadVal(v1,"artifacts.spikesscale", m_SignalGen.m_SpikeAmplitude); m_SignalGen.m_KspaceLineOffset = ReadVal(v1,"artifacts.kspaceLineOffset", m_SignalGen.m_KspaceLineOffset); m_SignalGen.m_EddyStrength = ReadVal(v1,"artifacts.eddyStrength", m_SignalGen.m_EddyStrength); m_SignalGen.m_Tau = ReadVal(v1,"artifacts.eddyTau", m_SignalGen.m_Tau); m_SignalGen.m_CroppingFactor = ReadVal(v1,"artifacts.aliasingfactor", m_SignalGen.m_CroppingFactor); m_SignalGen.m_DoAddGibbsRinging = ReadVal(v1,"artifacts.addringing", m_SignalGen.m_DoAddGibbsRinging); m_SignalGen.m_DoSimulateRelaxation = ReadVal(v1,"doSimulateRelaxation", m_SignalGen.m_DoSimulateRelaxation); m_SignalGen.m_DoDisablePartialVolume = ReadVal(v1,"doDisablePartialVolume", m_SignalGen.m_DoDisablePartialVolume); m_SignalGen.m_DoAddMotion = ReadVal(v1,"artifacts.doAddMotion", m_SignalGen.m_DoAddMotion); m_SignalGen.m_DoRandomizeMotion = ReadVal(v1,"artifacts.randomMotion", m_SignalGen.m_DoRandomizeMotion); m_SignalGen.m_Translation[0] = ReadVal(v1,"artifacts.translation0", m_SignalGen.m_Translation[0]); m_SignalGen.m_Translation[1] = ReadVal(v1,"artifacts.translation1", m_SignalGen.m_Translation[1]); m_SignalGen.m_Translation[2] = ReadVal(v1,"artifacts.translation2", m_SignalGen.m_Translation[2]); m_SignalGen.m_Rotation[0] = ReadVal(v1,"artifacts.rotation0", m_SignalGen.m_Rotation[0]); m_SignalGen.m_Rotation[1] = ReadVal(v1,"artifacts.rotation1", m_SignalGen.m_Rotation[1]); m_SignalGen.m_Rotation[2] = ReadVal(v1,"artifacts.rotation2", m_SignalGen.m_Rotation[2]); // m_SignalGen.SetNumWeightedVolumes(ReadVal(v1,"numgradients", m_SignalGen.GetNumWeightedVolumes())); SignalGenerationParameters::GradientListType gradients; BOOST_FOREACH( boost::property_tree::ptree::value_type const& v2, v1.second.get_child("gradients") ) { SignalGenerationParameters::GradientType g; g[0] = ReadVal(v2,"x",0); g[1] = ReadVal(v2,"y",0); g[2] = ReadVal(v2,"z",0); gradients.push_back(g); } m_SignalGen.SetGradienDirections(gradients); m_Misc.m_MotionVolumesBox = ReadVal(v1,"artifacts.motionvolumes", m_Misc.m_MotionVolumesBox); m_SignalGen.m_MotionVolumes.clear(); if ( m_Misc.m_MotionVolumesBox == "random" ) { for ( size_t i=0; i < m_SignalGen.GetNumVolumes(); ++i ) { m_SignalGen.m_MotionVolumes.push_back( bool( rand()%2 ) ); } MITK_DEBUG << "mitkFiberfoxParameters.cpp: Case m_Misc.m_MotionVolumesBox == \"random\"."; } else if ( ! m_Misc.m_MotionVolumesBox.empty() ) { std::stringstream stream( m_Misc.m_MotionVolumesBox ); std::vector numbers; int nummer = std::numeric_limits::max(); while( stream >> nummer ) { if( nummer < std::numeric_limits::max() ) { numbers.push_back( nummer ); } } // If a list of negative numbers is given: if( *(std::min_element( numbers.begin(), numbers.end() )) < 0 && *(std::max_element( numbers.begin(), numbers.end() )) <= 0 ) // cave: -0 == +0 { for ( size_t i=0; i(m_SignalGen.GetNumVolumes()) && -number >= 0 ) m_SignalGen.m_MotionVolumes.at(-number) = false; } MITK_DEBUG << "mitkFiberfoxParameters.cpp: Case list of negative numbers."; } // If a list of positive numbers is given: else if( *(std::min_element( numbers.begin(), numbers.end() )) >= 0 && *(std::max_element( numbers.begin(), numbers.end() )) >= 0 ) { for ( size_t i=0; i(m_SignalGen.GetNumVolumes()) && number >= 0) m_SignalGen.m_MotionVolumes.at(number) = true; } MITK_DEBUG << "mitkFiberfoxParameters.cpp: Case list of positive numbers."; } else { MITK_WARN << "mitkFiberfoxParameters.cpp: Inconsistent list of numbers in m_MotionVolumesBox."; break; } } else { MITK_WARN << "mitkFiberfoxParameters.cpp: Cannot make sense of string in m_MotionVolumesBox."; break; } try { if (ReadVal(v1,"artifacts.noisetype","")=="rice") { m_NoiseModel = std::make_shared< mitk::RicianNoiseModel<> >(); m_NoiseModel->SetNoiseVariance(ReadVal(v1,"artifacts.noisevariance",m_NoiseModel->GetNoiseVariance())); } } catch(...) { MITK_DEBUG << "mitkFiberfoxParameters.cpp: caught some error while trying m_NoiseModel->SetNoiseVariance()"; // throw; } try { if (ReadVal(v1,"artifacts.noisetype","")=="chisquare") { m_NoiseModel = std::make_shared< mitk::ChiSquareNoiseModel<> >(); m_NoiseModel->SetNoiseVariance(ReadVal(v1,"artifacts.noisevariance",m_NoiseModel->GetNoiseVariance())); } } catch(...) { MITK_DEBUG << "mitkFiberfoxParameters.cpp: caught some error while trying m_NoiseModel->SetNoiseVariance()"; // throw; } BOOST_FOREACH( boost::property_tree::ptree::value_type const& v2, v1.second.get_child("compartments") ) { mitk::DiffusionSignalModel<>* signalModel = nullptr; std::string model = ReadVal(v2,"model","",true); if (model=="stick") { mitk::StickModel<>* model = new mitk::StickModel<>(); model->SetDiffusivity(ReadVal(v2,"d",model->GetDiffusivity())); model->SetT2(ReadVal(v2,"t2",model->GetT2())); model->SetT1(ReadVal(v2,"t1",model->GetT1())); model->SetBvalue(m_SignalGen.m_Bvalue); model->m_CompartmentId = ReadVal(v2,"ID",0,true); if (ReadVal(v2,"type","",true)=="fiber") m_FiberModelList.push_back(model); else if (ReadVal(v2,"type","",true)=="non-fiber") m_NonFiberModelList.push_back(model); signalModel = model; } else if (model=="tensor") { mitk::TensorModel<>* model = new mitk::TensorModel<>(); model->SetDiffusivity1(ReadVal(v2,"d1",model->GetDiffusivity1())); model->SetDiffusivity2(ReadVal(v2,"d2",model->GetDiffusivity2())); model->SetDiffusivity3(ReadVal(v2,"d3",model->GetDiffusivity3())); model->SetT2(ReadVal(v2,"t2",model->GetT2())); model->SetT1(ReadVal(v2,"t1",model->GetT1())); model->SetBvalue(m_SignalGen.m_Bvalue); model->m_CompartmentId = ReadVal(v2,"ID",0,true); if (ReadVal(v2,"type","",true)=="fiber") m_FiberModelList.push_back(model); else if (ReadVal(v2,"type","",true)=="non-fiber") m_NonFiberModelList.push_back(model); signalModel = model; } else if (model=="ball") { mitk::BallModel<>* model = new mitk::BallModel<>(); model->SetDiffusivity(ReadVal(v2,"d",model->GetDiffusivity())); model->SetT2(ReadVal(v2,"t2",model->GetT2())); model->SetT1(ReadVal(v2,"t1",model->GetT1())); model->SetBvalue(m_SignalGen.m_Bvalue); model->m_CompartmentId = ReadVal(v2,"ID",0,true); if (ReadVal(v2,"type","",true)=="fiber") m_FiberModelList.push_back(model); else if (ReadVal(v2,"type","",true)=="non-fiber") m_NonFiberModelList.push_back(model); signalModel = model; } else if (model=="astrosticks") { mitk::AstroStickModel<>* model = new AstroStickModel<>(); model->SetDiffusivity(ReadVal(v2,"d",model->GetDiffusivity())); model->SetT2(ReadVal(v2,"t2",model->GetT2())); model->SetT1(ReadVal(v2,"t1",model->GetT1())); model->SetBvalue(m_SignalGen.m_Bvalue); model->SetRandomizeSticks(ReadVal(v2,"randomize",model->GetRandomizeSticks())); model->m_CompartmentId = ReadVal(v2,"ID",0,true); if (ReadVal(v2,"type","",true)=="fiber") m_FiberModelList.push_back(model); else if (ReadVal(v2,"type","",true)=="non-fiber") m_NonFiberModelList.push_back(model); signalModel = model; } else if (model=="dot") { mitk::DotModel<>* model = new mitk::DotModel<>(); model->SetT2(ReadVal(v2,"t2",model->GetT2())); model->SetT1(ReadVal(v2,"t1",model->GetT1())); model->m_CompartmentId = ReadVal(v2,"ID",0,true); if (ReadVal(v2,"type","",true)=="fiber") m_FiberModelList.push_back(model); else if (ReadVal(v2,"type","",true)=="non-fiber") m_NonFiberModelList.push_back(model); signalModel = model; } else if (model=="prototype") { mitk::RawShModel<>* model = new mitk::RawShModel<>(); model->SetMaxNumKernels(ReadVal(v2,"maxNumSamples",model->GetMaxNumKernels())); model->SetFaRange(ReadVal(v2,"minFA",model->GetFaRange().first), ReadVal(v2,"maxFA",model->GetFaRange().second)); model->SetAdcRange(ReadVal(v2,"minADC",model->GetAdcRange().first), ReadVal(v2,"maxADC",model->GetAdcRange().second)); model->m_CompartmentId = ReadVal(v2,"ID",0,true); unsigned int numCoeffs = ReadVal(v2,"numCoeffs",0,true); unsigned int numSamples = ReadVal(v2,"numSamples",0,true); for (unsigned int j=0; j coeffs(numCoeffs); for (unsigned int k=0; k(v2,"kernels."+boost::lexical_cast(j)+".coeffs."+boost::lexical_cast(k),0,true); } model->SetShCoefficients( coeffs, ReadVal(v2,"kernels."+boost::lexical_cast(j)+".B0",0,true) ); } if (ReadVal(v2,"type","",true)=="fiber") { m_FiberModelList.push_back(model); } else if (ReadVal(v2,"type","",true)=="non-fiber") { m_NonFiberModelList.push_back(model); } // else ? signalModel = model; } if (signalModel!=nullptr) { signalModel->SetGradientList(gradients); try { itk::ImageFileReader::Pointer reader = itk::ImageFileReader::New(); if ( itksys::SystemTools::FileExists(filename+"_VOLUME"+ReadVal(v2,"ID","")+".nii.gz") ) reader->SetFileName(filename+"_VOLUME"+ReadVal(v2,"ID","")+".nii.gz"); else if ( itksys::SystemTools::FileExists(filename+"_VOLUME"+ReadVal(v2,"ID","")+".nii") ) reader->SetFileName(filename+"_VOLUME"+ReadVal(v2,"ID","")+".nii"); else reader->SetFileName(filename+"_VOLUME"+ReadVal(v2,"ID","")+".nrrd"); reader->Update(); signalModel->SetVolumeFractionImage(reader->GetOutput()); MITK_INFO << "Volume fraction image loaded for compartment " << signalModel->m_CompartmentId; } catch(...) { MITK_INFO << "No volume fraction image found for compartment " << signalModel->m_CompartmentId; } } } } else { } } try { itk::ImageFileReader::Pointer reader = itk::ImageFileReader::New(); reader->SetFileName(filename+"_FMAP.nrrd"); if ( itksys::SystemTools::FileExists(filename+"_FMAP.nii.gz") ) reader->SetFileName(filename+"_FMAP.nii.gz"); else if ( itksys::SystemTools::FileExists(filename+"_FMAP.nii") ) reader->SetFileName(filename+"_FMAP.nii"); else reader->SetFileName(filename+"_FMAP.nrrd"); reader->Update(); m_SignalGen.m_FrequencyMap = reader->GetOutput(); MITK_INFO << "Frequency map loaded."; } catch(...) { MITK_INFO << "No frequency map found."; } try { itk::ImageFileReader::Pointer reader = itk::ImageFileReader::New(); if ( itksys::SystemTools::FileExists(filename+"_MASK.nii.gz") ) reader->SetFileName(filename+"_MASK.nii.gz"); else if ( itksys::SystemTools::FileExists(filename+"_MASK.nii") ) reader->SetFileName(filename+"_MASK.nii"); else reader->SetFileName(filename+"_MASK.nrrd"); reader->Update(); m_SignalGen.m_MaskImage = reader->GetOutput(); m_SignalGen.m_ImageRegion = m_SignalGen.m_MaskImage->GetLargestPossibleRegion(); m_SignalGen.m_ImageSpacing = m_SignalGen.m_MaskImage->GetSpacing(); m_SignalGen.m_ImageOrigin = m_SignalGen.m_MaskImage->GetOrigin(); m_SignalGen.m_ImageDirection = m_SignalGen.m_MaskImage->GetDirection(); MITK_INFO << "Mask image loaded."; } catch(...) { MITK_INFO << "No mask image found."; } setlocale(LC_ALL, currLocale.c_str()); } void mitk::FiberfoxParameters::PrintSelf() { MITK_INFO << "Not implemented :("; } diff --git a/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp b/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp index 95c60988a8..1bb35113ca 100755 --- a/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp +++ b/Modules/DiffusionImaging/FiberTracking/Testing/mitkLocalFiberPlausibilityTest.cpp @@ -1,156 +1,156 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include -#include +#include #include #include #include #include #include #include #include int mitkLocalFiberPlausibilityTest(int argc, char* argv[]) { omp_set_num_threads(1); MITK_TEST_BEGIN("mitkLocalFiberPlausibilityTest"); MITK_TEST_CONDITION_REQUIRED(argc==8,"check for input data") std::string fibFile = argv[1]; std::vector< std::string > referenceImages; referenceImages.push_back(argv[2]); referenceImages.push_back(argv[3]); std::string LDFP_ERROR_IMAGE = argv[4]; std::string LDFP_NUM_DIRECTIONS = argv[5]; std::string LDFP_VECTOR_FIELD = argv[6]; std::string LDFP_ERROR_IMAGE_IGNORE = argv[7]; float angularThreshold = 30; try { typedef itk::Image ItkUcharImgType; typedef itk::Image< itk::Vector< float, 3>, 3 > ItkDirectionImage3DType; typedef itk::VectorContainer< unsigned int, ItkDirectionImage3DType::Pointer > ItkDirectionImageContainerType; typedef itk::EvaluateDirectionImagesFilter< float > EvaluationFilterType; // load fiber bundle mitk::FiberBundle::Pointer inputTractogram = mitk::IOUtil::Load(fibFile); // load reference directions ItkDirectionImageContainerType::Pointer referenceImageContainer = ItkDirectionImageContainerType::New(); for (unsigned int i=0; i(referenceImages.at(i)); typedef mitk::ImageToItk< ItkDirectionImage3DType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(img); caster->Update(); ItkDirectionImage3DType::Pointer itkImg = caster->GetOutput(); referenceImageContainer->InsertElement(referenceImageContainer->Size(),itkImg); } catch(...){ MITK_INFO << "could not load: " << referenceImages.at(i); } } ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); ItkDirectionImage3DType::Pointer dirImg = referenceImageContainer->GetElement(0); itkMaskImage->SetSpacing( dirImg->GetSpacing() ); itkMaskImage->SetOrigin( dirImg->GetOrigin() ); itkMaskImage->SetDirection( dirImg->GetDirection() ); itkMaskImage->SetLargestPossibleRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->SetBufferedRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->SetRequestedRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->Allocate(); itkMaskImage->FillBuffer(1); // extract directions from fiber bundle itk::TractsToVectorImageFilter::Pointer fOdfFilter = itk::TractsToVectorImageFilter::New(); fOdfFilter->SetFiberBundle(inputTractogram); fOdfFilter->SetMaskImage(itkMaskImage); fOdfFilter->SetAngularThreshold(cos(angularThreshold*itk::Math::pi/180)); fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::SINGLE_VEC_NORM); fOdfFilter->SetMaxNumDirections(3); fOdfFilter->SetSizeThreshold(0.3); fOdfFilter->SetUseWorkingCopy(false); fOdfFilter->SetNumberOfThreads(1); fOdfFilter->Update(); itk::TractsToVectorImageFilter::ItkDirectionImageType::Pointer direction_image = fOdfFilter->GetDirectionImage(); // Get directions and num directions image ItkUcharImgType::Pointer numDirImage = fOdfFilter->GetNumDirectionsImage(); mitk::Image::Pointer mitkNumDirImage = mitk::Image::New(); mitkNumDirImage->InitializeByItk( numDirImage.GetPointer() ); mitkNumDirImage->SetVolume( numDirImage->GetBufferPointer() ); // mitk::FiberBundle::Pointer testDirections = fOdfFilter->GetOutputFiberBundle(); // evaluate directions with missing directions EvaluationFilterType::Pointer evaluationFilter = EvaluationFilterType::New(); // evaluationFilter->SetImageSet(directionImageContainer); evaluationFilter->SetReferenceImageSet(referenceImageContainer); evaluationFilter->SetMaskImage(itkMaskImage); evaluationFilter->SetIgnoreMissingDirections(false); evaluationFilter->Update(); EvaluationFilterType::OutputImageType::Pointer angularErrorImage = evaluationFilter->GetOutput(0); mitk::Image::Pointer mitkAngularErrorImage = mitk::Image::New(); mitkAngularErrorImage->InitializeByItk( angularErrorImage.GetPointer() ); mitkAngularErrorImage->SetVolume( angularErrorImage->GetBufferPointer() ); // evaluate directions without missing directions evaluationFilter->SetIgnoreMissingDirections(true); evaluationFilter->Update(); EvaluationFilterType::OutputImageType::Pointer angularErrorImageIgnore = evaluationFilter->GetOutput(0); mitk::Image::Pointer mitkAngularErrorImageIgnore = mitk::Image::New(); mitkAngularErrorImageIgnore->InitializeByItk( angularErrorImageIgnore.GetPointer() ); mitkAngularErrorImageIgnore->SetVolume( angularErrorImageIgnore->GetBufferPointer() ); mitk::Image::Pointer gtAngularErrorImageIgnore = mitk::IOUtil::Load(LDFP_ERROR_IMAGE_IGNORE); mitk::Image::Pointer gtAngularErrorImage = mitk::IOUtil::Load(LDFP_ERROR_IMAGE); mitk::Image::Pointer gtNumTestDirImage = mitk::IOUtil::Load(LDFP_NUM_DIRECTIONS); MITK_ASSERT_EQUAL(gtAngularErrorImageIgnore, mitkAngularErrorImageIgnore, "Check if error images are equal (ignored missing directions)."); MITK_ASSERT_EQUAL(gtAngularErrorImage, mitkAngularErrorImage, "Check if error images are equal."); MITK_ASSERT_EQUAL(gtNumTestDirImage, mitkNumDirImage, "Check if num direction images are equal."); } catch (itk::ExceptionObject e) { MITK_INFO << e; return EXIT_FAILURE; } catch (std::exception e) { MITK_INFO << e.what(); return EXIT_FAILURE; } catch (...) { MITK_INFO << "ERROR!?!"; return EXIT_FAILURE; } MITK_TEST_END(); } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberClustering.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberClustering.cpp index 00559e4c71..61ae8e9bf3 100644 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberClustering.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberClustering.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 #include -#include +#include #include #include #include #include #include #include #include #include #include mitk::FiberBundle::Pointer LoadFib(std::string filename) { std::vector fibInfile = mitk::IOUtil::Load(filename); if( fibInfile.empty() ) std::cout << "File " << filename << " could not be read!"; mitk::BaseData::Pointer baseData = fibInfile.at(0); return dynamic_cast(baseData.GetPointer()); } /*! \brief Spatially cluster fibers */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Fiber Clustering"); parser.setCategory("Fiber Processing"); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("", "i", mitkCommandLineParser::InputFile, "Input:", "input fiber bundle (.fib, .trk, .tck)", us::Any(), false); parser.addArgument("", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output root", us::Any(), false); parser.addArgument("cluster_size", "", mitkCommandLineParser::Int, "Cluster size:", "", 10); parser.addArgument("fiber_points", "", mitkCommandLineParser::Int, "Fiber points:", "", 12); parser.addArgument("min_fibers", "", mitkCommandLineParser::Int, "Min. fibers per cluster:", "", 1); parser.addArgument("max_clusters", "", mitkCommandLineParser::Int, "Max. clusters:", ""); parser.addArgument("merge_clusters", "", mitkCommandLineParser::Float, "Merge clusters:", "", -1.0); parser.addArgument("output_centroids", "", mitkCommandLineParser::Bool, "Output centroids:", ""); parser.addArgument("metrics", "", mitkCommandLineParser::StringList, "Metrics:", "EU_MEAN, EU_STD, EU_MAX, ANAT, MAP, LENGTH"); parser.addArgument("metric_weights", "", mitkCommandLineParser::StringList, "Metric weights:", "add one float weight for each used metric"); parser.addArgument("input_centroids", "", mitkCommandLineParser::String, "Input centroids:", ""); parser.addArgument("scalar_map", "", mitkCommandLineParser::String, "Scalar map:", ""); parser.addArgument("parcellation", "", mitkCommandLineParser::String, "Parcellation:", ""); parser.addArgument("file_ending", "", mitkCommandLineParser::String, "File ending:", ""); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string inFileName = us::any_cast(parsedArgs["i"]); std::string out_root = us::any_cast(parsedArgs["o"]); int cluster_size = 10; if (parsedArgs.count("cluster_size")) cluster_size = us::any_cast(parsedArgs["cluster_size"]); int fiber_points = 12; if (parsedArgs.count("fiber_points")) fiber_points = us::any_cast(parsedArgs["fiber_points"]); int min_fibers = 1; if (parsedArgs.count("min_fibers")) min_fibers = us::any_cast(parsedArgs["min_fibers"]); int max_clusters = 0; if (parsedArgs.count("max_clusters")) max_clusters = us::any_cast(parsedArgs["max_clusters"]); float merge_clusters = -1.0; if (parsedArgs.count("merge_clusters")) merge_clusters = us::any_cast(parsedArgs["merge_clusters"]); bool output_centroids = false; if (parsedArgs.count("output_centroids")) output_centroids = us::any_cast(parsedArgs["output_centroids"]); std::vector< std::string > metric_strings = {"EU_MEAN"}; if (parsedArgs.count("metrics")) metric_strings = us::any_cast(parsedArgs["metrics"]); std::vector< std::string > metric_weights = {"1.0"}; if (parsedArgs.count("metric_weights")) metric_weights = us::any_cast(parsedArgs["metric_weights"]); std::string input_centroids = ""; if (parsedArgs.count("input_centroids")) input_centroids = us::any_cast(parsedArgs["input_centroids"]); std::string scalar_map = ""; if (parsedArgs.count("scalar_map")) scalar_map = us::any_cast(parsedArgs["scalar_map"]); std::string parcellation = ""; if (parsedArgs.count("parcellation")) parcellation = us::any_cast(parsedArgs["parcellation"]); std::string file_ending = ".fib"; if (parsedArgs.count("file_ending")) file_ending = us::any_cast(parsedArgs["file_ending"]); if (metric_strings.size()!=metric_weights.size()) { MITK_INFO << "Each metric needs an associated metric weight!"; return EXIT_FAILURE; } try { typedef itk::Image< float, 3 > FloatImageType; typedef itk::Image< short, 3 > ShortImageType; mitk::FiberBundle::Pointer fib = LoadFib(inFileName); float max_d = 0; int i=1; std::vector< float > distances; while (max_d < fib->GetGeometry()->GetDiagonalLength()/2) { distances.push_back(cluster_size*i); max_d = cluster_size*i; ++i; } itk::TractClusteringFilter::Pointer clusterer = itk::TractClusteringFilter::New(); clusterer->SetDistances(distances); clusterer->SetTractogram(fib); if (input_centroids!="") { mitk::FiberBundle::Pointer in_centroids = LoadFib(input_centroids); clusterer->SetInCentroids(in_centroids); } std::vector< mitk::ClusteringMetric* > metrics; int mc = 0; for (auto m : metric_strings) { float w = boost::lexical_cast(metric_weights.at(mc)); MITK_INFO << "Metric: " << m << " (w=" << w << ")"; if (m=="EU_MEAN") metrics.push_back({new mitk::ClusteringMetricEuclideanMean()}); else if (m=="EU_STD") metrics.push_back({new mitk::ClusteringMetricEuclideanStd()}); else if (m=="EU_MAX") metrics.push_back({new mitk::ClusteringMetricEuclideanMax()}); else if (m=="ANGLES") metrics.push_back({new mitk::ClusteringMetricInnerAngles()}); else if (m=="LENGTH") metrics.push_back({new mitk::ClusteringMetricLength()}); else if (m=="MAP" && scalar_map!="") { mitk::Image::Pointer mitk_map = mitk::IOUtil::Load(scalar_map); if (mitk_map->GetDimension()==3) { FloatImageType::Pointer itk_map = FloatImageType::New(); mitk::CastToItkImage(mitk_map, itk_map); mitk::ClusteringMetricScalarMap* metric = new mitk::ClusteringMetricScalarMap(); metric->SetImages({itk_map}); metric->SetScale(distances.at(0)); metrics.push_back(metric); } } else if (m=="ANAT" && parcellation!="") { mitk::Image::Pointer mitk_map = mitk::IOUtil::Load(parcellation); if (mitk_map->GetDimension()==3) { ShortImageType::Pointer itk_map = ShortImageType::New(); mitk::CastToItkImage(mitk_map, itk_map); mitk::ClusteringMetricAnatomic* metric = new mitk::ClusteringMetricAnatomic(); metric->SetParcellations({itk_map}); metrics.push_back(metric); } } metrics.back()->SetScale(w); mc++; } if (metrics.empty()) { MITK_INFO << "No metric selected!"; return EXIT_FAILURE; } clusterer->SetMetrics(metrics); clusterer->SetMergeDuplicateThreshold(merge_clusters); clusterer->SetNumPoints(fiber_points); clusterer->SetMaxClusters(max_clusters); clusterer->SetMinClusterSize(min_fibers); clusterer->Update(); std::vector tracts = clusterer->GetOutTractograms(); std::vector centroids = clusterer->GetOutCentroids(); MITK_INFO << "Saving clusters"; std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect unsigned int c = 0; for (auto f : tracts) { mitk::IOUtil::Save(f, out_root + "Cluster_" + boost::lexical_cast(c) + file_ending); if (output_centroids) mitk::IOUtil::Save(centroids.at(c), out_root + "Centroid_" + boost::lexical_cast(c) + file_ending); ++c; } std::cout.rdbuf (old); // <-- restore } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberDirectionExtraction.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberDirectionExtraction.cpp index 225c8516d6..e57b84aee0 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberDirectionExtraction.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberDirectionExtraction.cpp @@ -1,175 +1,175 @@ /*=================================================================== 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 /*! \brief Extract principal fiber directions from a tractogram */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Fiber Direction Extraction"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setDescription("Extract principal fiber directions from a tractogram"); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input:", "input tractogram (.fib/.trk)", us::Any(), false); parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output root", us::Any(), false); parser.addArgument("mask", "m", mitkCommandLineParser::InputFile, "Mask:", "mask image"); parser.addArgument("athresh", "a", mitkCommandLineParser::Float, "Angular threshold:", "angular threshold in degrees. closer fiber directions are regarded as one direction and clustered together.", 25, true); parser.addArgument("peakthresh", "t", mitkCommandLineParser::Float, "Peak size threshold:", "peak size threshold relative to largest peak in voxel", 0.2, true); parser.addArgument("verbose", "v", mitkCommandLineParser::Bool, "Verbose:", "output optional and intermediate calculation results"); parser.addArgument("numdirs", "d", mitkCommandLineParser::Int, "Max. num. directions:", "maximum number of fibers per voxel", 3, true); parser.addArgument("normalization", "n", mitkCommandLineParser::Int, "Normalization method:", "1=global maximum, 2=single vector, 3=voxel-wise maximum", 1); parser.addArgument("file_ending", "f", mitkCommandLineParser::String, "Image type:", ".nrrd, .nii, .nii.gz"); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string fibFile = us::any_cast(parsedArgs["input"]); std::string maskImage(""); if (parsedArgs.count("mask")) maskImage = us::any_cast(parsedArgs["mask"]); float peakThreshold = 0.2; if (parsedArgs.count("peakthresh")) peakThreshold = us::any_cast(parsedArgs["peakthresh"]); float angularThreshold = 25; if (parsedArgs.count("athresh")) angularThreshold = us::any_cast(parsedArgs["athresh"]); std::string outRoot = us::any_cast(parsedArgs["out"]); bool verbose = false; if (parsedArgs.count("verbose")) verbose = us::any_cast(parsedArgs["verbose"]); int maxNumDirs = 3; if (parsedArgs.count("numdirs")) maxNumDirs = us::any_cast(parsedArgs["numdirs"]); int normalization = 1; if (parsedArgs.count("normalization")) normalization = us::any_cast(parsedArgs["normalization"]); std::string file_ending = ".nrrd"; if (parsedArgs.count("file_ending")) file_ending = us::any_cast(parsedArgs["file_ending"]); try { typedef itk::Image ItkUcharImgType; // load fiber bundle mitk::FiberBundle::Pointer inputTractogram = mitk::IOUtil::Load(fibFile); // load/create mask image ItkUcharImgType::Pointer itkMaskImage = nullptr; if (maskImage.compare("")!=0) { std::cout << "Using mask image"; itkMaskImage = ItkUcharImgType::New(); mitk::Image::Pointer mitkMaskImage = mitk::IOUtil::Load(maskImage); mitk::CastToItkImage(mitkMaskImage, itkMaskImage); } // extract directions from fiber bundle itk::TractsToVectorImageFilter::Pointer fOdfFilter = itk::TractsToVectorImageFilter::New(); fOdfFilter->SetFiberBundle(inputTractogram); fOdfFilter->SetMaskImage(itkMaskImage); fOdfFilter->SetAngularThreshold(cos(angularThreshold*itk::Math::pi/180)); switch (normalization) { case 1: fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::GLOBAL_MAX); break; case 2: fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::SINGLE_VEC_NORM); break; case 3: fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::MAX_VEC_NORM); break; } fOdfFilter->SetUseWorkingCopy(false); fOdfFilter->SetSizeThreshold(peakThreshold); fOdfFilter->SetMaxNumDirections(maxNumDirs); fOdfFilter->Update(); { itk::TractsToVectorImageFilter::ItkDirectionImageType::Pointer itkImg = fOdfFilter->GetDirectionImage(); typedef itk::ImageFileWriter< itk::TractsToVectorImageFilter::ItkDirectionImageType > WriterType; WriterType::Pointer writer = WriterType::New(); std::string outfilename = outRoot; outfilename.append("_DIRECTIONS"); outfilename.append(file_ending); writer->SetFileName(outfilename.c_str()); writer->SetInput(itkImg); writer->Update(); } if (verbose) { // write num direction image ItkUcharImgType::Pointer numDirImage = fOdfFilter->GetNumDirectionsImage(); typedef itk::ImageFileWriter< ItkUcharImgType > WriterType; WriterType::Pointer writer = WriterType::New(); std::string outfilename = outRoot; outfilename.append("_NUM_DIRECTIONS"); outfilename.append(file_ending); writer->SetFileName(outfilename.c_str()); writer->SetInput(numDirImage); writer->Update(); } } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberExtraction.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberExtraction.cpp index b534839be1..5cad39e703 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberExtraction.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberExtraction.cpp @@ -1,151 +1,151 @@ /*=================================================================== 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 #include #define _USE_MATH_DEFINES #include /*! \brief Extract fibers from a tractogram using planar figure ROIs */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Fiber Extraction"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setContributor("MIC"); parser.setDescription("Extract fibers from a tractogram using planar figure ROIs"); parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", mitkCommandLineParser::String, "Input:", "input tractogram (.fib/.trk)", us::Any(), false); parser.addArgument("out", "o", mitkCommandLineParser::String, "Output:", "output tractogram", us::Any(), false); parser.addArgument("planfirgure1", "pf1", mitkCommandLineParser::String, "Figure 1:", "first planar figure ROI", us::Any(), false); parser.addArgument("planfirgure2", "pf2", mitkCommandLineParser::String, "Figure 2:", "second planar figure ROI", us::Any()); parser.addArgument("operation", "op", mitkCommandLineParser::String, "Operation:", "logical operation (AND, OR, NOT)", us::Any()); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string inFib = us::any_cast(parsedArgs["input"]); std::string outFib = us::any_cast(parsedArgs["out"]); std::string pf1_path = us::any_cast(parsedArgs["planfirgure1"]); std::string operation(""); std::string pf2_path(""); if (parsedArgs.count("operation")) { operation = us::any_cast(parsedArgs["operation"]); if (parsedArgs.count("planfirgure2") && (operation=="AND" || operation=="OR")) pf2_path = us::any_cast(parsedArgs["planfirgure2"]); } try { // load fiber bundle mitk::FiberBundle::Pointer inputTractogram = mitk::IOUtil::Load(inFib); mitk::FiberBundle::Pointer result; mitk::StandaloneDataStorage::Pointer storage = mitk::StandaloneDataStorage::New(); auto data = mitk::IOUtil::Load(pf1_path)[0]; auto input1 = mitk::DataNode::New(); input1->SetData(data); if (input1.IsNotNull()) { mitk::PlanarFigureComposite::Pointer pfc = mitk::PlanarFigureComposite::New(); mitk::DataNode::Pointer pfcNode = mitk::DataNode::New(); pfcNode->SetData(pfc); mitk::DataStorage::SetOfObjects::Pointer set1 = mitk::DataStorage::SetOfObjects::New(); set1->push_back(pfcNode); storage->Add(pfcNode); auto input2 = mitk::DataNode::New(); if (!pf2_path.empty()) { data = mitk::IOUtil::Load(pf2_path)[0]; input2->SetData(data); } if (operation.empty()) { result = inputTractogram->ExtractFiberSubset(input1, nullptr); } else if (operation=="NOT") { pfc->setOperationType(mitk::PlanarFigureComposite::NOT); storage->Add(input1, set1); result = inputTractogram->ExtractFiberSubset(pfcNode, storage); } else if (operation=="AND" && input2.IsNotNull()) { pfc->setOperationType(mitk::PlanarFigureComposite::AND); storage->Add(input1, set1); storage->Add(input2, set1); result = inputTractogram->ExtractFiberSubset(pfcNode, storage); } else if (operation=="OR" && input2.IsNotNull()) { pfc->setOperationType(mitk::PlanarFigureComposite::OR); storage->Add(input1, set1); storage->Add(input2, set1); result = inputTractogram->ExtractFiberSubset(pfcNode, storage); } else { std::cout << "Could not process input:"; std::cout << pf1_path; std::cout << pf2_path; std::cout << operation; } } if (result.IsNotNull()) mitk::IOUtil::Save(result, outFib); else std::cout << "No valid fiber bundle extracted."; } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberExtractionRoi.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberExtractionRoi.cpp index a23ae3e9dc..7c63ae10b0 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberExtractionRoi.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberExtractionRoi.cpp @@ -1,198 +1,198 @@ /*=================================================================== 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 #include #include #include #define _USE_MATH_DEFINES #include typedef itksys::SystemTools ist; typedef itk::Image ItkFloatImgType; ItkFloatImgType::Pointer LoadItkImage(const std::string& filename) { mitk::Image::Pointer img = mitk::IOUtil::Load(filename); ItkFloatImgType::Pointer itk_image = ItkFloatImgType::New(); mitk::CastToItkImage(img, itk_image); return itk_image; } /*! \brief Extract fibers from a tractogram using binary image ROIs */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Fiber Extraction With ROI Image"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setContributor("MIC"); parser.setDescription("Extract fibers from a tractogram using binary image ROIs"); parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", mitkCommandLineParser::String, "Input:", "input tractogram (.fib/.trk/.tck/.dcm)", us::Any(), false); parser.addArgument("out", "o", mitkCommandLineParser::String, "Output:", "output tractogram", us::Any(), false); parser.addArgument("rois", "", mitkCommandLineParser::StringList, "ROI images:", "ROI images", us::Any(), false); parser.addArgument("both_ends", "", mitkCommandLineParser::Bool, "Both ends:", "Fibers are extracted if both endpoints are located in the ROI.", false); parser.addArgument("overlap_fraction", "", mitkCommandLineParser::Float, "Overlap fraction:", "Extract by overlap, not by endpoints. Extract fibers that overlap to at least the provided factor (0-1) with the ROI.", -1); parser.addArgument("invert", "", mitkCommandLineParser::Bool, "Invert:", "get streamlines not positive for any of the ROI images", false); parser.addArgument("interpolate", "", mitkCommandLineParser::Bool, "Interpolate:", "interpolate ROI images", false); parser.addArgument("threshold", "", mitkCommandLineParser::Float, "Threshold:", "positive means ROI image value threshold", 0.5); parser.addArgument("labels", "", mitkCommandLineParser::StringList, "Labels:", "positive means roi image value in labels vector", false); parser.addArgument("split_labels", "", mitkCommandLineParser::Bool, "Split labels:", "output a separate tractogram for each label-->label tract", false); parser.addArgument("skip_self_connections", "", mitkCommandLineParser::Bool, "Skip self connections:", "ignore streamlines between two identical labels", false); parser.addArgument("min_fibers", "", mitkCommandLineParser::Int, "Min. num. fibers:", "discard positive tracts with less fibers", 0); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string inFib = us::any_cast(parsedArgs["input"]); std::string outFib = us::any_cast(parsedArgs["out"]); mitkCommandLineParser::StringContainerType roi_files = us::any_cast(parsedArgs["rois"]); bool both_ends = false; if (parsedArgs.count("both_ends")) both_ends = us::any_cast(parsedArgs["both_ends"]); bool invert = false; if (parsedArgs.count("invert")) invert = us::any_cast(parsedArgs["invert"]); unsigned int min_fibers = 0; if (parsedArgs.count("min_fibers")) min_fibers = us::any_cast(parsedArgs["min_fibers"]); bool split_labels = false; if (parsedArgs.count("split_labels")) split_labels = us::any_cast(parsedArgs["split_labels"]); bool skip_self_connections = false; if (parsedArgs.count("skip_self_connections")) skip_self_connections = us::any_cast(parsedArgs["skip_self_connections"]); float overlap_fraction = -1; if (parsedArgs.count("overlap_fraction")) overlap_fraction = us::any_cast(parsedArgs["overlap_fraction"]); bool any_point = false; if (overlap_fraction>=0) any_point = true; bool interpolate = false; if (parsedArgs.count("interpolate")) interpolate = us::any_cast(parsedArgs["interpolate"]); float threshold = 0.5; if (parsedArgs.count("threshold")) threshold = us::any_cast(parsedArgs["threshold"]); mitkCommandLineParser::StringContainerType labels; if (parsedArgs.count("labels")) labels = us::any_cast(parsedArgs["labels"]); try { // load fiber bundle mitk::FiberBundle::Pointer inputTractogram = mitk::IOUtil::Load(inFib); std::vector< ItkFloatImgType::Pointer > roi_images; for (std::size_t i=0; i roi_images2; for (auto roi : roi_images) roi_images2.push_back(roi); std::vector< unsigned short > short_labels; for (auto l : labels) short_labels.push_back(boost::lexical_cast(l)); itk::FiberExtractionFilter::Pointer extractor = itk::FiberExtractionFilter::New(); extractor->SetInputFiberBundle(inputTractogram); extractor->SetRoiImages(roi_images2); extractor->SetOverlapFraction(overlap_fraction); extractor->SetBothEnds(both_ends); extractor->SetInterpolate(interpolate); extractor->SetThreshold(threshold); extractor->SetLabels(short_labels); extractor->SetSplitLabels(split_labels); extractor->SetMinFibersPerTract(min_fibers); extractor->SetSkipSelfConnections(skip_self_connections); if (invert) extractor->SetNoPositives(true); else extractor->SetNoNegatives(true); if (!any_point) extractor->SetMode(itk::FiberExtractionFilter::MODE::ENDPOINTS); if (short_labels.size()>0) extractor->SetInputType(itk::FiberExtractionFilter::INPUT::LABEL_MAP); extractor->Update(); mitk::FiberBundle::Pointer newFib = mitk::FiberBundle::New(nullptr); if (invert) mitk::IOUtil::Save(extractor->GetNegatives().at(0), outFib); else { if (!split_labels) { newFib = newFib->AddBundles(extractor->GetPositives()); mitk::IOUtil::Save(newFib, outFib); } else { int c = 0; std::vector< std::pair< unsigned int, unsigned int > > positive_labels = extractor->GetPositiveLabels(); for (auto fib : extractor->GetPositives()) { std::pair< unsigned int, unsigned int > l = positive_labels.at(c); mitk::IOUtil::Save(fib, outFib + "_" + boost::lexical_cast(l.first) + "-" + boost::lexical_cast(l.second) + ".trk"); ++c; } } } } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberJoin.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberJoin.cpp index 62f5da6516..c7bce4f46f 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberJoin.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberJoin.cpp @@ -1,100 +1,100 @@ /*=================================================================== 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 "mitkCommandLineParser.h" #include #include -#include +#include #include #include #include #include #define _USE_MATH_DEFINES #include mitk::FiberBundle::Pointer LoadFib(std::string filename) { std::vector fibInfile = mitk::IOUtil::Load(filename); if( fibInfile.empty() ) std::cout << "File " << filename << " could not be read!"; mitk::BaseData::Pointer baseData = fibInfile.at(0); return dynamic_cast(baseData.GetPointer()); } /*! \brief Join multiple tractograms */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Fiber Join"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setContributor("MIC"); parser.setDescription("Join multiple tractograms"); parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", mitkCommandLineParser::StringList, "Input:", "input tractograms", us::Any(), false); parser.addArgument("out", "o", mitkCommandLineParser::String, "Output:", "output tractogram", us::Any(), false); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; mitkCommandLineParser::StringContainerType inFibs = us::any_cast(parsedArgs["input"]); std::string outFib = us::any_cast(parsedArgs["out"]); if (inFibs.size()<=1) { std::cout << "More than one input tractogram required!"; return EXIT_FAILURE; } try { std::vector< mitk::FiberBundle::Pointer > tractograms; mitk::FiberBundle::Pointer result = LoadFib(inFibs.at(0)); for (std::size_t i=1; iAddBundles(tractograms); mitk::IOUtil::Save(result, outFib); } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberProcessing.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberProcessing.cpp index 6b18065250..77e5da6ecc 100644 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberProcessing.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/FiberProcessing.cpp @@ -1,246 +1,246 @@ /*=================================================================== 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 "mitkCommandLineParser.h" -#include +#include #include #include #include mitk::FiberBundle::Pointer LoadFib(std::string filename) { std::vector fibInfile = mitk::IOUtil::Load(filename); if( fibInfile.empty() ) std::cout << "File " << filename << " could not be read!"; mitk::BaseData::Pointer baseData = fibInfile.at(0); return dynamic_cast(baseData.GetPointer()); } /*! \brief Modify input tractogram: fiber resampling, compression, pruning and transformation. */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Fiber Processing"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setDescription("Modify input tractogram: fiber resampling, compression, pruning and transformation."); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.beginGroup("1. Mandatory arguments:"); parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input:", "Input fiber bundle (.fib, .trk, .tck)", us::Any(), false); parser.addArgument("outFile", "o", mitkCommandLineParser::OutputFile, "Output:", "Output fiber bundle (.fib, .trk)", us::Any(), false); parser.endGroup(); parser.beginGroup("2. Resampling:"); parser.addArgument("spline_resampling", "", mitkCommandLineParser::Float, "Spline resampling:", "Resample fiber using splines with the given point distance (in mm)"); parser.addArgument("linear_resampling", "", mitkCommandLineParser::Float, "Linear resampling:", "Resample fiber linearly with the given point distance (in mm)"); parser.addArgument("num_resampling", "", mitkCommandLineParser::Int, "Num. fiber points resampling:", "Resample all fibers to the given number of points"); parser.addArgument("compress", "", mitkCommandLineParser::Float, "Compress:", "Compress fiber using the given error threshold (in mm)"); parser.endGroup(); parser.beginGroup("3. Filtering:"); parser.addArgument("min_length", "", mitkCommandLineParser::Float, "Minimum length:", "Minimum fiber length (in mm)"); parser.addArgument("max_length", "", mitkCommandLineParser::Float, "Maximum length:", "Maximum fiber length (in mm)"); parser.addArgument("max_angle", "", mitkCommandLineParser::Float, "Maximum angle:", "Maximum angular STDEV over 1cm (in degree)"); parser.addArgument("remove", "", mitkCommandLineParser::Bool, "Remove fibers exceeding curvature threshold:", "If false, only the high curvature parts are removed"); parser.endGroup(); parser.beginGroup("4. Transformation:"); parser.addArgument("mirror", "", mitkCommandLineParser::Int, "Invert coordinates:", "Invert fiber coordinates XYZ (e.g. 010 to invert y-coordinate of each fiber point)"); parser.addArgument("rotate_x", "", mitkCommandLineParser::Float, "Rotate x-axis:", "Rotate around x-axis (in deg)"); parser.addArgument("rotate_y", "", mitkCommandLineParser::Float, "Rotate y-axis:", "Rotate around y-axis (in deg)"); parser.addArgument("rotate_z", "", mitkCommandLineParser::Float, "Rotate z-axis:", "Rotate around z-axis (in deg)"); parser.addArgument("scale_x", "", mitkCommandLineParser::Float, "Scale x-axis:", "Scale in direction of x-axis"); parser.addArgument("scale_y", "", mitkCommandLineParser::Float, "Scale y-axis:", "Scale in direction of y-axis"); parser.addArgument("scale_z", "", mitkCommandLineParser::Float, "Scale z-axis", "Scale in direction of z-axis"); parser.addArgument("translate_x", "", mitkCommandLineParser::Float, "Translate x-axis:", "Translate in direction of x-axis (in mm)"); parser.addArgument("translate_y", "", mitkCommandLineParser::Float, "Translate y-axis:", "Translate in direction of y-axis (in mm)"); parser.addArgument("translate_z", "", mitkCommandLineParser::Float, "Translate z-axis:", "Translate in direction of z-axis (in mm)"); parser.endGroup(); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; bool remove = false; if (parsedArgs.count("remove")) remove = us::any_cast(parsedArgs["remove"]); float spline_resampling = -1; if (parsedArgs.count("spline_resampling")) spline_resampling = us::any_cast(parsedArgs["spline_resampling"]); float linear_resampling = -1; if (parsedArgs.count("linear_resampling")) linear_resampling = us::any_cast(parsedArgs["linear_resampling"]); int num_resampling = -1; if (parsedArgs.count("num_resampling")) num_resampling = us::any_cast(parsedArgs["num_resampling"]); float compress = -1; if (parsedArgs.count("compress")) compress = us::any_cast(parsedArgs["compress"]); float minFiberLength = -1; if (parsedArgs.count("min_length")) minFiberLength = us::any_cast(parsedArgs["min_length"]); float maxFiberLength = -1; if (parsedArgs.count("max_length")) maxFiberLength = us::any_cast(parsedArgs["max_length"]); float maxAngularDev = -1; if (parsedArgs.count("max_angle")) maxAngularDev = us::any_cast(parsedArgs["max_angle"]); int axis = 0; if (parsedArgs.count("mirror")) axis = us::any_cast(parsedArgs["mirror"]); float rotateX = 0; if (parsedArgs.count("rotate_x")) rotateX = us::any_cast(parsedArgs["rotate_x"]); float rotateY = 0; if (parsedArgs.count("rotate_y")) rotateY = us::any_cast(parsedArgs["rotate_y"]); float rotateZ = 0; if (parsedArgs.count("rotate_z")) rotateZ = us::any_cast(parsedArgs["rotate_z"]); float scaleX = 0; if (parsedArgs.count("scale_x")) scaleX = us::any_cast(parsedArgs["scale_x"]); float scaleY = 0; if (parsedArgs.count("scale_y")) scaleY = us::any_cast(parsedArgs["scale_y"]); float scaleZ = 0; if (parsedArgs.count("scale_z")) scaleZ = us::any_cast(parsedArgs["scale_z"]); float translateX = 0; if (parsedArgs.count("translate_x")) translateX = us::any_cast(parsedArgs["translate_x"]); float translateY = 0; if (parsedArgs.count("translate_y")) translateY = us::any_cast(parsedArgs["translate_y"]); float translateZ = 0; if (parsedArgs.count("translate_z")) translateZ = us::any_cast(parsedArgs["translate_z"]); std::string inFileName = us::any_cast(parsedArgs["input"]); std::string outFileName = us::any_cast(parsedArgs["outFile"]); try { mitk::FiberBundle::Pointer fib = LoadFib(inFileName); if (maxAngularDev>0) { auto filter = itk::FiberCurvatureFilter::New(); filter->SetInputFiberBundle(fib); filter->SetAngularDeviation(maxAngularDev); filter->SetDistance(10); filter->SetRemoveFibers(remove); filter->Update(); fib = filter->GetOutputFiberBundle(); } if (minFiberLength>0) fib->RemoveShortFibers(minFiberLength); if (maxFiberLength>0) fib->RemoveLongFibers(maxFiberLength); if (spline_resampling>0) fib->ResampleSpline(spline_resampling); if (linear_resampling>0) fib->ResampleLinear(linear_resampling); if (num_resampling>0) fib->ResampleToNumPoints(num_resampling); if (compress>0) fib->Compress(compress); if (axis/100==1) fib->MirrorFibers(0); if ((axis%100)/10==1) fib->MirrorFibers(1); if (axis%10==1) fib->MirrorFibers(2); if (rotateX > 0 || rotateY > 0 || rotateZ > 0){ std::cout << "Rotate " << rotateX << " " << rotateY << " " << rotateZ; fib->RotateAroundAxis(rotateX, rotateY, rotateZ); } if (translateX > 0 || translateY > 0 || translateZ > 0){ fib->TranslateFibers(translateX, translateY, translateZ); } if (scaleX > 0 || scaleY > 0 || scaleZ > 0) fib->ScaleFibers(scaleX, scaleY, scaleZ); mitk::IOUtil::Save(fib.GetPointer(), outFileName ); } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/GetOverlappingTracts.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/GetOverlappingTracts.cpp index 33bbaaafb4..9fe96b6b7e 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/GetOverlappingTracts.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/GetOverlappingTracts.cpp @@ -1,173 +1,173 @@ /*=================================================================== 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 #define _USE_MATH_DEFINES #include typedef itksys::SystemTools ist; typedef itk::Image ItkFloatImgType; /*! \brief Extract fibers from a tractogram using binary image ROIs */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Get Overlapping Tracts"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setContributor("MIC"); parser.setDescription("Find tracts that overlap with the reference masks or tracts"); parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", mitkCommandLineParser::StringList, "Input:", "input tractograms (.fib/.trk/.tck/.dcm)", us::Any(), false); parser.addArgument("reference", "r", mitkCommandLineParser::StringList, "Reference:", "reference tractograms or mask images", us::Any(), false); parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output Folder:", "move input tracts that do/don't overlap here", us::Any(), false); parser.addArgument("overlap_fraction", "", mitkCommandLineParser::Float, "Overlap fraction:", "", 0.9); parser.addArgument("use_any_overlap", "", mitkCommandLineParser::Bool, "Use any overlap:", "Don't find maximum overlap but use first overlap larger threshold"); parser.addArgument("dont_save_tracts", "", mitkCommandLineParser::Bool, "Don't save tracts:", "if true, only text files documenting the overlaps are saved and no tract files are copied"); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; mitkCommandLineParser::StringContainerType input = us::any_cast(parsedArgs["input"]); mitkCommandLineParser::StringContainerType reference = us::any_cast(parsedArgs["reference"]); std::string out_folder = us::any_cast(parsedArgs["out"]); bool use_any_overlap = false; if (parsedArgs.count("use_any_overlap")) use_any_overlap = us::any_cast(parsedArgs["use_any_overlap"]); bool dont_save_tracts = false; if (parsedArgs.count("dont_save_tracts")) dont_save_tracts = us::any_cast(parsedArgs["dont_save_tracts"]); float overlap_threshold = 0.9; if (parsedArgs.count("overlap_fraction")) overlap_threshold = us::any_cast(parsedArgs["overlap_fraction"]); try { itk::TractDensityImageFilter< ItkFloatImgType >::Pointer filter = itk::TractDensityImageFilter< ItkFloatImgType >::New(); filter->SetDoFiberResampling(true); filter->SetUpsamplingFactor(0.25); filter->SetBinaryOutput(true); MITK_INFO << "Loading references"; std::vector< ItkFloatImgType::Pointer > masks; for (auto f : reference) { MITK_INFO << f; std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect mitk::FiberBundle::Pointer fib = mitk::IOUtil::Load(f); if (fib.IsNotNull()) { filter->SetFiberBundle(fib); filter->Update(); masks.push_back(filter->GetOutput()); } else { mitk::Image::Pointer m = mitk::IOUtil::Load(f); ItkFloatImgType::Pointer itkImage = ItkFloatImgType::New(); CastToItkImage(m, itkImage); masks.push_back(itkImage); } std::cout.rdbuf (old); // <-- restore } MITK_INFO << "Finding overlaps"; ofstream logfile; logfile.open (out_folder + "Overlaps.txt"); ofstream logfile2; logfile2.open (out_folder + "AllOverlaps.txt"); boost::progress_display disp(input.size()); for (auto f : input) { ++disp; std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect bool is_overlapping = false; mitk::FiberBundle::Pointer fib = mitk::IOUtil::Load(f); fib->ResampleLinear(2); float overlap = 0; float max_overlap = 0; std::string max_ref = "-"; int i = 0; std::string overlap_string = ist::GetFilenameWithoutExtension(f); for (auto m : masks) { overlap = fib->GetOverlap(m, false); if (overlap>max_overlap) { max_overlap = overlap; max_ref = ist::GetFilenameWithoutExtension(reference.at(i)); } if (use_any_overlap && overlap>=overlap_threshold) break; overlap_string += " " + ist::GetFilenameWithoutExtension(reference.at(i)) + " " + boost::lexical_cast(overlap); ++i; } if (overlap>=overlap_threshold) is_overlapping = true; logfile << ist::GetFilenameWithoutExtension(f) << " - " << max_ref << ": " << boost::lexical_cast(max_overlap) << "\n"; logfile2 << overlap_string << "\n"; if (!dont_save_tracts && is_overlapping) ist::CopyAFile(f, out_folder + ist::GetFilenameName(f)); std::cout.rdbuf (old); // <-- restore } logfile.close(); logfile2.close(); } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/Sift2WeightCopy.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/Sift2WeightCopy.cpp index 18c6358ef8..2dd38fb7e8 100644 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/Sift2WeightCopy.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/Sift2WeightCopy.cpp @@ -1,108 +1,108 @@ /*=================================================================== 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 "mitkCommandLineParser.h" -#include +#include #include #include #include #include mitk::FiberBundle::Pointer LoadFib(std::string filename) { std::vector fibInfile = mitk::IOUtil::Load(filename); if( fibInfile.empty() ) std::cout << "File " << filename << " could not be read!"; mitk::BaseData::Pointer baseData = fibInfile.at(0); return dynamic_cast(baseData.GetPointer()); } /*! \brief Import Sift2 Fiber Weights txt file. */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("SIFT2 Fiber Weight Import"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setDescription("Import SIFT2 fiber weights."); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", mitkCommandLineParser::String, "Input:", "input fiber bundle", us::Any(), false); parser.addArgument("weights", "w", mitkCommandLineParser::String, "Weights:", "input weights file (.txt)", us::Any(), false); parser.addArgument("output", "o", mitkCommandLineParser::String, "Output:", "output fiber bundle (.fib)", 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"]); std::string weightsFileName = us::any_cast(parsedArgs["weights"]); std::string outFileName = us::any_cast(parsedArgs["output"]); try { mitk::FiberBundle::Pointer fib = LoadFib(inFileName); std::ifstream fin; fin.open(weightsFileName); if (!fin.good()) return 1; // exit if file not found std::vector weights; for (float d; fin >> d; ) { weights.push_back(d); } for(std::size_t i = 0; i != weights.size(); i++) { fib->SetFiberWeight(i, weights[i]); } mitk::IOUtil::Save(fib.GetPointer(), outFileName ); } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensity.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensity.cpp index 13098ed6b0..ead6ac999d 100644 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensity.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensity.cpp @@ -1,215 +1,215 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include #include #include #include "mitkCommandLineParser.h" -#include +#include #include #include #include #include mitk::FiberBundle::Pointer LoadFib(std::string filename) { std::vector fibInfile = mitk::IOUtil::Load(filename); if( fibInfile.empty() ) std::cout << "File " << filename << " could not be read!"; mitk::BaseData::Pointer baseData = fibInfile.at(0); return dynamic_cast(baseData.GetPointer()); } /*! \brief Modify input tractogram: fiber resampling, compression, pruning and transformation. */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Tract Density"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setDescription("Generate tract density image, fiber envelope or fiber endpoints image."); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", mitkCommandLineParser::String, "Input:", "input fiber bundle (.fib)", us::Any(), false); parser.addArgument("output", "o", mitkCommandLineParser::String, "Output:", "output image", us::Any(), false); parser.addArgument("binary", "", mitkCommandLineParser::Bool, "Binary output:", "calculate binary tract envelope", us::Any()); parser.addArgument("normalize", "", mitkCommandLineParser::Bool, "Normalized output:", "normalize output to 0-1", us::Any()); parser.addArgument("endpoints", "", mitkCommandLineParser::Bool, "Output endpoints image:", "calculate image of fiber endpoints instead of mask", us::Any()); parser.addArgument("reference_image", "", mitkCommandLineParser::String, "Reference image:", "output image will have geometry of this reference image", us::Any()); parser.addArgument("upsampling", "", mitkCommandLineParser::Float, "Upsampling:", "upsampling", 1.0); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; bool binary = false; if (parsedArgs.count("binary")) binary = us::any_cast(parsedArgs["binary"]); bool endpoints = false; if (parsedArgs.count("endpoints")) endpoints = us::any_cast(parsedArgs["endpoints"]); bool normalize = false; if (parsedArgs.count("normalize")) normalize = us::any_cast(parsedArgs["normalize"]); float upsampling = 1.0; if (parsedArgs.count("upsampling")) upsampling = us::any_cast(parsedArgs["upsampling"]); MITK_INFO << "Upsampling: " << upsampling; std::string reference_image = ""; if (parsedArgs.count("reference_image")) reference_image = us::any_cast(parsedArgs["reference_image"]); std::string inFileName = us::any_cast(parsedArgs["input"]); std::string outFileName = us::any_cast(parsedArgs["output"]); try { mitk::FiberBundle::Pointer fib = LoadFib(inFileName); mitk::Image::Pointer ref_img; if (!reference_image.empty()) ref_img = mitk::IOUtil::Load(reference_image); if (endpoints) { typedef unsigned int OutPixType; typedef itk::Image OutImageType; typedef itk::TractsToFiberEndingsImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(upsampling); if (ref_img.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(ref_img, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); mitk::IOUtil::Save(img, outFileName ); } else if (binary) { typedef unsigned char OutPixType; typedef itk::Image OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetOutputAbsoluteValues(!normalize); generator->SetWorkOnFiberCopy(false); generator->SetUpsamplingFactor(upsampling); if (ref_img.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(ref_img, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); mitk::IOUtil::Save(img, outFileName ); } else { typedef float OutPixType; typedef itk::Image OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetOutputAbsoluteValues(!normalize); generator->SetWorkOnFiberCopy(false); generator->SetUpsamplingFactor(upsampling); if (ref_img.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(ref_img, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); mitk::IOUtil::Save(img, outFileName ); } } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensityFilter.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensityFilter.cpp index a71cd7d507..1f789fe9ce 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensityFilter.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/FiberProcessing/TractDensityFilter.cpp @@ -1,111 +1,111 @@ /*=================================================================== 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 #define _USE_MATH_DEFINES #include typedef itksys::SystemTools ist; typedef itk::Image ItkFloatImgType; /*! \brief Extract fibers from a tractogram using binary image ROIs */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Filter Outliers by Tract Density"); parser.setCategory("Fiber Tracking and Processing Methods"); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", mitkCommandLineParser::String, "Input:", "input tractogram (.fib/.trk/.tck/.dcm)", us::Any(), false); parser.addArgument("out", "o", mitkCommandLineParser::String, "Output:", "output tractogram", us::Any(), false); parser.addArgument("threshold", "", mitkCommandLineParser::Float, "Threshold:", "positive means ROI image value threshold", 0.05); parser.addArgument("overlap", "", mitkCommandLineParser::Float, "Overlap:", "positive means ROI image value threshold", 0.5); parser.addArgument("min_fibers", "", mitkCommandLineParser::Int, "Min. num. fibers:", "discard positive tracts with less fibers", 0); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string inFib = us::any_cast(parsedArgs["input"]); std::string outFib = us::any_cast(parsedArgs["out"]); int min_fibers = 0; if (parsedArgs.count("min_fibers")) min_fibers = us::any_cast(parsedArgs["min_fibers"]); float overlap = 0.5; if (parsedArgs.count("overlap")) overlap = us::any_cast(parsedArgs["overlap"]); float threshold = 0.05; if (parsedArgs.count("threshold")) threshold = us::any_cast(parsedArgs["threshold"]); try { mitk::FiberBundle::Pointer inputTractogram = mitk::IOUtil::Load(inFib); itk::TractDensityImageFilter< ItkFloatImgType >::Pointer generator = itk::TractDensityImageFilter< ItkFloatImgType >::New(); generator->SetFiberBundle(inputTractogram); generator->SetBinaryOutput(false); generator->SetOutputAbsoluteValues(false); generator->SetWorkOnFiberCopy(true); generator->Update(); itk::FiberExtractionFilter::Pointer extractor = itk::FiberExtractionFilter::New(); extractor->SetRoiImages({generator->GetOutput()}); extractor->SetInputFiberBundle(inputTractogram); extractor->SetOverlapFraction(overlap); extractor->SetInterpolate(true); extractor->SetThreshold(threshold); extractor->SetNoNegatives(true); extractor->Update(); if (extractor->GetPositives().at(0)->GetNumFibers()>=min_fibers) mitk::IOUtil::Save(extractor->GetPositives().at(0), outFib); } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/Fiberfox/Fiberfox.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/Fiberfox/Fiberfox.cpp index 037c650768..46664b3d4e 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/Fiberfox/Fiberfox.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/Fiberfox/Fiberfox.cpp @@ -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. ===================================================================*/ #include #include #include #include #include #include #include #include "mitkCommandLineParser.h" #include -#include +#include #include #include #include using namespace mitk; /*! * \brief Command line interface to Fiberfox. * Simulate a diffusion-weighted image from a tractogram using the specified parameter file. */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Fiberfox"); parser.setCategory("Diffusion Simulation Tools"); parser.setContributor("MIC"); parser.setDescription("Command line interface to Fiberfox." " Simulate a diffusion-weighted image from a tractogram using the specified parameter file."); parser.setArgumentPrefix("--", "-"); parser.addArgument("out", "o", mitkCommandLineParser::OutputFile, "Output root:", "output root", us::Any(), false); parser.addArgument("parameters", "p", mitkCommandLineParser::InputFile, "Parameter file:", "fiberfox parameter file (.ffp)", us::Any(), false); parser.addArgument("input", "i", mitkCommandLineParser::String, "Input:", "Input tractogram or diffusion-weighted image.", us::Any(), false); parser.addArgument("template", "t", mitkCommandLineParser::String, "Template image:", "Use parameters of the template diffusion-weighted image.", us::Any()); parser.addArgument("verbose", "v", mitkCommandLineParser::Bool, "Output additional images:", "output volume fraction images etc.", us::Any()); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) { return EXIT_FAILURE; } std::string outName = us::any_cast(parsedArgs["out"]); std::string paramName = us::any_cast(parsedArgs["parameters"]); std::string input=""; if (parsedArgs.count("input")) { input = us::any_cast(parsedArgs["input"]); } bool verbose = false; if (parsedArgs.count("verbose")) verbose = us::any_cast(parsedArgs["verbose"]); FiberfoxParameters parameters; parameters.LoadParameters(paramName); // Test if /path/dir is an existing directory: std::string file_extension = ""; if( itksys::SystemTools::FileIsDirectory( outName ) ) { while( *(--(outName.cend())) == '/') { outName.pop_back(); } outName = outName + '/'; parameters.m_Misc.m_OutputPath = outName; outName = outName + parameters.m_Misc.m_OutputPrefix; // using default m_OutputPrefix as initialized. } else { // outName is NOT an existing directory, so we need to remove all trailing slashes: while( *(--(outName.cend())) == '/') { outName.pop_back(); } // now split up the given outName into directory and (prefix of) filename: if( ! itksys::SystemTools::GetFilenamePath( outName ).empty() && itksys::SystemTools::FileIsDirectory(itksys::SystemTools::GetFilenamePath( outName ) ) ) { parameters.m_Misc.m_OutputPath = itksys::SystemTools::GetFilenamePath( outName ) + '/'; } else { parameters.m_Misc.m_OutputPath = itksys::SystemTools::GetCurrentWorkingDirectory() + '/'; } file_extension = itksys::SystemTools::GetFilenameExtension(outName); if( ! itksys::SystemTools::GetFilenameWithoutExtension( outName ).empty() ) { parameters.m_Misc.m_OutputPrefix = itksys::SystemTools::GetFilenameWithoutExtension( outName ); } else { parameters.m_Misc.m_OutputPrefix = "fiberfox"; } outName = parameters.m_Misc.m_OutputPath + parameters.m_Misc.m_OutputPrefix; } // check if log file already exists and avoid overwriting existing files: std::string NameTest = outName; int c = 0; while( itksys::SystemTools::FileExists( outName + ".log" ) && c <= std::numeric_limits::max() ) { outName = NameTest + "_" + boost::lexical_cast(c); ++c; } mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Diffusion Weighted Images", "Fiberbundles"}, {}); mitk::BaseData::Pointer inputData = mitk::IOUtil::Load(input, &functor)[0]; itk::TractsToDWIImageFilter< short >::Pointer tractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New(); if ( dynamic_cast(inputData.GetPointer()) ) // simulate dataset from fibers { tractsToDwiFilter->SetFiberBundle(dynamic_cast(inputData.GetPointer())); if (parsedArgs.count("template")) { MITK_INFO << "Loading template image"; typedef itk::VectorImage< short, 3 > ItkDwiType; mitk::BaseData::Pointer templateData = mitk::IOUtil::Load(us::any_cast(parsedArgs["template"]), &functor)[0]; mitk::Image::Pointer dwi = dynamic_cast(templateData.GetPointer()); ItkDwiType::Pointer itkVectorImagePointer = mitk::DiffusionPropertyHelper::GetItkVectorImage(dwi); parameters.m_SignalGen.m_ImageRegion = itkVectorImagePointer->GetLargestPossibleRegion(); parameters.m_SignalGen.m_ImageSpacing = itkVectorImagePointer->GetSpacing(); parameters.m_SignalGen.m_ImageOrigin = itkVectorImagePointer->GetOrigin(); parameters.m_SignalGen.m_ImageDirection = itkVectorImagePointer->GetDirection(); parameters.SetBvalue(static_cast(dwi->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue()); parameters.SetGradienDirections(static_cast( dwi->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer()); } } else if ( dynamic_cast(inputData.GetPointer()) ) // add artifacts to existing image { typedef itk::VectorImage< short, 3 > ItkDwiType; mitk::Image::Pointer diffImg = dynamic_cast(inputData.GetPointer()); ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(diffImg, itkVectorImagePointer); parameters.m_SignalGen.m_SignalScale = 1; parameters.m_SignalGen.m_ImageRegion = itkVectorImagePointer->GetLargestPossibleRegion(); parameters.m_SignalGen.m_ImageSpacing = itkVectorImagePointer->GetSpacing(); parameters.m_SignalGen.m_ImageOrigin = itkVectorImagePointer->GetOrigin(); parameters.m_SignalGen.m_ImageDirection = itkVectorImagePointer->GetDirection(); parameters.SetBvalue(static_cast (diffImg->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue()); parameters.SetGradienDirections( static_cast ( diffImg->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); tractsToDwiFilter->SetInputImage(itkVectorImagePointer); } if (verbose) { MITK_DEBUG << outName << ".ffp"; parameters.SaveParameters(outName+".ffp"); } tractsToDwiFilter->SetParameters(parameters); tractsToDwiFilter->Update(); mitk::Image::Pointer image = mitk::GrabItkImageMemory( tractsToDwiFilter->GetOutput() ); image->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( parameters.m_SignalGen.GetGradientDirections() ) ); image->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( parameters.m_SignalGen.GetBvalue() ) ); mitk::DiffusionPropertyHelper propertyHelper( image ); propertyHelper.InitializeImage(); if (file_extension=="") mitk::IOUtil::Save(image, "application/vnd.mitk.nii.gz", outName+".nii.gz"); else if (file_extension==".nii" || file_extension==".nii.gz") mitk::IOUtil::Save(image, "application/vnd.mitk.nii.gz", outName+file_extension); else mitk::IOUtil::Save(image, outName+file_extension); if (verbose) { std::vector< itk::TractsToDWIImageFilter< short >::ItkDoubleImgType::Pointer > volumeFractions = tractsToDwiFilter->GetVolumeFractions(); for (unsigned int k=0; kInitializeByItk(volumeFractions.at(k).GetPointer()); image->SetVolume(volumeFractions.at(k)->GetBufferPointer()); mitk::IOUtil::Save(image, outName+"_Compartment"+boost::lexical_cast(k+1)+".nii.gz"); } if (tractsToDwiFilter->GetPhaseImage().IsNotNull()) { mitk::Image::Pointer image = mitk::Image::New(); itk::TractsToDWIImageFilter< short >::DoubleDwiType::Pointer itkPhase = tractsToDwiFilter->GetPhaseImage(); image = mitk::GrabItkImageMemory( itkPhase.GetPointer() ); mitk::IOUtil::Save(image, outName+"_Phase.nii.gz"); } if (tractsToDwiFilter->GetKspaceImage().IsNotNull()) { mitk::Image::Pointer image = mitk::Image::New(); itk::TractsToDWIImageFilter< short >::DoubleDwiType::Pointer itkImage = tractsToDwiFilter->GetKspaceImage(); image = mitk::GrabItkImageMemory( itkImage.GetPointer() ); mitk::IOUtil::Save(image, outName+"_kSpace.nii.gz"); } int c = 1; std::vector< itk::TractsToDWIImageFilter< short >::DoubleDwiType::Pointer > output_real = tractsToDwiFilter->GetOutputImagesReal(); for (auto real : output_real) { mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk(real.GetPointer()); image->SetVolume(real->GetBufferPointer()); mitk::IOUtil::Save(image, outName+"_Coil-"+boost::lexical_cast(c)+"-real.nii.gz"); ++c; } c = 1; std::vector< itk::TractsToDWIImageFilter< short >::DoubleDwiType::Pointer > output_imag = tractsToDwiFilter->GetOutputImagesImag(); for (auto imag : output_imag) { mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk(imag.GetPointer()); image->SetVolume(imag->GetBufferPointer()); mitk::IOUtil::Save(image, outName+"_Coil-"+boost::lexical_cast(c)+"-imag.nii.gz"); ++c; } } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/Fiberfox/FiberfoxOptimization.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/Fiberfox/FiberfoxOptimization.cpp index 66c83ba95c..070cf357b2 100644 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/Fiberfox/FiberfoxOptimization.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/Fiberfox/FiberfoxOptimization.cpp @@ -1,831 +1,831 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #include #include #include #include #include #include #include #include #include "mitkCommandLineParser.h" #include -#include +#include #include #include #include #include #include #include #include #include #include #include using namespace mitk; double CalcErrorSignal(const std::vector& histo_mod, itk::VectorImage< short, 3 >* reference, itk::VectorImage< short, 3 >* simulation, itk::Image< unsigned char,3 >::Pointer mask, itk::Image< double,3 >::Pointer fa) { typedef itk::Image< double, 3 > DoubleImageType; typedef itk::VectorImage< short, 3 > DwiImageType; if (fa.IsNotNull()) { itk::ImageRegionIterator< DwiImageType > it1(reference, reference->GetLargestPossibleRegion()); itk::ImageRegionIterator< DwiImageType > it2(simulation, simulation->GetLargestPossibleRegion()); itk::ImageRegionConstIterator< DoubleImageType > it3(fa, fa->GetLargestPossibleRegion()); unsigned int count = 0; double error = 0; while(!it1.IsAtEnd()) { if (mask.IsNull() || (mask.IsNotNull() && mask->GetLargestPossibleRegion().IsInside(it1.GetIndex()) && mask->GetPixel(it1.GetIndex())>0) ) { double fa = it3.Get(); if (fa>0) { double mod = 1.0; for (int i=histo_mod.size()-1; i>=0; --i) if (fa >= (double)i/histo_mod.size()) { mod = histo_mod.at(i); break; } for (unsigned int i=0; iGetVectorLength(); ++i) { if (it1.Get()[i]>0) { double diff = (double)it2.Get()[i]/it1.Get()[i] - 1.0; error += std::pow(mod, 4) * fabs(diff); count++; } } } } ++it1; ++it2; ++it3; } return error/count; } else { itk::ImageRegionIterator< DwiImageType > it1(reference, reference->GetLargestPossibleRegion()); itk::ImageRegionIterator< DwiImageType > it2(simulation, simulation->GetLargestPossibleRegion()); unsigned int count = 0; double error = 0; while(!it1.IsAtEnd()) { if (mask.IsNull() || (mask.IsNotNull() && mask->GetLargestPossibleRegion().IsInside(it1.GetIndex()) && mask->GetPixel(it1.GetIndex())>0) ) { for (unsigned int i=0; iGetVectorLength(); ++i) { if (it1.Get()[i]>0) { double diff = (double)it2.Get()[i]/it1.Get()[i] - 1.0; error += fabs(diff); count++; } } } ++it1; ++it2; } return error/count; } return -1; } double CalcErrorFA(const std::vector& histo_mod, mitk::Image::Pointer dwi1, itk::VectorImage< short, 3 >* dwi2, itk::Image< unsigned char,3 >::Pointer mask, itk::Image< double,3 >::Pointer fa1, itk::Image< double,3 >::Pointer md1, bool b0_contrast) { typedef itk::TensorDerivedMeasurementsFilter MeasurementsType; typedef itk::Image< double, 3 > DoubleImageType; typedef itk::VectorImage< short, 3 > DwiType; DwiType::Pointer dwi1_itk = mitk::DiffusionPropertyHelper::GetItkVectorImage(dwi1); typedef itk::DiffusionTensor3DReconstructionImageFilter TensorReconstructionImageFilterType; DoubleImageType::Pointer fa2; { mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer gradientContainerCopy = mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::New(); for(auto it = mitk::DiffusionPropertyHelper::GetGradientContainer(dwi1)->Begin(); it != mitk::DiffusionPropertyHelper::GetGradientContainer(dwi1)->End(); it++) gradientContainerCopy->push_back(it.Value()); TensorReconstructionImageFilterType::Pointer tensorReconstructionFilter = TensorReconstructionImageFilterType::New(); tensorReconstructionFilter->SetBValue( mitk::DiffusionPropertyHelper::GetReferenceBValue(dwi1) ); tensorReconstructionFilter->SetGradientImage(gradientContainerCopy, dwi2 ); tensorReconstructionFilter->Update(); MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput( tensorReconstructionFilter->GetOutput() ); measurementsCalculator->SetMeasure(MeasurementsType::FA); measurementsCalculator->Update(); fa2 = measurementsCalculator->GetOutput(); } DoubleImageType::Pointer md2; if (md1.IsNotNull()) { typedef itk::AdcImageFilter< short, double > AdcFilterType; AdcFilterType::Pointer filter = AdcFilterType::New(); filter->SetInput( dwi2 ); filter->SetGradientDirections( mitk::DiffusionPropertyHelper::GetGradientContainer(dwi1) ); filter->SetB_value( mitk::DiffusionPropertyHelper::GetReferenceBValue(dwi1) ); filter->SetFitSignal(false); filter->Update(); md2 = filter->GetOutput(); } itk::ImageRegionConstIterator< DoubleImageType > it1(fa1, fa1->GetLargestPossibleRegion()); itk::ImageRegionConstIterator< DoubleImageType > it2(fa2, fa2->GetLargestPossibleRegion()); itk::ImageRegionConstIterator< itk::VectorImage< short, 3 > > it_diff1(dwi1_itk, dwi1_itk->GetLargestPossibleRegion()); itk::ImageRegionConstIterator< itk::VectorImage< short, 3 > > it_diff2(dwi2, dwi2->GetLargestPossibleRegion()); unsigned int count = 0; double error = 0; if (md1.IsNotNull() && md2.IsNotNull()) { itk::ImageRegionConstIterator< DoubleImageType > it3(md1, md1->GetLargestPossibleRegion()); itk::ImageRegionConstIterator< DoubleImageType > it4(md2, md2->GetLargestPossibleRegion()); while(!it1.IsAtEnd()) { if (mask.IsNull() || (mask.IsNotNull() && mask->GetLargestPossibleRegion().IsInside(it1.GetIndex()) && mask->GetPixel(it1.GetIndex())>0) ) { double fa = it1.Get(); if (fa>0 && it3.Get()>0) { double mod = 1.0; for (int i=histo_mod.size()-1; i>=0; --i) if (fa >= (double)i/histo_mod.size()) { mod = histo_mod.at(i); break; } double fa_diff = std::fabs(it2.Get()/fa - 1.0); double md_diff = std::fabs(it4.Get()/it3.Get() - 1.0); error += std::pow(mod, 4) * (fa_diff + md_diff); count += 2; if (b0_contrast && it_diff1.Get()[0]>0) { double b0_diff = (double)it_diff2.Get()[0]/it_diff1.Get()[0] - 1.0; error += std::pow(mod, 4) * std::fabs(b0_diff); ++count; } } } ++it1; ++it2; ++it3; ++it4; ++it_diff1; ++it_diff2; } } else { unsigned int count = 0; double error = 0; while(!it1.IsAtEnd()) { if (mask.IsNull() || (mask.IsNotNull() && mask->GetLargestPossibleRegion().IsInside(it1.GetIndex()) && mask->GetPixel(it1.GetIndex())>0) ) { double fa = it1.Get(); if (fa>0) { double mod = 1.0; for (int i=histo_mod.size()-1; i>=0; --i) if (fa >= (double)i/histo_mod.size()) { mod = histo_mod.at(i); break; } double fa_diff = fabs(it2.Get()/fa - 1.0); error += std::pow(mod, 4) * fa_diff; ++count; if (b0_contrast && it_diff1.Get()[0]>0) { double b0_diff = (double)it_diff2.Get()[0]/it_diff1.Get()[0] - 1.0; error += std::pow(mod, 4) * std::fabs(b0_diff); ++count; } } } ++it1; ++it2; ++it_diff1; ++it_diff2; } } return error/count; } FiberfoxParameters MakeProposalScale(FiberfoxParameters old_params, double temperature) { FiberfoxParameters new_params(old_params); std::random_device r; std::default_random_engine randgen(r()); std::normal_distribution normal_dist(0, new_params.m_SignalGen.m_SignalScale*0.1*temperature); double add = 0; while (add == 0) add = normal_dist(randgen); new_params.m_SignalGen.m_SignalScale += add; MITK_INFO << "Proposal Signal Scale: " << new_params.m_SignalGen.m_SignalScale << " (" << add << ")"; return new_params; } FiberfoxParameters MakeProposalRelaxation(FiberfoxParameters old_params, double temperature) { FiberfoxParameters new_params(old_params); std::random_device r; std::default_random_engine randgen(r()); std::uniform_int_distribution uint1(0, 3); int prop = uint1(randgen); switch(prop) { case 0: { int model_index = rand()%new_params.m_NonFiberModelList.size(); double t2 = new_params.m_NonFiberModelList[model_index]->GetT2(); std::normal_distribution normal_dist(0, t2*0.1*temperature); double add = 0; while (add == 0) add = normal_dist(randgen); if ( (t2+add)*1.5 > new_params.m_NonFiberModelList[model_index]->GetT1() ) add = -add; t2 += add; new_params.m_NonFiberModelList[model_index]->SetT2(t2); MITK_INFO << "Proposal T2 (Non-Fiber " << model_index << "): " << t2 << " (" << add << ")"; break; } case 1: { int model_index = rand()%new_params.m_FiberModelList.size(); double t2 = new_params.m_FiberModelList[model_index]->GetT2(); std::normal_distribution normal_dist(0, t2*0.1*temperature); double add = 0; while (add == 0) add = normal_dist(randgen); if ( (t2+add)*1.5 > new_params.m_FiberModelList[model_index]->GetT1() ) add = -add; t2 += add; new_params.m_FiberModelList[model_index]->SetT2(t2); MITK_INFO << "Proposal T2 (Fiber " << model_index << "): " << t2 << " (" << add << ")"; break; } case 2: { int model_index = rand()%new_params.m_NonFiberModelList.size(); double t1 = new_params.m_NonFiberModelList[model_index]->GetT1(); std::normal_distribution normal_dist(0, t1*0.1*temperature); double add = 0; while (add == 0) add = normal_dist(randgen); if ( t1+add < new_params.m_NonFiberModelList[model_index]->GetT2() * 1.5 ) add = -add; t1 += add; new_params.m_NonFiberModelList[model_index]->SetT1(t1); MITK_INFO << "Proposal T1 (Non-Fiber " << model_index << "): " << t1 << " (" << add << ")"; break; } case 3: { int model_index = rand()%new_params.m_FiberModelList.size(); double t1 = new_params.m_FiberModelList[model_index]->GetT1(); std::normal_distribution normal_dist(0, t1*0.1*temperature); double add = 0; while (add == 0) add = normal_dist(randgen); if ( t1+add < new_params.m_FiberModelList[model_index]->GetT2() * 1.5 ) add = -add; t1 += add; new_params.m_FiberModelList[model_index]->SetT1(t1); MITK_INFO << "Proposal T1 (Fiber " << model_index << "): " << t1 << " (" << add << ")"; break; } } return new_params; } double UpdateDiffusivity(double d, double temperature) { std::random_device r; std::default_random_engine randgen(r()); std::normal_distribution normal_dist(0, d*0.1*temperature); double add = 0; while (add == 0) add = normal_dist(randgen); if (d+add > 0.0025) d -= add; else if ( d+add < 0.0 ) d -= add; else d += add; return d; } void ProposeDiffusivities(mitk::DiffusionSignalModel<>* signalModel, double temperature) { if (dynamic_cast*>(signalModel)) { mitk::StickModel<>* m = dynamic_cast*>(signalModel); double new_d = UpdateDiffusivity(m->GetDiffusivity(), temperature); MITK_INFO << "d: " << new_d << " (" << new_d-m->GetDiffusivity() << ")"; m->SetDiffusivity(new_d); } else if (dynamic_cast*>(signalModel)) { mitk::TensorModel<>* m = dynamic_cast*>(signalModel); double new_d1 = UpdateDiffusivity(m->GetDiffusivity1(), temperature); double new_d2 = UpdateDiffusivity(m->GetDiffusivity2(), temperature); while (new_d1GetDiffusivity2(), temperature); MITK_INFO << "d1: " << new_d1 << " (" << new_d1-m->GetDiffusivity1() << ")"; MITK_INFO << "d2: " << new_d2 << " (" << new_d2-m->GetDiffusivity2() << ")"; m->SetDiffusivity1(new_d1); m->SetDiffusivity2(new_d2); m->SetDiffusivity3(new_d2); } else if (dynamic_cast*>(signalModel)) { mitk::BallModel<>* m = dynamic_cast*>(signalModel); double new_d = UpdateDiffusivity(m->GetDiffusivity(), temperature); MITK_INFO << "d: " << new_d << " (" << new_d-m->GetDiffusivity() << ")"; m->SetDiffusivity(new_d); } else if (dynamic_cast*>(signalModel)) { mitk::AstroStickModel<>* m = dynamic_cast*>(signalModel); double new_d = UpdateDiffusivity(m->GetDiffusivity(), temperature); MITK_INFO << "d: " << new_d << " (" << new_d-m->GetDiffusivity() << ")"; m->SetDiffusivity(new_d); } } FiberfoxParameters MakeProposalDiff(FiberfoxParameters old_params, double temperature) { FiberfoxParameters new_params(old_params); std::random_device r; std::default_random_engine randgen(r()); std::uniform_int_distribution uint1(0, new_params.m_NonFiberModelList.size() + new_params.m_FiberModelList.size() - 1); unsigned int prop = uint1(randgen); if (prop::Pointer > frac, double temperature) { FiberfoxParameters new_params(old_params); MITK_INFO << "Proposal Volume"; std::random_device r; std::default_random_engine randgen(r()); { std::normal_distribution normal_dist(0, old_tdi_thr*0.1*temperature); new_tdi_thr = old_tdi_thr + normal_dist(randgen); while (new_tdi_thr<=0.01) new_tdi_thr = old_tdi_thr + normal_dist(randgen); } { std::normal_distribution normal_dist(0, old_sqrt*0.1*temperature); new_sqrt = old_sqrt + normal_dist(randgen); while (new_sqrt<=0.01) new_sqrt = old_sqrt + normal_dist(randgen); } itk::TdiToVolumeFractionFilter< double >::Pointer fraction_generator = itk::TdiToVolumeFractionFilter< double >::New(); fraction_generator->SetTdiThreshold(new_tdi_thr); fraction_generator->SetSqrt(new_sqrt); fraction_generator->SetInput(0, frac.at(0)); fraction_generator->SetInput(1, frac.at(1)); fraction_generator->SetInput(2, frac.at(2)); fraction_generator->SetInput(3, frac.at(3)); fraction_generator->SetInput(4, frac.at(4)); fraction_generator->Update(); new_params.m_FiberModelList[0]->SetVolumeFractionImage(fraction_generator->GetOutput(0)); new_params.m_FiberModelList[1]->SetVolumeFractionImage(fraction_generator->GetOutput(1)); new_params.m_NonFiberModelList[0]->SetVolumeFractionImage(fraction_generator->GetOutput(2)); new_params.m_NonFiberModelList[1]->SetVolumeFractionImage(fraction_generator->GetOutput(3)); MITK_INFO << "TDI Threshold: " << new_tdi_thr << " (" << new_tdi_thr-old_tdi_thr << ")"; MITK_INFO << "SQRT: " << new_sqrt << " (" << new_sqrt-old_sqrt << ")"; return new_params; } /*! * \brief Command line interface to optimize Fiberfox parameters. */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("FiberfoxOptimization"); parser.setCategory("Optimize Fiberfox Parameters"); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.beginGroup("1. Mandatory Input:"); parser.addArgument("parameters", "p", mitkCommandLineParser::InputFile, "Parameter File:", "fiberfox parameter file (.ffp)", us::Any(), false); parser.addArgument("tracts", "t", mitkCommandLineParser::String, "Input Tractogram:", "Input tractogram.", us::Any(), false); parser.addArgument("out_folder", "o", mitkCommandLineParser::String, "Output Folder:", "", us::Any(), false); parser.addArgument("dmri", "d", mitkCommandLineParser::String, "Target image:", "Target dMRI to approximate.", us::Any(), false); parser.addArgument("mask", "", mitkCommandLineParser::InputFile, "Mask image:", "Error is only calculated inside the mask image", false); parser.endGroup(); parser.beginGroup("2. Parameters to optimize:"); parser.addArgument("no_diff", "", mitkCommandLineParser::Bool, "Don't optimize diffusivities:", "Don't optimize diffusivities"); parser.addArgument("no_relax", "", mitkCommandLineParser::Bool, "Don't optimize relaxation times:", "Don't optimize relaxation times"); parser.addArgument("no_scale", "", mitkCommandLineParser::Bool, "Don't optimize signal scale:", "Don't optimize global signal scale"); parser.endGroup(); parser.beginGroup("3. Error measure:"); parser.addArgument("fa_error", "", mitkCommandLineParser::Bool, "Optimize FA", "Optimize FA instead of raw signal. Requires FA image."); parser.addArgument("fa_image", "", mitkCommandLineParser::InputFile, "FA image:", "Weight error by FA histogram. Always necessary with option fa_error!"); parser.addArgument("md_image", "", mitkCommandLineParser::InputFile, "MD image:", "Optimize MD in conjunction with FA (recommended when optimizing FA)."); parser.endGroup(); parser.beginGroup("4. Optimization of volume fraction maps:"); parser.addArgument("tdi", "", mitkCommandLineParser::InputFile, "TDI:", "tract density image"); parser.addArgument("wm", "", mitkCommandLineParser::InputFile, "WM:", "white matter volume fraction image"); parser.addArgument("gm", "", mitkCommandLineParser::InputFile, "GM:", "gray matter volume fraction image"); parser.addArgument("dgm", "", mitkCommandLineParser::InputFile, "DGM:", "subcortical gray matter volume fraction image"); parser.addArgument("csf", "", mitkCommandLineParser::InputFile, "CSF:", "CSF volume fraction image"); parser.addArgument("tdi_threshold", "", mitkCommandLineParser::Float, "", "", 0.75); parser.addArgument("sqrt", "", mitkCommandLineParser::Float, "", "", 1.0); parser.endGroup(); parser.beginGroup("5. General parameters:"); parser.addArgument("iterations", "", mitkCommandLineParser::Int, "Iterations:", "Number of optimizations steps", 1000); parser.addArgument("start_temp", "", mitkCommandLineParser::Float, "Start temperature:", "Higher temperature means larger parameter change proposals", 1.0); parser.addArgument("end_temp", "", mitkCommandLineParser::Float, "End temperature:", "Higher temperature means larger parameter change proposals", 0.1); parser.endGroup(); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string paramName = us::any_cast(parsedArgs["parameters"]); std::string out_folder = us::any_cast(parsedArgs["out_folder"]); std::string tract_file = us::any_cast(parsedArgs["tracts"]); MITK_INFO << "Loading target dMRI and parameters"; FiberfoxParameters parameters; parameters.LoadParameters(paramName); typedef itk::VectorImage< short, 3 > ItkDwiType; mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Diffusion Weighted Images", "Fiberbundles"}, {}); auto dwi = mitk::IOUtil::Load(us::any_cast(parsedArgs["dmri"]), &functor); ItkDwiType::Pointer reference = mitk::DiffusionPropertyHelper::GetItkVectorImage(dwi); parameters.m_SignalGen.m_ImageRegion = reference->GetLargestPossibleRegion(); parameters.m_SignalGen.m_ImageSpacing = reference->GetSpacing(); parameters.m_SignalGen.m_ImageOrigin = reference->GetOrigin(); parameters.m_SignalGen.m_ImageDirection = reference->GetDirection(); parameters.SetBvalue(static_cast(dwi->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() )->GetValue()); parameters.SetGradienDirections(static_cast( dwi->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() )->GetGradientDirectionsContainer()); auto tracts = mitk::IOUtil::Load(tract_file, &functor); int iterations=1000; if (parsedArgs.count("iterations")) iterations = us::any_cast(parsedArgs["iterations"]); float start_temp=1.0; if (parsedArgs.count("start_temp")) start_temp = us::any_cast(parsedArgs["start_temp"]); float end_temp=0.1; if (parsedArgs.count("end_temp")) end_temp = us::any_cast(parsedArgs["end_temp"]); float tdi_threshold=0.75; if (parsedArgs.count("tdi_threshold")) tdi_threshold = us::any_cast(parsedArgs["tdi_threshold"]); float sqrt=1.0; if (parsedArgs.count("sqrt")) sqrt = us::any_cast(parsedArgs["sqrt"]); bool fa_error=false; if (parsedArgs.count("fa_error")) fa_error = true; std::string fa_file = ""; if (parsedArgs.count("fa_image")) fa_file = us::any_cast(parsedArgs["fa_image"]); std::string md_file = ""; if (parsedArgs.count("md_image")) md_file = us::any_cast(parsedArgs["md_image"]); std::vector< int > possible_proposals; if (!parsedArgs.count("no_diff")) { MITK_INFO << "Optimizing diffusivities"; possible_proposals.push_back(0); } if (!parsedArgs.count("no_relax")) { MITK_INFO << "Optimizing relaxation constants"; possible_proposals.push_back(1); } if (!parsedArgs.count("no_scale")) { MITK_INFO << "Optimizing global signal scale"; possible_proposals.push_back(2); } if (possible_proposals.empty()) { MITK_INFO << "Incompatible options. Nothing to optimize."; return EXIT_FAILURE; } itk::ImageFileReader< itk::Image< unsigned char, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< unsigned char, 3 > >::New(); reader->SetFileName( us::any_cast(parsedArgs["mask"]) ); reader->Update(); itk::Image< unsigned char,3 >::Pointer mask = reader->GetOutput(); std::vector< itk::Image< double, 3 >::Pointer > fracs; if ( parsedArgs.count("tdi")>0 && parsedArgs.count("wm")>0 && parsedArgs.count("gm")>0 && parsedArgs.count("dgm")>0 && parsedArgs.count("csf")>0 ) { MITK_INFO << "Optimizing volume fractions"; { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( us::any_cast(parsedArgs["tdi"]) ); reader->Update(); fracs.push_back(reader->GetOutput()); } { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( us::any_cast(parsedArgs["wm"]) ); reader->Update(); fracs.push_back(reader->GetOutput()); } { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( us::any_cast(parsedArgs["gm"]) ); reader->Update(); fracs.push_back(reader->GetOutput()); } { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( us::any_cast(parsedArgs["dgm"]) ); reader->Update(); fracs.push_back(reader->GetOutput()); } { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( us::any_cast(parsedArgs["csf"]) ); reader->Update(); fracs.push_back(reader->GetOutput()); } MITK_INFO << "Initial sqrt: " << sqrt; MITK_INFO << "Initial TDI threshold: " << tdi_threshold; possible_proposals.push_back(3); } std::vector< double > histogram_modifiers; itk::Image< double,3 >::Pointer fa_image = nullptr; if (fa_file.compare("")!=0) { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( fa_file ); reader->Update(); fa_image = reader->GetOutput(); int binsPerDimension = 20; using ImageToHistogramFilterType = itk::Statistics::MaskedImageToHistogramFilter< itk::Image< double,3 >, itk::Image< unsigned char,3 > >; ImageToHistogramFilterType::HistogramType::MeasurementVectorType lowerBound(binsPerDimension); lowerBound.Fill(0.0); ImageToHistogramFilterType::HistogramType::MeasurementVectorType upperBound(binsPerDimension); upperBound.Fill(1.0); ImageToHistogramFilterType::HistogramType::SizeType size(1); size.Fill(binsPerDimension); ImageToHistogramFilterType::Pointer imageToHistogramFilter = ImageToHistogramFilterType::New(); imageToHistogramFilter->SetInput( fa_image ); imageToHistogramFilter->SetHistogramBinMinimum( lowerBound ); imageToHistogramFilter->SetHistogramBinMaximum( upperBound ); imageToHistogramFilter->SetHistogramSize( size ); imageToHistogramFilter->SetMaskImage(mask); imageToHistogramFilter->SetMaskValue(1); imageToHistogramFilter->Update(); ImageToHistogramFilterType::HistogramType* histogram = imageToHistogramFilter->GetOutput(); unsigned int max = 0; for(unsigned int i = 0; i < histogram->GetSize()[0]; ++i) { if (histogram->GetFrequency(i)>max) max = histogram->GetFrequency(i); } MITK_INFO << "FA histogram modifiers:"; for(unsigned int i = 0; i < histogram->GetSize()[0]; ++i) { histogram_modifiers.push_back((double)max/histogram->GetFrequency(i)); MITK_INFO << std::pow(histogram_modifiers.back(), 4); } if (fa_error) MITK_INFO << "Using FA error measure."; } itk::Image< double,3 >::Pointer md_image = nullptr; if (md_file.compare("")!=0) { itk::ImageFileReader< itk::Image< double, 3 > >::Pointer reader = itk::ImageFileReader< itk::Image< double, 3 > >::New(); reader->SetFileName( md_file ); reader->Update(); md_image = reader->GetOutput(); if (fa_error) MITK_INFO << "Using MD error measure."; } if (fa_error && fa_image.IsNull()) { MITK_INFO << "Incompatible options. Need FA image to calculate FA error."; return EXIT_FAILURE; } itk::TractsToDWIImageFilter< short >::Pointer tractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New(); tractsToDwiFilter->SetFiberBundle(tracts); tractsToDwiFilter->SetParameters(parameters); tractsToDwiFilter->Update(); ItkDwiType::Pointer sim = tractsToDwiFilter->GetOutput(); { mitk::Image::Pointer image = mitk::GrabItkImageMemory( tractsToDwiFilter->GetOutput() ); image->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( parameters.m_SignalGen.GetGradientDirections() ) ); image->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( parameters.m_SignalGen.GetBvalue() ) ); mitk::DiffusionPropertyHelper propertyHelper( image ); propertyHelper.InitializeImage(); mitk::IOUtil::Save(image, out_folder + "/initial.dwi"); } double old_tdi_thr = tdi_threshold; double old_sqrt = sqrt; double new_tdi_thr; double new_sqrt; MITK_INFO << "\n\n"; MITK_INFO << "Iterations: " << iterations; MITK_INFO << "start_temp: " << start_temp; MITK_INFO << "end_temp: " << end_temp; double alpha = log(end_temp/start_temp); int accepted = 0; double last_error = 9999999; if (fa_error) { MITK_INFO << "Calculating FA error"; last_error = CalcErrorFA(histogram_modifiers, dwi, sim, mask, fa_image, md_image, true); } else { MITK_INFO << "Calculating raw-image error"; last_error = CalcErrorSignal(histogram_modifiers, reference, sim, mask, fa_image); } MITK_INFO << "Initial E = " << last_error; MITK_INFO << "\n\n**************************************************************************************"; std::random_device r; std::default_random_engine randgen(r()); std::uniform_int_distribution uint1(0, possible_proposals.size()-1); for (int i=0; i::Pointer tractsToDwiFilter = itk::TractsToDWIImageFilter< short >::New(); tractsToDwiFilter->SetFiberBundle(dynamic_cast(tracts.GetPointer())); tractsToDwiFilter->SetParameters(proposal); tractsToDwiFilter->Update(); ItkDwiType::Pointer sim = tractsToDwiFilter->GetOutput(); std::cout.rdbuf (old); // <-- restore double new_error = 9999999; if (fa_error && fa_image.IsNotNull()) new_error = CalcErrorFA(histogram_modifiers, dwi, sim, mask, fa_image, md_image, true); else new_error = CalcErrorSignal(histogram_modifiers, reference, sim, mask, fa_image); MITK_INFO << "E = " << new_error << "(" << new_error-last_error << ")"; if (last_errorGetOutput() ); image->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( parameters.m_SignalGen.GetGradientDirections() ) ); image->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( parameters.m_SignalGen.GetBvalue() ) ); mitk::DiffusionPropertyHelper propertyHelper( image ); propertyHelper.InitializeImage(); mitk::IOUtil::Save(image, out_folder + "/optimized.dwi"); proposal.SaveParameters(out_folder + "/optimized.ffp"); std::cout.rdbuf (old); // <-- restore accepted++; old_tdi_thr = new_tdi_thr; old_sqrt = new_sqrt; MITK_INFO << "Accepted (acc. rate " << (float)accepted/(i+1) << ")"; parameters = FiberfoxParameters(proposal); last_error = new_error; } MITK_INFO << "\n\n\n"; } return EXIT_SUCCESS; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/Misc/PeakExtraction.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/Misc/PeakExtraction.cpp index d3e4385371..ea2eac7eb8 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/Misc/PeakExtraction.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/Misc/PeakExtraction.cpp @@ -1,357 +1,357 @@ /*=================================================================== 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 "mitkCommandLineParser.h" #include #include -#include +#include #include #include template int StartPeakExtraction(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); parser.addArgument("image", "i", mitkCommandLineParser::InputFile, "Input image", "sh coefficient image", us::Any(), false); parser.addArgument("outroot", "o", mitkCommandLineParser::OutputDirectory, "Output directory", "output root", us::Any(), false); parser.addArgument("mask", "m", mitkCommandLineParser::InputFile, "Mask", "mask image"); parser.addArgument("normalization", "n", mitkCommandLineParser::Int, "Normalization", "0=no norm, 1=max norm, 2=single vec norm", 1, true); parser.addArgument("numpeaks", "p", mitkCommandLineParser::Int, "Max. number of peaks", "maximum number of extracted peaks", 2, true); parser.addArgument("peakthres", "r", mitkCommandLineParser::Float, "Peak threshold", "peak threshold relative to largest peak", 0.4, true); parser.addArgument("abspeakthres", "a", mitkCommandLineParser::Float, "Absolute peak threshold", "absolute peak threshold weighted with local GFA value", 0.06, true); parser.addArgument("shConvention", "s", mitkCommandLineParser::String, "Use specified SH-basis", "use specified SH-basis (MITK, FSL, MRtrix)", std::string("MITK"), true); parser.addArgument("noFlip", "f", mitkCommandLineParser::Bool, "No flip", "do not flip input image to match MITK coordinate convention"); parser.addArgument("clusterThres", "c", mitkCommandLineParser::Float, "Clustering threshold", "directions closer together than the specified angular threshold will be clustered (in rad)", 0.9); parser.addArgument("flipX", "fx", mitkCommandLineParser::Bool, "Flip X", "Flip peaks in x direction"); parser.addArgument("flipY", "fy", mitkCommandLineParser::Bool, "Flip Y", "Flip peaks in y direction"); parser.addArgument("flipZ", "fz", mitkCommandLineParser::Bool, "Flip Z", "Flip peaks in z direction"); parser.setCategory("Preprocessing Tools"); parser.setTitle("Peak Extraction"); parser.setDescription(""); parser.setContributor("MIC"); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; // mandatory arguments std::string imageName = us::any_cast(parsedArgs["image"]); std::string outRoot = us::any_cast(parsedArgs["outroot"]); // optional arguments std::string maskImageName(""); if (parsedArgs.count("mask")) maskImageName = us::any_cast(parsedArgs["mask"]); int normalization = 1; if (parsedArgs.count("normalization")) normalization = us::any_cast(parsedArgs["normalization"]); int numPeaks = 2; if (parsedArgs.count("numpeaks")) numPeaks = us::any_cast(parsedArgs["numpeaks"]); float peakThres = 0.4; if (parsedArgs.count("peakthres")) peakThres = us::any_cast(parsedArgs["peakthres"]); float absPeakThres = 0.06; if (parsedArgs.count("abspeakthres")) absPeakThres = us::any_cast(parsedArgs["abspeakthres"]); float clusterThres = 0.9; if (parsedArgs.count("clusterThres")) clusterThres = us::any_cast(parsedArgs["clusterThres"]); bool noFlip = false; if (parsedArgs.count("noFlip")) noFlip = us::any_cast(parsedArgs["noFlip"]); bool flipX = false; if (parsedArgs.count("flipX")) flipX = us::any_cast(parsedArgs["flipX"]); bool flipY = false; if (parsedArgs.count("flipY")) flipY = us::any_cast(parsedArgs["flipY"]); bool flipZ = false; if (parsedArgs.count("flipZ")) flipZ = us::any_cast(parsedArgs["flipZ"]); std::cout << "image: " << imageName; std::cout << "outroot: " << outRoot; if (!maskImageName.empty()) std::cout << "mask: " << maskImageName; else std::cout << "no mask image selected"; std::cout << "numpeaks: " << numPeaks; std::cout << "peakthres: " << peakThres; std::cout << "abspeakthres: " << absPeakThres; std::cout << "shOrder: " << shOrder; try { mitk::Image::Pointer image = mitk::IOUtil::Load(imageName); mitk::Image::Pointer mask = mitk::IOUtil::Load(maskImageName); typedef itk::Image ItkUcharImgType; typedef itk::FiniteDiffOdfMaximaExtractionFilter< float, shOrder, 20242 > MaximaExtractionFilterType; typename MaximaExtractionFilterType::Pointer peak_extraction_filter = MaximaExtractionFilterType::New(); int toolkitConvention = 0; if (parsedArgs.count("shConvention")) { std::string convention = us::any_cast(parsedArgs["shConvention"]).c_str(); if ( boost::algorithm::equals(convention, "FSL") ) { toolkitConvention = 1; std::cout << "Using FSL SH-basis"; } else if ( boost::algorithm::equals(convention, "MRtrix") ) { toolkitConvention = 2; std::cout << "Using MRtrix SH-basis"; } else std::cout << "Using MITK SH-basis"; } else std::cout << "Using MITK SH-basis"; ItkUcharImgType::Pointer itkMaskImage = nullptr; if (mask.IsNotNull()) { try{ itkMaskImage = ItkUcharImgType::New(); mitk::CastToItkImage(mask, itkMaskImage); peak_extraction_filter->SetMaskImage(itkMaskImage); } catch(...) { } } if (toolkitConvention>0) { std::cout << "Converting coefficient image to MITK format"; typedef itk::ShCoefficientImageImporter< float, shOrder > ConverterType; typedef mitk::ImageToItk< itk::Image< float, 4 > > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(image); caster->Update(); itk::Image< float, 4 >::Pointer itkImage = caster->GetOutput(); typename ConverterType::Pointer converter = ConverterType::New(); if (noFlip) { converter->SetInputImage(itkImage); } else { std::cout << "Flipping image"; itk::FixedArray flipAxes; flipAxes[0] = true; flipAxes[1] = true; flipAxes[2] = false; flipAxes[3] = false; itk::FlipImageFilter< itk::Image< float, 4 > >::Pointer flipper = itk::FlipImageFilter< itk::Image< float, 4 > >::New(); flipper->SetInput(itkImage); flipper->SetFlipAxes(flipAxes); flipper->Update(); itk::Image< float, 4 >::Pointer flipped = flipper->GetOutput(); itk::Matrix< double,4,4 > m = itkImage->GetDirection(); m[0][0] *= -1; m[1][1] *= -1; flipped->SetDirection(m); itk::Point< float, 4 > o = itkImage->GetOrigin(); o[0] -= (flipped->GetLargestPossibleRegion().GetSize(0)-1); o[1] -= (flipped->GetLargestPossibleRegion().GetSize(1)-1); flipped->SetOrigin(o); converter->SetInputImage(flipped); } std::cout << "Starting conversion"; switch (toolkitConvention) { case 1: peak_extraction_filter->SetToolkit(MaximaExtractionFilterType::FSL); break; case 2: peak_extraction_filter->SetToolkit(MaximaExtractionFilterType::MRTRIX); break; default: peak_extraction_filter->SetToolkit(MaximaExtractionFilterType::FSL); break; } converter->GenerateData(); peak_extraction_filter->SetInput(converter->GetCoefficientImage()); } else { try{ typedef mitk::ImageToItk< typename MaximaExtractionFilterType::CoefficientImageType > CasterType; typename CasterType::Pointer caster = CasterType::New(); caster->SetInput(image); caster->Update(); peak_extraction_filter->SetInput(caster->GetOutput()); } catch(...) { std::cout << "wrong image type"; return EXIT_FAILURE; } } peak_extraction_filter->SetMaxNumPeaks(numPeaks); peak_extraction_filter->SetPeakThreshold(peakThres); peak_extraction_filter->SetAbsolutePeakThreshold(absPeakThres); peak_extraction_filter->SetAngularThreshold(1); peak_extraction_filter->SetClusteringThreshold(clusterThres); peak_extraction_filter->SetFlipX(flipX); peak_extraction_filter->SetFlipY(flipY); peak_extraction_filter->SetFlipZ(flipZ); switch (normalization) { case 0: peak_extraction_filter->SetNormalizationMethod(MaximaExtractionFilterType::NO_NORM); break; case 1: peak_extraction_filter->SetNormalizationMethod(MaximaExtractionFilterType::MAX_VEC_NORM); break; case 2: peak_extraction_filter->SetNormalizationMethod(MaximaExtractionFilterType::SINGLE_VEC_NORM); break; } std::cout << "Starting extraction"; peak_extraction_filter->Update(); // write direction image { typename MaximaExtractionFilterType::PeakImageType::Pointer itkImg = peak_extraction_filter->GetPeakImage(); std::string outfilename = outRoot; outfilename.append("_PEAKS.nrrd"); typedef itk::ImageFileWriter< typename MaximaExtractionFilterType::PeakImageType > WriterType; typename WriterType::Pointer writer = WriterType::New(); writer->SetFileName(outfilename); writer->SetInput(itkImg); writer->Update(); } // write num directions image { ItkUcharImgType::Pointer numDirImage = peak_extraction_filter->GetNumDirectionsImage(); if (itkMaskImage.IsNotNull()) { numDirImage->SetDirection(itkMaskImage->GetDirection()); numDirImage->SetOrigin(itkMaskImage->GetOrigin()); } std::string outfilename = outRoot.c_str(); outfilename.append("_NUM_PEAKS.nrrd"); typedef itk::ImageFileWriter< ItkUcharImgType > WriterType; WriterType::Pointer writer = WriterType::New(); writer->SetFileName(outfilename); writer->SetInput(numDirImage); writer->Update(); } } catch (itk::ExceptionObject e) { std::cout << e; return EXIT_FAILURE; } catch (std::exception e) { std::cout << e.what(); return EXIT_FAILURE; } catch (...) { std::cout << "ERROR!?!"; return EXIT_FAILURE; } return EXIT_SUCCESS; } /*! \brief Extract maxima in the input spherical harmonics image. */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); parser.addArgument("image", "i", mitkCommandLineParser::InputFile, "Input image", "sh coefficient image", us::Any(), false); parser.addArgument("shOrder", "sh", mitkCommandLineParser::Int, "Spherical harmonics order", "spherical harmonics order"); parser.addArgument("outroot", "o", mitkCommandLineParser::OutputDirectory, "Output directory", "output root", us::Any(), false); parser.addArgument("mask", "m", mitkCommandLineParser::InputFile, "Mask", "mask image"); parser.addArgument("normalization", "n", mitkCommandLineParser::Int, "Normalization", "0=no norm, 1=max norm, 2=single vec norm", 1, true); parser.addArgument("numpeaks", "p", mitkCommandLineParser::Int, "Max. number of peaks", "maximum number of extracted peaks", 2, true); parser.addArgument("peakthres", "r", mitkCommandLineParser::Float, "Peak threshold", "peak threshold relative to largest peak", 0.4, true); parser.addArgument("abspeakthres", "a", mitkCommandLineParser::Float, "Absolute peak threshold", "absolute peak threshold weighted with local GFA value", 0.06, true); parser.addArgument("shConvention", "s", mitkCommandLineParser::String, "Use specified SH-basis", "use specified SH-basis (MITK, FSL, MRtrix)", std::string("MITK"), true); parser.addArgument("noFlip", "f", mitkCommandLineParser::Bool, "No flip", "do not flip input image to match MITK coordinate convention"); parser.setCategory("Preprocessing Tools"); parser.setTitle("Peak Extraction"); parser.setDescription("Extract maxima in the input spherical harmonics image."); 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 StartPeakExtraction<4>(argc, argv); case 6: return StartPeakExtraction<6>(argc, argv); case 8: return StartPeakExtraction<8>(argc, argv); case 10: return StartPeakExtraction<10>(argc, argv); case 12: return StartPeakExtraction<12>(argc, argv); } return EXIT_FAILURE; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/Misc/PythonTest.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/Misc/PythonTest.cpp index 8c570f93ba..b5c21e3952 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/Misc/PythonTest.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/Misc/PythonTest.cpp @@ -1,80 +1,80 @@ /*=================================================================== 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 typedef itk::Image< float, 3 > ItkImageType; /*! \brief */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); parser.addArgument("image", "i", mitkCommandLineParser::InputFile, "Input image", "sh coefficient image", us::Any(), false); parser.addArgument("script", "s", mitkCommandLineParser::InputFile, "", "", us::Any(), false); parser.addArgument("params", "p", mitkCommandLineParser::InputFile, "", "", us::Any(), false); parser.addArgument("out_file", "o", mitkCommandLineParser::OutputDirectory, "Output image", "output image", us::Any(), false); parser.setCategory("TEST"); parser.setTitle("TEST"); parser.setDescription("TEST"); parser.setContributor("MIC"); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string image_file = us::any_cast(parsedArgs["image"]); std::string script = us::any_cast(parsedArgs["script"]); std::string params = us::any_cast(parsedArgs["params"]); std::string out_file = us::any_cast(parsedArgs["out_file"]); mitk::Image::Pointer mitk_image = mitk::IOUtil::Load(image_file); us::ModuleContext* context = us::GetModuleContext(); us::ServiceReference m_PythonServiceRef = context->GetServiceReference(); mitk::IPythonService* m_PythonService = dynamic_cast ( context->GetService(m_PythonServiceRef) ); mitk::IPythonService::ForceLoadModule(); m_PythonService->Execute("import SimpleITK as sitk"); m_PythonService->Execute("import SimpleITK._SimpleITK as _SimpleITK"); m_PythonService->Execute("import numpy"); m_PythonService->CopyToPythonAsSimpleItkImage( mitk_image, "myvar"); m_PythonService->Execute("myparams=\""+params+"\""); m_PythonService->ExecuteScript(script); mitk::Image::Pointer out_seg = m_PythonService->CopySimpleItkImageFromPython("out_image"); mitk::IOUtil::Save(out_seg, out_file); return EXIT_FAILURE; } diff --git a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorConstrainedPlausibility.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorConstrainedPlausibility.cpp index d336f221fe..42338774b9 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorConstrainedPlausibility.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/AnchorConstrainedPlausibility.cpp @@ -1,575 +1,575 @@ /*=================================================================== 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 #include typedef itksys::SystemTools ist; typedef itk::Point PointType4; typedef itk::Image< float, 4 > PeakImgType; typedef itk::Image< unsigned char, 3 > ItkUcharImageType; std::vector< mitk::FiberBundle::Pointer > CombineTractograms(std::vector< mitk::FiberBundle::Pointer > reference, std::vector< mitk::FiberBundle::Pointer > candidates, int skip=-1) { std::vector< mitk::FiberBundle::Pointer > fib; for (auto f : reference) fib.push_back(f); int c = 0; for (auto f : candidates) { if (c!=skip) fib.push_back(f); ++c; } return fib; } std::vector< std::string > get_file_list(const std::string& path, std::vector< std::string > extensions={".fib", ".trk"}) { std::vector< std::string > file_list; itk::Directory::Pointer dir = itk::Directory::New(); if (dir->Load(path.c_str())) { int n = dir->GetNumberOfFiles(); for (int r = 0; r < n; r++) { const char *filename = dir->GetFile(r); std::string ext = ist::GetFilenameExtension(filename); for (auto e : extensions) { if (ext==e) { file_list.push_back(path + '/' + filename); break; } } } } return file_list; } /*! \brief Score input candidate tracts using ACP analysis */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Anchor Constrained Plausibility"); parser.setCategory("Fiber Tracking Evaluation"); parser.setDescription("Score input candidate tracts using ACP analysis"); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("", "a", mitkCommandLineParser::InputFile, "Anchor tractogram:", "anchor tracts in one tractogram file", us::Any(), false); parser.addArgument("", "p", mitkCommandLineParser::InputFile, "Input peaks:", "input peak image", us::Any(), false); parser.addArgument("", "c", mitkCommandLineParser::InputDirectory, "Candidates folder:", "folder containing candidate tracts", us::Any(), false); parser.addArgument("", "o", mitkCommandLineParser::OutputDirectory, "Output folder:", "output folder", us::Any(), false); parser.addArgument("anchor_masks", "", mitkCommandLineParser::StringList, "Reference Masks:", "reference tract masks for accuracy evaluation"); parser.addArgument("mask", "", mitkCommandLineParser::InputFile, "Mask image:", "scoring is only performed inside the mask image"); parser.addArgument("greedy_add", "", mitkCommandLineParser::Bool, "Greedy:", "if enabled, the candidate tracts are not jointly fitted to the residual image but one after the other employing a greedy scheme", false); parser.addArgument("lambda", "", mitkCommandLineParser::Float, "Lambda:", "modifier for regularization", 0.1); parser.addArgument("filter_outliers", "", mitkCommandLineParser::Bool, "Filter outliers:", "perform second optimization run with an upper weight bound based on the first weight estimation (99% quantile)", false); parser.addArgument("regu", "", mitkCommandLineParser::String, "Regularization:", "MSM, Variance, VoxelVariance, Lasso, GroupLasso, GroupVariance, NONE (default)"); parser.addArgument("use_num_streamlines", "", mitkCommandLineParser::Bool, "Use number of streamlines as score:", "Don't fit candidates, simply use number of streamlines per candidate as score", false); parser.addArgument("use_weights", "", mitkCommandLineParser::Bool, "Use input weights as score:", "Don't fit candidates, simply use first input streamline weight per candidate as score", false); parser.addArgument("filter_zero_weights", "", mitkCommandLineParser::Bool, "Filter zero-weights", "Remove streamlines with weight 0 from candidates", false); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string anchors_file = us::any_cast(parsedArgs["a"]); std::string peak_file_name = us::any_cast(parsedArgs["p"]); std::string candidate_tract_folder = us::any_cast(parsedArgs["c"]); std::string out_folder = us::any_cast(parsedArgs["o"]); bool greedy_add = false; if (parsedArgs.count("greedy_add")) greedy_add = us::any_cast(parsedArgs["greedy_add"]); float lambda = 0.1; if (parsedArgs.count("lambda")) lambda = us::any_cast(parsedArgs["lambda"]); bool filter_outliers = false; if (parsedArgs.count("filter_outliers")) filter_outliers = us::any_cast(parsedArgs["filter_outliers"]); bool filter_zero_weights = false; if (parsedArgs.count("filter_zero_weights")) filter_zero_weights = us::any_cast(parsedArgs["filter_zero_weights"]); std::string mask_file = ""; if (parsedArgs.count("mask")) mask_file = us::any_cast(parsedArgs["mask"]); mitkCommandLineParser::StringContainerType anchor_mask_files_folders; if (parsedArgs.count("anchor_masks")) anchor_mask_files_folders = us::any_cast(parsedArgs["anchor_masks"]); std::string regu = "NONE"; if (parsedArgs.count("regu")) regu = us::any_cast(parsedArgs["regu"]); bool use_weights = false; if (parsedArgs.count("use_weights")) use_weights = us::any_cast(parsedArgs["use_weights"]); bool use_num_streamlines = false; if (parsedArgs.count("use_num_streamlines")) use_num_streamlines = us::any_cast(parsedArgs["use_num_streamlines"]); try { itk::TimeProbe clock; clock.Start(); if (!ist::PathExists(out_folder)) { MITK_INFO << "Creating output directory"; ist::MakeDirectory(out_folder); } MITK_INFO << "Loading data"; std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect ofstream logfile; logfile.open (out_folder + "log.txt"); itk::ImageFileWriter< PeakImgType >::Pointer peak_image_writer = itk::ImageFileWriter< PeakImgType >::New(); mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Peak Image", "Fiberbundles"}, {}); mitk::Image::Pointer inputImage = dynamic_cast(mitk::IOUtil::Load(peak_file_name, &functor)[0].GetPointer()); float minSpacing = 1; if(inputImage->GetGeometry()->GetSpacing()[0]GetGeometry()->GetSpacing()[1] && inputImage->GetGeometry()->GetSpacing()[0]GetGeometry()->GetSpacing()[2]) minSpacing = inputImage->GetGeometry()->GetSpacing()[0]; else if (inputImage->GetGeometry()->GetSpacing()[1] < inputImage->GetGeometry()->GetSpacing()[2]) minSpacing = inputImage->GetGeometry()->GetSpacing()[1]; else minSpacing = inputImage->GetGeometry()->GetSpacing()[2]; // Load mask file. Fit is only performed inside the mask itk::FitFibersToImageFilter::UcharImgType::Pointer mask = nullptr; if (mask_file.compare("")!=0) { mitk::Image::Pointer mitk_mask = mitk::IOUtil::Load(mask_file); mitk::CastToItkImage(mitk_mask, mask); } // Load masks covering the true positives for evaluation purposes std::vector< itk::FitFibersToImageFilter::UcharImgType::Pointer > reference_masks; std::vector< std::string > anchor_mask_files; for (auto filename : anchor_mask_files_folders) { if (itksys::SystemTools::PathExists(filename)) { auto list = get_file_list(filename, {".nrrd",".nii.gz",".nii"}); for (auto f : list) { MITK_INFO << f; itk::FitFibersToImageFilter::UcharImgType::Pointer ref_mask = nullptr; mitk::Image::Pointer ref_mitk_mask = mitk::IOUtil::Load(f); mitk::CastToItkImage(ref_mitk_mask, ref_mask); reference_masks.push_back(ref_mask); anchor_mask_files.push_back(f); } } else if (itksys::SystemTools::FileExists(filename)) { anchor_mask_files.push_back(filename); itk::FitFibersToImageFilter::UcharImgType::Pointer ref_mask = nullptr; mitk::Image::Pointer ref_mitk_mask = mitk::IOUtil::Load(filename); mitk::CastToItkImage(ref_mitk_mask, ref_mask); reference_masks.push_back(ref_mask); } } // Load peak image typedef mitk::ImageToItk< PeakImgType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(inputImage); caster->Update(); PeakImgType::Pointer peak_image = caster->GetOutput(); // Load all candidate tracts std::vector< std::string > candidate_tract_files = get_file_list(candidate_tract_folder); std::vector< mitk::FiberBundle::Pointer > input_candidates; for (std::string f : candidate_tract_files) { mitk::FiberBundle::Pointer fib = mitk::IOUtil::Load(f); if (fib.IsNull()) continue; if (fib->GetNumFibers()<=0) continue; fib->ResampleLinear(minSpacing/10.0); input_candidates.push_back(fib); } std::cout.rdbuf (old); // <-- restore MITK_INFO << "Loaded " << candidate_tract_files.size() << " candidate tracts."; MITK_INFO << "Loaded " << reference_masks.size() << " reference masks."; double rmse = 0.0; int iteration = 0; std::string name = "NOANCHOR"; // Load reference tractogram consisting of all known tracts std::vector< mitk::FiberBundle::Pointer > input_reference; mitk::FiberBundle::Pointer anchor_tractogram = mitk::IOUtil::Load(anchors_file); if ( !(anchor_tractogram.IsNull() || anchor_tractogram->GetNumFibers()==0) ) { std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect anchor_tractogram->ResampleLinear(minSpacing/10.0); std::cout.rdbuf (old); // <-- restore input_reference.push_back(anchor_tractogram); // Fit known tracts to peak image to obtain underexplained image MITK_INFO << "Fit anchor tracts"; itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New(); fitter->SetTractograms(input_reference); fitter->SetLambda(lambda); fitter->SetFilterOutliers(filter_outliers); fitter->SetPeakImage(peak_image); fitter->SetVerbose(true); fitter->SetResampleFibers(false); fitter->SetMaskImage(mask); fitter->SetRegularization(VnlCostFunction::REGU::NONE); fitter->Update(); rmse = fitter->GetRMSE(); vnl_vector rms_diff = fitter->GetRmsDiffPerBundle(); logfile << "RMS_DIFF: " << setprecision(5) << rms_diff[0] << " " << name << " RMSE: " << rmse << "\n"; name = ist::GetFilenameWithoutExtension(anchors_file); mitk::FiberBundle::Pointer anchor_tracts = fitter->GetTractograms().at(0); anchor_tracts->SetFiberColors(255,255,255); mitk::IOUtil::Save(anchor_tracts, out_folder + boost::lexical_cast((int)(100000*rms_diff[0])) + "_" + name + ".fib"); peak_image = fitter->GetUnderexplainedImage(); peak_image_writer->SetInput(peak_image); peak_image_writer->SetFileName(out_folder + "Residual_" + name + ".nii.gz"); peak_image_writer->Update(); } if (use_weights || use_num_streamlines) { MITK_INFO << "Using tract weights as scores"; int c = 0; for (auto fib : input_candidates) { int mod = 1; double score = 0; if (use_weights) { score = fib->GetFiberWeight(0); mod = 100000; } else if (use_num_streamlines) score = fib->GetNumFibers(); fib->ColorFibersByOrientation(); std::string bundle_name = ist::GetFilenameWithoutExtension(candidate_tract_files.at(c)); std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect mitk::IOUtil::Save(fib, out_folder + boost::lexical_cast((int)(mod*score)) + "_" + bundle_name + ".fib"); float best_overlap = 0; int best_overlap_index = -1; int m_idx = 0; for (auto ref_mask : reference_masks) { float overlap = fib->GetOverlap(ref_mask, false); if (overlap>best_overlap) { best_overlap = overlap; best_overlap_index = m_idx; } ++m_idx; } unsigned int num_voxels = 0; { itk::TractDensityImageFilter< ItkUcharImageType >::Pointer masks_filter = itk::TractDensityImageFilter< ItkUcharImageType >::New(); masks_filter->SetInputImage(mask); masks_filter->SetBinaryOutput(true); masks_filter->SetFiberBundle(fib); masks_filter->SetUseImageGeometry(true); masks_filter->Update(); num_voxels = masks_filter->GetNumCoveredVoxels(); } double weight_sum = 0; for (int i=0; iGetNumFibers(); i++) weight_sum += fib->GetFiberWeight(i); std::cout.rdbuf (old); // <-- restore logfile << "RMS_DIFF: " << setprecision(5) << score << " " << bundle_name << " " << num_voxels << " " << fib->GetNumFibers() << " " << weight_sum << "\n"; if (best_overlap_index>=0) logfile << "Best_overlap: " << setprecision(5) << best_overlap << " " << ist::GetFilenameWithoutExtension(anchor_mask_files.at(best_overlap_index)) << "\n"; else logfile << "No_overlap\n"; ++c; } } else if (!greedy_add) { MITK_INFO << "Fit candidate tracts"; itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New(); fitter->SetLambda(lambda); fitter->SetFilterOutliers(filter_outliers); fitter->SetVerbose(true); fitter->SetPeakImage(peak_image); fitter->SetResampleFibers(false); fitter->SetMaskImage(mask); fitter->SetTractograms(input_candidates); fitter->SetFitIndividualFibers(true); if (regu=="MSM") fitter->SetRegularization(VnlCostFunction::REGU::MSM); else if (regu=="Variance") fitter->SetRegularization(VnlCostFunction::REGU::VARIANCE); else if (regu=="Lasso") fitter->SetRegularization(VnlCostFunction::REGU::LASSO); else if (regu=="VoxelVariance") fitter->SetRegularization(VnlCostFunction::REGU::VOXEL_VARIANCE); else if (regu=="GroupLasso") fitter->SetRegularization(VnlCostFunction::REGU::GROUP_LASSO); else if (regu=="GroupVariance") fitter->SetRegularization(VnlCostFunction::REGU::GROUP_VARIANCE); else if (regu=="NONE") fitter->SetRegularization(VnlCostFunction::REGU::NONE); fitter->Update(); vnl_vector rms_diff = fitter->GetRmsDiffPerBundle(); // vnl_vector log_rms_diff = rms_diff-rms_diff.min_value() + 1; // log_rms_diff = log_rms_diff.apply(std::log); // log_rms_diff /= log_rms_diff.max_value(); int c = 0; for (auto fib : input_candidates) { // fib->SetFiberWeights( log_rms_diff[c] ); // fib->ColorFibersByOrientation(); std::string bundle_name = ist::GetFilenameWithoutExtension(candidate_tract_files.at(c)); std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect if (filter_zero_weights) fib = fib->FilterByWeights(0); mitk::IOUtil::Save(fib, out_folder + boost::lexical_cast((int)(100000*rms_diff[c])) + "_" + bundle_name + ".fib"); float best_overlap = 0; int best_overlap_index = -1; int m_idx = 0; for (auto ref_mask : reference_masks) { float overlap = fib->GetOverlap(ref_mask, false); if (overlap>best_overlap) { best_overlap = overlap; best_overlap_index = m_idx; } ++m_idx; } unsigned int num_voxels = 0; { itk::TractDensityImageFilter< ItkUcharImageType >::Pointer masks_filter = itk::TractDensityImageFilter< ItkUcharImageType >::New(); masks_filter->SetInputImage(mask); masks_filter->SetBinaryOutput(true); masks_filter->SetFiberBundle(fib); masks_filter->SetUseImageGeometry(true); masks_filter->Update(); num_voxels = masks_filter->GetNumCoveredVoxels(); } double weight_sum = 0; for (int i=0; iGetNumFibers(); i++) weight_sum += fib->GetFiberWeight(i); std::cout.rdbuf (old); // <-- restore logfile << "RMS_DIFF: " << setprecision(5) << rms_diff[c] << " " << bundle_name << " " << num_voxels << " " << fib->GetNumFibers() << " " << weight_sum << "\n"; if (best_overlap_index>=0) logfile << "Best_overlap: " << setprecision(5) << best_overlap << " " << ist::GetFilenameWithoutExtension(anchor_mask_files.at(best_overlap_index)) << "\n"; else logfile << "No_overlap\n"; ++c; } mitk::FiberBundle::Pointer out_fib = mitk::FiberBundle::New(); out_fib = out_fib->AddBundles(input_candidates); out_fib->ColorFibersByFiberWeights(false, true); mitk::IOUtil::Save(out_fib, out_folder + "AllCandidates.fib"); peak_image = fitter->GetUnderexplainedImage(); peak_image_writer->SetInput(peak_image); peak_image_writer->SetFileName(out_folder + "Residual_AllCandidates.nii.gz"); peak_image_writer->Update(); } else { MITK_INFO << "RMSE: " << setprecision(5) << rmse; // fitter->SetPeakImage(peak_image); // Iteratively add candidate bundles in a greedy manner while (!input_candidates.empty()) { double next_rmse = rmse; double num_peaks = 0; mitk::FiberBundle::Pointer best_candidate = nullptr; PeakImgType::Pointer best_candidate_peak_image = nullptr; for (int i=0; i<(int)input_candidates.size(); ++i) { // WHY NECESSARY AGAIN?? itk::FitFibersToImageFilter::Pointer fitter = itk::FitFibersToImageFilter::New(); fitter->SetLambda(lambda); fitter->SetFilterOutliers(filter_outliers); fitter->SetVerbose(false); fitter->SetPeakImage(peak_image); fitter->SetResampleFibers(false); fitter->SetMaskImage(mask); // ****************************** fitter->SetTractograms({input_candidates.at(i)}); std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect fitter->Update(); std::cout.rdbuf (old); // <-- restore double candidate_rmse = fitter->GetRMSE(); if (candidate_rmseGetNumCoveredDirections(); best_candidate = fitter->GetTractograms().at(0); best_candidate_peak_image = fitter->GetUnderexplainedImage(); } } if (best_candidate.IsNull()) break; // fitter->SetPeakImage(peak_image); peak_image = best_candidate_peak_image; int i=0; std::vector< mitk::FiberBundle::Pointer > remaining_candidates; std::vector< std::string > remaining_candidate_files; for (auto fib : input_candidates) { if (fib!=best_candidate) { remaining_candidates.push_back(fib); remaining_candidate_files.push_back(candidate_tract_files.at(i)); } else name = ist::GetFilenameWithoutExtension(candidate_tract_files.at(i)); ++i; } input_candidates = remaining_candidates; candidate_tract_files = remaining_candidate_files; iteration++; std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect // Save winning candidate if (filter_zero_weights) best_candidate = best_candidate->FilterByWeights(0); mitk::IOUtil::Save(best_candidate, out_folder + boost::lexical_cast(iteration) + "_" + name + ".fib"); peak_image_writer->SetInput(peak_image); peak_image_writer->SetFileName(out_folder + boost::lexical_cast(iteration) + "_" + name + ".nrrd"); peak_image_writer->Update(); // Calculate best overlap with reference masks for evaluation purposes float best_overlap = 0; int best_overlap_index = -1; i = 0; for (auto ref_mask : reference_masks) { float overlap = best_candidate->GetOverlap(ref_mask, false); 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/ExtractSimilarTracts.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/ExtractSimilarTracts.cpp index 2645e71a7d..5cefcfc547 100644 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/ExtractSimilarTracts.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/ExtractSimilarTracts.cpp @@ -1,237 +1,237 @@ /*=================================================================== 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 typedef itksys::SystemTools ist; typedef itk::Image ItkFloatImgType; mitk::FiberBundle::Pointer LoadFib(std::string filename) { std::vector fibInfile = mitk::IOUtil::Load(filename); if( fibInfile.empty() ) std::cout << "File " << filename << " could not be read!"; mitk::BaseData::Pointer baseData = fibInfile.at(0); return dynamic_cast(baseData.GetPointer()); } ItkFloatImgType::Pointer LoadItkImage(const std::string& filename) { mitk::Image::Pointer img = mitk::IOUtil::Load(filename); ItkFloatImgType::Pointer itkMask = ItkFloatImgType::New(); mitk::CastToItkImage(img, itkMask); return itkMask; } /*! \brief Spatially cluster fibers */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Extract Similar Tracts"); parser.setCategory("Fiber Tracking Evaluation"); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("", "i", mitkCommandLineParser::InputFile, "Input:", "input fiber bundle (.fib, .trk, .tck)", us::Any(), false); parser.addArgument("ref_tracts", "", mitkCommandLineParser::StringList, "Ref. Tracts:", "reference tracts (.fib, .trk, .tck)", us::Any(), false); parser.addArgument("ref_masks", "", mitkCommandLineParser::StringList, "Ref. Masks:", "reference bundle masks", us::Any()); parser.addArgument("", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output root", us::Any(), false); parser.addArgument("distance", "", mitkCommandLineParser::Int, "Distance:", "", 10); parser.addArgument("metric", "", mitkCommandLineParser::String, "Metric:", "EU_MEAN (default), EU_STD, EU_MAX"); parser.addArgument("subsample", "", mitkCommandLineParser::Float, "Subsampling factor:", "Only use specified fraction of input fibers", 1.0); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string in_fib = us::any_cast(parsedArgs["i"]); std::string out_root = us::any_cast(parsedArgs["o"]); mitkCommandLineParser::StringContainerType ref_bundle_files = us::any_cast(parsedArgs["ref_tracts"]); mitkCommandLineParser::StringContainerType ref_mask_files; if (parsedArgs.count("ref_masks")) ref_mask_files = us::any_cast(parsedArgs["ref_masks"]); if (ref_mask_files.size()>0 && ref_mask_files.size()!=ref_bundle_files.size()) { MITK_INFO << "If reference masks are used, there has to be one mask per reference tract."; return EXIT_FAILURE; } int distance = 10; if (parsedArgs.count("distance")) distance = us::any_cast(parsedArgs["distance"]); std::string metric = "EU_MEAN"; if (parsedArgs.count("metric")) metric = us::any_cast(parsedArgs["metric"]); float subsample = 1.0; if (parsedArgs.count("subsample")) subsample = us::any_cast(parsedArgs["subsample"]); try { mitk::FiberBundle::Pointer fib = LoadFib(in_fib); std::srand(0); if (subsample<1.0) fib = fib->SubsampleFibers(subsample); mitk::FiberBundle::Pointer resampled_fib = fib->GetDeepCopy(); resampled_fib->ResampleToNumPoints(12); std::vector< mitk::FiberBundle::Pointer > ref_fibs; std::vector< ItkFloatImgType::Pointer > ref_masks; for (std::size_t i=0; i distances; distances.push_back(distance); mitk::FiberBundle::Pointer anchor_tractogram = mitk::FiberBundle::New(nullptr); unsigned int c = 0; for (auto ref_fib : ref_fibs) { MITK_INFO << "Extracting " << ist::GetFilenameName(ref_bundle_files.at(c)); std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect try { itk::TractClusteringFilter::Pointer segmenter = itk::TractClusteringFilter::New(); // calculate centroids from reference bundle { itk::TractClusteringFilter::Pointer clusterer = itk::TractClusteringFilter::New(); clusterer->SetDistances({10,20,30}); clusterer->SetTractogram(ref_fib); clusterer->SetMetrics({new mitk::ClusteringMetricEuclideanStd()}); clusterer->SetMergeDuplicateThreshold(0.0); clusterer->Update(); std::vector tracts = clusterer->GetOutCentroids(); ref_fib = mitk::FiberBundle::New(nullptr); ref_fib = ref_fib->AddBundles(tracts); mitk::IOUtil::Save(ref_fib, out_root + "centroids_" + ist::GetFilenameName(ref_bundle_files.at(c))); segmenter->SetInCentroids(ref_fib); } // segment tract segmenter->SetFilterMask(ref_masks.at(c)); segmenter->SetOverlapThreshold(0.8); segmenter->SetDistances(distances); segmenter->SetTractogram(resampled_fib); segmenter->SetMergeDuplicateThreshold(0.0); segmenter->SetDoResampling(false); if (metric=="EU_MEAN") segmenter->SetMetrics({new mitk::ClusteringMetricEuclideanMean()}); else if (metric=="EU_STD") segmenter->SetMetrics({new mitk::ClusteringMetricEuclideanStd()}); else if (metric=="EU_MAX") segmenter->SetMetrics({new mitk::ClusteringMetricEuclideanMax()}); segmenter->Update(); std::vector< std::vector< long > > clusters = segmenter->GetOutFiberIndices(); if (clusters.size()>0) { vtkSmartPointer weights = vtkSmartPointer::New(); mitk::FiberBundle::Pointer result = mitk::FiberBundle::New(nullptr); std::vector< mitk::FiberBundle::Pointer > result_fibs; for (unsigned int cluster_index=0; cluster_indexGeneratePolyDataByIds(clusters.at(cluster_index), weights))); result = result->AddBundles(result_fibs); anchor_tractogram = anchor_tractogram->AddBundle(result); mitk::IOUtil::Save(result, out_root + "anchor_" + ist::GetFilenameName(ref_bundle_files.at(c))); fib = mitk::FiberBundle::New(fib->GeneratePolyDataByIds(clusters.back(), weights)); resampled_fib = mitk::FiberBundle::New(resampled_fib->GeneratePolyDataByIds(clusters.back(), weights)); } } catch(itk::ExceptionObject& excpt) { MITK_INFO << "Exception while processing " << ist::GetFilenameName(ref_bundle_files.at(c)); MITK_INFO << excpt.GetDescription(); } catch(std::exception& excpt) { MITK_INFO << "Exception while processing " << ist::GetFilenameName(ref_bundle_files.at(c)); MITK_INFO << excpt.what(); } std::cout.rdbuf (old); // <-- restore if (fib->GetNumFibers()==0) break; ++c; } MITK_INFO << "Streamlines in anchor tractogram: " << anchor_tractogram->GetNumFibers(); mitk::IOUtil::Save(anchor_tractogram, out_root + "anchor_tractogram.trk"); MITK_INFO << "Streamlines remaining in candidate tractogram: " << fib->GetNumFibers(); mitk::IOUtil::Save(fib, out_root + "candidate_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/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/LocalDirectionalFiberPlausibility.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/LocalDirectionalFiberPlausibility.cpp index b47893d07e..368c4dcd47 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/LocalDirectionalFiberPlausibility.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/LocalDirectionalFiberPlausibility.cpp @@ -1,315 +1,315 @@ /*=================================================================== 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 "mitkCommandLineParser.h" #include #include #include #include -#include +#include #include #include #include #include /*! \brief Calculate angular error of a tractogram with respect to the input reference directions. */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Local Directional Fiber Plausibility"); parser.setCategory("Fiber Tracking Evaluation"); parser.setDescription("Calculate angular error of a tractogram with respect to the input reference directions."); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input:", "input tractogram (.fib, vtk ascii file format)", us::Any(), false); parser.addArgument("reference", "r", mitkCommandLineParser::StringList, "Reference images:", "reference direction images", us::Any(), false); parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output:", "output root", us::Any(), false); parser.addArgument("mask", "m", mitkCommandLineParser::StringList, "Masks:", "mask images"); parser.addArgument("athresh", "a", mitkCommandLineParser::Float, "Angular threshold:", "angular threshold in degrees. closer fiber directions are regarded as one direction and clustered together.", 25, true); parser.addArgument("sthresh", "s", mitkCommandLineParser::Float, "Size threshold:", "Relative peak size threshold per voxel.", 0.0, true); parser.addArgument("maxdirs", "md", mitkCommandLineParser::Int, "Max. Clusters:", "Maximum number of fiber clusters.", 0, true); parser.addArgument("verbose", "v", mitkCommandLineParser::Bool, "Verbose:", "output optional and intermediate calculation results"); parser.addArgument("ignore", "n", mitkCommandLineParser::Bool, "Ignore:", "don't increase error for missing or too many directions"); parser.addArgument("empty", "e", mitkCommandLineParser::Bool, "Empty Voxels:", "don't increase error for empty voxels"); parser.addArgument("fileID", "id", mitkCommandLineParser::String, "ID:", "optional ID field"); map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; mitkCommandLineParser::StringContainerType referenceImages = us::any_cast(parsedArgs["reference"]); mitkCommandLineParser::StringContainerType maskImages; if (parsedArgs.count("mask")) maskImages = us::any_cast(parsedArgs["mask"]); string fibFile = us::any_cast(parsedArgs["input"]); float angularThreshold = 25; if (parsedArgs.count("athresh")) angularThreshold = us::any_cast(parsedArgs["athresh"]); float sizeThreshold = 0; if (parsedArgs.count("sthresh")) sizeThreshold = us::any_cast(parsedArgs["sthresh"]); int maxDirs = 0; if (parsedArgs.count("maxdirs")) maxDirs = us::any_cast(parsedArgs["maxdirs"]); string outRoot = us::any_cast(parsedArgs["out"]); bool verbose = false; if (parsedArgs.count("verbose")) verbose = us::any_cast(parsedArgs["verbose"]); bool ignoreMissing = false; if (parsedArgs.count("ignore")) ignoreMissing = us::any_cast(parsedArgs["ignore"]); bool ignoreEmpty = false; if (parsedArgs.count("empty")) ignoreEmpty = us::any_cast(parsedArgs["empty"]); string fileID = ""; if (parsedArgs.count("fileID")) fileID = us::any_cast(parsedArgs["fileID"]); try { typedef itk::Image ItkUcharImgType; typedef itk::Image< itk::Vector< float, 3>, 3 > ItkDirectionImage3DType; typedef itk::VectorContainer< unsigned int, ItkDirectionImage3DType::Pointer > ItkDirectionImageContainerType; typedef itk::EvaluateDirectionImagesFilter< float > EvaluationFilterType; // load fiber bundle mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(mitk::IOUtil::LoadData(fibFile)[0].GetPointer()); // load reference directions ItkDirectionImageContainerType::Pointer referenceImageContainer = ItkDirectionImageContainerType::New(); for (unsigned int i=0; i(referenceImages.at(i)); typedef mitk::ImageToItk< ItkDirectionImage3DType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(img); caster->Update(); ItkDirectionImage3DType::Pointer itkImg = caster->GetOutput(); referenceImageContainer->InsertElement(referenceImageContainer->Size(),itkImg); } catch(...){ std::cout << "could not load: " << referenceImages.at(i); } } ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); ItkDirectionImage3DType::Pointer dirImg = referenceImageContainer->GetElement(0); itkMaskImage->SetSpacing( dirImg->GetSpacing() ); itkMaskImage->SetOrigin( dirImg->GetOrigin() ); itkMaskImage->SetDirection( dirImg->GetDirection() ); itkMaskImage->SetLargestPossibleRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->SetBufferedRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->SetRequestedRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->Allocate(); itkMaskImage->FillBuffer(1); // extract directions from fiber bundle itk::TractsToVectorImageFilter::Pointer fOdfFilter = itk::TractsToVectorImageFilter::New(); fOdfFilter->SetFiberBundle(inputTractogram); fOdfFilter->SetMaskImage(itkMaskImage); fOdfFilter->SetAngularThreshold(cos(angularThreshold*itk::Math::pi/180)); fOdfFilter->SetNormalizeVectors(true); fOdfFilter->SetUseWorkingCopy(false); fOdfFilter->SetSizeThreshold(sizeThreshold); fOdfFilter->SetMaxNumDirections(maxDirs); fOdfFilter->Update(); if (verbose) { // write vector field mitk::FiberBundle::Pointer directions = fOdfFilter->GetOutputFiberBundle(); string outfilename = outRoot; outfilename.append("_VECTOR_FIELD.fib"); mitk::IOUtil::Save(directions.GetPointer(), outfilename ); // write direction images { itk::TractsToVectorImageFilter::ItkDirectionImageType::Pointer itkImg = fOdfFilter->GetDirectionImage(); typedef itk::ImageFileWriter< itk::TractsToVectorImageFilter::ItkDirectionImageType > WriterType; WriterType::Pointer writer = WriterType::New(); string outfilename = outRoot; outfilename.append("_DIRECTIONS.nrrd"); writer->SetFileName(outfilename.c_str()); writer->SetInput(itkImg); writer->Update(); } // write num direction image { ItkUcharImgType::Pointer numDirImage = fOdfFilter->GetNumDirectionsImage(); typedef itk::ImageFileWriter< ItkUcharImgType > WriterType; WriterType::Pointer writer = WriterType::New(); string outfilename = outRoot; outfilename.append("_NUM_DIRECTIONS.nrrd"); writer->SetFileName(outfilename.c_str()); writer->SetInput(numDirImage); writer->Update(); } } string logFile = outRoot; logFile.append("_ANGULAR_ERROR.csv"); ofstream file; file.open (logFile.c_str()); if (maskImages.size()>0) { for (unsigned int i=0; i(maskImages.at(i)); mitk::CastToItkImage(mitkMaskImage, itkMaskImage); // evaluate directions EvaluationFilterType::Pointer evaluationFilter = EvaluationFilterType::New(); //evaluationFilter->SetImageSet(directionImageContainer); evaluationFilter->SetReferenceImageSet(referenceImageContainer); evaluationFilter->SetMaskImage(itkMaskImage); evaluationFilter->SetIgnoreMissingDirections(ignoreMissing); evaluationFilter->SetIgnoreEmptyVoxels(ignoreEmpty); evaluationFilter->Update(); if (verbose) { EvaluationFilterType::OutputImageType::Pointer angularErrorImage = evaluationFilter->GetOutput(0); typedef itk::ImageFileWriter< EvaluationFilterType::OutputImageType > WriterType; WriterType::Pointer writer = WriterType::New(); string outfilename = outRoot; outfilename.append("_ERROR_IMAGE.nrrd"); writer->SetFileName(outfilename.c_str()); writer->SetInput(angularErrorImage); writer->Update(); } string maskFileName = itksys::SystemTools::GetFilenameWithoutExtension(maskImages.at(i)); unsigned found = maskFileName.find_last_of("_"); string sens = itksys::SystemTools::GetFilenameWithoutLastExtension(fibFile); if (!fileID.empty()) sens = fileID; sens.append(","); sens.append(maskFileName.substr(found+1)); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMeanAngularError())); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMedianAngularError())); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMaxAngularError())); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMinAngularError())); sens.append(","); sens.append(boost::lexical_cast(std::sqrt(evaluationFilter->GetVarAngularError()))); sens.append(";\n"); file << sens; } } else { // evaluate directions EvaluationFilterType::Pointer evaluationFilter = EvaluationFilterType::New(); //evaluationFilter->SetImageSet(directionImageContainer); evaluationFilter->SetReferenceImageSet(referenceImageContainer); evaluationFilter->SetMaskImage(itkMaskImage); evaluationFilter->SetIgnoreMissingDirections(ignoreMissing); evaluationFilter->SetIgnoreEmptyVoxels(ignoreEmpty); evaluationFilter->Update(); if (verbose) { EvaluationFilterType::OutputImageType::Pointer angularErrorImage = evaluationFilter->GetOutput(0); typedef itk::ImageFileWriter< EvaluationFilterType::OutputImageType > WriterType; WriterType::Pointer writer = WriterType::New(); string outfilename = outRoot; outfilename.append("_ERROR_IMAGE.nrrd"); writer->SetFileName(outfilename.c_str()); writer->SetInput(angularErrorImage); writer->Update(); } string sens = itksys::SystemTools::GetFilenameWithoutLastExtension(fibFile); if (!fileID.empty()) sens = fileID; sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMeanAngularError())); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMedianAngularError())); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMaxAngularError())); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMinAngularError())); sens.append(","); sens.append(boost::lexical_cast(std::sqrt(evaluationFilter->GetVarAngularError()))); sens.append(";\n"); file << sens; } file.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/MergeOverlappingTracts.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/MergeOverlappingTracts.cpp index 56df393e72..1147856404 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/MergeOverlappingTracts.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/MergeOverlappingTracts.cpp @@ -1,250 +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 #include #include #include #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 itk::Image ItkUIntImgType; std::vector< std::string > get_file_list(const std::string& path, std::vector< std::string > extensions={".fib", ".trk"}) { std::vector< std::string > file_list; itk::Directory::Pointer dir = itk::Directory::New(); if (dir->Load(path.c_str())) { int n = dir->GetNumberOfFiles(); for (int r = 0; r < n; r++) { const char *filename = dir->GetFile(r); std::string ext = ist::GetFilenameExtension(filename); for (auto e : extensions) { if (ext==e) { file_list.push_back(path + '/' + filename); break; } } } } return file_list; } /*! \brief */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Merge Overlapping Tracts"); parser.setCategory("Fiber Tracking Evaluation"); parser.setDescription(""); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("in", "i", mitkCommandLineParser::InputFile, "Input Folder:", "input folder", us::Any(), false); parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output Folder:", "output folder", us::Any(), false); parser.addArgument("overlap", "", mitkCommandLineParser::Float, "Overlap threshold:", "Tracts with overlap larger than this threshold are merged", 0.8, false); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string input_folder = us::any_cast(parsedArgs["in"]); std::string out_folder = us::any_cast(parsedArgs["out"]); float overlap = 0.8; if (parsedArgs.count("overlap")) overlap = us::any_cast(parsedArgs["overlap"]); try { if (!ist::PathExists(out_folder)) ist::MakeDirectory(out_folder); std::vector< std::string > fib_files = get_file_list(input_folder, {".fib", ".trk", ".tck"}); if (fib_files.empty()) return EXIT_FAILURE; std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect std::vector< mitk::FiberBundle::Pointer > fibs; for (std::string f : fib_files) { mitk::FiberBundle::Pointer fib = mitk::IOUtil::Load(f); fibs.push_back(fib); } mitk::FiberBundle::Pointer combined = mitk::FiberBundle::New(); combined = combined->AddBundles(fibs); itk::TractsToFiberEndingsImageFilter< ItkFloatImgType >::Pointer endings = itk::TractsToFiberEndingsImageFilter< ItkFloatImgType >::New(); endings->SetFiberBundle(combined); endings->SetUpsamplingFactor(0.25); endings->Update(); ItkFloatImgType::Pointer ref_image = endings->GetOutput(); std::cout.rdbuf (old); // <-- restore for (int its = 0; its<3; its++) { std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect std::vector< ItkFloatImgType::Pointer > mask_images; for (auto fib : fibs) { itk::TractDensityImageFilter< ItkFloatImgType >::Pointer masks = itk::TractDensityImageFilter< ItkFloatImgType >::New(); masks->SetInputImage(ref_image); masks->SetBinaryOutput(true); masks->SetFiberBundle(fib); masks->SetUseImageGeometry(true); masks->Update(); mask_images.push_back(masks->GetOutput()); } int r=0; vnl_matrix< int > mat; mat.set_size(mask_images.size(), mask_images.size()); mat.fill(0); for (auto m1 : mask_images) { float max_overlap = overlap; int c = 0; for (auto m2 : mask_images) { if (c<=r) { ++c; continue; } itk::ImageRegionConstIterator it1(m1, m1->GetLargestPossibleRegion()); itk::ImageRegionConstIterator it2(m2, m2->GetLargestPossibleRegion()); unsigned int c1 = 0; unsigned int c2 = 0; unsigned int intersect = 0; while( !it1.IsAtEnd() ) { if( it1.Get()>0 && it2.Get()>0) ++intersect; if(it1.Get()>0) ++c1; if(it2.Get()>0) ++c2; ++it1; ++it2; } if ( (float)intersect/c1>max_overlap ) { max_overlap = (float)intersect/c1; mat.put(r,c, 1); } if ( (float)intersect/c2>max_overlap ) { max_overlap = (float)intersect/c2; mat.put(r,c, 1); } ++c; } ++r; } std::vector< mitk::FiberBundle::Pointer > out_fibs; std::vector< bool > used; for (unsigned int i=0; i0) { fib = fib->AddBundle(fibs.at(c)); MITK_INFO << c; used[c] = true; } } out_fibs.push_back(fib); } std::cout.rdbuf (old); // <-- restore MITK_INFO << fibs.size() << " --> " << out_fibs.size(); if (fibs.size()==out_fibs.size()) break; fibs = out_fibs; } int c = 0; for (auto fib : fibs) { std::streambuf *old = cout.rdbuf(); // <-- save std::stringstream ss; std::cout.rdbuf (ss.rdbuf()); // <-- redirect mitk::IOUtil::Save(fib, out_folder + "/bundle_" + boost::lexical_cast(c) + ".trk"); std::cout.rdbuf (old); // <-- restore ++c; } } 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/PeaksAngularError.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/PeaksAngularError.cpp index 3c6d23ce7a..1031da0df4 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/PeaksAngularError.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/PeaksAngularError.cpp @@ -1,207 +1,207 @@ /*=================================================================== 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 "mitkCommandLineParser.h" #include #include #include #include -#include +#include #include #include #define _USE_MATH_DEFINES #include /*! \brief Calculate angular error between two sets of directions stored in multiple 3D vector images where each pixel corresponds to a vector (itk::Image< itk::Vector< float, 3>, 3 >) */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); parser.addArgument("test", "t", mitkCommandLineParser::StringList, "Test images", "test direction images", us::Any(), false); parser.addArgument("reference", "r", mitkCommandLineParser::StringList, "Reference images", "reference direction images", us::Any(), false); parser.addArgument("out", "o", mitkCommandLineParser::OutputDirectory, "Output directory", "output root", us::Any(), false); parser.addArgument("mask", "m", mitkCommandLineParser::InputFile, "Mask", "mask image"); parser.addArgument("verbose", "v", mitkCommandLineParser::Bool, "Verbose", "output optional and intermediate calculation results"); parser.addArgument("ignore", "i", mitkCommandLineParser::Bool, "Ignore", "don't increase error for missing or too many directions"); parser.setCategory("Fiber Tracking Evaluation"); parser.setTitle("Peaks Angular Error"); parser.setDescription("Calculate angular error between two sets of directions stored in multiple 3D vector images where each pixel corresponds to a vector (itk::Image< itk::Vector< float, 3>, 3 >)"); parser.setContributor("MIC"); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; mitkCommandLineParser::StringContainerType testImages = us::any_cast(parsedArgs["test"]); mitkCommandLineParser::StringContainerType referenceImages = us::any_cast(parsedArgs["reference"]); std::string maskImage(""); if (parsedArgs.count("mask")) maskImage = us::any_cast(parsedArgs["mask"]); std::string outRoot = us::any_cast(parsedArgs["out"]); bool verbose = false; if (parsedArgs.count("verbose")) verbose = us::any_cast(parsedArgs["verbose"]); bool ignore = false; if (parsedArgs.count("ignore")) ignore = us::any_cast(parsedArgs["ignore"]); try { typedef itk::Image ItkUcharImgType; typedef itk::Image< itk::Vector< float, 3>, 3 > ItkDirectionImage3DType; typedef itk::VectorContainer< unsigned int, ItkDirectionImage3DType::Pointer > ItkDirectionImageContainerType; typedef itk::EvaluateDirectionImagesFilter< float > EvaluationFilterType; ItkDirectionImageContainerType::Pointer directionImageContainer = ItkDirectionImageContainerType::New(); for (unsigned int i=0; i(testImages.at(i)); typedef mitk::ImageToItk< ItkDirectionImage3DType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(img); caster->Update(); ItkDirectionImage3DType::Pointer itkImg = caster->GetOutput(); directionImageContainer->InsertElement(directionImageContainer->Size(),itkImg); } catch(...){ std::cout << "could not load: " << referenceImages.at(i); } } // load reference directions ItkDirectionImageContainerType::Pointer referenceImageContainer = ItkDirectionImageContainerType::New(); for (unsigned int i=0; i(referenceImages.at(i)); typedef mitk::ImageToItk< ItkDirectionImage3DType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(img); caster->Update(); ItkDirectionImage3DType::Pointer itkImg = caster->GetOutput(); referenceImageContainer->InsertElement(referenceImageContainer->Size(),itkImg); } catch(...){ std::cout << "could not load: " << referenceImages.at(i); } } // load/create mask image ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); if (maskImage.compare("")==0) { ItkDirectionImage3DType::Pointer dirImg = referenceImageContainer->GetElement(0); itkMaskImage->SetSpacing( dirImg->GetSpacing() ); itkMaskImage->SetOrigin( dirImg->GetOrigin() ); itkMaskImage->SetDirection( dirImg->GetDirection() ); itkMaskImage->SetLargestPossibleRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->SetBufferedRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->SetRequestedRegion( dirImg->GetLargestPossibleRegion() ); itkMaskImage->Allocate(); itkMaskImage->FillBuffer(1); } else { mitk::Image::Pointer mitkMaskImage = mitk::IOUtil::Load(maskImage); mitk::CastToItkImage(mitkMaskImage, itkMaskImage); } // evaluate directions EvaluationFilterType::Pointer evaluationFilter = EvaluationFilterType::New(); evaluationFilter->SetImageSet(directionImageContainer); evaluationFilter->SetReferenceImageSet(referenceImageContainer); evaluationFilter->SetMaskImage(itkMaskImage); evaluationFilter->SetIgnoreMissingDirections(ignore); evaluationFilter->Update(); if (verbose) { EvaluationFilterType::OutputImageType::Pointer angularErrorImage = evaluationFilter->GetOutput(0); typedef itk::ImageFileWriter< EvaluationFilterType::OutputImageType > WriterType; WriterType::Pointer writer = WriterType::New(); std::string outfilename = outRoot; outfilename.append("_ERROR_IMAGE.nrrd"); writer->SetFileName(outfilename.c_str()); writer->SetInput(angularErrorImage); writer->Update(); } std::string logFile = outRoot; logFile.append("_ANGULAR_ERROR.csv"); ofstream file; file.open (logFile.c_str()); std::string sens = "Mean:"; sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMeanAngularError())); sens.append(";\n"); sens.append("Median:"); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMedianAngularError())); sens.append(";\n"); sens.append("Maximum:"); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMaxAngularError())); sens.append(";\n"); sens.append("Minimum:"); sens.append(","); sens.append(boost::lexical_cast(evaluationFilter->GetMinAngularError())); sens.append(";\n"); sens.append("STDEV:"); sens.append(","); sens.append(boost::lexical_cast(std::sqrt(evaluationFilter->GetVarAngularError()))); sens.append(";\n"); file << sens; file.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/TractometerMetrics.cpp b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/TractometerMetrics.cpp index d64eeb5420..01030c2a78 100755 --- a/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/TractometerMetrics.cpp +++ b/Modules/DiffusionImaging/FiberTracking/cmdapps/TractographyEvaluation/TractometerMetrics.cpp @@ -1,415 +1,415 @@ /*=================================================================== 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 "mitkCommandLineParser.h" #include #include #include #include -#include +#include #include #include #include #include #define _USE_MATH_DEFINES #include /*! \brief Calculates the Tractometer evaluation metrics for tractograms (http://www.tractometer.org/) */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Tractometer Metrics"); parser.setCategory("Fiber Tracking Evaluation"); parser.setDescription("Calculates the Tractometer evaluation metrics for tractograms (http://www.tractometer.org/)"); 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 root", us::Any(), false); parser.addArgument("labels", "l", mitkCommandLineParser::StringList, "Label pairs:", "label pairs", false); parser.addArgument("labelimage", "li", mitkCommandLineParser::String, "Label image:", "label image", false); parser.addArgument("verbose", "v", mitkCommandLineParser::Bool, "Verbose:", "output valid, invalid and no connections as fiber bundles"); parser.addArgument("fileID", "id", mitkCommandLineParser::String, "ID:", "optional ID field"); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; mitkCommandLineParser::StringContainerType labelpairs = us::any_cast(parsedArgs["labels"]); std::string fibFile = us::any_cast(parsedArgs["input"]); std::string labelImageFile = us::any_cast(parsedArgs["labelimage"]); std::string outRoot = us::any_cast(parsedArgs["out"]); std::string fileID = ""; if (parsedArgs.count("fileID")) fileID = us::any_cast(parsedArgs["fileID"]); bool verbose = false; if (parsedArgs.count("verbose")) verbose = us::any_cast(parsedArgs["verbose"]); try { typedef itk::Image ItkShortImgType; typedef itk::Image ItkUcharImgType; // load fiber bundle mitk::FiberBundle::Pointer inputTractogram = mitk::IOUtil::Load(fibFile); mitk::Image::Pointer img = mitk::IOUtil::Load(labelImageFile); typedef mitk::ImageToItk< ItkShortImgType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(img); caster->Update(); ItkShortImgType::Pointer labelImage = caster->GetOutput(); std::string path = itksys::SystemTools::GetFilenamePath(labelImageFile); std::vector< bool > detected; std::vector< std::pair< int, int > > labelsvector; std::vector< ItkUcharImgType::Pointer > bundleMasks; std::vector< ItkUcharImgType::Pointer > bundleMasksCoverage; short max = 0; for (unsigned int i=0; i l; l.first = boost::lexical_cast(labelpairs.at(i)); l.second = boost::lexical_cast(labelpairs.at(i+1)); std::cout << labelpairs.at(i); std::cout << labelpairs.at(i+1); if (l.first>max) max=l.first; if (l.second>max) max=l.second; labelsvector.push_back(l); detected.push_back(false); { mitk::Image::Pointer img = mitk::IOUtil::Load(path+"/Bundle"+boost::lexical_cast(labelsvector.size())+"_MASK.nrrd"); typedef mitk::ImageToItk< ItkUcharImgType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(img); caster->Update(); ItkUcharImgType::Pointer bundle = caster->GetOutput(); bundleMasks.push_back(bundle); } { mitk::Image::Pointer img = mitk::IOUtil::Load(path+"/Bundle"+boost::lexical_cast(labelsvector.size())+"_MASK_COVERAGE.nrrd"); typedef mitk::ImageToItk< ItkUcharImgType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(img); caster->Update(); ItkUcharImgType::Pointer bundle = caster->GetOutput(); bundleMasksCoverage.push_back(bundle); } } vnl_matrix< unsigned char > matrix; matrix.set_size(max, max); matrix.fill(0); vtkSmartPointer polyData = inputTractogram->GetFiberPolyData(); int validConnections = 0; int noConnection = 0; int validBundles = 0; int invalidBundles = 0; int invalidConnections = 0; ItkUcharImgType::Pointer coverage = ItkUcharImgType::New(); coverage->SetSpacing(labelImage->GetSpacing()); coverage->SetOrigin(labelImage->GetOrigin()); coverage->SetDirection(labelImage->GetDirection()); coverage->SetLargestPossibleRegion(labelImage->GetLargestPossibleRegion()); coverage->SetBufferedRegion( labelImage->GetLargestPossibleRegion() ); coverage->SetRequestedRegion( labelImage->GetLargestPossibleRegion() ); coverage->Allocate(); coverage->FillBuffer(0); vtkSmartPointer noConnPoints = vtkSmartPointer::New(); vtkSmartPointer noConnCells = vtkSmartPointer::New(); vtkSmartPointer invalidPoints = vtkSmartPointer::New(); vtkSmartPointer invalidCells = vtkSmartPointer::New(); vtkSmartPointer validPoints = vtkSmartPointer::New(); vtkSmartPointer validCells = vtkSmartPointer::New(); boost::progress_display disp(inputTractogram->GetNumFibers()); for (int i=0; iGetNumFibers(); i++) { ++disp; vtkCell* cell = polyData->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (numPoints>1) { double* start = points->GetPoint(0); itk::Point itkStart; itkStart[0] = start[0]; itkStart[1] = start[1]; itkStart[2] = start[2]; itk::Index<3> idxStart; labelImage->TransformPhysicalPointToIndex(itkStart, idxStart); double* end = points->GetPoint(numPoints-1); itk::Point itkEnd; itkEnd[0] = end[0]; itkEnd[1] = end[1]; itkEnd[2] = end[2]; itk::Index<3> idxEnd; labelImage->TransformPhysicalPointToIndex(itkEnd, idxEnd); if ( labelImage->GetPixel(idxStart)==0 || labelImage->GetPixel(idxEnd)==0 ) { noConnection++; if (verbose) { vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vtkIdType id = noConnPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } noConnCells->InsertNextCell(container); } } else { bool invalid = true; for (unsigned int i=0; i l = labelsvector.at(i); if ( (labelImage->GetPixel(idxStart)==l.first && labelImage->GetPixel(idxEnd)==l.second) || (labelImage->GetPixel(idxStart)==l.second && labelImage->GetPixel(idxEnd)==l.first) ) { for (int j=0; jGetPoint(j); itk::Point itkP; itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; itk::Index<3> idx; bundle->TransformPhysicalPointToIndex(itkP, idx); if ( bundle->GetPixel(idx) == 0 && bundle->GetLargestPossibleRegion().IsInside(idx) ) { outside=true; } } if (!outside) { validConnections++; if (detected.at(i)==false) validBundles++; detected.at(i) = true; invalid = false; vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vtkIdType id = validPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); itk::Point itkP; itkP[0] = p[0]; itkP[1] = p[1]; itkP[2] = p[2]; itk::Index<3> idx; coverage->TransformPhysicalPointToIndex(itkP, idx); if ( coverage->GetLargestPossibleRegion().IsInside(idx) ) coverage->SetPixel(idx, 1); } validCells->InsertNextCell(container); } break; } } if (invalid==true) { invalidConnections++; int x = labelImage->GetPixel(idxStart)-1; int y = labelImage->GetPixel(idxEnd)-1; if (x>=0 && y>0 && x(matrix.cols()) && y(matrix.rows()) && (matrix[x][y]==0 || matrix[y][x]==0) ) { invalidBundles++; matrix[x][y]=1; matrix[y][x]=1; } if (verbose) { vtkSmartPointer container = vtkSmartPointer::New(); for (int j=0; jGetPoint(j); vtkIdType id = invalidPoints->InsertNextPoint(p); container->GetPointIds()->InsertNextId(id); } invalidCells->InsertNextCell(container); } } } } } if (verbose) { vtkSmartPointer noConnPolyData = vtkSmartPointer::New(); noConnPolyData->SetPoints(noConnPoints); noConnPolyData->SetLines(noConnCells); mitk::FiberBundle::Pointer noConnFib = mitk::FiberBundle::New(noConnPolyData); std::string ncfilename = outRoot; ncfilename.append("_NC.fib"); mitk::IOUtil::Save(noConnFib.GetPointer(), ncfilename ); vtkSmartPointer invalidPolyData = vtkSmartPointer::New(); invalidPolyData->SetPoints(invalidPoints); invalidPolyData->SetLines(invalidCells); mitk::FiberBundle::Pointer invalidFib = mitk::FiberBundle::New(invalidPolyData); std::string icfilename = outRoot; icfilename.append("_IC.fib"); mitk::IOUtil::Save(invalidFib.GetPointer(), icfilename ); vtkSmartPointer validPolyData = vtkSmartPointer::New(); validPolyData->SetPoints(validPoints); validPolyData->SetLines(validCells); mitk::FiberBundle::Pointer validFib = mitk::FiberBundle::New(validPolyData); std::string vcfilename = outRoot; vcfilename.append("_VC.fib"); mitk::IOUtil::Save(validFib.GetPointer(), vcfilename ); { typedef itk::ImageFileWriter< ItkUcharImgType > WriterType; WriterType::Pointer writer = WriterType::New(); writer->SetFileName(outRoot+"_ABC.nrrd"); writer->SetInput(coverage); writer->Update(); } } // calculate coverage int wmVoxels = 0; int coveredVoxels = 0; itk::ImageRegionIterator it (coverage, coverage->GetLargestPossibleRegion()); while(!it.IsAtEnd()) { bool wm = false; for (unsigned int i=0; iGetPixel(it.GetIndex())>0) { wm = true; wmVoxels++; break; } } if (wm && it.Get()>0) coveredVoxels++; ++it; } int numFibers = inputTractogram->GetNumFibers(); double nc = (double)noConnection/numFibers; double vc = (double)validConnections/numFibers; double ic = (double)invalidConnections/numFibers; if (numFibers==0) { nc = 0.0; vc = 0.0; ic = 0.0; } int vb = validBundles; int ib = invalidBundles; double abc = (double)coveredVoxels/wmVoxels; std::cout << "NC: " << nc; std::cout << "VC: " << vc; std::cout << "IC: " << ic; std::cout << "VB: " << vb; std::cout << "IB: " << ib; std::cout << "ABC: " << abc; std::string logFile = outRoot; logFile.append("_TRACTOMETER.csv"); ofstream file; file.open (logFile.c_str()); { std::string sens = itksys::SystemTools::GetFilenameWithoutLastExtension(fibFile); if (!fileID.empty()) sens = fileID; sens.append(","); sens.append(boost::lexical_cast(nc)); sens.append(","); sens.append(boost::lexical_cast(vc)); sens.append(","); sens.append(boost::lexical_cast(ic)); sens.append(","); sens.append(boost::lexical_cast(validBundles)); sens.append(","); sens.append(boost::lexical_cast(invalidBundles)); sens.append(","); sens.append(boost::lexical_cast(abc)); sens.append(";\n"); file << sens; } file.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/Quantification/IODataStructures/TbssImages/mitkNrrdTbssImageWriter.cpp b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssImageWriter.cpp index 1554faf924..672d79a6c9 100644 --- a/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssImageWriter.cpp +++ b/Modules/DiffusionImaging/Quantification/IODataStructures/TbssImages/mitkNrrdTbssImageWriter.cpp @@ -1,165 +1,165 @@ /*=================================================================== 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 __mitkNrrdTbssImageWriter__cpp #define __mitkNrrdTbssImageWriter__cpp #include "mitkNrrdTbssImageWriter.h" #include "itkMetaDataDictionary.h" #include "itkMetaDataObject.h" #include "itkNrrdImageIO.h" //#include "itkNiftiImageIO.h" #include "itkImageFileWriter.h" #include "itksys/SystemTools.hxx" -#include "boost/lexical_cast.hpp" +#include "mitkLexicalCast.h" #include #include mitk::NrrdTbssImageWriter::NrrdTbssImageWriter() : m_FileName(""), m_FilePrefix(""), m_FilePattern(""), m_Success(false) { this->SetNumberOfRequiredInputs( 1 ); } mitk::NrrdTbssImageWriter::~NrrdTbssImageWriter() {} void mitk::NrrdTbssImageWriter::GenerateData() { m_Success = false; InputType* input = this->GetInput(); if (input == nullptr) { itkWarningMacro(<<"Sorry, input to NrrdTbssImageWriter is nullptr!"); return; } if ( m_FileName == "" ) { itkWarningMacro( << "Sorry, filename has not been set!" ); return ; } itk::VectorImage::Pointer img = input->GetImage(); std::string key; std::string val; /* For the case of a tbss image containing data of the patients: Save info about the groups and the type of measurement */ std::vector< std::pair > groups = input->GetGroupInfo(); auto it = groups.begin(); int i=0; while(it != groups.end()) { std::pair p = *it; key = "Group_index_" + boost::lexical_cast(i); val = " " + p.first + " " + boost::lexical_cast(p.second); //sprintf( keybuffer, "Group_index_%04d", std::string(i) ); // sprintf( valbuffer, "%1d %1d", p.first, p.second); //std::cout << valbuffer << std::endl; //itk::EncapsulateMetaData< std::string >(input->GetImage()->GetMetaDataDictionary(),std::string(keybuffer),std::string(valbuffer)); itk::EncapsulateMetaData< std::string >(input->GetImage()->GetMetaDataDictionary(),key,val); it++; ++i; } key = "Measurement info"; val = input->GetMeasurementInfo(); itk::EncapsulateMetaData< std::string >(input->GetImage()->GetMetaDataDictionary(),key,val); typedef itk::VectorImage ImageType; itk::NrrdImageIO::Pointer io = itk::NrrdImageIO::New(); io->SetFileType( itk::ImageIOBase::Binary ); io->UseCompressionOn(); typedef itk::ImageFileWriter WriterType; WriterType::Pointer nrrdWriter = WriterType::New(); nrrdWriter->UseInputMetaDataDictionaryOn(); nrrdWriter->SetInput( img ); nrrdWriter->SetImageIO(io); nrrdWriter->SetFileName(m_FileName); nrrdWriter->UseCompressionOn(); nrrdWriter->SetImageIO(io); try { nrrdWriter->Update(); } catch (itk::ExceptionObject e) { std::cout << e << std::endl; } m_Success = true; } void mitk::NrrdTbssImageWriter::SetInput( InputType* tbssVol ) { this->ProcessObject::SetNthInput( 0, tbssVol ); } mitk::TbssImage* mitk::NrrdTbssImageWriter::GetInput() { if ( this->GetNumberOfInputs() < 1 ) { return nullptr; } else { return dynamic_cast ( this->ProcessObject::GetInput( 0 ) ); } } std::vector mitk::NrrdTbssImageWriter::GetPossibleFileExtensions() { std::vector possibleFileExtensions; possibleFileExtensions.push_back(".tbss"); return possibleFileExtensions; } std::string mitk::NrrdTbssImageWriter::GetSupportedBaseData() const { return TbssImage::GetStaticNameOfClass(); } #endif //__mitkNrrdTbssImageWriter__cpp diff --git a/Modules/DiffusionImaging/Quantification/cmdapps/MultishellMethods.cpp b/Modules/DiffusionImaging/Quantification/cmdapps/MultishellMethods.cpp index 3dc5a4d61b..68fc83c1ea 100644 --- a/Modules/DiffusionImaging/Quantification/cmdapps/MultishellMethods.cpp +++ b/Modules/DiffusionImaging/Quantification/cmdapps/MultishellMethods.cpp @@ -1,216 +1,216 @@ /*=================================================================== 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 "mitkCommandLineParser.h" -#include +#include #include #include #include #include #include #include #include #include #include #include #include int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setTitle("Multishell Methods"); parser.setCategory("Preprocessing Tools"); parser.setDescription(""); parser.setContributor("MIC"); parser.setArgumentPrefix("--", "-"); parser.addArgument("in", "i", mitkCommandLineParser::InputFile, "Input:", "input file", us::Any(), false); parser.addArgument("out", "o", mitkCommandLineParser::OutputFile, "Output:", "output file", us::Any(), false); parser.addArgument("adc", "D", mitkCommandLineParser::Bool, "ADC:", "ADC Average", us::Any(), false); parser.addArgument("akc", "K", mitkCommandLineParser::Bool, "Kurtosis fit:", "Kurtosis Fit", us::Any(), false); parser.addArgument("biexp", "B", mitkCommandLineParser::Bool, "BiExp fit:", "BiExp fit", us::Any(), false); parser.addArgument("targetbvalue", "b", mitkCommandLineParser::String, "b Value:", "target bValue (mean, min, max)", us::Any(), false); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; // mandatory arguments std::string inName = us::any_cast(parsedArgs["in"]); std::string outName = us::any_cast(parsedArgs["out"]); bool applyADC = us::any_cast(parsedArgs["adc"]); bool applyAKC = us::any_cast(parsedArgs["akc"]); bool applyBiExp = us::any_cast(parsedArgs["biexp"]); std::string targetType = us::any_cast(parsedArgs["targetbvalue"]); try { std::cout << "Loading " << inName; mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Diffusion Weighted Images"}, {}); mitk::Image::Pointer dwi = mitk::IOUtil::Load(inName, &functor); if ( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dwi ) ) { typedef itk::RadialMultishellToSingleshellImageFilter FilterType; typedef itk::DwiGradientLengthCorrectionFilter CorrectionFilterType; CorrectionFilterType::Pointer roundfilter = CorrectionFilterType::New(); roundfilter->SetRoundingValue( 1000 ); roundfilter->SetReferenceBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue( dwi )); roundfilter->SetReferenceGradientDirectionContainer(mitk::DiffusionPropertyHelper::GetGradientContainer(dwi)); roundfilter->Update(); dwi->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( roundfilter->GetNewBValue() ) ); dwi->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( roundfilter->GetOutputGradientDirectionContainer() ) ); // filter input parameter const mitk::DiffusionPropertyHelper::BValueMapType &originalShellMap = mitk::DiffusionPropertyHelper::GetBValueMap(dwi); mitk::DiffusionPropertyHelper::ImageType::Pointer vectorImage = mitk::DiffusionPropertyHelper::ImageType::New(); mitk::CastToItkImage(dwi, vectorImage); const mitk::DiffusionPropertyHelper::GradientDirectionsContainerType::Pointer gradientContainer = mitk::DiffusionPropertyHelper::GetGradientContainer(dwi); const unsigned int &bValue = mitk::DiffusionPropertyHelper::GetReferenceBValue( dwi ); // filter call vnl_vector bValueList(originalShellMap.size()-1); double targetBValue = bValueList.mean(); mitk::DiffusionPropertyHelper::BValueMapType::const_iterator it = originalShellMap.begin(); ++it; int i = 0 ; for(; it != originalShellMap.end(); ++it) bValueList.put(i++,it->first); if( targetType == "mean" ) targetBValue = bValueList.mean(); else if( targetType == "min" ) targetBValue = bValueList.min_value(); else if( targetType == "max" ) targetBValue = bValueList.max_value(); if(applyADC) { FilterType::Pointer filter = FilterType::New(); filter->SetInput(vectorImage); filter->SetOriginalGradientDirections(gradientContainer); filter->SetOriginalBValueMap(originalShellMap); filter->SetOriginalBValue(bValue); itk::ADCAverageFunctor::Pointer functor = itk::ADCAverageFunctor::New(); functor->setListOfBValues(bValueList); functor->setTargetBValue(targetBValue); filter->SetFunctor(functor); filter->Update(); // create new DWI image mitk::Image::Pointer outImage = mitk::GrabItkImageMemory( filter->GetOutput() ); outImage->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( targetBValue ) ); outImage->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( filter->GetTargetGradientDirections() ) ); mitk::DiffusionPropertyHelper propertyHelper( outImage ); propertyHelper.InitializeImage(); mitk::IOUtil::Save(outImage, (outName + "_ADC.dwi").c_str()); } if(applyAKC) { FilterType::Pointer filter = FilterType::New(); filter->SetInput(vectorImage); filter->SetOriginalGradientDirections(gradientContainer); filter->SetOriginalBValueMap(originalShellMap); filter->SetOriginalBValue(bValue); itk::KurtosisFitFunctor::Pointer functor = itk::KurtosisFitFunctor::New(); functor->setListOfBValues(bValueList); functor->setTargetBValue(targetBValue); filter->SetFunctor(functor); filter->Update(); // create new DWI image mitk::Image::Pointer outImage = mitk::GrabItkImageMemory( filter->GetOutput() ); outImage->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( targetBValue ) ); outImage->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( filter->GetTargetGradientDirections() ) ); mitk::DiffusionPropertyHelper propertyHelper( outImage ); propertyHelper.InitializeImage(); mitk::IOUtil::Save(outImage, (std::string(outName) + "_AKC.dwi").c_str()); } if(applyBiExp) { FilterType::Pointer filter = FilterType::New(); filter->SetInput(vectorImage); filter->SetOriginalGradientDirections(gradientContainer); filter->SetOriginalBValueMap(originalShellMap); filter->SetOriginalBValue(bValue); itk::BiExpFitFunctor::Pointer functor = itk::BiExpFitFunctor::New(); functor->setListOfBValues(bValueList); functor->setTargetBValue(targetBValue); filter->SetFunctor(functor); filter->Update(); // create new DWI image mitk::Image::Pointer outImage = mitk::GrabItkImageMemory( filter->GetOutput() ); outImage->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), mitk::FloatProperty::New( targetBValue ) ); outImage->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), mitk::GradientDirectionsProperty::New( filter->GetTargetGradientDirections() ) ); mitk::DiffusionPropertyHelper propertyHelper( outImage ); propertyHelper.InitializeImage(); mitk::IOUtil::Save(outImage, (std::string(outName) + "_BiExp.dwi").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/Quantification/cmdapps/QballReconstruction.cpp b/Modules/DiffusionImaging/Quantification/cmdapps/QballReconstruction.cpp index dc12f4571a..01c2dab1ab 100644 --- a/Modules/DiffusionImaging/Quantification/cmdapps/QballReconstruction.cpp +++ b/Modules/DiffusionImaging/Quantification/cmdapps/QballReconstruction.cpp @@ -1,263 +1,263 @@ /*=================================================================== 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 "mitkImage.h" #include "itkAnalyticalDiffusionQballReconstructionImageFilter.h" -#include +#include #include "mitkCommandLineParser.h" #include #include #include #include #include #include #include #include /** * Perform Q-ball reconstruction using a spherical harmonics basis */ int main(int argc, char* argv[]) { mitkCommandLineParser parser; parser.setArgumentPrefix("--", "-"); parser.addArgument("input", "i", mitkCommandLineParser::InputFile, "Input file", "input raw dwi (.dwi or .nii/.nii.gz)", us::Any(), false); parser.addArgument("outFile", "o", mitkCommandLineParser::OutputFile, "Output file", "output file", us::Any(), false); parser.addArgument("shOrder", "sh", mitkCommandLineParser::Int, "Spherical harmonics order", "spherical harmonics order", 4, true); parser.addArgument("b0Threshold", "t", mitkCommandLineParser::Int, "b0 threshold", "baseline image intensity threshold", 0, true); parser.addArgument("lambda", "r", mitkCommandLineParser::Float, "Lambda", "ragularization factor lambda", 0.006, true); parser.addArgument("csa", "csa", mitkCommandLineParser::Bool, "Constant solid angle consideration", "use constant solid angle consideration"); parser.addArgument("outputCoeffs", "shc", mitkCommandLineParser::Bool, "Output coefficients", "output file containing the SH coefficients"); parser.addArgument("mrtrix", "mb", mitkCommandLineParser::Bool, "MRtrix", "use MRtrix compatible spherical harmonics definition"); parser.setCategory("Signal Modelling"); parser.setTitle("Qball Reconstruction"); parser.setDescription(""); parser.setContributor("MIC"); std::map parsedArgs = parser.parseArguments(argc, argv); if (parsedArgs.size()==0) return EXIT_FAILURE; std::string inFileName = us::any_cast(parsedArgs["input"]); std::string outfilename = us::any_cast(parsedArgs["outFile"]); outfilename = itksys::SystemTools::GetFilenamePath(outfilename)+"/"+itksys::SystemTools::GetFilenameWithoutExtension(outfilename); int threshold = 0; if (parsedArgs.count("b0Threshold")) threshold = us::any_cast(parsedArgs["b0Threshold"]); int shOrder = 4; if (parsedArgs.count("shOrder")) shOrder = us::any_cast(parsedArgs["shOrder"]); float lambda = 0.006; if (parsedArgs.count("lambda")) lambda = us::any_cast(parsedArgs["lambda"]); int normalization = 0; if (parsedArgs.count("csa") && us::any_cast(parsedArgs["csa"])) normalization = 6; bool outCoeffs = false; if (parsedArgs.count("outputCoeffs")) outCoeffs = us::any_cast(parsedArgs["outputCoeffs"]); bool mrTrix = false; if (parsedArgs.count("mrtrix")) mrTrix = us::any_cast(parsedArgs["mrtrix"]); try { mitk::PreferenceListReaderOptionsFunctor functor = mitk::PreferenceListReaderOptionsFunctor({"Diffusion Weighted Images"}, {}); std::vector< mitk::BaseData::Pointer > infile = mitk::IOUtil::Load(inFileName, &functor); mitk::Image::Pointer dwi = dynamic_cast(infile.at(0).GetPointer()); mitk::DiffusionPropertyHelper propertyHelper(dwi); propertyHelper.AverageRedundantGradients(0.001); propertyHelper.InitializeImage(); mitk::OdfImage::Pointer image = mitk::OdfImage::New(); mitk::Image::Pointer coeffsImage = mitk::Image::New(); std::cout << "SH order: " << shOrder; std::cout << "lambda: " << lambda; std::cout << "B0 threshold: " << threshold; switch ( shOrder ) { case 4: { typedef itk::AnalyticalDiffusionQballReconstructionImageFilter FilterType; mitk::DiffusionPropertyHelper::ImageType::Pointer itkVectorImagePointer = mitk::DiffusionPropertyHelper::ImageType::New(); mitk::CastToItkImage(dwi, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(dwi)); filter->SetGradientImage( mitk::DiffusionPropertyHelper::GetGradientContainer(dwi), itkVectorImagePointer ); filter->SetThreshold( threshold ); filter->SetLambda(lambda); filter->SetUseMrtrixBasis(mrTrix); if (normalization==0) filter->SetNormalizationMethod(FilterType::QBAR_STANDARD); else filter->SetNormalizationMethod(FilterType::QBAR_SOLID_ANGLE); filter->Update(); image->InitializeByItk( filter->GetOutput() ); image->SetVolume( filter->GetOutput()->GetBufferPointer() ); coeffsImage->InitializeByItk( filter->GetCoefficientImage().GetPointer() ); coeffsImage->SetVolume( filter->GetCoefficientImage()->GetBufferPointer() ); break; } case 6: { typedef itk::AnalyticalDiffusionQballReconstructionImageFilter FilterType; mitk::DiffusionPropertyHelper::ImageType::Pointer itkVectorImagePointer = mitk::DiffusionPropertyHelper::ImageType::New(); mitk::CastToItkImage(dwi, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(dwi)); filter->SetGradientImage( mitk::DiffusionPropertyHelper::GetGradientContainer(dwi), itkVectorImagePointer ); filter->SetThreshold( threshold ); filter->SetLambda(lambda); filter->SetUseMrtrixBasis(mrTrix); if (normalization==0) filter->SetNormalizationMethod(FilterType::QBAR_STANDARD); else filter->SetNormalizationMethod(FilterType::QBAR_SOLID_ANGLE); filter->Update(); image->InitializeByItk( filter->GetOutput() ); image->SetVolume( filter->GetOutput()->GetBufferPointer() ); coeffsImage->InitializeByItk( filter->GetCoefficientImage().GetPointer() ); coeffsImage->SetVolume( filter->GetCoefficientImage()->GetBufferPointer() ); break; } case 8: { typedef itk::AnalyticalDiffusionQballReconstructionImageFilter FilterType; mitk::DiffusionPropertyHelper::ImageType::Pointer itkVectorImagePointer = mitk::DiffusionPropertyHelper::ImageType::New(); mitk::CastToItkImage(dwi, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(dwi)); filter->SetGradientImage( mitk::DiffusionPropertyHelper::GetGradientContainer(dwi), itkVectorImagePointer ); filter->SetThreshold( threshold ); filter->SetLambda(lambda); filter->SetUseMrtrixBasis(mrTrix); if (normalization==0) filter->SetNormalizationMethod(FilterType::QBAR_STANDARD); else filter->SetNormalizationMethod(FilterType::QBAR_SOLID_ANGLE); filter->Update(); image->InitializeByItk( filter->GetOutput() ); image->SetVolume( filter->GetOutput()->GetBufferPointer() ); coeffsImage->InitializeByItk( filter->GetCoefficientImage().GetPointer() ); coeffsImage->SetVolume( filter->GetCoefficientImage()->GetBufferPointer() ); break; } case 10: { typedef itk::AnalyticalDiffusionQballReconstructionImageFilter FilterType; mitk::DiffusionPropertyHelper::ImageType::Pointer itkVectorImagePointer = mitk::DiffusionPropertyHelper::ImageType::New(); mitk::CastToItkImage(dwi, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(dwi)); filter->SetGradientImage( mitk::DiffusionPropertyHelper::GetGradientContainer(dwi), itkVectorImagePointer ); filter->SetThreshold( threshold ); filter->SetLambda(lambda); filter->SetUseMrtrixBasis(mrTrix); if (normalization==0) filter->SetNormalizationMethod(FilterType::QBAR_STANDARD); else filter->SetNormalizationMethod(FilterType::QBAR_SOLID_ANGLE); filter->Update(); image->InitializeByItk( filter->GetOutput() ); image->SetVolume( filter->GetOutput()->GetBufferPointer() ); coeffsImage->InitializeByItk( filter->GetCoefficientImage().GetPointer() ); coeffsImage->SetVolume( filter->GetCoefficientImage()->GetBufferPointer() ); break; } case 12: { typedef itk::AnalyticalDiffusionQballReconstructionImageFilter FilterType; mitk::DiffusionPropertyHelper::ImageType::Pointer itkVectorImagePointer = mitk::DiffusionPropertyHelper::ImageType::New(); mitk::CastToItkImage(dwi, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(dwi)); filter->SetGradientImage( mitk::DiffusionPropertyHelper::GetGradientContainer(dwi), itkVectorImagePointer ); filter->SetThreshold( threshold ); filter->SetLambda(lambda); if (normalization==0) filter->SetNormalizationMethod(FilterType::QBAR_STANDARD); else filter->SetNormalizationMethod(FilterType::QBAR_SOLID_ANGLE); filter->Update(); image->InitializeByItk( filter->GetOutput() ); image->SetVolume( filter->GetOutput()->GetBufferPointer() ); coeffsImage->InitializeByItk( filter->GetCoefficientImage().GetPointer() ); coeffsImage->SetVolume( filter->GetCoefficientImage()->GetBufferPointer() ); break; } default: { std::cout << "Supplied SH order not supported. Using default order of 4."; typedef itk::AnalyticalDiffusionQballReconstructionImageFilter FilterType; mitk::DiffusionPropertyHelper::ImageType::Pointer itkVectorImagePointer = mitk::DiffusionPropertyHelper::ImageType::New(); mitk::CastToItkImage(dwi, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetBValue(mitk::DiffusionPropertyHelper::GetReferenceBValue(dwi)); filter->SetGradientImage( mitk::DiffusionPropertyHelper::GetGradientContainer(dwi), itkVectorImagePointer ); filter->SetThreshold( threshold ); filter->SetLambda(lambda); filter->SetUseMrtrixBasis(mrTrix); if (normalization==0) filter->SetNormalizationMethod(FilterType::QBAR_STANDARD); else filter->SetNormalizationMethod(FilterType::QBAR_SOLID_ANGLE); filter->Update(); image->InitializeByItk( filter->GetOutput() ); image->SetVolume( filter->GetOutput()->GetBufferPointer() ); coeffsImage->InitializeByItk( filter->GetCoefficientImage().GetPointer() ); coeffsImage->SetVolume( filter->GetCoefficientImage()->GetBufferPointer() ); } } std::string coeffout = outfilename; coeffout += "_shcoeffs.nrrd"; outfilename += ".odf"; mitk::IOUtil::Save(image, outfilename); if (outCoeffs) mitk::IOUtil::Save(coeffsImage, coeffout); } catch ( itk::ExceptionObject &err) { std::cout << "Exception: " << err; } catch ( std::exception err) { std::cout << "Exception: " << err.what(); } catch ( ... ) { std::cout << "Exception!"; } return EXIT_SUCCESS; } diff --git a/Modules/IGT/TrackingDevices/mitkNDIAuroraTypeInformation.cpp b/Modules/IGT/TrackingDevices/mitkNDIAuroraTypeInformation.cpp index 916fea69b1..ffde4634ce 100644 --- a/Modules/IGT/TrackingDevices/mitkNDIAuroraTypeInformation.cpp +++ b/Modules/IGT/TrackingDevices/mitkNDIAuroraTypeInformation.cpp @@ -1,153 +1,153 @@ /*=================================================================== 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 "mitkNDIAuroraTypeInformation.h" #include "mitkIGTHardwareException.h" #include "mitkNDITrackingDevice.h" namespace mitk { std::string NDIAuroraTypeInformation::GetTrackingDeviceName() { return "NDI Aurora"; } TrackingDeviceData NDIAuroraTypeInformation::GetDeviceDataAuroraCompact() { TrackingDeviceData data = { NDIAuroraTypeInformation::GetTrackingDeviceName(), "Aurora Compact", "NDIAuroraCompactFG_Dome.stl", "A" }; return data; } TrackingDeviceData NDIAuroraTypeInformation::GetDeviceDataAuroraPlanarCube() { TrackingDeviceData data = { NDIAuroraTypeInformation::GetTrackingDeviceName(), "Aurora Planar (Cube)", "NDIAurora.stl", "9" }; return data; } TrackingDeviceData NDIAuroraTypeInformation::GetDeviceDataAuroraPlanarDome() { TrackingDeviceData data = { NDIAuroraTypeInformation::GetTrackingDeviceName(), "Aurora Planar (Dome)", "NDIAuroraPlanarFG_Dome.stl", "A" }; return data; } TrackingDeviceData NDIAuroraTypeInformation::GetDeviceDataAuroraTabletop() { TrackingDeviceData data = { NDIAuroraTypeInformation::GetTrackingDeviceName(), "Aurora Tabletop", "NDIAuroraTabletopFG_Dome.stl", "A" }; return data; } NDIAuroraTypeInformation::NDIAuroraTypeInformation() { m_DeviceName = NDIAuroraTypeInformation::GetTrackingDeviceName(); - m_TrackingDeviceData.push_back(GetDeviceDataAuroraCompact()); m_TrackingDeviceData.push_back(GetDeviceDataAuroraPlanarCube()); m_TrackingDeviceData.push_back(GetDeviceDataAuroraPlanarDome()); m_TrackingDeviceData.push_back(GetDeviceDataAuroraTabletop()); + m_TrackingDeviceData.push_back(GetDeviceDataAuroraCompact()); } NDIAuroraTypeInformation::~NDIAuroraTypeInformation() { } mitk::TrackingDeviceSource::Pointer NDIAuroraTypeInformation::CreateTrackingDeviceSource( mitk::TrackingDevice::Pointer trackingDevice, mitk::NavigationToolStorage::Pointer navigationTools, std::string* errorMessage, std::vector* toolCorrespondencesInToolStorage) { MITK_DEBUG << "Creating Aurora tracking device."; mitk::TrackingDeviceSource::Pointer returnValue = mitk::TrackingDeviceSource::New(); mitk::NDITrackingDevice::Pointer thisDevice = dynamic_cast(trackingDevice.GetPointer()); try { //connect to aurora to dectect tools automatically thisDevice->OpenConnection(); } catch (mitk::IGTHardwareException& e) { errorMessage->append("Hardware error on opening the connection ("); errorMessage->append(e.GetDescription()); errorMessage->append(")"); return nullptr; } catch (mitk::IGTException& e) { errorMessage->append("Error on opening the connection ("); errorMessage->append(e.GetDescription()); errorMessage->append(")"); return nullptr; } //now search for automatically detected tools in the tool storage and save them mitk::NavigationToolStorage::Pointer newToolStorageInRightOrder = mitk::NavigationToolStorage::New(); std::vector alreadyFoundTools = std::vector(); *toolCorrespondencesInToolStorage = std::vector(); for (unsigned int i = 0; i < thisDevice->GetToolCount(); i++) { bool toolFound = false; for (unsigned int j = 0; j < navigationTools->GetToolCount(); j++) { //check if the serial number is the same to identify the tool if ((dynamic_cast(thisDevice->GetTool(i)))->GetSerialNumber() == navigationTools->GetTool(j)->GetSerialNumber()) { //check if this tool was already added to make sure that every tool is only added once (in case of same serial numbers) bool toolAlreadyAdded = false; for (unsigned int k = 0; k < alreadyFoundTools.size(); k++) { if (alreadyFoundTools.at(k) == j) { toolAlreadyAdded = true; } } if (!toolAlreadyAdded) { //add tool in right order newToolStorageInRightOrder->AddTool(navigationTools->GetTool(j)); toolCorrespondencesInToolStorage->push_back(j); //adapt name of tool dynamic_cast(thisDevice->GetTool(i))->SetToolName(navigationTools->GetTool(j)->GetToolName()); //set tip of tool dynamic_cast(thisDevice->GetTool(i))->SetToolTipPosition(navigationTools->GetTool(j)->GetToolTipPosition(), navigationTools->GetTool(j)->GetToolAxisOrientation()); //rember that this tool was already found alreadyFoundTools.push_back(j); toolFound = true; break; } } } if (!toolFound) { errorMessage->append("Error: did not find every automatically detected tool in the loaded tool storage: aborting initialization."); return nullptr; } } //And resort them (this was done in TrackingToolBoxWorker before). for (unsigned int i = 0; i < newToolStorageInRightOrder->GetToolCount(); i++) { navigationTools->AssignToolNumber(newToolStorageInRightOrder->GetTool(i)->GetIdentifier(), i); } returnValue->SetTrackingDevice(thisDevice); MITK_DEBUG << "Number of tools of created tracking device: " << thisDevice->GetToolCount(); MITK_DEBUG << "Number of outputs of created source: " << returnValue->GetNumberOfOutputs(); return returnValue; } } diff --git a/Modules/IGTUI/Qmitk/QmitkNDIAuroraWidget.ui b/Modules/IGTUI/Qmitk/QmitkNDIAuroraWidget.ui index 24cc19d363..76de061393 100644 --- a/Modules/IGTUI/Qmitk/QmitkNDIAuroraWidget.ui +++ b/Modules/IGTUI/Qmitk/QmitkNDIAuroraWidget.ui @@ -1,177 +1,195 @@ QmitkNDIAuroraWidget 0 0 400 153 - - + + + + + 0 + 0 + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" text-decoration: underline;">Aurora</span></p></body></html> - - + + - + Com Port: + + + 0 + 0 + + COM + + + 0 + 0 + + Auto Scan Qt::Horizontal 40 20 Port Type: /dev/ttyUSB /dev/ttyS Qt::Horizontal 40 20 Qt::Vertical 20 40 + + + + Qt::Horizontal + + + + 40 + 20 + + + + - - - 120 - 50 - - - - - 120 - 80 - - <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } -</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;" bgcolor="#000000"> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> </span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;"> </span></p> -<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; text-decoration: underline; color:#ffffff;">output:</span><span style=" font-size:8pt;"> </span></p></body></html> +</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8pt; font-weight:400; font-style:normal;" bgcolor="#000000"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" text-decoration: underline; color:#ffffff;">output:</span> </p></body></html> Qt::NoTextInteraction
- - - 120 - 0 - - - - - 120 - 16777215 - - Test Connection + + + + Qt::Vertical + + + + 20 + 40 + + + +
diff --git a/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.ui b/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.ui index d2a2dd9051..2b5778c388 100644 --- a/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.ui +++ b/Modules/IGTUI/Qmitk/QmitkNavigationToolCreationWidget.ui @@ -1,586 +1,586 @@ QmitkNavigationToolCreationWidgetControls 0 0 618 650 Form Device Type: 150 0 150 16777215 - 2 + 0 0 0 600 - 456 + 433 Basic Information 100 0 Name: NewTool 100 0 Calibration File: none 60 16777215 Load Qt::Vertical 20 40 0 0 600 - 456 + 433 Tool Visualization Default representation (shows tool coordinates) true Use surface from data storage 200 0 150 16777215 Qt::Horizontal 40 20 Load surface from file false 60 16777215 Load Qt::Horizontal 40 20 Qt::Vertical 20 8 0 0 600 - 456 + 433 Tool Landmarks 0 Control Points for Registration Tool Landmarks 0 0 - 276 - 161 + 600 + 433 Advanced 100 0 Tool Type: 150 0 150 16777215 Instrument Fiducial Skinmarker Unkown 100 0 Identifier: <not given> 100 0 Serial Number: <not given> Tooltip: Qt::Horizontal 40 20 Edit Tooltip true Qt::Vertical 20 40 Tool Axis: Qt::Horizontal 40 20 QAbstractSpinBox::CorrectToPreviousValue -9999 9999 1 -9999 9999 -9999 9999 Qt::Horizontal Qt::Horizontal 40 20 Cancel Finished QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
1
QmitkPointListWidget QWidget
QmitkPointListWidget.h
1
diff --git a/Modules/IGTUI/Qmitk/QmitkNavigationToolManagementWidgetControls.ui b/Modules/IGTUI/Qmitk/QmitkNavigationToolManagementWidgetControls.ui index 4964d23533..6b1cae8454 100644 --- a/Modules/IGTUI/Qmitk/QmitkNavigationToolManagementWidgetControls.ui +++ b/Modules/IGTUI/Qmitk/QmitkNavigationToolManagementWidgetControls.ui @@ -1,315 +1,273 @@ QmitkNavigationToolManagementWidgetControls 0 0 443 781 Form Qt::Horizontal 40 20 Whole Storage: Create New Load Save Qt::Horizontal 0 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:7.8pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Storage Name:</span></p></body></html> <none> Qt::Horizontal 40 20 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt; font-weight:600;">Tools:</span></p></body></html> Qt::Horizontal 40 20 - - - 60 - 16777215 - - Add - - - 60 - 16777215 - - Load <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> <html><head><meta name="qrichtext" content="1" /><style type="text/css"> p, li { white-space: pre-wrap; } </style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:7.8pt; font-weight:400; font-style:normal;"> <p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">Selected:</span></p></body></html> - - - 60 - 16777215 - - Up - - - 60 - 16777215 - - Down - - - 60 - 16777215 - - Delete - - - 60 - 16777215 - - Edit - - - 60 - 16777215 - - Save Qt::Vertical 20 40 0 150 Qt::Vertical 20 40 QmitkNavigationToolCreationWidget QWidget
QmitkNavigationToolCreationWidget.h
1
diff --git a/Modules/ModuleList.cmake b/Modules/ModuleList.cmake index 8ac0be92e5..89c06dd6e0 100644 --- a/Modules/ModuleList.cmake +++ b/Modules/ModuleList.cmake @@ -1,77 +1,78 @@ # The entries in the mitk_modules list must be # ordered according to their dependencies. set(MITK_MODULES Core CommandLine AppUtil RDF LegacyIO DataTypesExt Annotation LegacyGL AlgorithmsExt MapperExt DICOMReader DICOMReaderServices DICOMTesting SceneSerializationBase PlanarFigure ImageDenoising ImageExtraction SceneSerialization Gizmo GraphAlgorithms Multilabel ImageStatistics ContourModel SurfaceInterpolation Segmentation PlanarFigureSegmentation QtWidgets QtWidgetsExt Chart SegmentationUI MatchPointRegistration MatchPointRegistrationUI Classification GPGPU OpenIGTLink IGTBase IGT CameraCalibration OpenCL OpenCVVideoSupport QtOverlays ToFHardware ToFProcessing ToFUI PhotoacousticsHardware PhotoacousticsAlgorithms PhotoacousticsLib US USUI DicomUI Remeshing Python QtPython Persistence OpenIGTLinkUI IGTUI DicomRT RTUI IOExt XNAT TubeGraph BiophotonicsHardware DiffusionImaging TumorInvasionAnalysis BoundingShape RenderWindowManager RenderWindowManagerUI CEST + BasicImageProcessing ) if(MITK_ENABLE_PIC_READER) list(APPEND MITK_MODULES IpPicSupportIO) endif() diff --git a/Modules/OpenCVVideoSupport/Commands/mitkBasicCombinationOpenCVImageFilter.cpp b/Modules/OpenCVVideoSupport/Commands/mitkBasicCombinationOpenCVImageFilter.cpp index 555c6bcb1b..00a94cfe98 100644 --- a/Modules/OpenCVVideoSupport/Commands/mitkBasicCombinationOpenCVImageFilter.cpp +++ b/Modules/OpenCVVideoSupport/Commands/mitkBasicCombinationOpenCVImageFilter.cpp @@ -1,72 +1,73 @@ /*=================================================================== 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 "mitkBasicCombinationOpenCVImageFilter.h" +#include namespace mitk { bool BasicCombinationOpenCVImageFilter::OnFilterImage( cv::Mat& image ) { int imageId = this->GetCurrentImageId(); // go through the list of all filters for ( auto it = m_FilterList.begin(); it != m_FilterList.end(); ++it ) { // apply current filter and return false if the filter returned false if (! (*it)->FilterImage(image, imageId) ) { return false; } } return true; } void BasicCombinationOpenCVImageFilter::PushFilter( AbstractOpenCVImageFilter::Pointer filter ) { m_FilterList.push_back(filter); } AbstractOpenCVImageFilter::Pointer BasicCombinationOpenCVImageFilter::PopFilter( ) { AbstractOpenCVImageFilter::Pointer lastFilter = m_FilterList.at(m_FilterList.size()-1); m_FilterList.pop_back(); return lastFilter; } bool BasicCombinationOpenCVImageFilter::RemoveFilter( AbstractOpenCVImageFilter::Pointer filter ) { for ( auto it = m_FilterList.begin(); it != m_FilterList.end(); it++ ) { if (*it == filter) { m_FilterList.erase(it); return true; } } return false; } bool BasicCombinationOpenCVImageFilter::GetIsFilterOnTheList( AbstractOpenCVImageFilter::Pointer filter ) { return std::find(m_FilterList.begin(), m_FilterList.end(), filter) != m_FilterList.end(); } bool BasicCombinationOpenCVImageFilter::GetIsEmpty() { return m_FilterList.empty(); } } // namespace mitk diff --git a/Modules/QtWidgets/files.cmake b/Modules/QtWidgets/files.cmake index fc924b63fb..3caa14abb6 100644 --- a/Modules/QtWidgets/files.cmake +++ b/Modules/QtWidgets/files.cmake @@ -1,87 +1,107 @@ file(GLOB_RECURSE H_FILES RELATIVE "${CMAKE_CURRENT_SOURCE_DIR}" "${CMAKE_CURRENT_SOURCE_DIR}/include/*") set(CPP_FILES -QmitkApplicationCursor.cpp -QmitkDataStorageComboBox.cpp -QmitkDataStorageListModel.cpp -QmitkDataStorageTableModel.cpp -QmitkDataStorageTreeModel.cpp -QmitkFileReaderOptionsDialog.cpp -QmitkFileReaderWriterOptionsWidget.cpp -QmitkFileWriterOptionsDialog.cpp -QmitkIOUtil.cpp -QmitkLevelWindowPresetDefinitionDialog.cpp -QmitkLevelWindowRangeChangeDialog.cpp -QmitkLevelWindowWidgetContextMenu.cpp -QmitkLevelWindowWidget.cpp -QmitkLineEditLevelWindowWidget.cpp -QmitkMemoryUsageIndicatorView.cpp -QmitkMimeTypes.cpp -QmitkNodeDescriptor.cpp -QmitkColoredNodeDescriptor.cpp -QmitkNodeDescriptorManager.cpp -QmitkRenderWindowMenu.cpp -QmitkProgressBar.cpp -QmitkPropertiesTableEditor.cpp -QmitkPropertiesTableModel.cpp -QmitkPropertyDelegate.cpp -QmitkRegisterClasses.cpp -QmitkRenderingManager.cpp -QmitkRenderingManagerFactory.cpp -QmitkRenderWindow.cpp -QmitkServiceListWidget.cpp -QmitkSliderLevelWindowWidget.cpp -QmitkStdMultiWidget.cpp -QmitkMouseModeSwitcher.cpp -QmitkDataStorageFilterProxyModel.cpp -QmitkDataStorageComboBoxWithSelectNone.cpp -QmitkPropertyItem.cpp -QmitkPropertyItemDelegate.cpp -QmitkPropertyItemModel.cpp -QmitkStyleManager.cpp + QmitkAbstractDataStorageModel.cpp + QmitkApplicationCursor.cpp + QmitkDataStorageComboBox.cpp + QmitkDataStorageDefaultListModel.cpp + QmitkDataStorageListModel.cpp + QmitkDataStorageTableModel.cpp + QmitkDataStorageSimpleTreeModel.cpp + QmitkDataStorageTreeModel.cpp + QmitkDataStorageTreeModelInternalItem.cpp + QmitkFileReaderOptionsDialog.cpp + QmitkFileReaderWriterOptionsWidget.cpp + QmitkFileWriterOptionsDialog.cpp + QmitkIOUtil.cpp + QmitkLevelWindowPresetDefinitionDialog.cpp + QmitkLevelWindowRangeChangeDialog.cpp + QmitkLevelWindowWidgetContextMenu.cpp + QmitkLevelWindowWidget.cpp + QmitkLineEditLevelWindowWidget.cpp + QmitkMemoryUsageIndicatorView.cpp + QmitkMimeTypes.cpp + QmitkNodeDescriptor.cpp + QmitkColoredNodeDescriptor.cpp + QmitkNodeDescriptorManager.cpp + QmitkRenderWindowMenu.cpp + QmitkProgressBar.cpp + QmitkPropertiesTableEditor.cpp + QmitkPropertiesTableModel.cpp + QmitkPropertyDelegate.cpp + QmitkRegisterClasses.cpp + QmitkRenderingManager.cpp + QmitkRenderingManagerFactory.cpp + QmitkRenderWindow.cpp + QmitkServiceListWidget.cpp + QmitkSliderLevelWindowWidget.cpp + QmitkStdMultiWidget.cpp + QmitkMouseModeSwitcher.cpp + QmitkDataStorageFilterProxyModel.cpp + QmitkDataStorageComboBoxWithSelectNone.cpp + QmitkPropertyItem.cpp + QmitkPropertyItemDelegate.cpp + QmitkPropertyItemModel.cpp + QmitkStyleManager.cpp + QmitkAbstractDataStorageInspector.cpp + QmitkDataStorageListInspector.cpp + QmitkDataStorageTreeInspector.cpp + QmitkModelViewSelectionConnector.cpp + QmitkIDataStorageInspectorProvider.cpp + mitkQtWidgetsActivator.cpp + QmitkDataStorageInspectorGenerator.cpp ) set(MOC_H_FILES + include/QmitkAbstractDataStorageModel.h include/QmitkDataStorageComboBox.h include/QmitkDataStorageTableModel.h include/QmitkDataStorageTreeModel.h + include/QmitkDataStorageSimpleTreeModel.h + include/QmitkDataStorageDefaultListModel.h include/QmitkFileReaderOptionsDialog.h include/QmitkFileReaderWriterOptionsWidget.h include/QmitkFileWriterOptionsDialog.h include/QmitkLevelWindowPresetDefinitionDialog.h include/QmitkLevelWindowRangeChangeDialog.h include/QmitkLevelWindowWidgetContextMenu.h include/QmitkLevelWindowWidget.h include/QmitkLineEditLevelWindowWidget.h include/QmitkMemoryUsageIndicatorView.h include/QmitkNodeDescriptor.h include/QmitkColoredNodeDescriptor.h include/QmitkNodeDescriptorManager.h include/QmitkRenderWindowMenu.h include/QmitkProgressBar.h include/QmitkPropertiesTableEditor.h include/QmitkPropertyDelegate.h include/QmitkRenderingManager.h include/QmitkRenderWindow.h include/QmitkServiceListWidget.h include/QmitkSliderLevelWindowWidget.h include/QmitkStdMultiWidget.h include/QmitkMouseModeSwitcher.h include/QmitkDataStorageComboBoxWithSelectNone.h include/QmitkPropertyItemDelegate.h include/QmitkPropertyItemModel.h + include/QmitkDataStorageListInspector.h + include/QmitkAbstractDataStorageInspector.h + include/QmitkDataStorageTreeInspector.h + include/QmitkModelViewSelectionConnector.h ) set(UI_FILES src/QmitkFileReaderOptionsDialog.ui src/QmitkFileWriterOptionsDialog.ui src/QmitkLevelWindowPresetDefinition.ui src/QmitkLevelWindowWidget.ui src/QmitkLevelWindowRangeChange.ui src/QmitkMemoryUsageIndicator.ui src/QmitkServiceListWidgetControls.ui + src/QmitkDataStorageListInspector.ui + src/QmitkDataStorageTreeInspector.ui ) set(QRC_FILES resource/Qmitk.qrc ) diff --git a/Modules/QtWidgets/include/QmitkAbstractDataStorageInspector.h b/Modules/QtWidgets/include/QmitkAbstractDataStorageInspector.h new file mode 100644 index 0000000000..3a6e8ad903 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkAbstractDataStorageInspector.h @@ -0,0 +1,131 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKABSTRACTDATASTORAGEINSPECTOR_H +#define QMITKABSTRACTDATASTORAGEINSPECTOR_H + +#include + +#include + +// mitk core +#include +#include + +// qt +#include + +class QAbstractItemVew; + +/** +* @brief This abstract class is a convinient base class for easy implementation of widgets that +* offer a specific view onto a given DataStorage instance to inspect its contents. +* One may also get the selection in this inspector of the data storage. +*/ +class MITKQTWIDGETS_EXPORT QmitkAbstractDataStorageInspector : public QWidget +{ + Q_OBJECT + +public: + virtual ~QmitkAbstractDataStorageInspector(); + + /** + * @brief Sets the data storage that will be used /monitored by the widget. + * + * @param dataStorage A pointer to the data storage to set. + */ + void SetDataStorage(mitk::DataStorage* dataStorage); + + /** + * @brief Sets the node predicate and updates the widget, according to the node predicate. + * + * @param nodePredicate A pointer to node predicate. + */ + virtual void SetNodePredicate(mitk::NodePredicateBase* nodePredicate); + + mitk::NodePredicateBase* GetNodePredicate() const; + + using NodeList = QList; + + /** Returns the list of currently selected nodes.*/ + NodeList GetSelectedNodes() const; + + /** Returns an pointer to the view that is used in the inspector to show the content.*/ + virtual QAbstractItemView* GetView() = 0; + virtual const QAbstractItemView* GetView() const = 0; + + /** Returns the setting of the internal connector. It can be changed by SetSelectOnlyVisibleNodes()*/ + bool GetSelectOnlyVisibleNodes() const; + + using SelectionMode = QAbstractItemView::SelectionMode; + /** Sets the selection mode of the inspector.*/ + virtual void SetSelectionMode(SelectionMode mode) = 0; + virtual SelectionMode GetSelectionMode() const = 0; + +Q_SIGNALS: + /** + * @brief A signal that will be emitted if the selected node has changed. + * + * @param nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(NodeList nodes); + + public Q_SLOTS: + /** + * @brief Change the selection modus of the item view's selection model. + * + * If true, an incoming selection will be filtered (reduced) to only those nodes that are visible by the current view. + * An outgoing selection can then at most contain the filtered nodes. + * If false, the incoming non-visible selection will be stored and later added to the outgoing selection, + * to include the original selection that could not be modified. + * The part of the original selection, that is non-visible are the nodes that are not + * + * @param selectOnlyVisibleNodes The bool value to define the selection modus. + */ + void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes); + + /** + * @brief Transform a list of data nodes into a model selection and set this as a new selection of the + * selection model of the private member item view. + * + * The function filters the given list of nodes according to the 'm_SelectOnlyVisibleNodes' member variable. If + * necessary, the non-visible nodes are stored. This is done if 'm_SelectOnlyVisibleNodes' is false: In this case + * the selection may be filtered and only a subset of the selected nodes may be visible and therefore (de-)selectable + * in the data storage viewer. By storing the non-visible nodes it is possible to send the new, modified selection + * but also include the selected nodes from the original selection that could not be modified (see 'SetSelectOnlyVisibleNodes'). + * + * @param nodes A list of data nodes that should be newly selected. + */ + void SetCurrentSelection(NodeList selectedNodes); + +protected Q_SLOTS: + void OnSelectionChanged(NodeList selectedNodes); + +protected: + /** Helper function is called if data storage or predicate is changed to (re) initialize the widget correctly. + Implement the function in derived classes.*/ + virtual void Initialize() = 0; + + mitk::WeakPointer m_DataStorage; + mitk::NodePredicateBase::Pointer m_NodePredicate; + + std::unique_ptr m_Connector; + + QmitkAbstractDataStorageInspector(QWidget* parent = nullptr); + +}; + +#endif // QMITKABSTRACTDATASTORAGEMODEL_H diff --git a/Modules/QtWidgets/include/QmitkAbstractDataStorageModel.h b/Modules/QtWidgets/include/QmitkAbstractDataStorageModel.h new file mode 100644 index 0000000000..30faaec032 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkAbstractDataStorageModel.h @@ -0,0 +1,92 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKABSTRACTDATASTORAGEMODEL_H +#define QMITKABSTRACTDATASTORAGEMODEL_H + +#include + +// mitk core +#include +#include +#include + +// qt +#include + +/* +* @brief This abstract class extends the 'QAbstractItemModel' to accept an 'mitk::DataStorage' and a 'mitk::NodePredicateBase'. +* It registers itself as a node event listener of the data storage. +* The 'QmitkAbstractDataStorageModel' provides three empty functions, 'NodeAdded', 'NodeChanged' and 'NodeRemoved', that +* may be implemented by subclasses. These functions allow to react to the 'AddNodeEvent', 'ChangedNodeEvent' and +* 'RemoveNodeEvent' of the data storage. This might be useful to force an update on a custom view to correctly +* represent the content of the data storage. +* +* A concrete implementation of this class is used to store the temporarily shown data nodes of the data storage. +* These nodes may be a subset of all the nodes inside the data storage, if a specific node predicate is set. +* +* A model that implements this class has to return mitk::DataNode::Pointer objects for model indexes when the +* role is QmitkDataNodeRole. +*/ +class MITKQTWIDGETS_EXPORT QmitkAbstractDataStorageModel : public QAbstractItemModel +{ + Q_OBJECT + +public: + + virtual ~QmitkAbstractDataStorageModel(); + /* + * @brief Sets the data storage and adds listener for node events. + * + * @param dataStorage A pointer to the data storage to set. + */ + void SetDataStorage(mitk::DataStorage* dataStorage); + + mitk::DataStorage* GetDataStorage() { return m_DataStorage.Lock().GetPointer(); } + /* + * @brief Sets the node predicate and updates the model data, according to the node predicate. + * + * @param nodePredicate A pointer to node predicate. + */ + void SetNodePredicate(mitk::NodePredicateBase* nodePredicate); + + mitk::NodePredicateBase* GetNodePredicate() { return m_NodePredicate; } + +protected: + + virtual void DataStorageChanged() = 0; + virtual void NodePredicateChanged() = 0; + + virtual void NodeAdded(const mitk::DataNode* node) = 0; + virtual void NodeChanged(const mitk::DataNode* node) = 0; + virtual void NodeRemoved(const mitk::DataNode* node) = 0; + + QmitkAbstractDataStorageModel(QObject* parent = nullptr); + QmitkAbstractDataStorageModel(mitk::DataStorage* dataStorage, QObject* parent = nullptr); + + mitk::WeakPointer m_DataStorage; + mitk::NodePredicateBase::Pointer m_NodePredicate; + +private: + + /** Helper triggered on the storage delete event */ + void SetDataStorageDeleted(); + + unsigned long m_DataStorageDeletedTag; + +}; + +#endif // QMITKABSTRACTDATASTORAGEMODEL_H diff --git a/Modules/QtWidgets/include/QmitkDataStorageDefaultListModel.h b/Modules/QtWidgets/include/QmitkDataStorageDefaultListModel.h new file mode 100644 index 0000000000..cbfdf81916 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageDefaultListModel.h @@ -0,0 +1,82 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKDATASTORAGEDEFAULTLISTMODEL_H +#define QMITKDATASTORAGEDEFAULTLISTMODEL_H + +#include + +// qt widgets module +#include + +/** +* @brief The 'QmitkDataStorageDefaultListModel' is a basic list model, derived from the 'QmitkAbstractDataStorageModel'. +* It provides functions to accept a data storage and a node predicate in order to customize the model data nodes. +* Furthermore it overrides the functions of 'QAbstractItemModel' to create a simple qt list model. +* This model can be used in conjunction with a 'QmitkDataStorageSelectionConnector'. +*/ +class MITKQTWIDGETS_EXPORT QmitkDataStorageDefaultListModel : public QmitkAbstractDataStorageModel +{ + Q_OBJECT + +public: + + QmitkDataStorageDefaultListModel(QObject *parent); + + // override from 'QmitkAbstractDataStorageModel' + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void DataStorageChanged() override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodePredicateChanged() override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeAdded(const mitk::DataNode* node) override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeChanged(const mitk::DataNode* node) override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeRemoved(const mitk::DataNode* node) override; + + // override pure virtual from 'QAbstractItemModel' + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &child) const override; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + // override for customization + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + +private: + + void UpdateModelData(); + + std::vector m_DataNodes; + +}; + +#endif // QMITKDATASTORAGEDEFAULTLISTMODEL_H diff --git a/Modules/QtWidgets/include/QmitkDataStorageInspectorGenerator.h b/Modules/QtWidgets/include/QmitkDataStorageInspectorGenerator.h new file mode 100644 index 0000000000..d8fc1dd641 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageInspectorGenerator.h @@ -0,0 +1,41 @@ +/*=================================================================== + +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 QmitkDataStorageInspectorGenerator_H +#define QmitkDataStorageInspectorGenerator_H + +#include "QmitkIDataStorageInspectorProvider.h" + +#include + +class MITKQTWIDGETS_EXPORT QmitkDataStorageInspectorGenerator +{ +public: + using IDType = std::string; + + using ProviderMapType = std::map; + static ProviderMapType GetProviders(); + + static mitk::IDataStorageInspectorProvider *GetProvider(const IDType &id); + +protected: + QmitkDataStorageInspectorGenerator(); + virtual ~QmitkDataStorageInspectorGenerator(); + QmitkDataStorageInspectorGenerator(const QmitkDataStorageInspectorGenerator &source) = delete; + QmitkDataStorageInspectorGenerator& operator=(const QmitkDataStorageInspectorGenerator &) = delete; +}; + +#endif diff --git a/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.h b/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.h new file mode 100644 index 0000000000..2e964cf019 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.h @@ -0,0 +1,79 @@ +/*=================================================================== + +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 __QMITK_DATA_STORAGE_INSPECTOR_PROVIDER_BASE_H +#define __QMITK_DATA_STORAGE_INSPECTOR_PROVIDER_BASE_H + +#include + +// Microservices +#include +#include +#include + +// MITK +#include + + +/** + * @brief Base class for DataStorage inspector provider. + */ +template +class QmitkDataStorageInspectorProviderBase : public mitk::IDataStorageInspectorProvider +{ +public: + virtual QmitkAbstractDataStorageInspector* CreateInspector() const override; + + virtual std::string GetInspectorID() const override; + virtual std::string GetInspectorDisplayName() const override; + virtual std::string GetInspectorDescription() const override; + + us::ServiceRegistration RegisterService( + us::ModuleContext *context = us::GetModuleContext()); + + void UnregisterService(); + + QmitkDataStorageInspectorProviderBase(const std::string& id); + QmitkDataStorageInspectorProviderBase(const std::string& id, const std::string& displayName, const std::string& desc= "" ); + virtual ~QmitkDataStorageInspectorProviderBase(); + +protected: + QmitkDataStorageInspectorProviderBase(const QmitkDataStorageInspectorProviderBase &other); + QmitkDataStorageInspectorProviderBase &operator=(const QmitkDataStorageInspectorProviderBase &other) = delete; + + virtual us::ServiceProperties GetServiceProperties() const; + + /** + * \brief Set the service ranking for this file reader. + * + * Default is zero and should only be chosen differently for a reason. + * The ranking is used to determine which reader to use if several + * equivalent providers have been found. + * It may be used to replace a default provider from MITK in your own project. + */ + void SetRanking(int ranking); + int GetRanking() const; + +private: + class Impl; + std::unique_ptr d; +}; + +#ifndef ITK_MANUAL_INSTANTIATION +#include "QmitkDataStorageInspectorProviderBase.tpp" +#endif + +#endif /* __MODEL_FIT_PROVIDER_BASE_H */ diff --git a/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.tpp b/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.tpp new file mode 100644 index 0000000000..f7982f867c --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageInspectorProviderBase.tpp @@ -0,0 +1,149 @@ +/*=================================================================== + +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 + + template + class QmitkDataStorageInspectorProviderBase::Impl + { + public: + Impl(const std::string& id, const std::string& displayName, const std::string& desc) : m_Ranking(0), m_ID(id), m_DisplayName(displayName), m_Desc(desc) + { + }; + + Impl(const Impl &other) = default; + + void SetRanking(int ranking) + { + m_Ranking = ranking; + }; + + int GetRanking() const + { + return m_Ranking; + }; + + us::ServiceRegistration m_Reg; + int m_Ranking; + std::string m_ID; + std::string m_DisplayName; + std::string m_Desc; + }; + + template + QmitkDataStorageInspectorProviderBase::QmitkDataStorageInspectorProviderBase(const std::string& id) : QmitkDataStorageInspectorProviderBase(id, id) + { + } + + template + QmitkDataStorageInspectorProviderBase::QmitkDataStorageInspectorProviderBase(const std::string& id, const std::string& displayName, const std::string& desc) + { + d.reset(new Impl(id, displayName, desc)); + RegisterService(); + } + + template + QmitkDataStorageInspectorProviderBase::~QmitkDataStorageInspectorProviderBase() + { + UnregisterService(); + } + + template + QmitkDataStorageInspectorProviderBase::QmitkDataStorageInspectorProviderBase(const QmitkDataStorageInspectorProviderBase &other) : IDataStorageInspectorProvider(), d(new Impl(*other.d.get())) + { + } + + template + QmitkAbstractDataStorageInspector* + QmitkDataStorageInspectorProviderBase::CreateInspector() const + { + return new TInspector; + }; + + template + std::string + QmitkDataStorageInspectorProviderBase::GetInspectorID() const + { + return d->m_ID; + }; + + template + std::string + QmitkDataStorageInspectorProviderBase::GetInspectorDisplayName() const + { + return d->m_DisplayName; + }; + + template + std::string + QmitkDataStorageInspectorProviderBase::GetInspectorDescription() const + { + return d->m_Desc; + }; + + template + us::ServiceRegistration + QmitkDataStorageInspectorProviderBase::RegisterService(us::ModuleContext *context) + { + if (d->m_Reg) + return d->m_Reg; + + if (context == nullptr) + { + context = us::GetModuleContext(); + } + + us::ServiceProperties props = this->GetServiceProperties(); + d->m_Reg = context->RegisterService(this, props); + return d->m_Reg; + } + + template + void + QmitkDataStorageInspectorProviderBase::UnregisterService() + { + try + { + d->m_Reg.Unregister(); + } + catch (const std::exception &) + { + } + } + + template + us::ServiceProperties + QmitkDataStorageInspectorProviderBase::GetServiceProperties() const + { + us::ServiceProperties result; + + result[IDataStorageInspectorProvider::PROP_INSPECTOR_ID()] = this->d->m_ID; + result[us::ServiceConstants::SERVICE_RANKING()] = this->GetRanking(); + return result; + } + + template + void + QmitkDataStorageInspectorProviderBase::SetRanking(int ranking) { d->SetRanking(ranking); } + + template + int + QmitkDataStorageInspectorProviderBase::GetRanking() const { return d->GetRanking(); } diff --git a/Modules/QtWidgets/include/QmitkDataStorageListInspector.h b/Modules/QtWidgets/include/QmitkDataStorageListInspector.h new file mode 100644 index 0000000000..393469b6f3 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageListInspector.h @@ -0,0 +1,50 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKDATASTORAGELISTVIEWWIDGET_H +#define QMITKDATASTORAGELISTVIEWWIDGET_H + +#include + +#include +#include + +#include "ui_QmitkDataStorageListInspector.h" + +/* +* @brief This is an inspector that offers a simple list view on a data storage. +*/ +class MITKQTWIDGETS_EXPORT QmitkDataStorageListInspector : public QmitkAbstractDataStorageInspector +{ + Q_OBJECT + +public: + QmitkDataStorageListInspector(QWidget* parent = nullptr); + + virtual QAbstractItemView* GetView() override; + virtual const QAbstractItemView* GetView() const override; + + virtual void SetSelectionMode(SelectionMode mode) override; + virtual SelectionMode GetSelectionMode() const override; + +protected: + virtual void Initialize() override; + + QmitkAbstractDataStorageModel* m_StorageModel; + Ui_QmitkDataStorageListInspector m_Controls; +}; + +#endif // QMITKABSTRACTDATASTORAGEMODEL_H diff --git a/Modules/QtWidgets/include/QmitkDataStorageSimpleTreeModel.h b/Modules/QtWidgets/include/QmitkDataStorageSimpleTreeModel.h new file mode 100644 index 0000000000..e2dd6b31f9 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageSimpleTreeModel.h @@ -0,0 +1,105 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKDATASTORAGESIMPLETREEMODEL_H +#define QMITKDATASTORAGESIMPLETREEMODEL_H + +#include + +// qt widgets module +#include + +class QmitkDataStorageTreeModelInternalItem; + +/** +* @brief The 'QmitkDataStorageSimpleTreeModel' is a basic tree model, derived from the 'QmitkAbstractDataStorageModel'. +* It provides functions to accept a data storage and a node predicate in order to customize the model data nodes. +* Furthermore it overrides the functions of 'QAbstractItemModel' to create a simple qt list model.* +* This model can be used in conjunction with a 'QmitkDataStorageSelectionConnector'. +* This model is a "light" version of the classic QmitkDataStorgageTreeModel. The differences between both are the following: +* - This class currently does not support DragNDrop. +* - This class does not have the ability to change hirarchy or changes the layer property +*of nodes. This was skipped on purpose, because that is not the job of the storage model. +* - If a tree item A is removed this class does not attach children of A to the parent +*of A. Instead the complete tree representation is updated. This was changed on purpose +*because otherwise the internal representation of the model would not reflect the data storage graph anymore. +*/ +class MITKQTWIDGETS_EXPORT QmitkDataStorageSimpleTreeModel : public QmitkAbstractDataStorageModel +{ + Q_OBJECT + +public: + QmitkDataStorageSimpleTreeModel(QObject *parent); + virtual ~QmitkDataStorageSimpleTreeModel(); + + // override from 'QmitkAbstractDataStorageModel' + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void DataStorageChanged() override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodePredicateChanged() override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeAdded(const mitk::DataNode *node) override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeChanged(const mitk::DataNode *node) override; + /* + * @brief See 'QmitkAbstractDataStorageModel' + */ + void NodeRemoved(const mitk::DataNode *node) override; + + // override pure virtual from 'QAbstractItemModel' + QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; + QModelIndex parent(const QModelIndex &child) const override; + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + Qt::ItemFlags flags(const QModelIndex &index) const override; + +protected: + using TreeItem = QmitkDataStorageTreeModelInternalItem; + +private: + void UpdateModelData(); + void AddNodeInternal(const mitk::DataNode *node); + + mitk::DataNode *GetParentNode(const mitk::DataNode *node) const; + + TreeItem *TreeItemFromIndex(const QModelIndex &index) const; + QModelIndex IndexFromTreeItem(TreeItem *item) const; + + void ResetTree(); + + TreeItem *m_Root; + + /**helper structure to check, if a tree item is realy part of the model. + Prefered over iterating over the tree by hand because we can use std::find.*/ + std::list m_TreeItems; +}; + +#endif // QmitkDataStorageSimpleTreeModel_H diff --git a/Modules/QtWidgets/include/QmitkDataStorageTreeInspector.h b/Modules/QtWidgets/include/QmitkDataStorageTreeInspector.h new file mode 100644 index 0000000000..90e90de04b --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageTreeInspector.h @@ -0,0 +1,52 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKDATASTORAGETREEINSPECTOR_H +#define QMITKDATASTORAGETREEINSPECTOR_H + +#include + +#include +#include + +#include "ui_QmitkDataStorageTreeInspector.h" + +/* +* @brief This is an inspector that offers a simple tree view on a data storage. +* Something like the "data manager plugin", but in simple/light (with less functionality) +* It uses the QmitkDataStorageSimpleTreeModel. +*/ +class MITKQTWIDGETS_EXPORT QmitkDataStorageTreeInspector : public QmitkAbstractDataStorageInspector +{ + Q_OBJECT + +public: + QmitkDataStorageTreeInspector(QWidget* parent = nullptr); + + virtual QAbstractItemView* GetView() override; + virtual const QAbstractItemView* GetView() const override; + + virtual void SetSelectionMode(SelectionMode mode) override; + virtual SelectionMode GetSelectionMode() const override; + +protected: + virtual void Initialize() override; + + QmitkAbstractDataStorageModel* m_StorageModel; + Ui_QmitkDataStorageTreeInspector m_Controls; +}; + +#endif // QMITKABSTRACTDATASTORAGEMODEL_H diff --git a/Modules/QtWidgets/include/QmitkDataStorageTreeModel.h b/Modules/QtWidgets/include/QmitkDataStorageTreeModel.h index 1449714dd2..03ee7de417 100644 --- a/Modules/QtWidgets/include/QmitkDataStorageTreeModel.h +++ b/Modules/QtWidgets/include/QmitkDataStorageTreeModel.h @@ -1,277 +1,213 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QMITKDATASTORAGETREEMODEL_H_ #define QMITKDATASTORAGETREEMODEL_H_ #include #include #include #include #include #include "QmitkCustomVariants.h" #include "QmitkEnums.h" #include #include #include -/// \ingroup QmitkModule +class QmitkDataStorageTreeModelInternalItem; + +/** \ingroup QmitkModule + @warning This class causes invalid point exception when used with invalid QModelIndex instances. + The index validation is not sufficient. This may cause unspecific crashes in situation where + this class is used multiple times or with multiple selection models. See https://phabricator.mitk.org/T24348 + for more information. +*/ class MITKQTWIDGETS_EXPORT QmitkDataStorageTreeModel : public QAbstractItemModel { Q_OBJECT //# CONSTANTS,TYPEDEFS public: static const std::string COLUMN_NAME; static const std::string COLUMN_TYPE; static const std::string COLUMN_VISIBILITY; //# CTORS,DTOR public: QmitkDataStorageTreeModel(mitk::DataStorage *_DataStorage, bool _PlaceNewNodesOnTop = false, QObject *parent = nullptr); ~QmitkDataStorageTreeModel() override; //# GETTER public: /// /// Get node at a specific model index. /// This function is used to get a node from a QModelIndex /// mitk::DataNode::Pointer GetNode(const QModelIndex &index) const; /// /// Returns a copy of the node-vector that is shown by this model /// virtual QList GetNodeSet() const; /// /// Get the DataStorage. /// const mitk::DataStorage::Pointer GetDataStorage() const; /// /// Get the top placement flag /// bool GetPlaceNewNodesOnTopFlag() { return m_PlaceNewNodesOnTop; } /// /// Set the top placement flag /// void SetPlaceNewNodesOnTop(bool _PlaceNewNodesOnTop); //# (Re-)implemented from QAbstractItemModel //# Read model Qt::ItemFlags flags(const QModelIndex &index) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; //# hierarchical model /// /// called whenever the model or the view needs to create a QModelIndex for a particular /// child item (or a top-level item if parent is an invalid QModelIndex) /// QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; QModelIndex parent(const QModelIndex &index) const override; //# editable model bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) override; bool dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override; Qt::DropActions supportedDropActions() const override; Qt::DropActions supportedDragActions() const override; QStringList mimeTypes() const override; QMimeData *mimeData(const QModelIndexList &indexes) const override; static QMimeData *mimeDataFromModelIndexList(const QModelIndexList &indexes); //# End of QAbstractItemModel //# SETTER public: /// /// Sets the DataStorage. The whole model will be resetted. /// void SetDataStorage(mitk::DataStorage *_DataStorage); /// /// Notify that the DataStorage was deleted. The whole model will be resetted. /// void SetDataStorageDeleted(); /// /// Adds a node to this model. /// If a predicate is set (not null) the node will be checked against it.The node has to have a data object (no one /// wants to see empty nodes). /// virtual void AddNode(const mitk::DataNode *node); /// /// Removes a node from this model. Also removes any event listener from the node. /// virtual void RemoveNode(const mitk::DataNode *node); /// /// Sets a node to modfified. Called by the DataStorage /// virtual void SetNodeModified(const mitk::DataNode *node); /// /// \return an index for the given datatreenode in the tree. If the node is not found /// QModelIndex GetIndex(const mitk::DataNode *) const; /// Set whether to allow hierarchy changes by dragging and dropping void SetAllowHierarchyChange(bool allowHierarchyChange); signals: void nodeVisibilityChanged(); //# MISC protected: - /// - /// Helper class to represent a tree structure of DataNodes - /// - class TreeItem - { - public: - /// - /// Constructs a new TreeItem with the given DataNode (must not be 0) - /// - TreeItem(mitk::DataNode *_DataNode, TreeItem *_Parent = nullptr); - /// - /// Removes itself as child from its parent-> Does not delete its children - /// \sa Delete() - /// - virtual ~TreeItem(); - /// - /// Find the index of an item - /// - int IndexOfChild(const TreeItem *item) const; - /// - /// \return The child at pos index or 0 if it not exists - /// - TreeItem *GetChild(int index) const; - /// - /// Find the TreeItem containing a special tree node (recursive tree function) - /// - TreeItem *Find(const mitk::DataNode *_DataNode) const; - /// - /// Get the amount of children - /// - int GetChildCount() const; - /// - /// \return the index of this node in its parent list - /// - int GetIndex() const; - /// - /// \return the parent of this tree item - /// - TreeItem *GetParent() const; - /// - /// Return the DataNode associated with this node - /// - mitk::DataNode::Pointer GetDataNode() const; - /// - /// Get all children as vector - /// - std::vector GetChildren() const; - - /// - /// add another item as a child of this (only if not already in that list) - /// - void AddChild(TreeItem *item); - /// - /// remove another item as child from this - /// - void RemoveChild(TreeItem *item); - /// - /// inserts a child at the given position. if pos is not in range - /// the element is added at the end - /// - void InsertChild(TreeItem *item, int index = -1); - /// Sets the parent on the treeitem - void SetParent(TreeItem *_Parent); - /// - /// Deletes the whole tree branch - /// - void Delete(); - - protected: - TreeItem *m_Parent; - std::vector m_Children; - mitk::DataNode::Pointer m_DataNode; - }; + + using TreeItem = QmitkDataStorageTreeModelInternalItem; QList ToTreeItemPtrList(const QMimeData *mimeData); QList ToTreeItemPtrList(const QByteArray &ba); /// /// Adjusts the LayerProperty according to the nodes position /// void AdjustLayerProperty(); /// /// invoked after m_DataStorage or m_Predicate changed /// TreeItem *TreeItemFromIndex(const QModelIndex &index) const; /// /// Gives a ModelIndex for the Tree Item /// QModelIndex IndexFromTreeItem(TreeItem *) const; /// /// Returns the first element in the nodes sources list (if available) or 0 /// mitk::DataNode *GetParentNode(const mitk::DataNode *node) const; /// /// Adds all Childs in parent to vec. Before a child is added the function is called recursively /// void TreeToVector(TreeItem *parent, std::vector &vec) const; /// /// Adds all Childs in parent to vec. Before a child is added the function is called recursively /// void TreeToNodeSet(TreeItem *parent, QList &vec) const; /// /// Update Tree Model /// void Update(); //# ATTRIBUTES protected: mitk::WeakPointer m_DataStorage; mitk::NodePredicateBase::Pointer m_Predicate; bool m_PlaceNewNodesOnTop; TreeItem *m_Root; /// Flag to block the data storage events if nodes are added/removed by this class. bool m_BlockDataStorageEvents; /// This decides whether or not it is allowed to assign a different parent to a node /// If it is false, it is not possible to change the hierarchy of nodes by dragging /// and dropping. /// If it is true, dragging nodes on another node will replace all of their parents /// with that one. bool m_AllowHierarchyChange; private: void AddNodeInternal(const mitk::DataNode *); void RemoveNodeInternal(const mitk::DataNode *); /// /// Checks if dicom properties patient name, study names and series name exists /// bool DicomPropertiesExists(const mitk::DataNode &) const; unsigned long m_DataStorageDeletedTag; }; #endif /* QMITKDATASTORAGETREEMODEL_H_ */ diff --git a/Modules/QtWidgets/include/QmitkDataStorageTreeModelInternalItem.h b/Modules/QtWidgets/include/QmitkDataStorageTreeModelInternalItem.h new file mode 100644 index 0000000000..e61d5c8819 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkDataStorageTreeModelInternalItem.h @@ -0,0 +1,101 @@ +/*=================================================================== + +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 QMITKDATASTORAGETREEMODELINTERNALITEM_H_ +#define QMITKDATASTORAGETREEMODELINTERNALITEM_H_ + +#include + +#include + +#include +#include + + /// + /// Helper class to represent a tree structure of DataNodes + /// + class MITKQTWIDGETS_EXPORT QmitkDataStorageTreeModelInternalItem + { + public: + /// + /// Constructs a new QmitkDataStorageTreeModelInternalItem with the given DataNode (must not be 0) + /// + QmitkDataStorageTreeModelInternalItem(mitk::DataNode *_DataNode, QmitkDataStorageTreeModelInternalItem *_Parent = 0); + /// + /// Removes itself as child from its parent-> Does not delete its children + /// \sa Delete() + /// + virtual ~QmitkDataStorageTreeModelInternalItem(); + /// + /// Find the index of an item + /// + int IndexOfChild(const QmitkDataStorageTreeModelInternalItem *item) const; + /// + /// \return The child at pos index or 0 if it not exists + /// + QmitkDataStorageTreeModelInternalItem *GetChild(int index) const; + /// + /// Find the QmitkDataStorageTreeModelInternalItem containing a special tree node (recursive tree function) + /// + QmitkDataStorageTreeModelInternalItem *Find(const mitk::DataNode *_DataNode) const; + /// + /// Get the amount of children + /// + int GetChildCount() const; + /// + /// \return the index of this node in its parent list + /// + int GetIndex() const; + /// + /// \return the parent of this tree item + /// + QmitkDataStorageTreeModelInternalItem *GetParent() const; + /// + /// Return the DataNode associated with this node + /// + mitk::DataNode* GetDataNode() const; + /// + /// Get all children as vector + /// + std::vector GetChildren() const; + + /// + /// add another item as a child of this (only if not already in that list) + /// + void AddChild(QmitkDataStorageTreeModelInternalItem *item); + /// + /// remove another item as child from this + /// + void RemoveChild(QmitkDataStorageTreeModelInternalItem *item); + /// + /// inserts a child at the given position. if pos is not in range + /// the element is added at the end + /// + void InsertChild(QmitkDataStorageTreeModelInternalItem *item, int index = -1); + /// Sets the parent on the QmitkDataStorageTreeModelInternalItem + void SetParent(QmitkDataStorageTreeModelInternalItem *_Parent); + /// + /// Deletes the whole tree branch + /// + void Delete(); + + protected: + QmitkDataStorageTreeModelInternalItem *m_Parent; + std::vector m_Children; + mitk::DataNode::Pointer m_DataNode; + }; + +#endif /* QMITKDATASTORAGETREEMODEL_H_ */ diff --git a/Modules/QtWidgets/include/QmitkIDataStorageInspectorProvider.h b/Modules/QtWidgets/include/QmitkIDataStorageInspectorProvider.h new file mode 100644 index 0000000000..d5cfb53ede --- /dev/null +++ b/Modules/QtWidgets/include/QmitkIDataStorageInspectorProvider.h @@ -0,0 +1,71 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef __I_ABSTRACT_DATA_STORAGE_PROVIDER_H +#define __I_ABSTRACT_DATA_STORAGE_PROVIDER_H + +#include + +#include + +class QmitkAbstractDataStorageInspector; + +namespace mitk +{ + /** + * \ingroup MicroServices_Interfaces + * + * \brief The common interface for all DataStorage inspector providers. + * + * Implementations of this interface must be registered as a service + * to make themselves available via the service registry. + * + * It is recommended to derive new implementations from QmitkDataStorageInspectorProviderBase + * which provide correct service registration semantics. + * + * \sa QmitkDataStorageInspectorProviderBase + */ + struct MITKQTWIDGETS_EXPORT IDataStorageInspectorProvider + { + virtual ~IDataStorageInspectorProvider(); + + /** + * \brief returns an inspector instance represented by the provider. + */ + virtual QmitkAbstractDataStorageInspector* CreateInspector() const = 0; + + /** Return the uniqe ID for the inspector type provided.*/ + virtual std::string GetInspectorID() const = 0; + /** Return the display name (e.g. used in the UI) for the inspector type provided.*/ + virtual std::string GetInspectorDisplayName() const = 0; + /** Returns a description of the inspector type provided.*/ + virtual std::string GetInspectorDescription() const = 0; + + /** + * @brief Service property name for the inspector ID. + * + * The property value must be of type \c std::string. + * + * @return The property name. + */ + static std::string PROP_INSPECTOR_ID(); + }; + +} // namespace mitk + +MITK_DECLARE_SERVICE_INTERFACE(mitk::IDataStorageInspectorProvider, "org.mitk.IDataStorageInspectorProvider") + +#endif /* __I_MODEL_FIT_PROVIDER_H */ diff --git a/Modules/QtWidgets/include/QmitkModelViewSelectionConnector.h b/Modules/QtWidgets/include/QmitkModelViewSelectionConnector.h new file mode 100644 index 0000000000..5b2d361a58 --- /dev/null +++ b/Modules/QtWidgets/include/QmitkModelViewSelectionConnector.h @@ -0,0 +1,155 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKMODELVIEWSELECTIONCONNECTOR_H +#define QMITKMODELVIEWSELECTIONCONNECTOR_H + +#include + +// qt widgets module +#include + + // qt +#include + +/** +* @brief The 'QmitkModelViewSelectionConnector' is used to handle the selections of a model-view-pair. +* +* The class accepts a view and a model, which are used to react to selection changes. This class is able to propagate selection changes +* to and receive from its surrounding class. +* +* The model-view-pair can be added as a selection listener to a selection service. This should be done by using 'AddPostSelectionListener' +* with the existing selection service of the surrounding 'QmitkAbstractView'. +* The model-view-pair can be set as a selection provider. This should be done by using 'SetAsSelectionProvider' with the existing +* selection provider of the surrounding 'QmitkAbstractView'. +* +* The 'QmitkModelViewSelectionConnector' offers a public slot and signal that can be used to set / propagate the selected +* nodes in the current view: +* The 'SetCurrentSelection'-slot finds the indices of the given selected nodes in its internal data storage model and +* changes the selection of the internal data storage model accordingly. +* The 'CurrentSelectionChanged'-signal sends a list of selected nodes to its environment. +* The 'CurrentSelectionChanged'-signal is emitted by the 'ChangeModelSelection'-function, which transforms the internal item view's +* selection into a data node list. The 'ChangeModelSelection'-function is called whenever the selection of the item view's +* selection model changes. +*/ +class MITKQTWIDGETS_EXPORT QmitkModelViewSelectionConnector : public QObject +{ + Q_OBJECT + +public: + + QmitkModelViewSelectionConnector(); + /** + * @brief Set the view whose selection model is used to propagate or receive selection changes. Use the view's data model + * to transform selected nodes into model indexes and vice versa. + * + * @pre The view's data model needs to be a 'QmitkAbstractDataStorageModel'. If so, the data model is received from + * the view and stored as a private member. + * The data model must return 'mitk::DataNode::Pointer' objects for model indexes if the role is 'QmitkDataNodeRole'. + * @throw mitk::Exception, if the view is invalid or the view's data model is not a valid 'QmitkAbstractDataStorageModel'. + * + * @param view The view to set. + */ + void SetView(QAbstractItemView* view); + + /** + * @brief Retrieve the currently selected nodes (equals the last CurrentSelectionChanged values). + */ + QList GetSelectedNodes() const; + + bool GetSelectOnlyVisibleNodes() const; + +Q_SIGNALS: + /** + * @brief A signal that will be emitted by the 'ChangeModelSelection'-function. This happens if the selection model + * of the private member item view has changed. + * + * @param nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(QList nodes); + +public Q_SLOTS: + /** + * @brief Change the selection mode of the item view's selection model. + * + * If true, an incoming selection will be filtered (reduced) to only those nodes that are visible to the current view. + * An outgoing selection can then at most contain the filtered nodes. + * If false, the incoming non-visible selection will be stored and later added to the outgoing selection, + * to include the part of the original selection that was not visible. + * The part of the original selection, that is non-visible are the nodes that do not met the predicate of the + * associated QmitkAbstractDataStorageModel. + * + * @param selectOnlyVisibleNodes The bool value to define the selection modus. + */ + void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes); + + /** + * @brief Transform a list of data nodes into a model selection and set this as a new selection of the + * selection model of the private member item view. + * + * The function filters the given list of nodes according to the 'm_SelectOnlyVisibleNodes' member variable. If + * necessary, the non-visible nodes are stored. This is done if 'm_SelectOnlyVisibleNodes' is false: In this case + * the selection may be filtered and only a subset of the selected nodes may be visible and therefore (de-)selectable + * in the data storage viewer. By storing the non-visible nodes it is possible to send the new, modified selection + * but also include the selected nodes from the original selection that could not be modified (see 'SetSelectOnlyVisibleNodes'). + * + * @param nodes A list of data nodes that should be newly selected. + */ + void SetCurrentSelection(QList selectedNodes); + +private Q_SLOTS: + /** + * @brief Transform a model selection into a data node list and emit the 'CurrentSelectionChanged'-signal. + * + * The function adds the selected nodes from the original selection that could not be modified, if + * 'm_SelectOnlyVisibleNodes' is false. + * This slot is internally connected to the 'selectionChanged'-signal of the selection model of the private member item view. + * + * @param selected The newly selected items. + * @param deselected The newly deselected items. + */ + void ChangeModelSelection(const QItemSelection& selected, const QItemSelection& deselected); + +private: + + QmitkAbstractDataStorageModel* m_Model; + QAbstractItemView* m_View; + + bool m_SelectOnlyVisibleNodes; + QList m_NonVisibleSelection; + + /* + * @brief Retrieve the currently selected nodes from the selection model of the private member item view by + * transforming the selection indexes into a data node list. + * + * In order to transform the indices into data nodes, the private data storage model must return + * 'mitk::DataNode::Pointer' objects for model indexes if the role is QmitkDataNodeRole. + */ + QList GetInternalSelectedNodes() const; + /* + * @brief Filter the list of given nodes such that only those nodes are used that are valid + * when using the data storage model's node predicate. + * If no node predicate was set or the data storage model is invalid, the input list + * of given nodes is returned. + */ + QList FilterNodeList(const QList& nodes) const; +}; + +/* +* @brief Return true, if the nodes in the list of two given selections are equal (Sorting is ignored. Any permutation is valid.)*/ +bool MITKQTWIDGETS_EXPORT EqualNodeSelections(const QList& selection1, const QList& selection2); + +#endif // QMITKMODELVIEWSELECTIONCONNECTOR_H diff --git a/Modules/QtWidgets/src/QmitkAbstractDataStorageInspector.cpp b/Modules/QtWidgets/src/QmitkAbstractDataStorageInspector.cpp new file mode 100644 index 0000000000..d42d6846f8 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkAbstractDataStorageInspector.cpp @@ -0,0 +1,83 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include + +QmitkAbstractDataStorageInspector::QmitkAbstractDataStorageInspector(QWidget* parent/* = nullptr*/) + : QWidget(parent) + , m_NodePredicate(nullptr) +{ + m_Connector = std::make_unique(); + + connect(m_Connector.get(), &QmitkModelViewSelectionConnector::CurrentSelectionChanged, this, &QmitkAbstractDataStorageInspector::OnSelectionChanged); +} + +QmitkAbstractDataStorageInspector::~QmitkAbstractDataStorageInspector() +{ +} + +void QmitkAbstractDataStorageInspector::SetDataStorage(mitk::DataStorage* dataStorage) +{ + if (m_DataStorage != dataStorage) + { + m_DataStorage = dataStorage; + + if (!m_DataStorage.IsExpired()) + { + this->Initialize(); + } + } +} + +void QmitkAbstractDataStorageInspector::SetNodePredicate(mitk::NodePredicateBase* nodePredicate) +{ + if (m_NodePredicate != nodePredicate) + { + m_NodePredicate = nodePredicate; + + this->Initialize(); + } +} + +mitk::NodePredicateBase* QmitkAbstractDataStorageInspector::GetNodePredicate() const +{ + return m_NodePredicate; +} + +QmitkAbstractDataStorageInspector::NodeList QmitkAbstractDataStorageInspector::GetSelectedNodes() const +{ + return m_Connector->GetSelectedNodes(); +}; + +bool QmitkAbstractDataStorageInspector::GetSelectOnlyVisibleNodes() const +{ + return m_Connector->GetSelectOnlyVisibleNodes(); +}; + +void QmitkAbstractDataStorageInspector::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) +{ + m_Connector->SetSelectOnlyVisibleNodes(selectOnlyVisibleNodes); +}; + +void QmitkAbstractDataStorageInspector::SetCurrentSelection(NodeList selectedNodes) +{ + m_Connector->SetCurrentSelection(selectedNodes); +}; + +void QmitkAbstractDataStorageInspector::OnSelectionChanged(NodeList selectedNodes) +{ + emit CurrentSelectionChanged(selectedNodes); +}; diff --git a/Modules/QtWidgets/src/QmitkAbstractDataStorageModel.cpp b/Modules/QtWidgets/src/QmitkAbstractDataStorageModel.cpp new file mode 100644 index 0000000000..9afb4d48f6 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkAbstractDataStorageModel.cpp @@ -0,0 +1,115 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include + +QmitkAbstractDataStorageModel::QmitkAbstractDataStorageModel(QObject* parent/* = nullptr*/) + : QAbstractItemModel(parent) + , m_DataStorage(nullptr) + , m_NodePredicate(nullptr) +{ + // nothing here +} + +QmitkAbstractDataStorageModel::QmitkAbstractDataStorageModel(mitk::DataStorage* dataStorage, QObject* parent/* = nullptr*/) + : QAbstractItemModel(parent) + , m_DataStorage(nullptr) + , m_NodePredicate(nullptr) +{ + SetDataStorage(dataStorage); +} + +QmitkAbstractDataStorageModel::~QmitkAbstractDataStorageModel() +{ + if (!m_DataStorage.IsExpired()) + { + auto dataStorage = m_DataStorage.Lock(); + + // remove Listener for the data storage itself + dataStorage->RemoveObserver(m_DataStorageDeletedTag); + + // remove listener from data storage + dataStorage->AddNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeAdded)); + dataStorage->RemoveNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeRemoved)); + dataStorage->ChangedNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeChanged)); + } +} + +void QmitkAbstractDataStorageModel::SetDataStorage(mitk::DataStorage* dataStorage) +{ + if (m_DataStorage == dataStorage) + { + return; + } + + if (!m_DataStorage.IsExpired()) + { + auto dataStorage = m_DataStorage.Lock(); + + // remove Listener for the data storage itself + dataStorage->RemoveObserver(m_DataStorageDeletedTag); + + // remove listener from old data storage + dataStorage->AddNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeAdded)); + dataStorage->RemoveNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeRemoved)); + dataStorage->ChangedNodeEvent.RemoveListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeChanged)); + } + + m_DataStorage = dataStorage; + + if (!m_DataStorage.IsExpired()) + { + auto dataStorage = m_DataStorage.Lock(); + + // add Listener for the data storage itself + auto command = itk::SimpleMemberCommand::New(); + command->SetCallbackFunction(this, &QmitkAbstractDataStorageModel::SetDataStorageDeleted); + m_DataStorageDeletedTag = dataStorage->AddObserver(itk::DeleteEvent(), command); + + // add listener for new data storage + dataStorage->AddNodeEvent.AddListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeAdded)); + dataStorage->RemoveNodeEvent.AddListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeRemoved)); + dataStorage->ChangedNodeEvent.AddListener( + mitk::MessageDelegate1(this, &QmitkAbstractDataStorageModel::NodeChanged)); + } + // update model if the data storage has been changed + DataStorageChanged(); +} + +void QmitkAbstractDataStorageModel::SetDataStorageDeleted() +{ + this->SetDataStorage(nullptr); +} + +void QmitkAbstractDataStorageModel::SetNodePredicate(mitk::NodePredicateBase* nodePredicate) +{ + if (m_NodePredicate == nodePredicate) + { + return; + } + + m_NodePredicate = nodePredicate; + // update model if the node predicate has been changed + NodePredicateChanged(); +} diff --git a/Modules/QtWidgets/src/QmitkDataStorageDefaultListModel.cpp b/Modules/QtWidgets/src/QmitkDataStorageDefaultListModel.cpp new file mode 100644 index 0000000000..6f3a9db5ad --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageDefaultListModel.cpp @@ -0,0 +1,172 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include + +// qt widgets module +#include "QmitkCustomVariants.h" +#include "QmitkEnums.h" +#include "QmitkNodeDescriptorManager.h" + +QmitkDataStorageDefaultListModel::QmitkDataStorageDefaultListModel(QObject *parent) : QmitkAbstractDataStorageModel(parent) +{ +} + +void QmitkDataStorageDefaultListModel::DataStorageChanged() +{ + UpdateModelData(); +} + +void QmitkDataStorageDefaultListModel::NodePredicateChanged() +{ + UpdateModelData(); +} + +void QmitkDataStorageDefaultListModel::NodeAdded(const mitk::DataNode* /*node*/) +{ + UpdateModelData(); +} + +void QmitkDataStorageDefaultListModel::NodeChanged(const mitk::DataNode* /*node*/) +{ + // nothing here, since the "'NodeChanged'-event is currently sent far too often + //UpdateModelData(); +} + +void QmitkDataStorageDefaultListModel::NodeRemoved(const mitk::DataNode* /*node*/) +{ + UpdateModelData(); +} + +QModelIndex QmitkDataStorageDefaultListModel::index(int row, int column, const QModelIndex &parent) const +{ + bool hasIndex = this->hasIndex(row, column, parent); + if (hasIndex) + { + return this->createIndex(row, column); + } + + return QModelIndex(); +} + +QModelIndex QmitkDataStorageDefaultListModel::parent(const QModelIndex &/*child*/) const +{ + return QModelIndex(); +} + +int QmitkDataStorageDefaultListModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + { + return 0; + } + + return m_DataNodes.size(); +} + +int QmitkDataStorageDefaultListModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + { + return 0; + } + + return 1; +} + +QVariant QmitkDataStorageDefaultListModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.model() != this) + { + return QVariant(); + } + + if(index.row() < 0 || index.row() >= static_cast(m_DataNodes.size())) + { + return QVariant(); + } + + mitk::DataNode::Pointer dataNode = m_DataNodes.at(index.row()); + QString nodeName = QString::fromStdString(dataNode->GetName()); + if (nodeName.isEmpty()) + nodeName = "unnamed"; + + if (role == Qt::DisplayRole) + return nodeName; + else if (role == Qt::ToolTipRole) + return nodeName; + else if (role == Qt::DecorationRole) + { + QmitkNodeDescriptor *nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); + return nodeDescriptor->GetIcon(dataNode); + } + else if (role == QmitkDataNodeRole) + { + return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); + } + else if (role == QmitkDataNodeRawPointerRole) + { + return QVariant::fromValue(dataNode); + } + + return QVariant(); +} + +QVariant QmitkDataStorageDefaultListModel::headerData(int /*section*/, Qt::Orientation /*orientation*/, int /*role*/) const +{ + return QVariant(tr("Nodes")); +} + +Qt::ItemFlags QmitkDataStorageDefaultListModel::flags(const QModelIndex &index) const +{ + if (index.isValid() && index.model() == this) + { + return Qt::ItemIsEnabled | Qt::ItemIsSelectable; + } + + return Qt::NoItemFlags; +} + +void QmitkDataStorageDefaultListModel::UpdateModelData() +{ + mitk::DataStorage::SetOfObjects::ConstPointer dataNodes; + if (!m_DataStorage.IsExpired()) + { + auto dataStorage = m_DataStorage.Lock(); + if (m_NodePredicate.IsNotNull()) + { + dataNodes = dataStorage->GetSubset(m_NodePredicate); + } + else + { + dataNodes = dataStorage->GetAll(); + } + } + + // update the model, so that it will be filled with the nodes of the new data storage + beginResetModel(); + m_DataNodes.clear(); + + // add all (filtered) nodes to the vector of nodes + if (dataNodes != nullptr) + { + for (auto& node : *dataNodes) + { + m_DataNodes.push_back(node); + } + } + endResetModel(); +} diff --git a/Modules/QtWidgets/src/QmitkDataStorageInspectorGenerator.cpp b/Modules/QtWidgets/src/QmitkDataStorageInspectorGenerator.cpp new file mode 100644 index 0000000000..188c4d1029 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageInspectorGenerator.cpp @@ -0,0 +1,61 @@ +/*=================================================================== + +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 "usModuleContext.h" +#include "usGetModuleContext.h" + +#include "mitkLogMacros.h" +#include "QmitkDataStorageInspectorGenerator.h" + +mitk::IDataStorageInspectorProvider* QmitkDataStorageInspectorGenerator::GetProvider(const IDType& id) +{ + mitk::IDataStorageInspectorProvider* result = nullptr; + + std::string filter = "(" + mitk::IDataStorageInspectorProvider::PROP_INSPECTOR_ID() + "=" + id + ")"; + std::vector > providerRegisters = us::GetModuleContext()->GetServiceReferences(filter); + + if (!providerRegisters.empty()) + { + if (providerRegisters.size() > 1) + { + MITK_WARN << "Multiple provider for class id'" << id << "' found. Using just one."; + } + result = us::GetModuleContext()->GetService(providerRegisters.front()); + } + + return result; +}; + +QmitkDataStorageInspectorGenerator::ProviderMapType QmitkDataStorageInspectorGenerator::GetProviders() +{ + std::vector > providerRegisters = us::GetModuleContext()->GetServiceReferences(); + + ProviderMapType result; + + for (auto regs : providerRegisters) + { + auto provider = us::GetModuleContext()->GetService(regs); + result.insert(std::make_pair(provider->GetInspectorID(), provider)); + } + + return result; +}; + +QmitkDataStorageInspectorGenerator::QmitkDataStorageInspectorGenerator() += default; + +QmitkDataStorageInspectorGenerator::~QmitkDataStorageInspectorGenerator() += default; \ No newline at end of file diff --git a/Modules/QtWidgets/src/QmitkDataStorageListInspector.cpp b/Modules/QtWidgets/src/QmitkDataStorageListInspector.cpp new file mode 100644 index 0000000000..a5d3182d1f --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageListInspector.cpp @@ -0,0 +1,61 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include + +#include + +QmitkDataStorageListInspector::QmitkDataStorageListInspector(QWidget* parent/* = nullptr*/) + : QmitkAbstractDataStorageInspector(parent) +{ + m_Controls.setupUi(this); + + m_Controls.view->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_Controls.view->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.view->setAlternatingRowColors(true); + + m_StorageModel = new QmitkDataStorageDefaultListModel(this); + + m_Controls.view->setModel(m_StorageModel); +} + +QAbstractItemView* QmitkDataStorageListInspector::GetView() +{ + return m_Controls.view; +}; + +const QAbstractItemView* QmitkDataStorageListInspector::GetView() const +{ + return m_Controls.view; +}; + +void QmitkDataStorageListInspector::Initialize() +{ + m_StorageModel->SetDataStorage(m_DataStorage.Lock()); + m_StorageModel->SetNodePredicate(m_NodePredicate); + + m_Connector->SetView(m_Controls.view); +} + +void QmitkDataStorageListInspector::SetSelectionMode(SelectionMode mode) +{ + m_Controls.view->setSelectionMode(mode); +} + +QmitkDataStorageListInspector::SelectionMode QmitkDataStorageListInspector::GetSelectionMode() const +{ + return m_Controls.view->selectionMode(); +}; diff --git a/Modules/QtWidgets/src/QmitkDataStorageListInspector.ui b/Modules/QtWidgets/src/QmitkDataStorageListInspector.ui new file mode 100644 index 0000000000..abce896fce --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageListInspector.ui @@ -0,0 +1,46 @@ + + + QmitkDataStorageListInspector + + + + 0 + 0 + 400 + 300 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QAbstractItemView::NoEditTriggers + + + true + + + + + + + + diff --git a/Modules/QtWidgets/src/QmitkDataStorageSimpleTreeModel.cpp b/Modules/QtWidgets/src/QmitkDataStorageSimpleTreeModel.cpp new file mode 100644 index 0000000000..0189f5df4d --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageSimpleTreeModel.cpp @@ -0,0 +1,370 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include +#include +#include + +// qt widgets module +#include "QmitkCustomVariants.h" +#include "QmitkEnums.h" + +QmitkDataStorageSimpleTreeModel::QmitkDataStorageSimpleTreeModel(QObject *parent) + : QmitkAbstractDataStorageModel(parent), m_Root(nullptr) +{ + ResetTree(); +} + +QmitkDataStorageSimpleTreeModel::~QmitkDataStorageSimpleTreeModel() +{ + m_Root->Delete(); + m_Root = nullptr; +}; + +void QmitkDataStorageSimpleTreeModel::ResetTree() +{ + mitk::DataNode::Pointer rootDataNode = mitk::DataNode::New(); + rootDataNode->SetName("Data Storage"); + m_Root = new TreeItem(rootDataNode, 0); +} + +void QmitkDataStorageSimpleTreeModel::DataStorageChanged() +{ + if (m_Root) + { + m_Root->Delete(); + } + + ResetTree(); + UpdateModelData(); +} + +void QmitkDataStorageSimpleTreeModel::NodePredicateChanged() +{ + ResetTree(); + UpdateModelData(); +} + +void QmitkDataStorageSimpleTreeModel::NodeAdded(const mitk::DataNode *node) +{ + if (node == nullptr || m_DataStorage.IsExpired() || !m_DataStorage.Lock()->Exists(node) || + m_Root->Find(node) != nullptr) + return; + + this->AddNodeInternal(node); +} + +void QmitkDataStorageSimpleTreeModel::NodeChanged(const mitk::DataNode *node) +{ + TreeItem *treeItem = m_Root->Find(node); + if (treeItem) + { + TreeItem *parentTreeItem = treeItem->GetParent(); + // as the root node should not be removed one should always have a parent item + if (!parentTreeItem) + return; + QModelIndex index = this->createIndex(treeItem->GetIndex(), 0, treeItem); + + // now emit the dataChanged signal + emit dataChanged(index, index); + } +} + +void QmitkDataStorageSimpleTreeModel::NodeRemoved(const mitk::DataNode *node) +{ + if (node == nullptr || !m_Root) + return; + + TreeItem *treeItem = m_Root->Find(node); + if (!treeItem) + return; // return because there is no treeitem containing this node + + TreeItem *parentTreeItem = treeItem->GetParent(); + QModelIndex parentIndex = this->IndexFromTreeItem(parentTreeItem); + + // emit beginRemoveRows event (QModelIndex is empty because we dont have a tree model) + this->beginRemoveRows(parentIndex, treeItem->GetIndex(), treeItem->GetIndex()); + + // remove node + std::vector children = treeItem->GetChildren(); + m_TreeItems.remove(treeItem); + delete treeItem; //delete in tree + + if (!children.empty()) + { + //if not empty we have to rebuild the whole representation, + //because the children could be now top level, or at another + //source/parent. + this->UpdateModelData(); + } +} + +QModelIndex QmitkDataStorageSimpleTreeModel::index(int row, int column, const QModelIndex &parent) const +{ + TreeItem *parentItem; + + if (!parent.isValid() || parent.model() != this) + parentItem = m_Root; + else + parentItem = static_cast(parent.internalPointer()); + + if (parentItem) + { + TreeItem *childItem = parentItem->GetChild(row); + if (childItem) + return createIndex(row, column, childItem); + } + + return QModelIndex(); +} + +QModelIndex QmitkDataStorageSimpleTreeModel::parent(const QModelIndex &child) const +{ + if (!child.isValid() || !m_Root || child.model() != this) + return QModelIndex(); + + TreeItem *childItem = this->TreeItemFromIndex(child); + + if (!childItem) + return QModelIndex(); + + TreeItem *parentItem = childItem->GetParent(); + + if (parentItem == m_Root) + return QModelIndex(); + + return this->createIndex(parentItem->GetIndex(), 0, parentItem); +} + +QmitkDataStorageSimpleTreeModel::TreeItem *QmitkDataStorageSimpleTreeModel::TreeItemFromIndex( + const QModelIndex &index) const +{ + if (index.isValid() && index.model() == this) + { + auto item = static_cast(index.internalPointer()); + auto finding = std::find(std::begin(m_TreeItems), std::end(m_TreeItems), item); + if (finding == std::end(m_TreeItems)) + { + return nullptr; + } + return item; + } + else + return m_Root; +} + +int QmitkDataStorageSimpleTreeModel::rowCount(const QModelIndex &parent) const +{ + TreeItem *parentTreeItem = this->TreeItemFromIndex(parent); + if (parentTreeItem) + return parentTreeItem->GetChildCount(); + else + return 0; +} + +int QmitkDataStorageSimpleTreeModel::columnCount(const QModelIndex &/*parent*/) const +{ + return 1; +} + +QVariant QmitkDataStorageSimpleTreeModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid() || index.model() != this) + { + return QVariant(); + } + + auto treeItem = this->TreeItemFromIndex(index); + if (!treeItem) + return QVariant(); + + mitk::DataNode *dataNode = treeItem->GetDataNode(); + + QString nodeName = QString::fromStdString(dataNode->GetName()); + if (nodeName.isEmpty()) + { + nodeName = "unnamed"; + } + + if (role == Qt::DisplayRole) + return nodeName; + else if (role == Qt::ToolTipRole) + return nodeName; + else if (role == Qt::DecorationRole) + { + QmitkNodeDescriptor *nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); + return nodeDescriptor->GetIcon(dataNode); + } + else if (role == QmitkDataNodeRole) + { + return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); + } + else if (role == QmitkDataNodeRawPointerRole) + { + return QVariant::fromValue(dataNode); + } + + return QVariant(); +} + +bool QmitkDataStorageSimpleTreeModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!index.isValid() || index.model() != this) + return false; + + auto treeItem = this->TreeItemFromIndex(index); + if (!treeItem) + return false; + + mitk::DataNode *dataNode = treeItem->GetDataNode(); + if (!dataNode) + return false; + + if (role == Qt::EditRole && !value.toString().isEmpty()) + { + dataNode->SetName(value.toString().toStdString().c_str()); + } + else if (role == Qt::CheckStateRole) + { + // Please note: value.toInt() returns 2, independentely from the actual checkstate of the index element. + // Therefore the checkstate is being estimated again here. + + QVariant qcheckstate = index.data(Qt::CheckStateRole); + int checkstate = qcheckstate.toInt(); + bool isVisible = bool(checkstate); + dataNode->SetVisibility(!isVisible); + } + // inform listeners about changes + emit dataChanged(index, index); + return true; +} + +QVariant QmitkDataStorageSimpleTreeModel::headerData(int /*section*/, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Horizontal && role == Qt::DisplayRole && m_Root) + return QString::fromStdString(m_Root->GetDataNode()->GetName()); + + return QVariant(); +} + +Qt::ItemFlags QmitkDataStorageSimpleTreeModel::flags(const QModelIndex &index) const +{ + if (index.isValid() && index.model() == this) + { + auto treeItem = this->TreeItemFromIndex(index); + if (!treeItem) + return Qt::NoItemFlags; + + const auto dataNode = treeItem->GetDataNode(); + if (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(dataNode)) + { + return Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable; + } + else + { + return Qt::NoItemFlags; + } + + } + + return Qt::NoItemFlags; +} + +mitk::DataNode *QmitkDataStorageSimpleTreeModel::GetParentNode(const mitk::DataNode *node) const +{ + mitk::DataNode *dataNode = nullptr; + + mitk::DataStorage::SetOfObjects::ConstPointer _Sources = m_DataStorage.Lock()->GetSources(node); + + if (_Sources->Size() > 0) + dataNode = _Sources->front(); + + return dataNode; +} + +void QmitkDataStorageSimpleTreeModel::AddNodeInternal(const mitk::DataNode *node) +{ + if (node == nullptr || m_DataStorage.IsExpired() || !m_DataStorage.Lock()->Exists(node) || m_Root->Find(node) != 0) + return; + + // find out if we have a root node + TreeItem *parentTreeItem = m_Root; + QModelIndex index; + mitk::DataNode *parentDataNode = this->GetParentNode(node); + + if (parentDataNode) // no top level data node + { + parentTreeItem = m_Root->Find(parentDataNode); // find the corresponding tree item + if (!parentTreeItem) + { + this->NodeAdded(parentDataNode); + parentTreeItem = m_Root->Find(parentDataNode); + if (!parentTreeItem) + return; + } + + // get the index of this parent with the help of the grand parent + index = this->createIndex(parentTreeItem->GetIndex(), 0, parentTreeItem); + } + + int firstRowWithASiblingBelow = 0; + int nodeLayer = -1; + node->GetIntProperty("layer", nodeLayer); + for (TreeItem *siblingTreeItem : parentTreeItem->GetChildren()) + { + int siblingLayer = -1; + if (mitk::DataNode *siblingNode = siblingTreeItem->GetDataNode()) + { + siblingNode->GetIntProperty("layer", siblingLayer); + } + if (nodeLayer > siblingLayer) + { + break; + } + ++firstRowWithASiblingBelow; + } + beginInsertRows(index, firstRowWithASiblingBelow, firstRowWithASiblingBelow); + auto newNode = new TreeItem(const_cast(node)); + parentTreeItem->InsertChild(newNode, firstRowWithASiblingBelow); + m_TreeItems.push_back(newNode); + + endInsertRows(); +} + +QModelIndex QmitkDataStorageSimpleTreeModel::IndexFromTreeItem(TreeItem *item) const +{ + if (item == m_Root) + return QModelIndex(); + else + return this->createIndex(item->GetIndex(), 0, item); +} + +void QmitkDataStorageSimpleTreeModel::UpdateModelData() +{ + if (!m_DataStorage.IsExpired()) + { + auto nodeset = m_DataStorage.Lock()->GetAll(); + if (m_NodePredicate != nullptr) + { + nodeset = m_DataStorage.Lock()->GetSubset(m_NodePredicate); + } + + for (const auto& node : *nodeset) + { + this->AddNodeInternal(node); + } + } +} diff --git a/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.cpp b/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.cpp new file mode 100644 index 0000000000..c8bb5c952b --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.cpp @@ -0,0 +1,65 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#include + +#include + +QmitkDataStorageTreeInspector::QmitkDataStorageTreeInspector(QWidget* parent/* = nullptr*/) + : QmitkAbstractDataStorageInspector(parent) +{ + m_Controls.setupUi(this); + + m_Controls.view->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_Controls.view->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.view->setAlternatingRowColors(true); + m_Controls.view->setHeaderHidden(true); + m_Controls.view->setTextElideMode(Qt::ElideMiddle); + + m_StorageModel = new QmitkDataStorageSimpleTreeModel(this); + + m_Controls.view->setModel(m_StorageModel); +} + +QAbstractItemView* QmitkDataStorageTreeInspector::GetView() +{ + return m_Controls.view; +}; + +const QAbstractItemView* QmitkDataStorageTreeInspector::GetView() const +{ + return m_Controls.view; +}; + +void QmitkDataStorageTreeInspector::Initialize() +{ + m_StorageModel->SetDataStorage(m_DataStorage.Lock()); + m_StorageModel->SetNodePredicate(m_NodePredicate); + + m_Connector->SetView(m_Controls.view); + + m_Controls.view->expandAll(); +} + +void QmitkDataStorageTreeInspector::SetSelectionMode(SelectionMode mode) +{ + m_Controls.view->setSelectionMode(mode); +} + +QmitkDataStorageTreeInspector::SelectionMode QmitkDataStorageTreeInspector::GetSelectionMode() const +{ + return m_Controls.view->selectionMode(); +}; diff --git a/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.ui b/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.ui new file mode 100644 index 0000000000..4517c402e4 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageTreeInspector.ui @@ -0,0 +1,46 @@ + + + QmitkDataStorageTreeInspector + + + + 0 + 0 + 400 + 300 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QAbstractItemView::NoEditTriggers + + + true + + + + + + + + diff --git a/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp b/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp index c27f72a607..d83c8d96cd 100644 --- a/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp +++ b/Modules/QtWidgets/src/QmitkDataStorageTreeModel.cpp @@ -1,1005 +1,884 @@ /*=================================================================== 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 "QmitkDataStorageTreeModel.h" +#include "QmitkDataStorageTreeModelInternalItem.h" #include "QmitkNodeDescriptorManager.h" #include #include #include #include #include #include #include #include #include QmitkDataStorageTreeModel::QmitkDataStorageTreeModel(mitk::DataStorage *_DataStorage, bool _PlaceNewNodesOnTop, QObject *parent) : QAbstractItemModel(parent), m_DataStorage(nullptr), m_PlaceNewNodesOnTop(_PlaceNewNodesOnTop), m_Root(nullptr), m_BlockDataStorageEvents(false), m_AllowHierarchyChange(false) { this->SetDataStorage(_DataStorage); } QmitkDataStorageTreeModel::~QmitkDataStorageTreeModel() { // set data storage to 0 = remove all listeners this->SetDataStorage(nullptr); m_Root->Delete(); m_Root = nullptr; } mitk::DataNode::Pointer QmitkDataStorageTreeModel::GetNode(const QModelIndex &index) const { return this->TreeItemFromIndex(index)->GetDataNode(); } const mitk::DataStorage::Pointer QmitkDataStorageTreeModel::GetDataStorage() const { return m_DataStorage.Lock(); } QModelIndex QmitkDataStorageTreeModel::index(int row, int column, const QModelIndex &parent) const { TreeItem *parentItem; if (!parent.isValid()) parentItem = m_Root; else parentItem = static_cast(parent.internalPointer()); TreeItem *childItem = parentItem->GetChild(row); if (childItem) return createIndex(row, column, childItem); else return QModelIndex(); } int QmitkDataStorageTreeModel::rowCount(const QModelIndex &parent) const { TreeItem *parentTreeItem = this->TreeItemFromIndex(parent); return parentTreeItem->GetChildCount(); } Qt::ItemFlags QmitkDataStorageTreeModel::flags(const QModelIndex &index) const { if (index.isValid()) { return Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable | Qt::ItemIsEditable | Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled; } else { return Qt::ItemIsDropEnabled; } } int QmitkDataStorageTreeModel::columnCount(const QModelIndex & /* parent = QModelIndex() */) const { return 1; } QModelIndex QmitkDataStorageTreeModel::parent(const QModelIndex &index) const { if (!index.isValid()) return QModelIndex(); TreeItem *childItem = this->TreeItemFromIndex(index); TreeItem *parentItem = childItem->GetParent(); if (parentItem == m_Root) return QModelIndex(); return this->createIndex(parentItem->GetIndex(), 0, parentItem); } QmitkDataStorageTreeModel::TreeItem *QmitkDataStorageTreeModel::TreeItemFromIndex(const QModelIndex &index) const { if (index.isValid()) return static_cast(index.internalPointer()); else return m_Root; } Qt::DropActions QmitkDataStorageTreeModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } Qt::DropActions QmitkDataStorageTreeModel::supportedDragActions() const { return Qt::CopyAction | Qt::MoveAction; } bool QmitkDataStorageTreeModel::dropMimeData( const QMimeData *data, Qt::DropAction action, int row, int /*column*/, const QModelIndex &parent) { // Early exit, returning true, but not actually doing anything (ignoring data). if (action == Qt::IgnoreAction) { return true; } // Note, we are returning true if we handled it, and false otherwise bool returnValue = false; if (data->hasFormat("application/x-qabstractitemmodeldatalist")) { returnValue = true; // First we extract a Qlist of TreeItem* pointers. QList listOfItemsToDrop = ToTreeItemPtrList(data); if (listOfItemsToDrop.empty()) { return false; } // Retrieve the TreeItem* where we are dropping stuff, and its parent. TreeItem *dropItem = this->TreeItemFromIndex(parent); TreeItem *parentItem = dropItem->GetParent(); // If item was dropped onto empty space, we select the root node if (dropItem == m_Root) { parentItem = m_Root; } // Dragging and Dropping is only allowed within the same parent, so use the first item in list to validate. // (otherwise, you could have a derived image such as a segmentation, and assign it to another image). // NOTE: We are assuming the input list is valid... i.e. when it was dragged, all the items had the same parent. // Determine whether or not the drag and drop operation is a valid one. // Examples of invalid operations include: // - dragging nodes with different parents // - dragging nodes from one parent to another parent, if m_AllowHierarchyChange is false // - dragging a node on one of its child nodes (only relevant if m_AllowHierarchyChange is true) bool isValidDragAndDropOperation(true); // different parents { TreeItem *firstParent = listOfItemsToDrop[0]->GetParent(); QList::iterator diIter; for (diIter = listOfItemsToDrop.begin() + 1; diIter != listOfItemsToDrop.end(); diIter++) { if (firstParent != (*diIter)->GetParent()) { isValidDragAndDropOperation = false; break; } } } // dragging from one parent to another if ((!m_AllowHierarchyChange) && isValidDragAndDropOperation) { if (row == -1) // drag onto a node { isValidDragAndDropOperation = listOfItemsToDrop[0]->GetParent() == parentItem; } else // drag between nodes { isValidDragAndDropOperation = listOfItemsToDrop[0]->GetParent() == dropItem; } } // dragging on a child node of one the dragged nodes { QList::iterator diIter; for (diIter = listOfItemsToDrop.begin(); diIter != listOfItemsToDrop.end(); diIter++) { TreeItem *tempItem = dropItem; while (tempItem != m_Root) { tempItem = tempItem->GetParent(); if (tempItem == *diIter) { isValidDragAndDropOperation = false; } } } } if (!isValidDragAndDropOperation) return isValidDragAndDropOperation; if (listOfItemsToDrop[0] != dropItem && isValidDragAndDropOperation) { // Retrieve the index of where we are dropping stuff. QModelIndex parentModelIndex = this->IndexFromTreeItem(parentItem); int dragIndex = 0; // Iterate through the list of TreeItem (which may be at non-consecutive indexes). QList::iterator diIter; for (diIter = listOfItemsToDrop.begin(); diIter != listOfItemsToDrop.end(); diIter++) { TreeItem *itemToDrop = *diIter; // if the item is dragged down we have to compensate its final position for the // fact it is deleted lateron, this only applies if it is dragged within the same level if ((itemToDrop->GetIndex() < row) && (itemToDrop->GetParent() == dropItem)) { dragIndex = 1; } // Here we assume that as you remove items, one at a time, that GetIndex() will be valid. this->beginRemoveRows( this->IndexFromTreeItem(itemToDrop->GetParent()), itemToDrop->GetIndex(), itemToDrop->GetIndex()); itemToDrop->GetParent()->RemoveChild(itemToDrop); this->endRemoveRows(); } // row = -1 dropped on an item, row != -1 dropped in between two items // Select the target index position, or put it at the end of the list. int dropIndex = 0; if (row != -1) { if (dragIndex == 0) dropIndex = std::min(row, parentItem->GetChildCount() - 1); else dropIndex = std::min(row - 1, parentItem->GetChildCount() - 1); } else { dropIndex = dropItem->GetIndex(); } QModelIndex dropItemModelIndex = this->IndexFromTreeItem(dropItem); if ((row == -1 && dropItemModelIndex.row() == -1) || dropItemModelIndex.row() > parentItem->GetChildCount()) dropIndex = parentItem->GetChildCount() - 1; // Now insert items again at the drop item position if (m_AllowHierarchyChange) { this->beginInsertRows(dropItemModelIndex, dropIndex, dropIndex + listOfItemsToDrop.size() - 1); } else { this->beginInsertRows(parentModelIndex, dropIndex, dropIndex + listOfItemsToDrop.size() - 1); } for (diIter = listOfItemsToDrop.begin(); diIter != listOfItemsToDrop.end(); diIter++) { // dropped on node, behaviour depends on preference setting if (m_AllowHierarchyChange) { auto dataStorage = m_DataStorage.Lock(); m_BlockDataStorageEvents = true; mitk::DataNode *droppedNode = (*diIter)->GetDataNode(); mitk::DataNode *dropOntoNode = dropItem->GetDataNode(); dataStorage->Remove(droppedNode); dataStorage->Add(droppedNode, dropOntoNode); m_BlockDataStorageEvents = false; dropItem->InsertChild((*diIter), dropIndex); } else { if (row == -1) // drag onto a node { parentItem->InsertChild((*diIter), dropIndex); } else // drag between nodes { dropItem->InsertChild((*diIter), dropIndex); } } dropIndex++; } this->endInsertRows(); // Change Layers to match. this->AdjustLayerProperty(); } } else if (data->hasFormat("application/x-mitk-datanodes")) { returnValue = true; int numberOfNodesDropped = 0; QList dataNodeList = QmitkMimeTypes::ToDataNodePtrList(data); mitk::DataNode *node = nullptr; foreach (node, dataNodeList) { if (node && !m_DataStorage.IsExpired() && !m_DataStorage.Lock()->Exists(node)) { m_DataStorage.Lock()->Add(node); mitk::BaseData::Pointer basedata = node->GetData(); if (basedata.IsNotNull()) { mitk::RenderingManager::GetInstance()->InitializeViews( basedata->GetTimeGeometry(), mitk::RenderingManager::REQUEST_UPDATE_ALL, true); numberOfNodesDropped++; } } } // Only do a rendering update, if we actually dropped anything. if (numberOfNodesDropped > 0) { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } return returnValue; } QStringList QmitkDataStorageTreeModel::mimeTypes() const { QStringList types = QAbstractItemModel::mimeTypes(); types << "application/x-qabstractitemmodeldatalist"; types << "application/x-mitk-datanodes"; return types; } QMimeData *QmitkDataStorageTreeModel::mimeData(const QModelIndexList &indexes) const { return mimeDataFromModelIndexList(indexes); } QMimeData *QmitkDataStorageTreeModel::mimeDataFromModelIndexList(const QModelIndexList &indexes) { QMimeData *ret = new QMimeData; QString treeItemAddresses(""); QString dataNodeAddresses(""); QByteArray baTreeItemPtrs; QByteArray baDataNodePtrs; QDataStream dsTreeItemPtrs(&baTreeItemPtrs, QIODevice::WriteOnly); QDataStream dsDataNodePtrs(&baDataNodePtrs, QIODevice::WriteOnly); for (int i = 0; i < indexes.size(); i++) { TreeItem *treeItem = static_cast(indexes.at(i).internalPointer()); dsTreeItemPtrs << reinterpret_cast(treeItem); - dsDataNodePtrs << reinterpret_cast(treeItem->GetDataNode().GetPointer()); + dsDataNodePtrs << reinterpret_cast(treeItem->GetDataNode()); // --------------- deprecated ----------------- unsigned long long treeItemAddress = reinterpret_cast(treeItem); - unsigned long long dataNodeAddress = reinterpret_cast(treeItem->GetDataNode().GetPointer()); + unsigned long long dataNodeAddress = reinterpret_cast(treeItem->GetDataNode()); QTextStream(&treeItemAddresses) << treeItemAddress; QTextStream(&dataNodeAddresses) << dataNodeAddress; if (i != indexes.size() - 1) { QTextStream(&treeItemAddresses) << ","; QTextStream(&dataNodeAddresses) << ","; } // -------------- end deprecated ------------- } // ------------------ deprecated ----------------- ret->setData("application/x-qabstractitemmodeldatalist", QByteArray(treeItemAddresses.toLatin1())); ret->setData("application/x-mitk-datanodes", QByteArray(dataNodeAddresses.toLatin1())); // --------------- end deprecated ----------------- ret->setData(QmitkMimeTypes::DataStorageTreeItemPtrs, baTreeItemPtrs); ret->setData(QmitkMimeTypes::DataNodePtrs, baDataNodePtrs); return ret; } QVariant QmitkDataStorageTreeModel::data(const QModelIndex &index, int role) const { mitk::DataNode *dataNode = this->TreeItemFromIndex(index)->GetDataNode(); // get name of treeItem (may also be edited) QString nodeName = QString::fromStdString(dataNode->GetName()); if (nodeName.isEmpty()) { nodeName = "unnamed"; } if (role == Qt::DisplayRole) return nodeName; else if (role == Qt::ToolTipRole) return nodeName; else if (role == Qt::DecorationRole) { QmitkNodeDescriptor *nodeDescriptor = QmitkNodeDescriptorManager::GetInstance()->GetDescriptor(dataNode); return nodeDescriptor->GetIcon(dataNode); } else if (role == Qt::CheckStateRole) { return dataNode->IsVisible(nullptr); } else if (role == QmitkDataNodeRole) { return QVariant::fromValue(mitk::DataNode::Pointer(dataNode)); } else if (role == QmitkDataNodeRawPointerRole) { return QVariant::fromValue(dataNode); } return QVariant(); } bool QmitkDataStorageTreeModel::DicomPropertiesExists(const mitk::DataNode &node) const { bool propertiesExists = false; mitk::BaseProperty *seriesDescription_deprecated = (node.GetProperty("dicom.series.SeriesDescription")); mitk::BaseProperty *studyDescription_deprecated = (node.GetProperty("dicom.study.StudyDescription")); mitk::BaseProperty *patientsName_deprecated = (node.GetProperty("dicom.patient.PatientsName")); mitk::BaseProperty *seriesDescription = (node.GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x103e).c_str())); mitk::BaseProperty *studyDescription = (node.GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0008, 0x1030).c_str())); mitk::BaseProperty *patientsName = (node.GetProperty(mitk::GeneratePropertyNameForDICOMTag(0x0010, 0x0010).c_str())); if (patientsName != nullptr && studyDescription != nullptr && seriesDescription != nullptr) { if ((!patientsName->GetValueAsString().empty()) && (!studyDescription->GetValueAsString().empty()) && (!seriesDescription->GetValueAsString().empty())) { propertiesExists = true; } } /** Code coveres the deprecated property naming for backwards compatibility */ if (patientsName_deprecated != nullptr && studyDescription_deprecated != nullptr && seriesDescription_deprecated != nullptr) { if ((!patientsName_deprecated->GetValueAsString().empty()) && (!studyDescription_deprecated->GetValueAsString().empty()) && (!seriesDescription_deprecated->GetValueAsString().empty())) { propertiesExists = true; } } return propertiesExists; } QVariant QmitkDataStorageTreeModel::headerData(int /*section*/, Qt::Orientation orientation, int role) const { if (orientation == Qt::Horizontal && role == Qt::DisplayRole && m_Root) return QString::fromStdString(m_Root->GetDataNode()->GetName()); return QVariant(); } void QmitkDataStorageTreeModel::SetDataStorage(mitk::DataStorage *_DataStorage) { if (m_DataStorage != _DataStorage) // dont take the same again { if (!m_DataStorage.IsExpired()) { auto dataStorage = m_DataStorage.Lock(); // remove Listener for the data storage itself dataStorage->RemoveObserver(m_DataStorageDeletedTag); // remove listeners for the nodes dataStorage->AddNodeEvent.RemoveListener( mitk::MessageDelegate1(this, &QmitkDataStorageTreeModel::AddNode)); dataStorage->ChangedNodeEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::SetNodeModified)); dataStorage->RemoveNodeEvent.RemoveListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::RemoveNode)); } // take over the new data storage m_DataStorage = _DataStorage; // delete the old root (if necessary, create new) if (m_Root) m_Root->Delete(); mitk::DataNode::Pointer rootDataNode = mitk::DataNode::New(); rootDataNode->SetName("Data Manager"); m_Root = new TreeItem(rootDataNode, nullptr); this->beginResetModel(); this->endResetModel(); if (!m_DataStorage.IsExpired()) { auto dataStorage = m_DataStorage.Lock(); // add Listener for the data storage itself auto command = itk::SimpleMemberCommand::New(); command->SetCallbackFunction(this, &QmitkDataStorageTreeModel::SetDataStorageDeleted); m_DataStorageDeletedTag = dataStorage->AddObserver(itk::DeleteEvent(), command); // add listeners for the nodes dataStorage->AddNodeEvent.AddListener(mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::AddNode)); dataStorage->ChangedNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::SetNodeModified)); dataStorage->RemoveNodeEvent.AddListener( mitk::MessageDelegate1( this, &QmitkDataStorageTreeModel::RemoveNode)); mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = dataStorage->GetSubset(m_Predicate); // finally add all nodes to the model this->Update(); } } } void QmitkDataStorageTreeModel::SetDataStorageDeleted() { this->SetDataStorage(nullptr); } void QmitkDataStorageTreeModel::AddNodeInternal(const mitk::DataNode *node) { if (node == nullptr || m_DataStorage.IsExpired() || !m_DataStorage.Lock()->Exists(node) || m_Root->Find(node) != nullptr) return; // find out if we have a root node TreeItem *parentTreeItem = m_Root; QModelIndex index; mitk::DataNode *parentDataNode = this->GetParentNode(node); if (parentDataNode) // no top level data node { parentTreeItem = m_Root->Find(parentDataNode); // find the corresponding tree item if (!parentTreeItem) { this->AddNode(parentDataNode); parentTreeItem = m_Root->Find(parentDataNode); if (!parentTreeItem) return; } // get the index of this parent with the help of the grand parent index = this->createIndex(parentTreeItem->GetIndex(), 0, parentTreeItem); } // add node if (m_PlaceNewNodesOnTop) { // emit beginInsertRows event beginInsertRows(index, 0, 0); parentTreeItem->InsertChild(new TreeItem(const_cast(node)), 0); } else { int firstRowWithASiblingBelow = 0; int nodeLayer = -1; node->GetIntProperty("layer", nodeLayer); for (TreeItem* siblingTreeItem: parentTreeItem->GetChildren()) { int siblingLayer = -1; if (mitk::DataNode* siblingNode = siblingTreeItem->GetDataNode()) { siblingNode->GetIntProperty("layer", siblingLayer); } if (nodeLayer > siblingLayer) { break; } ++firstRowWithASiblingBelow; } beginInsertRows(index, firstRowWithASiblingBelow, firstRowWithASiblingBelow); parentTreeItem->InsertChild(new TreeItem(const_cast(node)), firstRowWithASiblingBelow); } // emit endInsertRows event endInsertRows(); if(m_PlaceNewNodesOnTop) { this->AdjustLayerProperty(); } } void QmitkDataStorageTreeModel::AddNode(const mitk::DataNode *node) { if (node == nullptr || m_BlockDataStorageEvents || m_DataStorage.IsExpired() || !m_DataStorage.Lock()->Exists(node) || m_Root->Find(node) != nullptr) return; this->AddNodeInternal(node); } void QmitkDataStorageTreeModel::SetPlaceNewNodesOnTop(bool _PlaceNewNodesOnTop) { m_PlaceNewNodesOnTop = _PlaceNewNodesOnTop; } void QmitkDataStorageTreeModel::RemoveNodeInternal(const mitk::DataNode *node) { if (!m_Root) return; TreeItem *treeItem = m_Root->Find(node); if (!treeItem) return; // return because there is no treeitem containing this node TreeItem *parentTreeItem = treeItem->GetParent(); QModelIndex parentIndex = this->IndexFromTreeItem(parentTreeItem); // emit beginRemoveRows event (QModelIndex is empty because we dont have a tree model) this->beginRemoveRows(parentIndex, treeItem->GetIndex(), treeItem->GetIndex()); // remove node std::vector children = treeItem->GetChildren(); delete treeItem; // emit endRemoveRows event endRemoveRows(); // move all children of deleted node into its parent for (std::vector::iterator it = children.begin(); it != children.end(); it++) { // emit beginInsertRows event beginInsertRows(parentIndex, parentTreeItem->GetChildCount(), parentTreeItem->GetChildCount()); // add nodes again parentTreeItem->AddChild(*it); // emit endInsertRows event endInsertRows(); } this->AdjustLayerProperty(); } void QmitkDataStorageTreeModel::RemoveNode(const mitk::DataNode *node) { if (node == nullptr || m_BlockDataStorageEvents) return; this->RemoveNodeInternal(node); } void QmitkDataStorageTreeModel::SetNodeModified(const mitk::DataNode *node) { TreeItem *treeItem = m_Root->Find(node); if (treeItem) { TreeItem *parentTreeItem = treeItem->GetParent(); // as the root node should not be removed one should always have a parent item if (!parentTreeItem) return; QModelIndex index = this->createIndex(treeItem->GetIndex(), 0, treeItem); // now emit the dataChanged signal emit dataChanged(index, index); } } mitk::DataNode *QmitkDataStorageTreeModel::GetParentNode(const mitk::DataNode *node) const { mitk::DataNode *dataNode = nullptr; mitk::DataStorage::SetOfObjects::ConstPointer _Sources = m_DataStorage.Lock()->GetSources(node); if (_Sources->Size() > 0) dataNode = _Sources->front(); return dataNode; } bool QmitkDataStorageTreeModel::setData(const QModelIndex &index, const QVariant &value, int role) { mitk::DataNode *dataNode = this->TreeItemFromIndex(index)->GetDataNode(); if (!dataNode) return false; if (role == Qt::EditRole && !value.toString().isEmpty()) { dataNode->SetStringProperty("name", value.toString().toStdString().c_str()); mitk::PlanarFigure *planarFigure = dynamic_cast(dataNode->GetData()); if (planarFigure != nullptr) mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else if (role == Qt::CheckStateRole) { // Please note: value.toInt() returns 2, independentely from the actual checkstate of the index element. // Therefore the checkstate is being estimated again here. QVariant qcheckstate = index.data(Qt::CheckStateRole); int checkstate = qcheckstate.toInt(); bool isVisible = bool(checkstate); dataNode->SetVisibility(!isVisible); emit nodeVisibilityChanged(); } // inform listeners about changes emit dataChanged(index, index); return true; } bool QmitkDataStorageTreeModel::setHeaderData(int /*section*/, Qt::Orientation /*orientation*/, const QVariant & /* value */, int /*role = Qt::EditRole*/) { return false; } void QmitkDataStorageTreeModel::AdjustLayerProperty() { /// transform the tree into an array and set the layer property descending std::vector vec; this->TreeToVector(m_Root, vec); int i = vec.size() - 1; for (std::vector::const_iterator it = vec.begin(); it != vec.end(); ++it) { mitk::DataNode::Pointer dataNode = (*it)->GetDataNode(); bool fixedLayer = false; if (!(dataNode->GetBoolProperty("fixedLayer", fixedLayer) && fixedLayer)) dataNode->SetIntProperty("layer", i); --i; } mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkDataStorageTreeModel::TreeToVector(TreeItem *parent, std::vector &vec) const { TreeItem *current; for (int i = 0; i < parent->GetChildCount(); ++i) { current = parent->GetChild(i); this->TreeToVector(current, vec); vec.push_back(current); } } QModelIndex QmitkDataStorageTreeModel::IndexFromTreeItem(TreeItem *item) const { if (item == m_Root) return QModelIndex(); else return this->createIndex(item->GetIndex(), 0, item); } QList QmitkDataStorageTreeModel::GetNodeSet() const { QList res; if (m_Root) this->TreeToNodeSet(m_Root, res); return res; } void QmitkDataStorageTreeModel::TreeToNodeSet(TreeItem *parent, QList &vec) const { TreeItem *current; for (int i = 0; i < parent->GetChildCount(); ++i) { current = parent->GetChild(i); vec.push_back(current->GetDataNode()); this->TreeToNodeSet(current, vec); } } QModelIndex QmitkDataStorageTreeModel::GetIndex(const mitk::DataNode *node) const { if (m_Root) { TreeItem *item = m_Root->Find(node); if (item) return this->IndexFromTreeItem(item); } return QModelIndex(); } QList QmitkDataStorageTreeModel::ToTreeItemPtrList(const QMimeData *mimeData) { if (mimeData == nullptr || !mimeData->hasFormat(QmitkMimeTypes::DataStorageTreeItemPtrs)) { return QList(); } return ToTreeItemPtrList(mimeData->data(QmitkMimeTypes::DataStorageTreeItemPtrs)); } QList QmitkDataStorageTreeModel::ToTreeItemPtrList(const QByteArray &ba) { QList result; QDataStream ds(ba); while (!ds.atEnd()) { quintptr treeItemPtr; ds >> treeItemPtr; result.push_back(reinterpret_cast(treeItemPtr)); } return result; } -QmitkDataStorageTreeModel::TreeItem::TreeItem(mitk::DataNode *_DataNode, TreeItem *_Parent) - : m_Parent(_Parent), m_DataNode(_DataNode) -{ - if (m_Parent) - m_Parent->AddChild(this); -} - -QmitkDataStorageTreeModel::TreeItem::~TreeItem() -{ - if (m_Parent) - m_Parent->RemoveChild(this); -} - -void QmitkDataStorageTreeModel::TreeItem::Delete() -{ - while (m_Children.size() > 0) - delete m_Children.back(); - - delete this; -} - -QmitkDataStorageTreeModel::TreeItem *QmitkDataStorageTreeModel::TreeItem::Find(const mitk::DataNode *_DataNode) const -{ - QmitkDataStorageTreeModel::TreeItem *item = nullptr; - if (_DataNode) - { - if (m_DataNode == _DataNode) - item = const_cast(this); - else - { - for (std::vector::const_iterator it = m_Children.begin(); it != m_Children.end(); ++it) - { - if (item) - break; - item = (*it)->Find(_DataNode); - } - } - } - return item; -} - -int QmitkDataStorageTreeModel::TreeItem::IndexOfChild(const TreeItem *item) const -{ - std::vector::const_iterator it = std::find(m_Children.begin(), m_Children.end(), item); - return it != m_Children.end() ? std::distance(m_Children.begin(), it) : -1; -} - -QmitkDataStorageTreeModel::TreeItem *QmitkDataStorageTreeModel::TreeItem::GetChild(int index) const -{ - return (m_Children.size() > 0 && index >= 0 && index < (int)m_Children.size()) ? m_Children.at(index) : nullptr; -} - -void QmitkDataStorageTreeModel::TreeItem::AddChild(TreeItem *item) -{ - this->InsertChild(item); -} - -void QmitkDataStorageTreeModel::TreeItem::RemoveChild(TreeItem *item) -{ - std::vector::iterator it = std::find(m_Children.begin(), m_Children.end(), item); - if (it != m_Children.end()) - { - m_Children.erase(it); - item->SetParent(nullptr); - } -} - -int QmitkDataStorageTreeModel::TreeItem::GetChildCount() const -{ - return m_Children.size(); -} - -int QmitkDataStorageTreeModel::TreeItem::GetIndex() const -{ - if (m_Parent) - return m_Parent->IndexOfChild(this); - - return 0; -} - -QmitkDataStorageTreeModel::TreeItem *QmitkDataStorageTreeModel::TreeItem::GetParent() const -{ - return m_Parent; -} - -mitk::DataNode::Pointer QmitkDataStorageTreeModel::TreeItem::GetDataNode() const -{ - return m_DataNode; -} - -void QmitkDataStorageTreeModel::TreeItem::InsertChild(TreeItem *item, int index) -{ - std::vector::iterator it = std::find(m_Children.begin(), m_Children.end(), item); - if (it == m_Children.end()) - { - if (m_Children.size() > 0 && index >= 0 && index < (int)m_Children.size()) - { - it = m_Children.begin(); - std::advance(it, index); - m_Children.insert(it, item); - } - else - m_Children.push_back(item); - - // add parent if necessary - if (item->GetParent() != this) - item->SetParent(this); - } -} - -std::vector QmitkDataStorageTreeModel::TreeItem::GetChildren() const -{ - return m_Children; -} - -void QmitkDataStorageTreeModel::TreeItem::SetParent(TreeItem *_Parent) -{ - m_Parent = _Parent; - if (m_Parent) - m_Parent->AddChild(this); -} - void QmitkDataStorageTreeModel::Update() { if (!m_DataStorage.IsExpired()) { mitk::DataStorage::SetOfObjects::ConstPointer _NodeSet = m_DataStorage.Lock()->GetAll(); /// Regardless the value of this preference, the new nodes must not be inserted /// at the top now, but at the position according to their layer. bool newNodesWereToBePlacedOnTop = m_PlaceNewNodesOnTop; m_PlaceNewNodesOnTop = false; for (const auto& node: *_NodeSet) { this->AddNodeInternal(node); } m_PlaceNewNodesOnTop = newNodesWereToBePlacedOnTop; /// Adjust the layers to ensure that derived nodes are above their sources. this->AdjustLayerProperty(); } } void QmitkDataStorageTreeModel::SetAllowHierarchyChange(bool allowHierarchyChange) { m_AllowHierarchyChange = allowHierarchyChange; } diff --git a/Modules/QtWidgets/src/QmitkDataStorageTreeModelInternalItem.cpp b/Modules/QtWidgets/src/QmitkDataStorageTreeModelInternalItem.cpp new file mode 100644 index 0000000000..ae7741b899 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkDataStorageTreeModelInternalItem.cpp @@ -0,0 +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 "QmitkDataStorageTreeModelInternalItem.h" + +#include "QmitkNodeDescriptorManager.h" +#include +#include +#include + +QmitkDataStorageTreeModelInternalItem::QmitkDataStorageTreeModelInternalItem(mitk::DataNode *_DataNode, QmitkDataStorageTreeModelInternalItem *_Parent) + : m_Parent(_Parent), m_DataNode(_DataNode) +{ + if (m_Parent) + m_Parent->AddChild(this); +} + +QmitkDataStorageTreeModelInternalItem::~QmitkDataStorageTreeModelInternalItem() +{ + if (m_Parent) + m_Parent->RemoveChild(this); +} + +void QmitkDataStorageTreeModelInternalItem::Delete() +{ + while (m_Children.size() > 0) + delete m_Children.back(); + + delete this; +} + +QmitkDataStorageTreeModelInternalItem *QmitkDataStorageTreeModelInternalItem::Find(const mitk::DataNode *_DataNode) const +{ + QmitkDataStorageTreeModelInternalItem *item = nullptr; + if (_DataNode) + { + if (m_DataNode == _DataNode) + item = const_cast(this); + else + { + for (std::vector::const_iterator it = m_Children.begin(); it != m_Children.end(); ++it) + { + if (item) + break; + item = (*it)->Find(_DataNode); + } + } + } + return item; +} + +int QmitkDataStorageTreeModelInternalItem::IndexOfChild(const QmitkDataStorageTreeModelInternalItem *item) const +{ + std::vector::const_iterator it = std::find(m_Children.begin(), m_Children.end(), item); + return it != m_Children.end() ? std::distance(m_Children.begin(), it) : -1; +} + +QmitkDataStorageTreeModelInternalItem *QmitkDataStorageTreeModelInternalItem::GetChild(int index) const +{ + return (m_Children.size() > 0 && index >= 0 && index < (int)m_Children.size()) ? m_Children.at(index) : 0; +} + +void QmitkDataStorageTreeModelInternalItem::AddChild(QmitkDataStorageTreeModelInternalItem *item) +{ + this->InsertChild(item); +} + +void QmitkDataStorageTreeModelInternalItem::RemoveChild(QmitkDataStorageTreeModelInternalItem *item) +{ + std::vector::iterator it = std::find(m_Children.begin(), m_Children.end(), item); + if (it != m_Children.end()) + { + m_Children.erase(it); + item->SetParent(0); + } +} + +int QmitkDataStorageTreeModelInternalItem::GetChildCount() const +{ + return m_Children.size(); +} + +int QmitkDataStorageTreeModelInternalItem::GetIndex() const +{ + if (m_Parent) + return m_Parent->IndexOfChild(this); + + return 0; +} + +QmitkDataStorageTreeModelInternalItem *QmitkDataStorageTreeModelInternalItem::GetParent() const +{ + return m_Parent; +} + +mitk::DataNode* QmitkDataStorageTreeModelInternalItem::GetDataNode() const +{ + return m_DataNode; +} + +void QmitkDataStorageTreeModelInternalItem::InsertChild(QmitkDataStorageTreeModelInternalItem *item, int index) +{ + std::vector::iterator it = std::find(m_Children.begin(), m_Children.end(), item); + if (it == m_Children.end()) + { + if (m_Children.size() > 0 && index >= 0 && index < (int)m_Children.size()) + { + it = m_Children.begin(); + std::advance(it, index); + m_Children.insert(it, item); + } + else + m_Children.push_back(item); + + // add parent if necessary + if (item->GetParent() != this) + item->SetParent(this); + } +} + +std::vector QmitkDataStorageTreeModelInternalItem::GetChildren() const +{ + return m_Children; +} + +void QmitkDataStorageTreeModelInternalItem::SetParent(QmitkDataStorageTreeModelInternalItem *_Parent) +{ + m_Parent = _Parent; + if (m_Parent) + m_Parent->AddChild(this); +} diff --git a/Modules/Core/test/mitkImageDataItemTest.cpp b/Modules/QtWidgets/src/QmitkIDataStorageInspectorProvider.cpp similarity index 55% copy from Modules/Core/test/mitkImageDataItemTest.cpp copy to Modules/QtWidgets/src/QmitkIDataStorageInspectorProvider.cpp index b332e9eca7..a78f82850c 100644 --- a/Modules/Core/test/mitkImageDataItemTest.cpp +++ b/Modules/QtWidgets/src/QmitkIDataStorageInspectorProvider.cpp @@ -1,32 +1,29 @@ /*=================================================================== 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 "mitkImage.h" -#include "mitkImageDataItem.h" +#include "QmitkIDataStorageInspectorProvider.h" -#include -int mitkImageDataItemTest(int /*argc*/, char * /*argv*/ []) +namespace mitk { - auto pixels = new unsigned long[100]; - void *data = pixels; + IDataStorageInspectorProvider::~IDataStorageInspectorProvider() {} - std::cout << "Testing pseudo-type independent deleting: "; - delete[](unsigned char *) data; - std::cout << "[PASSED]" << std::endl; + std::string mitk::IDataStorageInspectorProvider::PROP_INSPECTOR_ID() + { + static std::string s = "org.mitk.IDataStorageInspectorProvider.inspectorid"; + return s; + } - std::cout << "[TEST DONE]" << std::endl; - return EXIT_SUCCESS; -} +} \ No newline at end of file diff --git a/Modules/QtWidgets/src/QmitkModelViewSelectionConnector.cpp b/Modules/QtWidgets/src/QmitkModelViewSelectionConnector.cpp new file mode 100644 index 0000000000..b582b9e240 --- /dev/null +++ b/Modules/QtWidgets/src/QmitkModelViewSelectionConnector.cpp @@ -0,0 +1,189 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +// mitk gui qt common plugin +#include "QmitkModelViewSelectionConnector.h" + +// qt widgets module +#include "QmitkCustomVariants.h" +#include "QmitkEnums.h" + +QmitkModelViewSelectionConnector::QmitkModelViewSelectionConnector() + : m_Model(nullptr) + , m_View(nullptr) + , m_SelectOnlyVisibleNodes(false) +{ + // nothing here +} + +void QmitkModelViewSelectionConnector::SetView(QAbstractItemView* view) +{ + if (nullptr != m_View) + { + disconnect(m_View->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(ChangeModelSelection(const QItemSelection&, const QItemSelection&))); + } + + // reset model-view pair and check for valid function argument + m_View = nullptr; + if (nullptr == view) + { + mitkThrow() << "Invalid item view. To use the model-view selection connector please specify a valid 'QAbstractItemView'."; + } + + auto storageModel = dynamic_cast(view->model()); + + if (storageModel == nullptr) + { + mitkThrow() << "Invalid data model. To use the model-view selection connector please set a valid 'QmitkAbstractDataStorageModel' for the given item view."; + } + + // a valid item view and a valid data model was found + m_View = view; + m_Model = storageModel; + connect(m_View->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), SLOT(ChangeModelSelection(const QItemSelection&, const QItemSelection&))); +} + +void QmitkModelViewSelectionConnector::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) +{ + m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; +} + +void QmitkModelViewSelectionConnector::SetCurrentSelection(QList selectedNodes) +{ + if (nullptr == m_Model || nullptr == m_View) + { + return; + } + + // filter input nodes and return the modified input node list + QList filteredNodes = FilterNodeList(selectedNodes); + + bool equal = EqualNodeSelections(this->GetInternalSelectedNodes(), filteredNodes); + if (equal) + { + return; + } + + if (!m_SelectOnlyVisibleNodes) + { + // store the unmodified selection + m_NonVisibleSelection = selectedNodes; + // remove the nodes in the original selection that are already contained in the filtered input node list + // this will keep the selection of the original nodes that are not presented by the current view unmodified, but allows to change the selection of the filtered nodes + // later, the nodes of the 'm_NonVisibleSelection' member have to be added again to the list of selected (filtered) nodes, if a selection is sent from the current view (see 'ModelSelectionChanged') + auto lambda = [&filteredNodes](mitk::DataNode::Pointer original) { return filteredNodes.contains(original); }; + m_NonVisibleSelection.erase(std::remove_if(m_NonVisibleSelection.begin(), m_NonVisibleSelection.end(), lambda), m_NonVisibleSelection.end()); + } + + // create new selection by retrieving the corresponding indices of the (filtered) nodes + QItemSelection newCurrentSelection; + for (const auto& node : filteredNodes) + { + QModelIndexList matched = m_Model->match(m_Model->index(0, 0), QmitkDataNodeRole, QVariant::fromValue(node), 1, Qt::MatchRecursive); + if (!matched.empty()) + { + newCurrentSelection.select(matched.front(), matched.front()); + } + } + + m_View->selectionModel()->select(newCurrentSelection, QItemSelectionModel::ClearAndSelect); +} + +void QmitkModelViewSelectionConnector::ChangeModelSelection(const QItemSelection& /*selected*/, const QItemSelection& /*deselected*/) +{ + emit CurrentSelectionChanged(GetSelectedNodes()); +} + +bool QmitkModelViewSelectionConnector::GetSelectOnlyVisibleNodes() const +{ + return m_SelectOnlyVisibleNodes; +} + +QList QmitkModelViewSelectionConnector::GetSelectedNodes() const +{ + auto nodes = GetInternalSelectedNodes(); + + if (!m_SelectOnlyVisibleNodes) + { + // add the non-visible nodes from the original selection + nodes.append(m_NonVisibleSelection); + } + + return nodes; +} + +QList QmitkModelViewSelectionConnector::GetInternalSelectedNodes() const +{ + if (nullptr == m_Model || nullptr == m_View) + { + return QList(); + } + + QList nodes; + QModelIndexList selectedIndexes = m_View->selectionModel()->selectedIndexes(); + for (const auto& index : selectedIndexes) + { + QVariant qvariantDataNode = m_Model->data(index, QmitkDataNodeRole); + if (qvariantDataNode.canConvert()) + { + nodes.push_back(qvariantDataNode.value()); + } + } + return nodes; +} + +QList QmitkModelViewSelectionConnector::FilterNodeList(const QList& nodes) const +{ + if (nodes.isEmpty()) + { + return QList(); + } + + if (nullptr == m_Model) + { + return nodes; + } + + mitk::NodePredicateBase* nodePredicate = m_Model->GetNodePredicate(); + if (nullptr == nodePredicate) + { + // no filter set + return nodes; + } + + QList result; + for (const auto& node : nodes) + { + if (true == nodePredicate->CheckNode(node)) + { + result.push_back(node); + } + } + + return result; +} + +bool MITKQTWIDGETS_EXPORT EqualNodeSelections(const QList& selection1, const QList& selection2) +{ + if (selection1.size() == selection2.size()) + { + // lambda to compare node pointer inside both lists + auto lambda = [](mitk::DataNode::Pointer lhs, mitk::DataNode::Pointer rhs) { return lhs == rhs; }; + return std::is_permutation(selection1.begin(), selection1.end(), selection2.begin(), selection2.end(), lambda); + } + + return false; +} diff --git a/Modules/QtWidgets/src/mitkQtWidgetsActivator.cpp b/Modules/QtWidgets/src/mitkQtWidgetsActivator.cpp new file mode 100644 index 0000000000..8763ca1435 --- /dev/null +++ b/Modules/QtWidgets/src/mitkQtWidgetsActivator.cpp @@ -0,0 +1,38 @@ +/*=================================================================== + +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 "mitkQtWidgetsActivator.h" + +// Micro Services +#include +#include + +// Qmitk +#include "QmitkDataStorageInspectorProviderBase.h" +#include "QmitkDataStorageListInspector.h" +#include "QmitkDataStorageTreeInspector.h" + +void MitkQtWidgetsActivator::Load(us::ModuleContext * /*context*/) +{ + m_TreeInspector.reset(new QmitkDataStorageInspectorProviderBase("org.mitk.QmitkDataStorageListInspector", "Simple list", "Displays the filtered content of the data storage in a simple list.")); + m_ListInspector.reset(new QmitkDataStorageInspectorProviderBase("org.mitk.QmitkDataStorageTreeInspector", "Rendering tree", "Displays the filtered content of the data storage as the current rendering tree. \n(Equals the old data manager view)")); +} + +void MitkQtWidgetsActivator::Unload(us::ModuleContext *) +{ +} + +US_EXPORT_MODULE_ACTIVATOR(MitkQtWidgetsActivator) \ No newline at end of file diff --git a/Modules/QtWidgets/src/mitkQtWidgetsActivator.h b/Modules/QtWidgets/src/mitkQtWidgetsActivator.h new file mode 100644 index 0000000000..24624b0aa9 --- /dev/null +++ b/Modules/QtWidgets/src/mitkQtWidgetsActivator.h @@ -0,0 +1,44 @@ +/*=================================================================== + +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 MITKQTWIDGETSACTIVATOR_H_ +#define MITKQTWIDGETSACTIVATOR_H_ + +// Micro Services +#include +#include +#include +#include + +#include + +#include "QmitkIDataStorageInspectorProvider.h" + +/* + * This is the module activator for the "QtWidgets" module. + */ +class MitkQtWidgetsActivator : public us::ModuleActivator +{ +public: + void Load(us::ModuleContext *context) override; + void Unload(us::ModuleContext *) override; + +private: + std::unique_ptr m_TreeInspector; + std::unique_ptr m_ListInspector; +}; + +#endif // MITKCOREACTIVATOR_H_ diff --git a/Modules/QtWidgetsExt/resource/arrow-down.svg b/Modules/QtWidgetsExt/resource/arrow-down.svg index 6ff3a3a53c..e90c9fe748 100644 --- a/Modules/QtWidgetsExt/resource/arrow-down.svg +++ b/Modules/QtWidgetsExt/resource/arrow-down.svg @@ -1,2 +1,2 @@ - + diff --git a/Modules/QtWidgetsExt/resource/arrow-up.svg b/Modules/QtWidgetsExt/resource/arrow-up.svg index 322b7932b8..99ccfb82e3 100644 --- a/Modules/QtWidgetsExt/resource/arrow-up.svg +++ b/Modules/QtWidgetsExt/resource/arrow-up.svg @@ -1,2 +1,2 @@ - + diff --git a/Modules/QtWidgetsExt/resource/eraser.svg b/Modules/QtWidgetsExt/resource/eraser.svg index 725d88fed0..1a777baef7 100644 --- a/Modules/QtWidgetsExt/resource/eraser.svg +++ b/Modules/QtWidgetsExt/resource/eraser.svg @@ -1,2 +1,2 @@ - + diff --git a/Modules/QtWidgetsExt/resource/folder-open.svg b/Modules/QtWidgetsExt/resource/folder-open.svg index 12990d0ae8..d0f8ed7ebb 100644 --- a/Modules/QtWidgetsExt/resource/folder-open.svg +++ b/Modules/QtWidgetsExt/resource/folder-open.svg @@ -1,2 +1,2 @@ - + diff --git a/Modules/QtWidgetsExt/resource/plus-xyz.svg b/Modules/QtWidgetsExt/resource/plus-xyz.svg index 303346fa4d..4da0fa0f79 100644 --- a/Modules/QtWidgetsExt/resource/plus-xyz.svg +++ b/Modules/QtWidgetsExt/resource/plus-xyz.svg @@ -1,82 +1,82 @@ image/svg+xml diff --git a/Modules/QtWidgetsExt/resource/plus.svg b/Modules/QtWidgetsExt/resource/plus.svg index c180bc77f4..d19839734e 100644 --- a/Modules/QtWidgetsExt/resource/plus.svg +++ b/Modules/QtWidgetsExt/resource/plus.svg @@ -1,2 +1,2 @@ - + diff --git a/Modules/QtWidgetsExt/resource/save.svg b/Modules/QtWidgetsExt/resource/save.svg index e396a59486..d12d2aab74 100644 --- a/Modules/QtWidgetsExt/resource/save.svg +++ b/Modules/QtWidgetsExt/resource/save.svg @@ -1,2 +1,2 @@ - + diff --git a/Modules/SceneSerializationBase/include/mitkStringsToNumbers.h b/Modules/SceneSerializationBase/include/mitkStringsToNumbers.h index 7f3ab613f8..f94a1e6a44 100644 --- a/Modules/SceneSerializationBase/include/mitkStringsToNumbers.h +++ b/Modules/SceneSerializationBase/include/mitkStringsToNumbers.h @@ -1,61 +1,61 @@ /*=================================================================== 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 mitkVectorPropertySerializer_h #define mitkVectorPropertySerializer_h -#include +#include namespace mitk { //! Convert an array of strings to an array of numbers via boost::lexical_cast. //! //! Call mitk::StringsToNumbers for all count elements of something that can be accessed //! via operator[], e.g. to fill a Point3D / Vector3D. //! //! \param count the number of elements to convert from "strings" to "numbers" //! \param numbers a container for at least "count" numeric values with indices starting from 0 //! \param strings a container for at least three string values with indices starting from 0 //! //! \warning This method has absolutely no means of verifying that your containers //! are big enough. It is the caller's responsibility to make sure that //! both the input and the output container can be addressed via [0], [1], [2]. //! //! \exception propagates boost::bad_lexical_cast exception when unparsable strings are encountered //! //! \code //! std::vector serialized_double_values = ... read from some file ... //! mitk::Point3D point; //! try //! { //! mitk::StringToDouble(3, serialized_double_values, point); //! } //! catch (boost::bad_lexical_cast& e) //! { //! MITK_ERROR << "Bad cast from string to double: " << e.what(); //! } //! \endcode template void StringsToNumbers(unsigned int count, const STRING_ARRAY &strings, DOUBLE_ARRAY &numbers) { for (unsigned int i = 0; i < count; ++i) { numbers[i] = boost::lexical_cast(strings[i]); } } } #endif diff --git a/Modules/SceneSerializationBase/include/mitkVectorPropertySerializer.h b/Modules/SceneSerializationBase/include/mitkVectorPropertySerializer.h index 9fe5c58daa..4721c0ad92 100644 --- a/Modules/SceneSerializationBase/include/mitkVectorPropertySerializer.h +++ b/Modules/SceneSerializationBase/include/mitkVectorPropertySerializer.h @@ -1,157 +1,157 @@ /*=================================================================== 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 mitkVectorPropertySerializer_h #define mitkVectorPropertySerializer_h #include "mitkBasePropertySerializer.h" #include "mitkVectorProperty.h" -#include +#include namespace mitk { /** \brief Serializes a VectorProperty Serializes an instance of VectorProperty into a XML structure like \verbatim \endverbatim This class is implemented as a template and makes use of std::stringstream for necessary conversions of specific data types to and from string. For numeric types, the class adds a precision token to stringstream that should usually suffice. */ template class MITKSCENESERIALIZATIONBASE_EXPORT VectorPropertySerializer : public BasePropertySerializer { public: // Expand manually most of mitkClassMacro: // mitkClassMacro(VectorProperty, mitk::BaseProperty); // This manual expansion is done to override explicitely // the GetNameOfClass methods typedef VectorProperty PropertyType; typedef VectorPropertySerializer Self; typedef BasePropertySerializer SuperClass; typedef itk::SmartPointer Pointer; typedef itk::SmartPointer ConstPointer; std::vector GetClassHierarchy() const override { return mitk::GetClassHierarchy(); } // This function must return different // strings in function of the template parameter! // Serialization depends on this feature. static const char *GetStaticNameOfClass() { // concatenate a prefix dependent on the template type and our own classname static std::string nameOfClass = std::string(VectorPropertyDataType::prefix()) + "VectorPropertySerializer"; return nameOfClass.c_str(); } const char *GetNameOfClass() const override { return this->GetStaticNameOfClass(); } itkFactorylessNewMacro(Self); itkCloneMacro(Self) //! Build an XML version of this property TiXmlElement *Serialize() override { auto listElement = new TiXmlElement("Values"); if (const PropertyType *prop = dynamic_cast(m_Property.GetPointer())) { typename PropertyType::VectorType elements = prop->GetValue(); unsigned int index(0); for (auto listEntry : elements) { std::stringstream indexS; indexS << index++; auto entryElement = new TiXmlElement("Value"); entryElement->SetAttribute("idx", indexS.str()); entryElement->SetAttribute("value", boost::lexical_cast(listEntry)); listElement->LinkEndChild(entryElement); } return listElement; } else { return nullptr; } } //! Construct a property from an XML serialization BaseProperty::Pointer Deserialize(TiXmlElement *listElement) override { typename PropertyType::VectorType datalist; if (listElement) { MITK_DEBUG << "Deserializing " << *listElement; unsigned int index(0); std::string valueString; DATATYPE value; for (TiXmlElement *valueElement = listElement->FirstChildElement("Value"); valueElement; valueElement = valueElement->NextSiblingElement("Value")) { if (valueElement->QueryValueAttribute("value", &valueString) != TIXML_SUCCESS) { MITK_ERROR << "Missing value attribute in list"; return nullptr; } try { value = boost::lexical_cast(valueString); } catch (boost::bad_lexical_cast &e) { MITK_ERROR << "Could not parse '" << valueString << "' as number: " << e.what(); return nullptr; } datalist.push_back(value); ++index; } typename PropertyType::Pointer property = PropertyType::New(); property->SetValue(datalist); return property.GetPointer(); } else { MITK_ERROR << "Missing tag."; } return nullptr; } }; typedef VectorPropertySerializer DoubleVectorPropertySerializer; typedef VectorPropertySerializer IntVectorPropertySerializer; } // namespace #endif diff --git a/Modules/SceneSerializationBase/src/mitkDoublePropertySerializer.cpp b/Modules/SceneSerializationBase/src/mitkDoublePropertySerializer.cpp index 87fe4909fd..483b36fe00 100644 --- a/Modules/SceneSerializationBase/src/mitkDoublePropertySerializer.cpp +++ b/Modules/SceneSerializationBase/src/mitkDoublePropertySerializer.cpp @@ -1,87 +1,87 @@ /*=================================================================== 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 mitkDoublePropertySerializer_h_included #define mitkDoublePropertySerializer_h_included #include "mitkBasePropertySerializer.h" #include "mitkProperties.h" -#include +#include #include #include namespace mitk { class DoublePropertySerializer : public BasePropertySerializer { public: mitkClassMacro(DoublePropertySerializer, BasePropertySerializer); itkFactorylessNewMacro(Self) itkCloneMacro(Self) TiXmlElement *Serialize() override { if (const DoubleProperty *prop = dynamic_cast(m_Property.GetPointer())) { LocaleSwitch localeSwitch("C"); auto element = new TiXmlElement("double"); element->SetAttribute("value", boost::lexical_cast(prop->GetValue())); return element; } else return nullptr; } BaseProperty::Pointer Deserialize(TiXmlElement *element) override { if (!element) return nullptr; LocaleSwitch localeSwitch("C"); std::string d; if (element->QueryStringAttribute("value", &d) == TIXML_SUCCESS) { try { return DoubleProperty::New(boost::lexical_cast(d)).GetPointer(); } catch (boost::bad_lexical_cast &e) { MITK_ERROR << "Could not parse string as number: " << e.what(); return nullptr; } } else { return nullptr; } } protected: DoublePropertySerializer() {} ~DoublePropertySerializer() override {} }; } // namespace // important to put this into the GLOBAL namespace (because it starts with 'namespace mitk') MITK_REGISTER_SERIALIZER(DoublePropertySerializer); #endif diff --git a/Modules/SceneSerializationBase/src/mitkFloatLookupTablePropertySerializer.cpp b/Modules/SceneSerializationBase/src/mitkFloatLookupTablePropertySerializer.cpp index 56e1657a10..ea6bb8630f 100644 --- a/Modules/SceneSerializationBase/src/mitkFloatLookupTablePropertySerializer.cpp +++ b/Modules/SceneSerializationBase/src/mitkFloatLookupTablePropertySerializer.cpp @@ -1,95 +1,95 @@ /*=================================================================== 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 mitkFloatLookupTablePropertySerializer_h_included #define mitkFloatLookupTablePropertySerializer_h_included #include "mitkBasePropertySerializer.h" #include "mitkProperties.h" -#include +#include #include namespace mitk { class FloatLookupTablePropertySerializer : public BasePropertySerializer { public: mitkClassMacro(FloatLookupTablePropertySerializer, BasePropertySerializer); itkFactorylessNewMacro(Self) itkCloneMacro(Self) TiXmlElement *Serialize() override { const FloatLookupTableProperty *prop = dynamic_cast(m_Property.GetPointer()); if (prop == nullptr) return nullptr; LocaleSwitch localeSwitch("C"); FloatLookupTable lut = prop->GetValue(); // if (lut.IsNull()) // return nullptr; // really? const FloatLookupTable::LookupTableType &map = lut.GetLookupTable(); auto element = new TiXmlElement("FloatLookupTableTable"); for (auto it = map.begin(); it != map.end(); ++it) { auto tableEntry = new TiXmlElement("LUTValue"); tableEntry->SetAttribute("id", it->first); tableEntry->SetAttribute("value", boost::lexical_cast(it->second)); element->LinkEndChild(tableEntry); } return element; } BaseProperty::Pointer Deserialize(TiXmlElement *element) override { if (!element) return nullptr; LocaleSwitch localeSwitch("C"); FloatLookupTable lut; for (TiXmlElement *child = element->FirstChildElement("LUTValue"); child != nullptr; child = child->NextSiblingElement("LUTValue")) { int tempID; if (child->QueryIntAttribute("id", &tempID) != TIXML_SUCCESS) return nullptr; FloatLookupTable::IdentifierType id = static_cast(tempID); std::string value_string; if (child->QueryStringAttribute("value", &value_string) != TIXML_SUCCESS) return nullptr; try { lut.SetTableValue(id, boost::lexical_cast(value_string)); } catch (boost::bad_lexical_cast &e) { MITK_ERROR << "Could not parse string as number: " << e.what(); return nullptr; } } return FloatLookupTableProperty::New(lut).GetPointer(); } protected: FloatLookupTablePropertySerializer() {} ~FloatLookupTablePropertySerializer() override {} }; } // namespace // important to put this into the GLOBAL namespace (because it starts with 'namespace mitk') MITK_REGISTER_SERIALIZER(FloatLookupTablePropertySerializer); #endif diff --git a/Modules/SceneSerializationBase/src/mitkLevelWindowPropertySerializer.cpp b/Modules/SceneSerializationBase/src/mitkLevelWindowPropertySerializer.cpp index 455dbc0097..79f1c217d2 100644 --- a/Modules/SceneSerializationBase/src/mitkLevelWindowPropertySerializer.cpp +++ b/Modules/SceneSerializationBase/src/mitkLevelWindowPropertySerializer.cpp @@ -1,139 +1,139 @@ /*=================================================================== 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 mitkLevelWindowPropertySerializer_h_included #define mitkLevelWindowPropertySerializer_h_included #include "mitkBasePropertySerializer.h" #include "mitkLevelWindowProperty.h" -#include +#include #include namespace mitk { class LevelWindowPropertySerializer : public BasePropertySerializer { public: mitkClassMacro(LevelWindowPropertySerializer, BasePropertySerializer); itkFactorylessNewMacro(Self) itkCloneMacro(Self) TiXmlElement *Serialize() override { if (const LevelWindowProperty *prop = dynamic_cast(m_Property.GetPointer())) { LocaleSwitch localeSwitch("C"); auto element = new TiXmlElement("LevelWindow"); LevelWindow lw = prop->GetLevelWindow(); std::string boolString("false"); if (lw.IsFixed() == true) boolString = "true"; element->SetAttribute("fixed", boolString.c_str()); std::string boolStringFltImage("false"); if (lw.IsFloatingValues() == true) boolStringFltImage = "true"; element->SetAttribute("isFloatingImage", boolStringFltImage.c_str()); auto child = new TiXmlElement("CurrentSettings"); element->LinkEndChild(child); child->SetAttribute("level", boost::lexical_cast(lw.GetLevel())); child->SetAttribute("window", boost::lexical_cast(lw.GetWindow())); child = new TiXmlElement("DefaultSettings"); element->LinkEndChild(child); child->SetAttribute("level", boost::lexical_cast(lw.GetDefaultLevel())); child->SetAttribute("window", boost::lexical_cast(lw.GetDefaultWindow())); child = new TiXmlElement("CurrentRange"); element->LinkEndChild(child); child->SetAttribute("min", boost::lexical_cast(lw.GetRangeMin())); child->SetAttribute("max", boost::lexical_cast(lw.GetRangeMax())); return element; } else return nullptr; } BaseProperty::Pointer Deserialize(TiXmlElement *element) override { if (!element) return nullptr; LocaleSwitch localeSwitch("C"); bool isFixed(false); if (element->Attribute("fixed")) isFixed = std::string(element->Attribute("fixed")) == "true"; bool isFloatingImage(false); if (element->Attribute("isFloatingImage")) isFloatingImage = std::string(element->Attribute("isFloatingImage")) == "true"; std::string level_string; std::string window_string; TiXmlElement *child = element->FirstChildElement("CurrentSettings"); if (child->QueryStringAttribute("level", &level_string) != TIXML_SUCCESS) return nullptr; if (child->QueryStringAttribute("window", &window_string) != TIXML_SUCCESS) return nullptr; std::string defaultLevel_string; std::string defaultWindow_string; child = element->FirstChildElement("DefaultSettings"); if (child->QueryStringAttribute("level", &defaultLevel_string) != TIXML_SUCCESS) return nullptr; if (child->QueryStringAttribute("window", &defaultWindow_string) != TIXML_SUCCESS) return nullptr; std::string minRange_string; std::string maxRange_string; child = element->FirstChildElement("CurrentRange"); if (child->QueryStringAttribute("min", &minRange_string) != TIXML_SUCCESS) return nullptr; if (child->QueryStringAttribute("max", &maxRange_string) != TIXML_SUCCESS) return nullptr; LevelWindow lw; try { lw.SetRangeMinMax(boost::lexical_cast(minRange_string), boost::lexical_cast(maxRange_string)); lw.SetDefaultLevelWindow(boost::lexical_cast(defaultLevel_string), boost::lexical_cast(defaultWindow_string)); lw.SetLevelWindow(boost::lexical_cast(level_string), boost::lexical_cast(window_string)); lw.SetFixed(isFixed); lw.SetFloatingValues(isFloatingImage); } catch (boost::bad_lexical_cast &e) { MITK_ERROR << "Could not parse string as number: " << e.what(); return nullptr; } return LevelWindowProperty::New(lw).GetPointer(); } protected: LevelWindowPropertySerializer() {} ~LevelWindowPropertySerializer() override {} }; } // namespace // important to put this into the GLOBAL namespace (because it starts with 'namespace mitk') MITK_REGISTER_SERIALIZER(LevelWindowPropertySerializer); #endif diff --git a/Modules/SceneSerializationBase/src/mitkTransferFunctionPropertySerializer.cpp b/Modules/SceneSerializationBase/src/mitkTransferFunctionPropertySerializer.cpp index 27a4213e6d..42d29cbae9 100644 --- a/Modules/SceneSerializationBase/src/mitkTransferFunctionPropertySerializer.cpp +++ b/Modules/SceneSerializationBase/src/mitkTransferFunctionPropertySerializer.cpp @@ -1,264 +1,264 @@ /*=================================================================== 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 "mitkTransferFunctionPropertySerializer.h" -#include +#include #include namespace mitk { mitk::TransferFunctionPropertySerializer::TransferFunctionPropertySerializer() {} mitk::TransferFunctionPropertySerializer::~TransferFunctionPropertySerializer() {} TiXmlElement *mitk::TransferFunctionPropertySerializer::Serialize() { if (const auto *prop = dynamic_cast(mitk::BasePropertySerializer::m_Property.GetPointer())) { LocaleSwitch localeSwitch("C"); TransferFunction *transferfunction = prop->GetValue(); if (!transferfunction) return nullptr; auto element = new TiXmlElement("TransferFunction"); // serialize scalar opacity function auto scalarOpacityPointlist = new TiXmlElement("ScalarOpacity"); TransferFunction::ControlPoints scalarOpacityPoints = transferfunction->GetScalarOpacityPoints(); for (auto iter = scalarOpacityPoints.begin(); iter != scalarOpacityPoints.end(); ++iter) { auto pointel = new TiXmlElement("point"); pointel->SetAttribute("x", boost::lexical_cast(iter->first)); pointel->SetAttribute("y", boost::lexical_cast(iter->second)); scalarOpacityPointlist->LinkEndChild(pointel); } element->LinkEndChild(scalarOpacityPointlist); // serialize gradient opacity function auto gradientOpacityPointlist = new TiXmlElement("GradientOpacity"); TransferFunction::ControlPoints gradientOpacityPoints = transferfunction->GetGradientOpacityPoints(); for (auto iter = gradientOpacityPoints.begin(); iter != gradientOpacityPoints.end(); ++iter) { auto pointel = new TiXmlElement("point"); pointel->SetAttribute("x", boost::lexical_cast(iter->first)); pointel->SetAttribute("y", boost::lexical_cast(iter->second)); gradientOpacityPointlist->LinkEndChild(pointel); } element->LinkEndChild(gradientOpacityPointlist); // serialize color function vtkColorTransferFunction *ctf = transferfunction->GetColorTransferFunction(); if (ctf == nullptr) return nullptr; auto pointlist = new TiXmlElement("Color"); for (int i = 0; i < ctf->GetSize(); i++) { double myVal[6]; ctf->GetNodeValue(i, myVal); auto pointel = new TiXmlElement("point"); pointel->SetAttribute("x", boost::lexical_cast(myVal[0])); pointel->SetAttribute("r", boost::lexical_cast(myVal[1])); pointel->SetAttribute("g", boost::lexical_cast(myVal[2])); pointel->SetAttribute("b", boost::lexical_cast(myVal[3])); pointel->SetAttribute("midpoint", boost::lexical_cast(myVal[4])); pointel->SetAttribute("sharpness", boost::lexical_cast(myVal[5])); pointlist->LinkEndChild(pointel); } element->LinkEndChild(pointlist); return element; } else return nullptr; } bool mitk::TransferFunctionPropertySerializer::SerializeTransferFunction(const char *filename, TransferFunction::Pointer tf) { TransferFunctionPropertySerializer::Pointer tfps = TransferFunctionPropertySerializer::New(); tfps->SetProperty(TransferFunctionProperty::New(tf)); TiXmlElement *s = tfps->Serialize(); if (!s) { MITK_ERROR << "cant serialize transfer function"; return false; } TiXmlDocument document; auto decl = new TiXmlDeclaration( "1.0", "UTF-8", ""); // TODO what to write here? encoding? standalone would mean that we provide a DTD somewhere... document.LinkEndChild(decl); auto version = new TiXmlElement("Version"); version->SetAttribute("TransferfunctionVersion", 1); document.LinkEndChild(version); document.LinkEndChild(s); if (!document.SaveFile(filename)) { MITK_ERROR << "Could not write scene to " << filename << "\nTinyXML reports '" << document.ErrorDesc() << "'"; return false; } return true; } BaseProperty::Pointer mitk::TransferFunctionPropertySerializer::Deserialize(TiXmlElement *element) { if (!element) return nullptr; mitk::LocaleSwitch localeSwitch("C"); TransferFunction::Pointer tf = TransferFunction::New(); // deserialize scalar opacity function TiXmlElement *scalarOpacityPointlist = element->FirstChildElement("ScalarOpacity"); if (scalarOpacityPointlist == nullptr) { return nullptr; } tf->ClearScalarOpacityPoints(); try { for (TiXmlElement *pointElement = scalarOpacityPointlist->FirstChildElement("point"); pointElement != nullptr; pointElement = pointElement->NextSiblingElement("point")) { std::string x; std::string y; if (pointElement->QueryStringAttribute("x", &x) != TIXML_SUCCESS) return nullptr; if (pointElement->QueryStringAttribute("y", &y) != TIXML_SUCCESS) return nullptr; tf->AddScalarOpacityPoint(boost::lexical_cast(x), boost::lexical_cast(y)); } TiXmlElement *gradientOpacityPointlist = element->FirstChildElement("GradientOpacity"); if (gradientOpacityPointlist == nullptr) { return nullptr; } tf->ClearGradientOpacityPoints(); for (TiXmlElement *pointElement = gradientOpacityPointlist->FirstChildElement("point"); pointElement != nullptr; pointElement = pointElement->NextSiblingElement("point")) { std::string x; std::string y; if (pointElement->QueryStringAttribute("x", &x) != TIXML_SUCCESS) return nullptr; if (pointElement->QueryStringAttribute("y", &y) != TIXML_SUCCESS) return nullptr; tf->AddGradientOpacityPoint(boost::lexical_cast(x), boost::lexical_cast(y)); } TiXmlElement *rgbPointlist = element->FirstChildElement("Color"); if (rgbPointlist == nullptr) { return nullptr; } vtkColorTransferFunction *ctf = tf->GetColorTransferFunction(); if (ctf == nullptr) { return nullptr; } ctf->RemoveAllPoints(); for (TiXmlElement *pointElement = rgbPointlist->FirstChildElement("point"); pointElement != nullptr; pointElement = pointElement->NextSiblingElement("point")) { std::string x; std::string r, g, b, midpoint, sharpness; if (pointElement->QueryStringAttribute("x", &x) != TIXML_SUCCESS) return nullptr; if (pointElement->QueryStringAttribute("r", &r) != TIXML_SUCCESS) return nullptr; if (pointElement->QueryStringAttribute("g", &g) != TIXML_SUCCESS) return nullptr; if (pointElement->QueryStringAttribute("b", &b) != TIXML_SUCCESS) return nullptr; if (pointElement->QueryStringAttribute("midpoint", &midpoint) != TIXML_SUCCESS) return nullptr; if (pointElement->QueryStringAttribute("sharpness", &sharpness) != TIXML_SUCCESS) return nullptr; ctf->AddRGBPoint(boost::lexical_cast(x), boost::lexical_cast(r), boost::lexical_cast(g), boost::lexical_cast(b), boost::lexical_cast(midpoint), boost::lexical_cast(sharpness)); } } catch (boost::bad_lexical_cast &e) { MITK_ERROR << "Could not parse string as number: " << e.what(); return nullptr; } return TransferFunctionProperty::New(tf).GetPointer(); } mitk::TransferFunction::Pointer mitk::TransferFunctionPropertySerializer::DeserializeTransferFunction( const char *filePath) { TiXmlDocument document(filePath); if (!document.LoadFile()) { MITK_ERROR << "Could not open/read/parse " << filePath << "\nTinyXML reports: " << document.ErrorDesc() << std::endl; return nullptr; } // find version node --> note version in some variable int fileVersion = 1; TiXmlElement *versionObject = document.FirstChildElement("Version"); if (versionObject) { if (versionObject->QueryIntAttribute("TransferfunctionVersion", &fileVersion) != TIXML_SUCCESS) { MITK_WARN << "Transferfunction file " << filePath << " does not contain version information! Trying version 1 format."; } } TiXmlElement *input = document.FirstChildElement("TransferFunction"); TransferFunctionPropertySerializer::Pointer tfpd = TransferFunctionPropertySerializer::New(); BaseProperty::Pointer bp = tfpd->Deserialize(input); TransferFunctionProperty::Pointer tfp = dynamic_cast(bp.GetPointer()); if (tfp.IsNotNull()) { TransferFunction::Pointer tf = tfp->GetValue(); return tf; } MITK_WARN << "Can't deserialize transfer function"; return nullptr; } } // namespace // important to put this into the GLOBAL namespace (because it starts with 'namespace mitk') MITK_REGISTER_SERIALIZER(TransferFunctionPropertySerializer); diff --git a/Modules/SceneSerializationBase/test/mitkVectorPropertySerializerTest.cpp b/Modules/SceneSerializationBase/test/mitkVectorPropertySerializerTest.cpp index 957c13cf03..3666847a1a 100644 --- a/Modules/SceneSerializationBase/test/mitkVectorPropertySerializerTest.cpp +++ b/Modules/SceneSerializationBase/test/mitkVectorPropertySerializerTest.cpp @@ -1,145 +1,145 @@ /*=================================================================== 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 "mitkTestFixture.h" #include "mitkTestingMacros.h" #include "mitkBasePropertySerializer.h" #include "mitkVectorProperty.h" -#include +#include #include #include #include "mitkEqual.h" /** \brief Test for VectorPropertySerializer. Creates simple std::vector instances, puts them into a VectorProperty of appropriate type, then asks a serializer to serialize them into XML. Test expects that there is a deserializer somewhere in the system (i.e. registered with the ITK object factory. The test further expects that this deserializer is able to create a VectorProperty from XML and that this VectorProperty equals the input of serialization. */ class mitkVectorPropertySerializerTestSuite : public mitk::TestFixture { CPPUNIT_TEST_SUITE(mitkVectorPropertySerializerTestSuite); MITK_TEST(TestSerialize); MITK_TEST(TestSerialize); MITK_TEST(TestSerializeIntTypedef); MITK_TEST(TestSerializeDoubleTypedef); CPPUNIT_TEST_SUITE_END(); public: void setUp() override {} void tearDown() override {} template typename mitk::VectorProperty::Pointer MakeExampleProperty() { typename mitk::VectorProperty::Pointer vectorProperty = mitk::VectorProperty::New(); std::vector data; data.push_back(static_cast(-918273674.6172838)); data.push_back(0); data.push_back(static_cast(+6172838.918273674)); data.push_back(sqrt(2)); if (std::numeric_limits::has_infinity) { data.push_back(std::numeric_limits::infinity()); data.push_back(-std::numeric_limits::infinity()); } // do NOT test NaN: cannot be == to itself, so cannot be tested like the others // NaN is covered in a different test (FloatToStringTest at the time of writing this) // data.push_back( std::numeric_limits::quiet_NaN() ); vectorProperty->SetValue(data); return vectorProperty; } mitk::BaseProperty::Pointer TestSerialize(mitk::BaseProperty *property) { std::string serializername = std::string(property->GetNameOfClass()) + "Serializer"; std::list allSerializers = itk::ObjectFactoryBase::CreateAllInstance(serializername.c_str()); CPPUNIT_ASSERT_EQUAL(size_t(1), allSerializers.size()); auto *serializer = dynamic_cast(allSerializers.begin()->GetPointer()); CPPUNIT_ASSERT(serializer != nullptr); if (!serializer) return nullptr; serializer->SetProperty(property); TiXmlElement *serialization(nullptr); try { serialization = serializer->Serialize(); } catch (...) { } CPPUNIT_ASSERT(serialization != nullptr); if (!serialization) return nullptr; mitk::BaseProperty::Pointer restoredProperty = serializer->Deserialize(serialization); CPPUNIT_ASSERT(restoredProperty.IsNotNull()); return restoredProperty; } template void TestSerialize() { auto property = MakeExampleProperty(); mitk::BaseProperty::Pointer restored_property = TestSerialize(property); typename mitk::VectorProperty::Pointer restored_vector_property = dynamic_cast *>(restored_property.GetPointer()); CPPUNIT_ASSERT(restored_vector_property.IsNotNull()); auto orig_vector = property->GetValue(); auto restored_vector = restored_vector_property->GetValue(); CPPUNIT_ASSERT_EQUAL(orig_vector.size(), restored_vector.size()); for (unsigned int i = 0; i < orig_vector.size(); ++i) { // compare using Equal, i.e. with tolerance of mitk::eps CPPUNIT_ASSERT_MESSAGE(std::string("Verifying element ") + boost::lexical_cast(i), mitk::Equal(orig_vector[i], restored_vector[i])); } } void TestSerializeIntTypedef() { mitk::IntVectorProperty::Pointer intVectorProperty = MakeExampleProperty().GetPointer(); TestSerialize(intVectorProperty.GetPointer()); } void TestSerializeDoubleTypedef() { mitk::DoubleVectorProperty::Pointer doubleVectorProperty = MakeExampleProperty().GetPointer(); TestSerialize(doubleVectorProperty.GetPointer()); } }; // class MITK_TEST_SUITE_REGISTRATION(mitkVectorPropertySerializer) diff --git a/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidget.cpp b/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidget.cpp index 6a24e17155..2077361fa9 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidget.cpp +++ b/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidget.cpp @@ -1,283 +1,283 @@ /*=================================================================== 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 const std::string QmitkToFCompositeFilterWidget::VIEW_ID = "org.mitk.views.qmitktofcompositefilterwidget"; QmitkToFCompositeFilterWidget::QmitkToFCompositeFilterWidget(QWidget* parent, Qt::WindowFlags f): QWidget(parent, f) { this->m_ToFCompositeFilter = nullptr; m_Controls = nullptr; CreateQtPartControl(this); } QmitkToFCompositeFilterWidget::~QmitkToFCompositeFilterWidget() { } void QmitkToFCompositeFilterWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkToFCompositeFilterWidgetControls; m_Controls->setupUi(parent); int min = m_Controls->m_ThresholdFilterMinValueSpinBox->value(); int max = m_Controls->m_ThresholdFilterMaxValueSpinBox->value(); m_Controls->m_ThresholdFilterRangeSlider->setMinimum(min); m_Controls->m_ThresholdFilterRangeSlider->setMaximum(max); m_Controls->m_ThresholdFilterRangeSlider->setMinimumValue(min); m_Controls->m_ThresholdFilterRangeSlider->setMaximumValue(max); this->CreateConnections(); this->OnShowAdvancedOptionsCheckboxChecked(false); } } void QmitkToFCompositeFilterWidget::CreateConnections() { if ( m_Controls ) { connect(m_Controls->m_TemporalMedianFilterNumOfFramesSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnTemporalMedianFilterNumOfFramesSpinBoxValueChanged(int))); connect(m_Controls->m_BilateralFilterDomainSigmaSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnBilateralFilterDomainSigmaSpinBoxValueChanged(double))); connect(m_Controls->m_BilateralFilterRangeSigmaSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnBilateralFilterRangeSigmaSpinBoxValueChanged(double))); connect(m_Controls->m_BilateralFilterKernelRadiusSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnBilateralFilterKernelRadiusSpinBoxValueChanged(int))); connect(m_Controls->m_ThresholdFilterMinValueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnThresholdFilterMinValueChanged(int))); connect(m_Controls->m_ThresholdFilterMaxValueSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnThresholdFilterMaxValueChanged(int))); connect( (QObject*)(m_Controls->m_TemporalMedianFilterCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnTemporalMedianFilterCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_AverageFilterCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnAverageFilterCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_ThresholdFilterCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnThresholdFilterCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->maskSegmentationCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnMaskSegmentationCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_BilateralFilterCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnBilateralFilterCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_MedianFilterCheckBox), SIGNAL(toggled(bool)), this, SLOT(OnMedianFilterCheckBoxChecked(bool)) ); connect( (QObject*)(m_Controls->m_ShowAdvancedOptionsCheckbox), SIGNAL(toggled(bool)), this, SLOT(OnShowAdvancedOptionsCheckboxChecked(bool)) ); - connect(m_Controls->m_ThresholdFilterRangeSlider, SIGNAL(spanChanged(int, int) ),this, SLOT( OnSpanChanged(int , int ) )); + connect(m_Controls->m_ThresholdFilterRangeSlider, SIGNAL(valuesChanged(int, int) ),this, SLOT( OnSpanChanged(int , int ) )); //reset button connect(m_Controls->m_ThresholdFilterRangeSliderReset, SIGNAL(pressed()), this, SLOT(OnResetThresholdFilterRangeSlider())); } } void QmitkToFCompositeFilterWidget::SetToFCompositeFilter(mitk::ToFCompositeFilter* toFCompositeFilter) { this->m_ToFCompositeFilter = toFCompositeFilter; } mitk::ToFCompositeFilter* QmitkToFCompositeFilterWidget::GetToFCompositeFilter() { if (this->m_ToFCompositeFilter.IsNull()) { this->m_ToFCompositeFilter = mitk::ToFCompositeFilter::New(); } return this->m_ToFCompositeFilter; } void QmitkToFCompositeFilterWidget::SetDataStorage(mitk::DataStorage::Pointer dataStorage) { m_DataStorage = dataStorage; m_Controls->maskImageComboBox->SetDataStorage(dataStorage); m_Controls->maskImageComboBox->SetPredicate(mitk::NodePredicateAnd::New(mitk::NodePredicateDataType::New("Image"),mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)))); } void QmitkToFCompositeFilterWidget::UpdateFilterParameter() { OnTemporalMedianFilterCheckBoxChecked(m_Controls->m_TemporalMedianFilterCheckBox->isChecked()); OnAverageFilterCheckBoxChecked(m_Controls->m_AverageFilterCheckBox->isChecked()); OnMedianFilterCheckBoxChecked(m_Controls->m_MedianFilterCheckBox->isChecked()); OnThresholdFilterCheckBoxChecked(m_Controls->m_ThresholdFilterCheckBox->isChecked()); OnBilateralFilterCheckBoxChecked(m_Controls->m_BilateralFilterCheckBox->isChecked()); } void QmitkToFCompositeFilterWidget::SetWidgetConfiguration(bool threshold, bool mask, bool tempMedian, bool tempAverage, bool median, bool bilateral ) { m_Controls->m_ThresholdFilterCheckBox->setChecked(threshold); m_Controls->maskSegmentationCheckBox->setChecked(mask); m_Controls->m_TemporalMedianFilterCheckBox->setChecked(tempMedian); m_Controls->m_AverageFilterCheckBox->setChecked(tempAverage); m_Controls->m_MedianFilterCheckBox->setChecked(median); m_Controls->m_BilateralFilterCheckBox->setChecked(bilateral); } void QmitkToFCompositeFilterWidget::SetStandardParametersBilateralFilter(double domainSigma, double rangeSigma, int kernelRadius) { m_Controls->m_BilateralFilterDomainSigmaSpinBox->setValue(domainSigma); m_Controls->m_BilateralFilterRangeSigmaSpinBox->setValue(rangeSigma); m_Controls->m_BilateralFilterKernelRadiusSpinBox->setValue(kernelRadius); } void QmitkToFCompositeFilterWidget::SetStandardParametersThresholdFilter(int min, int max) { m_Controls->m_ThresholdFilterMinValueSpinBox->setValue(min); m_Controls->m_ThresholdFilterMaxValueSpinBox->setValue(max); } void QmitkToFCompositeFilterWidget::SetStandardParameterTemporalAveraging(int nImages) { m_Controls->m_TemporalMedianFilterNumOfFramesSpinBox->setValue(nImages); } void QmitkToFCompositeFilterWidget::OnTemporalMedianFilterCheckBoxChecked(bool checked) { this->m_ToFCompositeFilter->SetApplyTemporalMedianFilter(checked); // disable average filter if temporal median filter is enabled if (checked) { m_Controls->m_AverageFilterCheckBox->setChecked(false); this->m_ToFCompositeFilter->SetApplyAverageFilter(false); } } void QmitkToFCompositeFilterWidget::OnAverageFilterCheckBoxChecked(bool checked) { this->m_ToFCompositeFilter->SetApplyAverageFilter(checked); // disable temporal median filter if average filter is enabled if (checked) { m_Controls->m_TemporalMedianFilterCheckBox->setChecked(false); this->m_ToFCompositeFilter->SetApplyTemporalMedianFilter(false); } } void QmitkToFCompositeFilterWidget::OnShowAdvancedOptionsCheckboxChecked(bool checked) { this->m_Controls->m_AverageFilterCheckBox->setVisible(checked); this->m_Controls->m_BilateralFilterCheckBox->setVisible(checked); this->m_Controls->m_BilateralFilterDomainSigmaSpinBox->setVisible(checked); this->m_Controls->m_BilateralFilterKernelRadiusSpinBox->setVisible(checked); this->m_Controls->m_BilateralFilterRangeSigmaSpinBox->setVisible(checked); this->m_Controls->m_MedianFilterCheckBox->setVisible(checked); this->m_Controls->m_TemporalMedianFilterCheckBox->setVisible(checked); this->m_Controls->m_TemporalMedianFilterNumOfFramesSpinBox->setVisible(checked); this->m_Controls->m_ThresholdFilterCheckBox->setVisible(checked); this->m_Controls->m_ThresholdFilterMaxValueSpinBox->setVisible(checked); this->m_Controls->m_ThresholdFilterMinValueSpinBox->setVisible(checked); this->m_Controls->m_ThresholdFilterRangeSlider->setVisible(checked); this->m_Controls->m_ThresholdFilterRangeSliderReset->setVisible(checked); this->m_Controls->label_3->setVisible(checked); this->m_Controls->label_4->setVisible(checked); this->m_Controls->label_12->setVisible(checked); this->m_Controls->maskImageComboBox->setVisible(checked); this->m_Controls->maskSegmentationCheckBox->setVisible(checked); } void QmitkToFCompositeFilterWidget::OnThresholdFilterCheckBoxChecked(bool checked) { this->m_ToFCompositeFilter->SetApplyThresholdFilter(checked); } void QmitkToFCompositeFilterWidget::OnMaskSegmentationCheckBoxChecked(bool checked) { this->m_ToFCompositeFilter->SetApplyMaskSegmentation(checked); if (checked) { mitk::DataNode::Pointer maskImageNode = m_Controls->maskImageComboBox->GetSelectedNode(); if (maskImageNode.IsNotNull()) { mitk::Image::Pointer maskImage = dynamic_cast(maskImageNode->GetData()); this->m_ToFCompositeFilter->SetSegmentationMask(maskImage); } } } void QmitkToFCompositeFilterWidget::OnMedianFilterCheckBoxChecked(bool checked) { this->m_ToFCompositeFilter->SetApplyMedianFilter(checked); } void QmitkToFCompositeFilterWidget::OnBilateralFilterCheckBoxChecked(bool checked) { this->m_ToFCompositeFilter->SetApplyBilateralFilter(checked); } void QmitkToFCompositeFilterWidget::OnTemporalMedianFilterNumOfFramesSpinBoxValueChanged(int value) { this->m_ToFCompositeFilter->SetTemporalMedianFilterParameter(value); } void QmitkToFCompositeFilterWidget::OnBilateralFilterDomainSigmaSpinBoxValueChanged(double) { SetBilateralFilterParameter(); } void QmitkToFCompositeFilterWidget::OnBilateralFilterRangeSigmaSpinBoxValueChanged(double) { SetBilateralFilterParameter(); } void QmitkToFCompositeFilterWidget::OnBilateralFilterKernelRadiusSpinBoxValueChanged(int) { SetBilateralFilterParameter(); } void QmitkToFCompositeFilterWidget::OnThresholdFilterMinValueChanged(int value) { m_Controls->m_ThresholdFilterRangeSlider->setMinimumValue(value); SetThresholdFilterParameter(); } void QmitkToFCompositeFilterWidget::OnThresholdFilterMaxValueChanged(int value) { m_Controls->m_ThresholdFilterRangeSlider->setMaximumValue(value); SetThresholdFilterParameter(); } void QmitkToFCompositeFilterWidget::SetThresholdFilterParameter() { int min = m_Controls->m_ThresholdFilterMinValueSpinBox->value(); int max = m_Controls->m_ThresholdFilterMaxValueSpinBox->value(); this->m_ToFCompositeFilter->SetThresholdFilterParameter(min, max); } void QmitkToFCompositeFilterWidget::SetBilateralFilterParameter() { double domainSigma = m_Controls->m_BilateralFilterDomainSigmaSpinBox->value(); double rangeSigma = m_Controls->m_BilateralFilterRangeSigmaSpinBox->value(); int kernelRadius = m_Controls->m_BilateralFilterKernelRadiusSpinBox->value(); this->m_ToFCompositeFilter->SetBilateralFilterParameter(domainSigma, rangeSigma, kernelRadius); } void QmitkToFCompositeFilterWidget::OnSpanChanged(int, int) { int lowerVal = m_Controls->m_ThresholdFilterRangeSlider->minimumValue(); int upperVal = m_Controls->m_ThresholdFilterRangeSlider->maximumValue(); m_Controls->m_ThresholdFilterMinValueSpinBox->setValue(lowerVal); m_Controls->m_ThresholdFilterMaxValueSpinBox->setValue(upperVal); } void QmitkToFCompositeFilterWidget::OnResetThresholdFilterRangeSlider() { int lower = 1; int upper = 7000; m_Controls->m_ThresholdFilterRangeSlider->setMinimumValue(lower); m_Controls->m_ThresholdFilterRangeSlider->setMaximumValue(upper); m_Controls->m_ThresholdFilterMinValueSpinBox->setValue(lower); m_Controls->m_ThresholdFilterMaxValueSpinBox->setValue(upper); } diff --git a/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidgetControls.ui b/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidgetControls.ui index 81ff4de855..49cf34efda 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidgetControls.ui +++ b/Modules/ToFUI/Qmitk/QmitkToFCompositeFilterWidgetControls.ui @@ -1,244 +1,247 @@ QmitkToFCompositeFilterWidgetControls 0 0 467 210 0 0 QmitkToFCompositeFilter 11 ToF Preprocessing Show Advanced Options Threshold Filter 7000 0 QFrame::StyledPanel QFrame::Raised 0 - + + 0 + + + 0 + + + 0 + + 0 modify actual seen window by dragging left and right slider. Qt::Horizontal - + 0 0 - - - 48 - 16777215 - - Resets range to histogram minimum and maximum. Reset 7000 7000 Mask segmentation true Median Filter (t) Average Filter 100 10 true Median Filter Bilateral Filter σ_d: 2.000000000000000 σ_r: 60.000000000000000 radius: ctkRangeSlider - QWidget + QSlider
ctkRangeSlider.h
QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
diff --git a/Modules/ToFUI/Qmitk/QmitkToFConnectionWidgetControls.ui b/Modules/ToFUI/Qmitk/QmitkToFConnectionWidgetControls.ui index 6b35d713fc..fcca8f0608 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFConnectionWidgetControls.ui +++ b/Modules/ToFUI/Qmitk/QmitkToFConnectionWidgetControls.ui @@ -1,175 +1,196 @@ QmitkToFConnectionWidgetControls2 0 0 579 229 + + + 0 + 0 + + 0 0 QmitkToFConnection - - - - - - - - - - + + + + 0 + 0 + + + 0 0 0 100 16777215 100 false 0 0 200 80 16777215 80 10 Connect to camera Connect :/images/powerRed.png :/images/powerGreen.png:/images/powerRed.png 30 30 true 11 ToF camera connection - - - - Qt::Vertical + + + + + 0 + 0 + - - - 20 - 40 - + + + + + + + 0 + 0 + - + + + + + + + 0 + 0 + + + QmitkToFPMDParameterWidget QWidget
QmitkToFPMDParameterWidget.h
1
QmitkToFMESAParameterWidget QWidget
QmitkToFMESAParameterWidget.h
1
QmitkKinectParameterWidget QWidget
QmitkKinectParameterWidget.h
1
QmitkServiceListWidget QWidget
QmitkServiceListWidget.h
1
QmitkStructureSensorParameterWidget QWidget
QmitkStructureSensorParameterWidget.h
1
diff --git a/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.cpp b/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.cpp index 8275fa8aca..ad033b8a4f 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.cpp +++ b/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.cpp @@ -1,442 +1,533 @@ /*=================================================================== 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 "QmitkToFPointSetWidget.h" +#include #include #include const std::string QmitkToFPointSetWidget::VIEW_ID = "org.mitk.views.qmitktofpointsetwidget"; -QmitkToFPointSetWidget::QmitkToFPointSetWidget(QWidget* parent, Qt::WindowFlags f): QWidget(parent, f) +QmitkToFPointSetWidget::QmitkToFPointSetWidget(QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f) , m_DataStorage(nullptr) , m_DistanceImage(nullptr) , m_CameraIntrinsics(nullptr) -, m_VtkTextActor(nullptr) -, m_ForegroundRenderer1(nullptr) -, m_ForegroundRenderer2(nullptr) -, m_ForegroundRenderer3(nullptr) -, m_RenderWindow1(nullptr) -, m_RenderWindow2(nullptr) -, m_RenderWindow3(nullptr) +, m_TextAnnotationAxial(nullptr) +, m_TextAnnotationSagittal(nullptr) +, m_TextAnnotationCoronal(nullptr) +, m_TextAnnotation3D(nullptr) +, m_RendererAxial(nullptr) +, m_RendererSagittal(nullptr) +, m_RendererCoronal(nullptr) +, m_Renderer3D(nullptr) , m_MeasurementPointSet2D(nullptr) , m_MeasurementPointSet3DNode(nullptr) , m_PointSet2D(nullptr) , m_PointSet3DNode(nullptr) , m_PointSetInteractor(nullptr) , m_MeasurementPointSetInteractor(nullptr) , m_MeasurementPointSetChangedObserverTag(0) , m_PointSetChangedObserverTag(0) , m_WindowHeight(0) { m_Controls = nullptr; CreateQtPartControl(this); } QmitkToFPointSetWidget::~QmitkToFPointSetWidget() { this->CleanUpWidget(); } void QmitkToFPointSetWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkToFPointSetWidgetControls; m_Controls->setupUi(parent); this->CreateConnections(); } } void QmitkToFPointSetWidget::CreateConnections() { - if ( m_Controls ) + if (m_Controls) { - connect( (QObject*)(m_Controls->measureButton), SIGNAL(clicked()),(QObject*) this, SLOT(OnMeasurement()) ); - connect( (QObject*)(m_Controls->pointSetButton), SIGNAL(clicked()),(QObject*) this, SLOT(OnPointSet()) ); + connect((QObject*)(m_Controls->measureButton), SIGNAL(clicked()), (QObject*) this, SLOT(OnMeasurement())); + connect((QObject*)(m_Controls->pointSetButton), SIGNAL(clicked()), (QObject*) this, SLOT(OnPointSet())); } } void QmitkToFPointSetWidget::InitializeWidget(QHash renderWindowHashMap, mitk::DataStorage::Pointer dataStorage, mitk::CameraIntrinsics::Pointer cameraIntrinsics) { // initialize members m_CameraIntrinsics = cameraIntrinsics; m_DataStorage = dataStorage; - // m_RenderWindowPart = renderWindowPart; - m_RenderWindow1 = renderWindowHashMap.value("axial")->GetRenderWindow(); - m_RenderWindow2 = renderWindowHashMap.value("sagittal")->GetRenderWindow(); - m_RenderWindow3 = renderWindowHashMap.value("coronal")->GetRenderWindow(); - m_RenderWindow4 = renderWindowHashMap.value("3d")->GetRenderWindow(); - if ((m_RenderWindow1 != nullptr) && (m_RenderWindow2 != nullptr) && (m_RenderWindow3 != nullptr) && (m_RenderWindow4 != nullptr) && (dataStorage.IsNotNull())) + // Get renderers of render windows + m_RendererAxial = renderWindowHashMap.value("axial")->GetRenderer(); + m_RendererSagittal = renderWindowHashMap.value("sagittal")->GetRenderer(); + m_RendererCoronal = renderWindowHashMap.value("coronal")->GetRenderer(); + m_Renderer3D = renderWindowHashMap.value("3d")->GetRenderer(); + if ((m_RendererAxial.IsNotNull()) && (m_RendererSagittal.IsNotNull()) && (m_RendererCoronal.IsNotNull()) && (m_Renderer3D.IsNotNull()) && (dataStorage.IsNotNull())) { // enable buttons m_Controls->pointSetButton->setEnabled(true); m_Controls->measureButton->setEnabled(true); - // initialize overlays - this->m_VtkTextActor = vtkSmartPointer::New(); - this->m_VtkTextActor->SetInput("Choose measurement points with SHIFT+Click"); - m_WindowHeight = renderWindowHashMap.value("axial")->GetRenderer()->GetSizeY(); - this->m_VtkTextActor->SetDisplayPosition(10,m_WindowHeight-30); - this->m_VtkTextActor->GetTextProperty()->SetFontSize(16); - // this->m_VtkTextActor->GetTextProperty()->SetColor(1,0,0); - this->m_VtkTextActor->GetTextProperty()->BoldOn(); - this->m_VtkTextActor->SetVisibility(0); - if (m_ForegroundRenderer1==nullptr) - { - this->m_ForegroundRenderer1 = vtkSmartPointer::New(); - this->m_ForegroundRenderer1->AddActor(m_VtkTextActor); - mitk::VtkLayerController::GetInstance(m_RenderWindow1)->InsertForegroundRenderer(m_ForegroundRenderer1,true); - } - if (m_ForegroundRenderer2==nullptr) - { - this->m_ForegroundRenderer2 = vtkSmartPointer::New(); - this->m_ForegroundRenderer2->AddActor(m_VtkTextActor); - mitk::VtkLayerController::GetInstance(m_RenderWindow2)->InsertForegroundRenderer(m_ForegroundRenderer2,true); - } - if (m_ForegroundRenderer3==nullptr) - { - this->m_ForegroundRenderer3 =vtkSmartPointer::New(); - this->m_ForegroundRenderer3->AddActor(m_VtkTextActor); - mitk::VtkLayerController::GetInstance(m_RenderWindow3)->InsertForegroundRenderer(m_ForegroundRenderer3,true); - } - mitk::DataNode::Pointer measurementPointSet2DNode = dataStorage->GetNamedNode("Measurement PointSet 2D") ; - if(dataStorage->Exists(measurementPointSet2DNode)) + // initialize axial text annotation + m_TextAnnotationAxial = mitk::TextAnnotation2D::New(); + m_TextAnnotationAxial->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotationAxial->SetFontSize(16); + m_TextAnnotationAxial->SetColor(1, 0, 0); + m_TextAnnotationAxial->SetOpacity(1); + m_WindowHeight = m_RendererAxial->GetSizeY(); + mitk::Point2D axialAnnotationPosition; + axialAnnotationPosition[0] = 10; + axialAnnotationPosition[0] = m_WindowHeight - 30; + m_TextAnnotationAxial->SetPosition2D(axialAnnotationPosition); + m_TextAnnotationAxial->SetVisibility(false); + // add annotation to axial render window + mitk::LayoutAnnotationRenderer::AddAnnotation(m_TextAnnotationAxial, m_RendererAxial); + // initialize sagittal text annotation + m_TextAnnotationSagittal = mitk::TextAnnotation2D::New(); + m_TextAnnotationSagittal->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotationSagittal->SetFontSize(16); + m_TextAnnotationSagittal->SetColor(1, 0, 0); + m_TextAnnotationSagittal->SetOpacity(1); + m_WindowHeight = m_RendererSagittal->GetSizeY(); + mitk::Point2D sagittalAnnotationPosition; + sagittalAnnotationPosition[0] = 10; + sagittalAnnotationPosition[0] = m_WindowHeight - 30; + m_TextAnnotationSagittal->SetPosition2D(sagittalAnnotationPosition); + m_TextAnnotationSagittal->SetVisibility(false); + // add annotation to axial render window + mitk::LayoutAnnotationRenderer::AddAnnotation(m_TextAnnotationSagittal, m_RendererSagittal); + // initialize coronal text annotation + m_TextAnnotationCoronal = mitk::TextAnnotation2D::New(); + m_TextAnnotationCoronal->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotationCoronal->SetFontSize(16); + m_TextAnnotationCoronal->SetColor(1, 0, 0); + m_TextAnnotationCoronal->SetOpacity(1); + m_WindowHeight = m_RendererCoronal->GetSizeY(); + mitk::Point2D coronalAnnotationPosition; + coronalAnnotationPosition[0] = 10; + coronalAnnotationPosition[0] = m_WindowHeight - 30; + m_TextAnnotationCoronal->SetPosition2D(coronalAnnotationPosition); + m_TextAnnotationCoronal->SetVisibility(false); + // add annotation to axial render window + mitk::LayoutAnnotationRenderer::AddAnnotation(m_TextAnnotationCoronal, m_RendererCoronal); + // initialize 3D text annotation + m_TextAnnotation3D = mitk::TextAnnotation2D::New(); + m_TextAnnotation3D->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotation3D->SetFontSize(16); + m_TextAnnotation3D->SetColor(1, 0, 0); + m_TextAnnotation3D->SetOpacity(1); + m_WindowHeight = m_Renderer3D->GetSizeY(); + mitk::Point2D annotationPosition3D; + annotationPosition3D[0] = 10; + annotationPosition3D[0] = m_WindowHeight - 30; + m_TextAnnotation3D->SetPosition2D(annotationPosition3D); + m_TextAnnotation3D->SetVisibility(false); + // add annotation to axial render window + mitk::LayoutAnnotationRenderer::AddAnnotation(m_TextAnnotation3D, m_Renderer3D); + + //mitk::LayoutAnnotationRenderer::AddAnnotation(m_TextAnnotation, renderWindowHashMap.value("axial")->GetRenderer()); + //mitk::LayoutAnnotationRenderer::AddAnnotation(m_TextAnnotation, renderWindowHashMap.value("coronal")->GetRenderer()); + + //// initialize overlays + //this->m_VtkTextActor = vtkSmartPointer::New(); + //this->m_VtkTextActor->SetInput("Choose measurement points with SHIFT+Click"); + //m_WindowHeight = renderWindowHashMap.value("axial")->GetRenderer()->GetSizeY(); + ////this->m_VtkTextActor->SetDisplayPosition(10, m_WindowHeight - 30); + //this->m_VtkTextActor->SetDisplayPosition(50, 50); + //this->m_VtkTextActor->GetTextProperty()->SetFontSize(16); + ////this->m_VtkTextActor->GetTextProperty()->SetColor(1, 0, 0); + //this->m_VtkTextActor->GetTextProperty()->BoldOn(); + //this->m_VtkTextActor->SetVisibility(1); + //if (m_ForegroundRenderer1==nullptr) + //{ + // this->m_ForegroundRenderer1 = vtkSmartPointer::New(); + // this->m_ForegroundRenderer1->AddActor(m_VtkTextActor); + // mitk::VtkLayerController::GetInstance(m_RenderWindow1)->InsertForegroundRenderer(m_ForegroundRenderer1,true); + //} + //if (m_ForegroundRenderer2==nullptr) + //{ + // this->m_ForegroundRenderer2 = vtkSmartPointer::New(); + // this->m_ForegroundRenderer2->AddActor(m_VtkTextActor); + // mitk::VtkLayerController::GetInstance(m_RenderWindow2)->InsertForegroundRenderer(m_ForegroundRenderer2,true); + //} + //if (m_ForegroundRenderer3==nullptr) + //{ + // this->m_ForegroundRenderer3 =vtkSmartPointer::New(); + // this->m_ForegroundRenderer3->AddActor(m_VtkTextActor); + // mitk::VtkLayerController::GetInstance(m_RenderWindow3)->InsertForegroundRenderer(m_ForegroundRenderer3,true); + //} + + mitk::DataNode::Pointer measurementPointSet2DNode = dataStorage->GetNamedNode("Measurement PointSet 2D"); + if (dataStorage->Exists(measurementPointSet2DNode)) { dataStorage->Remove(measurementPointSet2DNode); } // initialize 2D measurement point set m_MeasurementPointSet2D = mitk::PointSet::New(); measurementPointSet2DNode = mitk::DataNode::New(); measurementPointSet2DNode->SetName("Measurement PointSet 2D"); - measurementPointSet2DNode->SetBoolProperty("helper object",true); - measurementPointSet2DNode->SetBoolProperty("show contour",true); + measurementPointSet2DNode->SetBoolProperty("helper object", true); + measurementPointSet2DNode->SetBoolProperty("show contour", true); measurementPointSet2DNode->SetVisibility(false, renderWindowHashMap.value("3d")->GetRenderer()); measurementPointSet2DNode->SetData(m_MeasurementPointSet2D); dataStorage->Add(measurementPointSet2DNode); m_MeasurementPointSetInteractor = mitk::PointSetDataInteractor::New(); m_MeasurementPointSetInteractor->LoadStateMachine("PointSet.xml"); m_MeasurementPointSetInteractor->SetEventConfig("PointSetConfig.xml"); m_MeasurementPointSetInteractor->SetDataNode(measurementPointSet2DNode); m_MeasurementPointSetInteractor->SetMaxPoints(2); // create observer for m_MeasurementPointSet2D itk::SimpleMemberCommand::Pointer measurementPointSetChangedCommand; measurementPointSetChangedCommand = itk::SimpleMemberCommand::New(); measurementPointSetChangedCommand->SetCallbackFunction(this, &QmitkToFPointSetWidget::MeasurementPointSetChanged); m_MeasurementPointSetChangedObserverTag = m_MeasurementPointSet2D->AddObserver(itk::ModifiedEvent(), measurementPointSetChangedCommand); // initialize 3D measurement PointSet m_MeasurementPointSet3DNode = dataStorage->GetNamedNode("Measurement PointSet 3D"); - if(dataStorage->Exists(m_MeasurementPointSet3DNode)) + if (dataStorage->Exists(m_MeasurementPointSet3DNode)) { dataStorage->Remove(m_MeasurementPointSet3DNode); } m_MeasurementPointSet3DNode = mitk::DataNode::New(); m_MeasurementPointSet3DNode->SetName("Measurement PointSet 3D"); - m_MeasurementPointSet3DNode->SetBoolProperty("helper object",true); - m_MeasurementPointSet3DNode->SetBoolProperty("show contour",true); - m_MeasurementPointSet3DNode->SetFloatProperty("pointsize",5.0f); + m_MeasurementPointSet3DNode->SetBoolProperty("helper object", true); + m_MeasurementPointSet3DNode->SetBoolProperty("show contour", true); + m_MeasurementPointSet3DNode->SetFloatProperty("pointsize", 5.0f); mitk::PointSet::Pointer measurementPointSet3D = mitk::PointSet::New(); m_MeasurementPointSet3DNode->SetData(measurementPointSet3D); dataStorage->Add(m_MeasurementPointSet3DNode); // initialize PointSets - mitk::DataNode::Pointer pointSet2DNode = dataStorage->GetNamedNode("ToF PointSet 2D") ; - if(dataStorage->Exists(pointSet2DNode)) + mitk::DataNode::Pointer pointSet2DNode = dataStorage->GetNamedNode("ToF PointSet 2D"); + if (dataStorage->Exists(pointSet2DNode)) { dataStorage->Remove(pointSet2DNode); } m_PointSet2D = mitk::PointSet::New(); pointSet2DNode = mitk::DataNode::New(); pointSet2DNode->SetName("ToF PointSet 2D"); pointSet2DNode->SetVisibility(false, renderWindowHashMap.value("3d")->GetRenderer()); pointSet2DNode->SetData(m_PointSet2D); dataStorage->Add(pointSet2DNode); m_PointSetInteractor = mitk::PointSetDataInteractor::New(); m_PointSetInteractor->LoadStateMachine("PointSet.xml"); m_PointSetInteractor->SetEventConfig("PointSetConfig.xml"); m_PointSetInteractor->SetDataNode(pointSet2DNode); // create observer for m_MeasurementPointSet2D itk::SimpleMemberCommand::Pointer pointSetChangedCommand; pointSetChangedCommand = itk::SimpleMemberCommand::New(); pointSetChangedCommand->SetCallbackFunction(this, &QmitkToFPointSetWidget::PointSetChanged); m_PointSetChangedObserverTag = m_PointSet2D->AddObserver(itk::ModifiedEvent(), pointSetChangedCommand); // initialize 3D point set mitk::DataNode::Pointer pointSet3DNode = dataStorage->GetNamedNode("ToF PointSet 3D"); - if(dataStorage->Exists(pointSet3DNode)) + if (dataStorage->Exists(pointSet3DNode)) { dataStorage->Remove(pointSet3DNode); } m_PointSet3DNode = mitk::DataNode::New(); m_PointSet3DNode->SetName("ToF PointSet 3D"); - m_PointSet3DNode->SetFloatProperty("pointsize",5.0f); + m_PointSet3DNode->SetFloatProperty("pointsize", 5.0f); mitk::PointSet::Pointer pointSet3D = mitk::PointSet::New(); m_PointSet3DNode->SetData(pointSet3D); dataStorage->Add(m_PointSet3DNode); } } void QmitkToFPointSetWidget::CleanUpWidget() { // toggle button state if (m_Controls->measureButton->isChecked()) { m_Controls->measureButton->setChecked(false); this->OnMeasurement(); } if (m_Controls->pointSetButton->isChecked()) { m_Controls->pointSetButton->setChecked(false); this->OnPointSet(); } // remove observer if (m_MeasurementPointSet2D.IsNotNull()) { m_MeasurementPointSet2D->RemoveObserver(m_MeasurementPointSetChangedObserverTag); } if (m_PointSet2D.IsNotNull()) { m_PointSet2D->RemoveObserver(m_PointSetChangedObserverTag); } -// if (m_DistanceImage.IsNotNull()) -// { -// m_DistanceImage->RemoveObserver(m_DistanceImageChangedObserverTag); -// } - // remove foreground renderer - if (m_ForegroundRenderer1&&m_RenderWindow1) - { - if (mitk::VtkLayerController::GetInstance(m_RenderWindow1)) - { - mitk::VtkLayerController::GetInstance(m_RenderWindow1)->RemoveRenderer(m_ForegroundRenderer1); - } - m_ForegroundRenderer1 = nullptr; - } - if (m_ForegroundRenderer2&&m_RenderWindow2) - { - if (mitk::VtkLayerController::GetInstance(m_RenderWindow2)) - { - mitk::VtkLayerController::GetInstance(m_RenderWindow2)->RemoveRenderer(m_ForegroundRenderer2); - } - m_ForegroundRenderer2 = nullptr; - } - if (m_ForegroundRenderer3&&m_RenderWindow3) - { - if (mitk::VtkLayerController::GetInstance(m_RenderWindow3)) - { - mitk::VtkLayerController::GetInstance(m_RenderWindow3)->RemoveRenderer(m_ForegroundRenderer3); - } - m_ForegroundRenderer3 = nullptr; - } + // if (m_DistanceImage.IsNotNull()) + // { + // m_DistanceImage->RemoveObserver(m_DistanceImageChangedObserverTag); + // } + //// remove foreground renderer + //if (m_ForegroundRenderer1&&m_RenderWindow1) + //{ + // if (mitk::VtkLayerController::GetInstance(m_RenderWindow1)) + // { + // mitk::VtkLayerController::GetInstance(m_RenderWindow1)->RemoveRenderer(m_ForegroundRenderer1); + // } + // m_ForegroundRenderer1 = nullptr; + //} + //if (m_ForegroundRenderer2&&m_RenderWindow2) + //{ + // if (mitk::VtkLayerController::GetInstance(m_RenderWindow2)) + // { + // mitk::VtkLayerController::GetInstance(m_RenderWindow2)->RemoveRenderer(m_ForegroundRenderer2); + // } + // m_ForegroundRenderer2 = nullptr; + //} + //if (m_ForegroundRenderer3&&m_RenderWindow3) + //{ + // if (mitk::VtkLayerController::GetInstance(m_RenderWindow3)) + // { + // mitk::VtkLayerController::GetInstance(m_RenderWindow3)->RemoveRenderer(m_ForegroundRenderer3); + // } + // m_ForegroundRenderer3 = nullptr; + //} if (mitk::RenderingManager::GetInstance()) { mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } void QmitkToFPointSetWidget::SetDistanceImage(mitk::Image::Pointer distanceImage) { -// // remove existing observer -// if (m_DistanceImage.IsNotNull()) -// { -// m_DistanceImage->RemoveObserver(m_DistanceImageChangedObserverTag); -// } + // // remove existing observer + // if (m_DistanceImage.IsNotNull()) + // { + // m_DistanceImage->RemoveObserver(m_DistanceImageChangedObserverTag); + // } m_DistanceImage = distanceImage; -// // create observer for m_DistanceImage -// itk::SimpleMemberCommand::Pointer distanceImageChangedCommand; -// distanceImageChangedCommand = itk::SimpleMemberCommand::New(); -// distanceImageChangedCommand->SetCallbackFunction(this, &QmitkToFPointSetWidget::MeasurementPointSetChanged); -// m_DistanceImageChangedObserverTag = m_DistanceImage->AddObserver(itk::ModifiedEvent(), distanceImageChangedCommand); + // // create observer for m_DistanceImage + // itk::SimpleMemberCommand::Pointer distanceImageChangedCommand; + // distanceImageChangedCommand = itk::SimpleMemberCommand::New(); + // distanceImageChangedCommand->SetCallbackFunction(this, &QmitkToFPointSetWidget::MeasurementPointSetChanged); + // m_DistanceImageChangedObserverTag = m_DistanceImage->AddObserver(itk::ModifiedEvent(), distanceImageChangedCommand); } void QmitkToFPointSetWidget::SetCameraIntrinsics(mitk::CameraIntrinsics::Pointer cameraIntrinsics) { m_CameraIntrinsics = cameraIntrinsics; } void QmitkToFPointSetWidget::OnMeasurement() { // always show 2D PointSet in foreground mitk::DataNode::Pointer pointSetNode = m_DataStorage->GetNamedNode("Measurement PointSet 2D"); if (pointSetNode.IsNotNull()) { - pointSetNode->SetIntProperty("layer",100); + pointSetNode->SetIntProperty("layer", 100); } if (m_Controls->measureButton->isChecked()) { // disable point set interaction if (m_Controls->pointSetButton->isChecked()) { m_Controls->pointSetButton->setChecked(false); // remove interactor m_PointSetInteractor->EnableInteraction(false); } // show overlays - m_VtkTextActor->SetVisibility(1); - this->m_VtkTextActor->SetInput("Choose measurement points with SHIFT+Click"); + m_TextAnnotationAxial->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotationSagittal->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotationCoronal->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotation3D->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotationAxial->SetVisibility(true); + m_TextAnnotationSagittal->SetVisibility(true); + m_TextAnnotationCoronal->SetVisibility(true); + m_TextAnnotation3D->SetVisibility(true); // enable interactor m_MeasurementPointSetInteractor->EnableInteraction(true); // initial update of measurement this->MeasurementPointSetChanged(); } else { // hide overlays - m_VtkTextActor->SetVisibility(0); + m_TextAnnotationAxial->SetVisibility(false); + m_TextAnnotationSagittal->SetVisibility(false); + m_TextAnnotationCoronal->SetVisibility(false); + m_TextAnnotation3D->SetVisibility(false); // disable interactor m_MeasurementPointSetInteractor->EnableInteraction(false); } } void QmitkToFPointSetWidget::OnPointSet() { // always show 2D PointSet in foreground mitk::DataNode::Pointer pointSetNode = m_DataStorage->GetNamedNode("ToF PointSet 2D"); if (pointSetNode.IsNotNull()) { - pointSetNode->SetIntProperty("layer",100); + pointSetNode->SetIntProperty("layer", 100); } if (m_Controls->pointSetButton->isChecked()) { // disable measurement if (m_Controls->measureButton->isChecked()) { m_Controls->measureButton->setChecked(false); // remove interactor m_MeasurementPointSetInteractor->EnableInteraction(false); } // show overlays - m_VtkTextActor->SetVisibility(1); - this->m_VtkTextActor->SetInput("Choose points with SHIFT+Click"); + m_TextAnnotationAxial->SetText("Choose points with SHIFT+Click"); + m_TextAnnotationSagittal->SetText("Choose points with SHIFT+Click"); + m_TextAnnotationCoronal->SetText("Choose points with SHIFT+Click"); + m_TextAnnotation3D->SetText("Choose points with SHIFT+Click"); + m_TextAnnotationAxial->SetVisibility(true); + m_TextAnnotationSagittal->SetVisibility(true); + m_TextAnnotationCoronal->SetVisibility(true); + m_TextAnnotation3D->SetVisibility(true); // enable interactor m_PointSetInteractor->EnableInteraction(true); // initial update of PointSet this->PointSetChanged(); } else { // hide overlays - m_VtkTextActor->SetVisibility(0); + m_TextAnnotationAxial->SetVisibility(false); + m_TextAnnotationSagittal->SetVisibility(false); + m_TextAnnotationCoronal->SetVisibility(false); + m_TextAnnotation3D->SetVisibility(false); // disable interactor m_PointSetInteractor->EnableInteraction(false); } } void QmitkToFPointSetWidget::MeasurementPointSetChanged() { - // replace text actor - this->m_VtkTextActor->SetDisplayPosition(10,m_WindowHeight-30); - if (m_MeasurementPointSet2D->GetSize()==2) + if (m_MeasurementPointSet2D->GetSize() == 2) { // check if points are inside the image range int imageSizeX = m_DistanceImage->GetDimensions()[0]; int imageSizeY = m_DistanceImage->GetDimensions()[1]; mitk::Point3D point1 = m_MeasurementPointSet2D->GetPoint(0); mitk::Point3D point2 = m_MeasurementPointSet2D->GetPoint(1); - if ((point1[0]>=0.0f)&&(point1[0]=0)&&(point1[1]=0.0f)&&(point2[0]=0)&&(point2[1]= 0.0f) && (point1[0] < imageSizeX) && (point1[1] >= 0) && (point1[1] < imageSizeY) && + (point2[0] >= 0.0f) && (point2[0] < imageSizeX) && (point2[1] >= 0) && (point2[1] < imageSizeY)) { // create PointSet filter mitk::ToFDistanceImageToPointSetFilter::Pointer toFDistanceImageToPointSetFilter = mitk::ToFDistanceImageToPointSetFilter::New(); if (m_CameraIntrinsics.IsNotNull()) { toFDistanceImageToPointSetFilter->SetCameraIntrinsics(m_CameraIntrinsics); } toFDistanceImageToPointSetFilter->SetInput(m_DistanceImage); toFDistanceImageToPointSetFilter->SetSubset(m_MeasurementPointSet2D); toFDistanceImageToPointSetFilter->Update(); mitk::PointSet::Pointer measurementPointSet3D = toFDistanceImageToPointSetFilter->GetOutput(); m_MeasurementPointSet3DNode->SetData(measurementPointSet3D); // calculate distance between points - if (measurementPointSet3D->GetSize()==2) + if (measurementPointSet3D->GetSize() == 2) { mitk::Point3D point1 = measurementPointSet3D->GetPoint(0); mitk::Point3D point2 = measurementPointSet3D->GetPoint(1); float distance = point1.EuclideanDistanceTo(point2); std::stringstream stream; - stream<m_VtkTextActor->SetInput(stream.str().c_str()); + stream << distance << " mm"; + m_TextAnnotationAxial->SetText(stream.str().c_str()); + m_TextAnnotationSagittal->SetText(stream.str().c_str()); + m_TextAnnotationCoronal->SetText(stream.str().c_str()); + m_TextAnnotation3D->SetText(stream.str().c_str()); + //this->m_VtkTextActor->SetInput(stream.str().c_str()); } else { - this->m_VtkTextActor->SetInput("Choose measurement points with SHIFT+Click"); + m_TextAnnotationAxial->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotationSagittal->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotationCoronal->SetText("Choose measurement points with SHIFT+Click"); + m_TextAnnotation3D->SetText("Choose measurement points with SHIFT+Click"); } } else { - this->m_VtkTextActor->SetInput("Measurement outside image range."); + this->m_TextAnnotationAxial->SetText("Measurement outside image range."); + this->m_TextAnnotationSagittal->SetText("Measurement outside image range."); + this->m_TextAnnotationCoronal->SetText("Measurement outside image range."); + this->m_TextAnnotation3D->SetText("Measurement outside image range."); } } else { // initialize 3D pointset empty mitk::PointSet::Pointer pointSet3D = mitk::PointSet::New(); m_MeasurementPointSet3DNode->SetData(pointSet3D); } } void QmitkToFPointSetWidget::PointSetChanged() { if (m_DistanceImage.IsNotNull()) { - int imageSizeX = m_DistanceImage->GetDimensions()[0]; - int imageSizeY = m_DistanceImage->GetDimensions()[1]; - int pointSetValid = 1; - for (int i=0; iGetSize(); i++) - { - mitk::Point3D currentPoint = m_PointSet2D->GetPoint(i); - if ((currentPoint[0]>=0.0f)&&(currentPoint[0]=0)&&(currentPoint[1]GetDimensions()[0]; + int imageSizeY = m_DistanceImage->GetDimensions()[1]; + int pointSetValid = 1; + for (int i = 0; i < m_PointSet2D->GetSize(); i++) { - pointSetValid*=0; + mitk::Point3D currentPoint = m_PointSet2D->GetPoint(i); + if ((currentPoint[0] >= 0.0f) && (currentPoint[0] < imageSizeX) && (currentPoint[1] >= 0) && (currentPoint[1] < imageSizeY)) + { + pointSetValid *= 1; + } + else + { + pointSetValid *= 0; + } } - } - if (m_PointSet2D->GetSize()>0) - { - if (pointSetValid) + if (m_PointSet2D->GetSize() > 0) { - // create PointSet filter - mitk::ToFDistanceImageToPointSetFilter::Pointer toFDistanceImageToPointSetFilter = mitk::ToFDistanceImageToPointSetFilter::New(); - if (m_CameraIntrinsics.IsNotNull()) + if (pointSetValid) { - toFDistanceImageToPointSetFilter->SetCameraIntrinsics(m_CameraIntrinsics); + // create PointSet filter + mitk::ToFDistanceImageToPointSetFilter::Pointer toFDistanceImageToPointSetFilter = mitk::ToFDistanceImageToPointSetFilter::New(); + if (m_CameraIntrinsics.IsNotNull()) + { + toFDistanceImageToPointSetFilter->SetCameraIntrinsics(m_CameraIntrinsics); + } + toFDistanceImageToPointSetFilter->SetInput(m_DistanceImage); + toFDistanceImageToPointSetFilter->SetSubset(m_PointSet2D); + toFDistanceImageToPointSetFilter->Update(); + mitk::PointSet::Pointer pointSet3D = toFDistanceImageToPointSetFilter->GetOutput(); + m_PointSet3DNode->SetData(pointSet3D); + this->m_TextAnnotation3D->SetText("Choose points with SHIFT+Click"); } - toFDistanceImageToPointSetFilter->SetInput(m_DistanceImage); - toFDistanceImageToPointSetFilter->SetSubset(m_PointSet2D); - toFDistanceImageToPointSetFilter->Update(); - mitk::PointSet::Pointer pointSet3D = toFDistanceImageToPointSetFilter->GetOutput(); - m_PointSet3DNode->SetData(pointSet3D); - this->m_VtkTextActor->SetInput("Choose points with SHIFT+Click"); } + else + { + this->m_TextAnnotation3D->SetText("Point set outside image range."); + } + } else { - this->m_VtkTextActor->SetInput("Point set outside image range."); + // initialize 3D pointset empty + mitk::PointSet::Pointer pointSet3D = mitk::PointSet::New(); + m_PointSet3DNode->SetData(pointSet3D); } } - else - { - // initialize 3D pointset empty - mitk::PointSet::Pointer pointSet3D = mitk::PointSet::New(); - m_PointSet3DNode->SetData(pointSet3D); - } - } } diff --git a/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.h b/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.h index 0b79b6ff13..1dd799368f 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.h +++ b/Modules/ToFUI/Qmitk/QmitkToFPointSetWidget.h @@ -1,147 +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 _QmitkToFPointSetWidget_H_INCLUDED #define _QmitkToFPointSetWidget_H_INCLUDED #include #include "ui_QmitkToFPointSetWidgetControls.h" //mitk headers #include #include #include #include #include +#include #include //Qmitk headers #include // vtk includes #include #include #include /** * @brief Widget allowing interaction with point sets for measurement and PointSet definition * * The widget allows to * 1. Measure the distance between two points in 3D ToF space by clicking the points in the 2D slices * 2. Defining a ToF PointSet both in 2D and 3D. CameraIntrinsics are used for calculation between 2D and 3D * * NOTE: * You have to make sure that the widget is initialized at a position in the plugin using it, where the distance * image is available. CleanUp has to be called to make sure that all observers and renderers are removed correctly. * * @ingroup ToFUI */ class MITKTOFUI_EXPORT QmitkToFPointSetWidget :public QWidget { //this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) Q_OBJECT public: static const std::string VIEW_ID; QmitkToFPointSetWidget(QWidget* p = nullptr, Qt::WindowFlags f1 = nullptr); ~QmitkToFPointSetWidget() override; /* @brief This method is part of the widget an needs not to be called seperately. */ virtual void CreateQtPartControl(QWidget *parent); /* @brief This method is part of the widget an needs not to be called seperately. (Creation of the connections of main and control widget.)*/ virtual void CreateConnections(); /*! \brief initializes the widget. Observers to the change events of the point sets are created, text actors are activated to be rendered into the foreground of the render window. \param stdMultiWidget QmitkStdMultiWidget used for painting overlays for measurement \param dataStorage DataStorage to add PointSets \param distanceImage range image used to calculate 3D PointSet from 2D index */ void InitializeWidget(QHash renderWindowHashMap, mitk::DataStorage::Pointer dataStorage, mitk::CameraIntrinsics::Pointer cameraIntrinsics=nullptr); /*! \brief cleans up the widget when it's functionality is not used anymore. Removes observers and deletes foreground renderer */ void CleanUpWidget(); /*! \brief set the image holding the distance information used for measuring */ void SetDistanceImage(mitk::Image::Pointer distanceImage); /*! \brief Set intrinsic parameters of the used device */ void SetCameraIntrinsics(mitk::CameraIntrinsics::Pointer cameraIntrinsics); signals: protected slots: /*! \brief Activates the interactor for the measurement point set */ void OnMeasurement(); /*! \brief Activates the interactor for the point set */ void OnPointSet(); protected: /*! \brief function called when the 2D measurement PointSet has changed */ void MeasurementPointSetChanged(); /*! \brief function called when the 2D PointSet has changed */ void PointSetChanged(); Ui::QmitkToFPointSetWidgetControls* m_Controls; ///< member holding the UI elements of this widget mitk::DataStorage::Pointer m_DataStorage; ///< member holding the set DataStorage mitk::Image::Pointer m_DistanceImage; ///< image holding the range data of the ToF camera mitk::CameraIntrinsics::Pointer m_CameraIntrinsics; ///< intrinsic parameters of the camera - vtkSmartPointer m_VtkTextActor; ///< actor containing the text of the overlay - vtkSmartPointer m_ForegroundRenderer1; ///< renderer responsible for text rendering in the foreground of widget 1 - vtkSmartPointer m_ForegroundRenderer2; ///< renderer responsible for text rendering in the foreground of widget 2 - vtkSmartPointer m_ForegroundRenderer3; ///< renderer responsible for text rendering in the foreground of widget 3 - vtkSmartPointer m_RenderWindow1; ///< vtk render window used for showing overlay in widget 1 - vtkSmartPointer m_RenderWindow2; ///< vtk render window used for showing overlay in widget 2 - vtkSmartPointer m_RenderWindow3; ///< vtk render window used for showing overlay in widget 3 - vtkSmartPointer m_RenderWindow4; ///< vtk render window used for showing overlay in widget 3 + mitk::TextAnnotation2D::Pointer m_TextAnnotationAxial; ///< text annotation used to display measurements in axial window + mitk::TextAnnotation2D::Pointer m_TextAnnotationSagittal; ///< text annotation used to display measurement in axial window + mitk::TextAnnotation2D::Pointer m_TextAnnotationCoronal; ///< text annotation used to display measurement in axial window + mitk::TextAnnotation2D::Pointer m_TextAnnotation3D; ///< text annotation used to display measurement in 3d window + mitk::VtkPropRenderer::Pointer m_RendererAxial; ///< renderer of axial render window + mitk::VtkPropRenderer::Pointer m_RendererSagittal; ///< renderer of sagittal render window + mitk::VtkPropRenderer::Pointer m_RendererCoronal; ///< renderer of coronal render window + mitk::VtkPropRenderer::Pointer m_Renderer3D; ///< renderer of 3D render window mitk::PointSet::Pointer m_MeasurementPointSet2D; ///< PointSet holding the 2D ToF image point selection used for measuring mitk::DataNode::Pointer m_MeasurementPointSet3DNode; ///< DataNode holding the 3D ToF coordinates used for measuring mitk::PointSet::Pointer m_PointSet2D; ///< PointSet holding the 2D ToF image points mitk::DataNode::Pointer m_PointSet3DNode; ///< DataNode holding the 3D ToF coordinates mitk::PointSetDataInteractor::Pointer m_PointSetInteractor; ///< PointSetInteractor used for PointSet definition mitk::PointSetDataInteractor::Pointer m_MeasurementPointSetInteractor; ///< PointSetInteractor used for measurement long m_MeasurementPointSetChangedObserverTag; ///< observer tag for measurement PointSet observer long m_PointSetChangedObserverTag; ///< observer tag for PointSet observer // long m_DistanceImageChangedObserverTag; ///< observer tag for distance image observer int m_WindowHeight; ///< Height of the renderWindow private: }; #endif // _QmitkToFPointSetWidget_H_INCLUDED diff --git a/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidget.cpp b/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidget.cpp index be5f8d7576..818c3e10c3 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidget.cpp +++ b/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidget.cpp @@ -1,419 +1,419 @@ /*=================================================================== 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 "QmitkToFVisualisationSettingsWidget.h" #include #include #include //QT headers #include #include #include const std::string QmitkToFVisualisationSettingsWidget::VIEW_ID = "org.mitk.views.qmitktofvisualisationsettingswidget"; QmitkToFVisualisationSettingsWidget::QmitkToFVisualisationSettingsWidget(QWidget* parent, Qt::WindowFlags f): QWidget(parent, f) , m_Controls(nullptr) , m_RangeSliderMin(0) , m_RangeSliderMax(0) , m_MitkDistanceImageNode(nullptr) , m_MitkAmplitudeImageNode(nullptr) , m_MitkIntensityImageNode(nullptr) , m_Widget1ColorTransferFunction(nullptr) , m_Widget2ColorTransferFunction(nullptr) , m_Widget3ColorTransferFunction(nullptr) , m_Widget1TransferFunctionType(1) , m_Widget2TransferFunctionType(0) , m_Widget3TransferFunctionType(0) { CreateQtPartControl(this); } QmitkToFVisualisationSettingsWidget::~QmitkToFVisualisationSettingsWidget() { } void QmitkToFVisualisationSettingsWidget::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkToFVisualisationSettingsWidgetControls; m_Controls->setupUi(parent); this->CreateConnections(); } } void QmitkToFVisualisationSettingsWidget::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_SelectWidgetCombobox), SIGNAL(currentIndexChanged(int)),(QObject*) this, SLOT(OnWidgetSelected(int)) ); connect( (QObject*)(m_Controls->m_SelectTransferFunctionTypeCombobox), SIGNAL(currentIndexChanged(int)),(QObject*) this, SLOT(OnTransferFunctionTypeSelected(int)) ); connect( (QObject*)(m_Controls->m_TransferFunctionResetButton), SIGNAL(clicked()),(QObject*) this, SLOT(OnTransferFunctionReset()) ); connect(m_Controls->m_XEditColor, SIGNAL(returnPressed()), this, SLOT(OnSetXValueColor())); connect(m_Controls->m_RangeSliderMaxEdit, SIGNAL(returnPressed()), this, SLOT(OnRangeSliderMaxChanged())); connect(m_Controls->m_RangeSliderMinEdit, SIGNAL(returnPressed()), this, SLOT(OnRangeSliderMinChanged())); connect(m_Controls->m_RangeSliderReset, SIGNAL(pressed()), this, SLOT(OnResetSlider())); - connect(m_Controls->m_RangeSlider, SIGNAL(spanChanged(int, int) ),this, SLOT( OnSpanChanged(int , int ) )); + connect(m_Controls->m_RangeSlider, SIGNAL(valuesChanged(int, int) ),this, SLOT( OnSpanChanged(int , int ) )); connect(m_Controls->m_AdvancedOptionsCheckbox, SIGNAL(toggled(bool) ),this, SLOT( OnShowAdvancedOptionsCheckboxChecked(bool) )); m_Controls->m_RangeSlider->setMaximum(2048); m_Controls->m_RangeSlider->setMinimum(-2048); m_Controls->m_ColorTransferFunctionCanvas->SetQLineEdits(m_Controls->m_XEditColor, nullptr); m_Controls->m_ColorTransferFunctionCanvas->SetTitle(""/*"Value -> Grayscale/Color"*/); this->OnShowAdvancedOptionsCheckboxChecked(false); } } void QmitkToFVisualisationSettingsWidget::OnSetXValueColor() { m_Controls->m_ColorTransferFunctionCanvas->SetX(m_Controls->m_XEditColor->text().toFloat()); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkToFVisualisationSettingsWidget::OnRangeSliderMaxChanged() { m_Controls->m_RangeSlider->setMaximum(m_Controls->m_RangeSliderMaxEdit->text().toInt()); UpdateRanges(); m_Controls->m_ColorTransferFunctionCanvas->update(); } void QmitkToFVisualisationSettingsWidget::OnRangeSliderMinChanged() { m_Controls->m_RangeSlider->setMinimum(m_Controls->m_RangeSliderMinEdit->text().toInt()); UpdateRanges(); m_Controls->m_ColorTransferFunctionCanvas->update(); } void QmitkToFVisualisationSettingsWidget::OnSpanChanged(int /*lower*/, int /*upper*/) { UpdateRanges(); m_Controls->m_ColorTransferFunctionCanvas->update(); } void QmitkToFVisualisationSettingsWidget::OnResetSlider() { m_Controls->m_RangeSlider->setMaximumValue(m_RangeSliderMax); m_Controls->m_RangeSlider->setMinimumValue(m_RangeSliderMin); UpdateRanges(); m_Controls->m_ColorTransferFunctionCanvas->update(); } void QmitkToFVisualisationSettingsWidget::UpdateRanges() { int lower = m_Controls->m_RangeSlider->minimumValue(); int upper = m_Controls->m_RangeSlider->maximumValue(); m_Controls->m_ColorTransferFunctionCanvas->SetMin(lower); m_Controls->m_ColorTransferFunctionCanvas->SetMax(upper); } void QmitkToFVisualisationSettingsWidget::UpdateSurfaceProperty() { if(this->m_MitkSurfaceNode.IsNotNull()) { mitk::TransferFunction::Pointer transferFunction = mitk::TransferFunction::New(); transferFunction->SetColorTransferFunction(this->GetSelectedColorTransferFunction()); this->m_MitkSurfaceNode->SetProperty("Surface.TransferFunction", mitk::TransferFunctionProperty::New(transferFunction)); } } void QmitkToFVisualisationSettingsWidget::Initialize(mitk::DataNode* distanceImageNode, mitk::DataNode* amplitudeImageNode, mitk::DataNode* intensityImageNode, mitk::DataNode* surfaceNode) { this->m_MitkDistanceImageNode = distanceImageNode; this->m_MitkAmplitudeImageNode = amplitudeImageNode; this->m_MitkIntensityImageNode = intensityImageNode; this->m_MitkSurfaceNode = surfaceNode; // Initialize transfer functions for image DataNodes such that: // Widget1 (Distance): color from red (2nd min) to blue (max) // Widget2 (Amplitude): grey value from black (2nd min) to white (max) // Widget3 (Intensity): grey value from black (2nd min) to white (max) if (!m_MitkDistanceImageNode && !m_MitkAmplitudeImageNode && !m_MitkIntensityImageNode) { m_Controls->m_ColorTransferFunctionCanvas->setEnabled(false); } else { m_Controls->m_ColorTransferFunctionCanvas->setEnabled(true); int numberOfImages = 0; if (m_MitkDistanceImageNode) { m_Widget1ColorTransferFunction = vtkColorTransferFunction::New(); this->m_Widget1TransferFunctionType = 1; m_Controls->m_SelectTransferFunctionTypeCombobox->setCurrentIndex(this->m_Widget1TransferFunctionType); numberOfImages++; } if (m_MitkAmplitudeImageNode) { m_Widget2ColorTransferFunction = vtkColorTransferFunction::New(); this->m_Widget2TransferFunctionType = 0; numberOfImages++; } if (m_MitkIntensityImageNode) { m_Widget3ColorTransferFunction = vtkColorTransferFunction::New(); this->m_Widget3TransferFunctionType = 0; numberOfImages++; } m_Controls->m_SelectWidgetCombobox->setMaxCount(numberOfImages); } this->ReinitTransferFunction(0,1); this->ReinitTransferFunction(1,0); this->ReinitTransferFunction(2,0); } void QmitkToFVisualisationSettingsWidget::UpdateCanvas() { m_Controls->m_ColorTransferFunctionCanvas->SetColorTransferFunction( this->GetSelectedColorTransferFunction() ); UpdateRanges(); m_Controls->m_ColorTransferFunctionCanvas->update(); } void QmitkToFVisualisationSettingsWidget::OnTransferFunctionTypeSelected(int index) { int currentWidgetIndex = m_Controls->m_SelectWidgetCombobox->currentIndex(); if (currentWidgetIndex == 0) { this->m_Widget1TransferFunctionType = index; } else if (currentWidgetIndex == 1) { this->m_Widget2TransferFunctionType = index; } else if (currentWidgetIndex == 2) { this->m_Widget3TransferFunctionType = index; } else { return; } this->UpdateSurfaceProperty(); } void QmitkToFVisualisationSettingsWidget::OnShowAdvancedOptionsCheckboxChecked(bool checked) { this->m_Controls->m_MappingGroupBox->setVisible(checked); this->m_Controls->m_SelectTransferFunctionTypeCombobox->setVisible(checked); this->m_Controls->m_SelectWidgetCombobox->setVisible(checked); this->m_Controls->m_TransferFunctionResetButton->setVisible(checked); } void QmitkToFVisualisationSettingsWidget::OnWidgetSelected(int index) { int currentWidgetIndex = index; double valMin[6]; double valMax[6]; int numPoints; if (currentWidgetIndex == 0) { m_Controls->m_SelectTransferFunctionTypeCombobox->setCurrentIndex(this->m_Widget1TransferFunctionType); numPoints = this->m_Widget1ColorTransferFunction->GetSize(); this->m_Widget1ColorTransferFunction->GetNodeValue( 0, valMin ); this->m_Widget1ColorTransferFunction->GetNodeValue( numPoints-1, valMax ); m_Controls->m_ColorTransferFunctionCanvas->SetColorTransferFunction( this->m_Widget1ColorTransferFunction ); } else if (currentWidgetIndex == 1) { m_Controls->m_SelectTransferFunctionTypeCombobox->setCurrentIndex(this->m_Widget2TransferFunctionType); numPoints = this->m_Widget2ColorTransferFunction->GetSize(); this->m_Widget2ColorTransferFunction->GetNodeValue( 0, valMin ); this->m_Widget2ColorTransferFunction->GetNodeValue( numPoints-1, valMax ); m_Controls->m_ColorTransferFunctionCanvas->SetColorTransferFunction( this->m_Widget2ColorTransferFunction ); } else if (currentWidgetIndex == 2) { m_Controls->m_SelectTransferFunctionTypeCombobox->setCurrentIndex(this->m_Widget3TransferFunctionType); numPoints = this->m_Widget3ColorTransferFunction->GetSize(); this->m_Widget3ColorTransferFunction->GetNodeValue( 0, valMin ); this->m_Widget3ColorTransferFunction->GetNodeValue( numPoints-1, valMax ); m_Controls->m_ColorTransferFunctionCanvas->SetColorTransferFunction( this->m_Widget3ColorTransferFunction ); } else if (currentWidgetIndex == 3) { } else { return; } m_RangeSliderMin = valMin[0]; m_RangeSliderMax = valMax[0]; int border = (m_RangeSliderMax - m_RangeSliderMin) * 0.1; m_Controls->m_RangeSlider->setMinimum(m_RangeSliderMin - border); m_Controls->m_RangeSlider->setMaximum(m_RangeSliderMax + border); m_Controls->m_RangeSliderMinEdit->setText(QString("").setNum(m_RangeSliderMin - border)); m_Controls->m_RangeSliderMaxEdit->setText(QString("").setNum(m_RangeSliderMax + border)); m_Controls->m_RangeSlider->setRange( m_RangeSliderMin, m_RangeSliderMax); UpdateRanges(); m_Controls->m_ColorTransferFunctionCanvas->update(); this->UpdateSurfaceProperty(); } void QmitkToFVisualisationSettingsWidget::ResetTransferFunction(vtkColorTransferFunction* colorTransferFunction, int type, double min, double max) { colorTransferFunction->RemoveAllPoints(); if (type == 0) { colorTransferFunction->AddRGBPoint(min, 0, 0, 0); colorTransferFunction->AddRGBPoint(max, 1, 1, 1); } else { if (min>0.01) { colorTransferFunction->AddRGBPoint(0.0, 0, 0, 0); colorTransferFunction->AddRGBPoint(min-0.01, 0, 0, 0); } colorTransferFunction->AddRGBPoint(min, 1, 0, 0); colorTransferFunction->AddRGBPoint(min+(max-min)/2, 1, 1, 0); colorTransferFunction->AddRGBPoint(max, 0, 0, 1); } colorTransferFunction->SetColorSpaceToHSV(); } void QmitkToFVisualisationSettingsWidget::ReinitTransferFunction(int widget, int type) { switch (widget) { case 0: { mitk::Image::Pointer distanceImage = dynamic_cast(m_MitkDistanceImageNode->GetData()); // use second minimum to draw 0 values (that are usually segmented) black m_RangeSliderMin = distanceImage->GetStatistics()->GetScalarValue2ndMin(); m_RangeSliderMax = distanceImage->GetStatistics()->GetScalarValueMax(); MITK_INFO<<"Distance Min: "<m_Widget1ColorTransferFunction, type, this->m_RangeSliderMin, this->m_RangeSliderMax); m_Controls->m_ColorTransferFunctionCanvas->SetColorTransferFunction( this->m_Widget1ColorTransferFunction ); mitk::TransferFunction::Pointer tf1 = mitk::TransferFunction::New(); tf1->SetColorTransferFunction( m_Widget1ColorTransferFunction ); m_MitkDistanceImageNode->SetProperty("Image Rendering.Transfer Function",mitk::TransferFunctionProperty::New(tf1)); break; } case 1: { if (m_MitkAmplitudeImageNode) { mitk::Image::Pointer amplitudeImage = dynamic_cast(m_MitkAmplitudeImageNode->GetData()); if (amplitudeImage.IsNotNull()) { m_RangeSliderMin = amplitudeImage->GetStatistics()->GetScalarValueMin(); m_RangeSliderMax = amplitudeImage->GetStatistics()->GetScalarValueMax(); MITK_INFO<<"Amplitude Min: "<m_Widget2ColorTransferFunction, type, this->m_RangeSliderMin, this->m_RangeSliderMax); m_Controls->m_ColorTransferFunctionCanvas->SetColorTransferFunction( this->m_Widget2ColorTransferFunction ); mitk::TransferFunction::Pointer tf2 = mitk::TransferFunction::New(); tf2->SetColorTransferFunction( m_Widget2ColorTransferFunction ); m_MitkAmplitudeImageNode->SetProperty("Image Rendering.Transfer Function",mitk::TransferFunctionProperty::New(tf2)); } } break; } case 2: { if (m_MitkIntensityImageNode) { mitk::Image::Pointer intensityImage = dynamic_cast(m_MitkIntensityImageNode->GetData()); if (intensityImage.IsNotNull()) { m_RangeSliderMin = intensityImage->GetStatistics()->GetScalarValueMin(); m_RangeSliderMax = intensityImage->GetStatistics()->GetScalarValueMax(); MITK_INFO<<"Intensity Min: "<m_Widget3ColorTransferFunction, type, this->m_RangeSliderMin, this->m_RangeSliderMax); m_Controls->m_ColorTransferFunctionCanvas->SetColorTransferFunction( this->m_Widget3ColorTransferFunction ); mitk::TransferFunction::Pointer tf3 = mitk::TransferFunction::New(); tf3->SetColorTransferFunction( m_Widget3ColorTransferFunction ); m_MitkIntensityImageNode->SetProperty("Image Rendering.Transfer Function",mitk::TransferFunctionProperty::New(tf3)); } } break; } default: break; } this->UpdateSurfaceProperty(); } void QmitkToFVisualisationSettingsWidget::OnTransferFunctionReset() { int currentTransferFunctionTypeIndex = m_Controls->m_SelectTransferFunctionTypeCombobox->currentIndex(); int currentWidgetIndex = m_Controls->m_SelectWidgetCombobox->currentIndex(); this->ReinitTransferFunction(currentWidgetIndex,currentTransferFunctionTypeIndex); int border = (m_RangeSliderMax - m_RangeSliderMin) * 0.1; m_Controls->m_RangeSlider->setMinimum(m_RangeSliderMin - border); m_Controls->m_RangeSlider->setMaximum(m_RangeSliderMax + border); m_Controls->m_RangeSliderMinEdit->setText(QString("").setNum(m_RangeSliderMin - border)); m_Controls->m_RangeSliderMaxEdit->setText(QString("").setNum(m_RangeSliderMax + border)); m_Controls->m_RangeSlider->setRange( m_RangeSliderMin, m_RangeSliderMax); UpdateRanges(); m_Controls->m_ColorTransferFunctionCanvas->update(); this->UpdateSurfaceProperty(); } vtkColorTransferFunction* QmitkToFVisualisationSettingsWidget::GetWidget1ColorTransferFunction() { return this->m_Widget1ColorTransferFunction; } vtkColorTransferFunction* QmitkToFVisualisationSettingsWidget::GetWidget2ColorTransferFunction() { return this->m_Widget2ColorTransferFunction; } vtkColorTransferFunction* QmitkToFVisualisationSettingsWidget::GetWidget3ColorTransferFunction() { return this->m_Widget3ColorTransferFunction; } vtkColorTransferFunction* QmitkToFVisualisationSettingsWidget::GetSelectedColorTransferFunction() { int currentWidgetIndex = m_Controls->m_SelectWidgetCombobox->currentIndex(); if (currentWidgetIndex==0) { return this->m_Widget1ColorTransferFunction; } else if (currentWidgetIndex==1) { return this->m_Widget2ColorTransferFunction; } else if (currentWidgetIndex==2) { return this->m_Widget3ColorTransferFunction; } else { return this->m_Widget3ColorTransferFunction; } } int QmitkToFVisualisationSettingsWidget::GetSelectedImageIndex() { return this->m_Controls->m_SelectWidgetCombobox->currentIndex(); } diff --git a/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidgetControls.ui b/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidgetControls.ui index dc1e7ca403..74938d0a7c 100644 --- a/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidgetControls.ui +++ b/Modules/ToFUI/Qmitk/QmitkToFVisualisationSettingsWidgetControls.ui @@ -1,445 +1,439 @@ QmitkToFVisualisationSettingsWidgetControls 0 0 482 - 230 + 211 0 0 QmitkToFVisualisationSettings - + 11 ToF Visualization - - - - Show advanced options - - - 0 0 200 50 10 0 3 QComboBox::InsertAtBottom QComboBox::AdjustToContents 30 30 true Distance :/images/widget1.png:/images/widget1.png Amplitude :/images/widget2.png:/images/widget2.png Intensity :/images/widget3.png:/images/widget3.png true 0 0 150 50 16777215 50 10 0 3 QComboBox::InsertAtBottom QComboBox::AdjustToContents 100 35 true :/images/grayscale.png:/images/grayscale.png :/images/color.png:/images/color.png 100 50 16777215 50 10 Fit scale + + + + Show advanced options + + + Gray value/color mapping QFrame::StyledPanel QFrame::Raised - + + 0 + + + 0 + + + 0 + + 0 - - modify actual seen window by dragging left and right slider. - Qt::Horizontal - + 0 0 - - - 48 - 16777215 - - Resets range to histogram minimum and maximum. Reset - + 1 1 - - - 0 - 28 - - Left-click to select a point or add a new point. Hold left mouse button to move selected point. Click right mouse button to delete a point. Double-click left mouse button to change color of a point. true 0 0 48 0 48 16777215 7 Edit x-coordinate (grayvalue) of currently selected point. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Qt::Horizontal 86 20 0 0 48 0 48 16777215 7 Edit x-coordinate (grayvalue) of currently selected point. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter Qt::Horizontal 85 20 0 0 48 0 48 16777215 7 Edit x-coordinate (grayvalue) of currently selected point. Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - ctkRangeSlider - QWidget -
ctkRangeSlider.h
-
QmitkColorTransferFunctionCanvas QWidget
QmitkColorTransferFunctionCanvas.h
+ + ctkRangeSlider + QSlider +
ctkRangeSlider.h
+
diff --git a/Modules/US/USModel/mitkUSDevice.cpp b/Modules/US/USModel/mitkUSDevice.cpp index 8e80410b82..05ea8dcffc 100644 --- a/Modules/US/USModel/mitkUSDevice.cpp +++ b/Modules/US/USModel/mitkUSDevice.cpp @@ -1,692 +1,712 @@ /*=================================================================== 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 "mitkUSDevice.h" #include "mitkImageReadAccessor.h" // US Control Interfaces #include "mitkUSControlInterfaceProbes.h" #include "mitkUSControlInterfaceBMode.h" #include "mitkUSControlInterfaceDoppler.h" // Microservices #include #include #include #include mitk::USDevice::PropertyKeys mitk::USDevice::GetPropertyKeys() { static mitk::USDevice::PropertyKeys propertyKeys; return propertyKeys; } mitk::USDevice::USImageCropArea mitk::USDevice::GetCropArea() { MITK_INFO << "Return Crop Area L:" << m_CropArea.cropLeft << " R:" << m_CropArea.cropRight << " T:" << m_CropArea.cropTop << " B:" << m_CropArea.cropBottom; return m_CropArea; } mitk::USDevice::USDevice(std::string manufacturer, std::string model) : mitk::ImageSource(), + m_FreezeBarrier(nullptr), + m_FreezeMutex(), + m_MultiThreader(itk::MultiThreader::New()), + m_ImageMutex(itk::FastMutexLock::New()), + m_ThreadID(-1), + m_ImageVector(), + m_Spacing(), + m_IGTLServer(nullptr), + m_IGTLMessageProvider(nullptr), + m_ImageToIGTLMsgFilter(nullptr), m_IsFreezed(false), m_DeviceState(State_NoState), m_NumberOfOutputs(1), + m_ServiceProperties(), + m_ServiceRegistration(), m_Manufacturer(manufacturer), m_Name(model), + m_Comment(), m_SpawnAcquireThread(true), - m_MultiThreader(itk::MultiThreader::New()), - m_ImageMutex(itk::FastMutexLock::New()), - m_ThreadID(-1), m_UnregisteringStarted(false) { USImageCropArea empty; empty.cropBottom = 0; empty.cropTop = 0; empty.cropLeft = 0; empty.cropRight = 0; this->m_CropArea = empty; // set number of outputs this->SetNumberOfIndexedOutputs(m_NumberOfOutputs); // create a new output mitk::Image::Pointer newOutput = mitk::Image::New(); this->SetNthOutput(0, newOutput); } mitk::USDevice::USDevice(mitk::USImageMetadata::Pointer metadata) : mitk::ImageSource(), - m_IsFreezed(false), - m_DeviceState(State_NoState), - m_SpawnAcquireThread(true), + m_FreezeBarrier(nullptr), + m_FreezeMutex(), m_MultiThreader(itk::MultiThreader::New()), m_ImageMutex(itk::FastMutexLock::New()), m_ThreadID(-1), + m_ImageVector(), + m_Spacing(), + m_IGTLServer(nullptr), + m_IGTLMessageProvider(nullptr), + m_ImageToIGTLMsgFilter(nullptr), + m_IsFreezed(false), + m_DeviceState(State_NoState), + m_NumberOfOutputs(1), + m_ServiceProperties(), + m_ServiceRegistration(), + m_SpawnAcquireThread(true), m_UnregisteringStarted(false) { m_Manufacturer = metadata->GetDeviceManufacturer(); m_Name = metadata->GetDeviceModel(); m_Comment = metadata->GetDeviceComment(); USImageCropArea empty; empty.cropBottom = 0; empty.cropTop = 0; empty.cropLeft = 0; empty.cropRight = 0; this->m_CropArea = empty; // set number of outputs - this->SetNumberOfIndexedOutputs(1); + this->SetNumberOfIndexedOutputs(m_NumberOfOutputs); // create a new output mitk::Image::Pointer newOutput = mitk::Image::New(); this->SetNthOutput(0, newOutput); } mitk::USDevice::~USDevice() { if (m_ThreadID >= 0) { m_MultiThreader->TerminateThread(m_ThreadID); } // make sure that the us device is not registered at the micro service // anymore after it is destructed this->UnregisterOnService(); } mitk::USAbstractControlInterface::Pointer mitk::USDevice::GetControlInterfaceCustom() { MITK_INFO << "Custom control interface does not exist for this object."; return nullptr; } mitk::USControlInterfaceBMode::Pointer mitk::USDevice::GetControlInterfaceBMode() { MITK_INFO << "Control interface BMode does not exist for this object."; return nullptr; } mitk::USControlInterfaceProbes::Pointer mitk::USDevice::GetControlInterfaceProbes() { MITK_INFO << "Control interface Probes does not exist for this object."; return nullptr; } mitk::USControlInterfaceDoppler::Pointer mitk::USDevice::GetControlInterfaceDoppler() { MITK_INFO << "Control interface Doppler does not exist for this object."; return nullptr; } void mitk::USDevice::SetManufacturer(std::string manufacturer) { m_Manufacturer = manufacturer; if (m_DeviceState >= State_Initialized) { this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_MANUFACTURER, manufacturer); } } void mitk::USDevice::SetName(std::string name) { m_Name = name; if (m_DeviceState >= State_Initialized) { this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_NAME, name); } } void mitk::USDevice::SetComment(std::string comment) { m_Comment = comment; if (m_DeviceState >= State_Initialized) { this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_COMMENT, comment); } } us::ServiceProperties mitk::USDevice::ConstructServiceProperties() { mitk::USDevice::PropertyKeys propertyKeys = mitk::USDevice::GetPropertyKeys(); us::ServiceProperties props; props[propertyKeys.US_PROPKEY_ISCONNECTED] = this->GetIsConnected() ? "true" : "false"; props[propertyKeys.US_PROPKEY_ISACTIVE] = this->GetIsActive() ? "true" : "false"; props[propertyKeys.US_PROPKEY_LABEL] = this->GetServicePropertyLabel(); // get identifier of selected probe if there is one selected mitk::USControlInterfaceProbes::Pointer probesControls = this->GetControlInterfaceProbes(); if (probesControls.IsNotNull() && probesControls->GetIsActive()) { mitk::USProbe::Pointer probe = probesControls->GetSelectedProbe(); if (probe.IsNotNull()) { props[propertyKeys.US_PROPKEY_PROBES_SELECTED] = probe->GetName(); } } props[propertyKeys.US_PROPKEY_CLASS] = GetDeviceClass(); props[propertyKeys.US_PROPKEY_MANUFACTURER] = m_Manufacturer; props[propertyKeys.US_PROPKEY_NAME] = m_Name; props[propertyKeys.US_PROPKEY_COMMENT] = m_Comment; m_ServiceProperties = props; return props; } void mitk::USDevice::UnregisterOnService() { // unregister on micro service if (m_ServiceRegistration && !m_UnregisteringStarted) { // make sure that unregister is not started a second // time due to a callback during unregister for example m_UnregisteringStarted = true; m_ServiceRegistration.Unregister(); m_ServiceRegistration = 0; } } bool mitk::USDevice::Initialize() { if (!this->OnInitialization()) { return false; } m_DeviceState = State_Initialized; // Get Context and Module us::ModuleContext* context = us::GetModuleContext(); us::ServiceProperties props = this->ConstructServiceProperties(); m_ServiceRegistration = context->RegisterService(this, props); return true; } bool mitk::USDevice::Connect() { MITK_DEBUG << "mitk::USDevice::Connect() called"; if (this->GetIsConnected()) { MITK_INFO("mitkUSDevice") << "Tried to connect an ultrasound device that " "was already connected. Ignoring call..."; return true; } if (!this->GetIsInitialized()) { MITK_ERROR("mitkUSDevice") << "Cannot connect device if it is not in initialized state."; return false; } // Prepare connection, fail if this fails. if (!this->OnConnection()) { return false; } // Update state m_DeviceState = State_Connected; this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISCONNECTED, true); return true; } void mitk::USDevice::ConnectAsynchron() { this->m_MultiThreader->SpawnThread(this->ConnectThread, this); } bool mitk::USDevice::Disconnect() { if (!GetIsConnected()) { MITK_WARN << "Tried to disconnect an ultrasound device that was not " "connected. Ignoring call..."; return false; } // Prepare connection, fail if this fails. if (!this->OnDisconnection()) return false; // Update state m_DeviceState = State_Initialized; this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISCONNECTED, false); return true; } bool mitk::USDevice::Activate() { if (!this->GetIsConnected()) { MITK_INFO("mitkUSDevice") << "Cannot activate device if it is not in connected state."; return true; } if (OnActivation()) { m_DeviceState = State_Activated; m_FreezeBarrier = itk::ConditionVariable::New(); // spawn thread for aquire images if us device is active if (m_SpawnAcquireThread) { this->m_ThreadID = this->m_MultiThreader->SpawnThread(this->Acquire, this); } this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE, true); this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL, this->GetServicePropertyLabel()); // initialize the b mode control properties of the micro service mitk::USControlInterfaceBMode::Pointer bmodeControls = this->GetControlInterfaceBMode(); if (bmodeControls.IsNotNull()) { bmodeControls->Initialize(); } } this->ProvideViaOIGTL(); return m_DeviceState == State_Activated; } void mitk::USDevice::ProvideViaOIGTL() { // create a new OpenIGTLink Server if (m_IGTLServer.IsNull()) m_IGTLServer = mitk::IGTLServer::New(true); m_IGTLServer->SetName(this->GetName()); // create a new OpenIGTLink Device source if (m_IGTLMessageProvider.IsNull()) m_IGTLMessageProvider = mitk::IGTLMessageProvider::New(); // set the OpenIGTLink server as the source for the device source m_IGTLMessageProvider->SetIGTLDevice(m_IGTLServer); // register the provider so that it can be configured with the IGTL manager // plugin. This could be hardcoded but now I already have the fancy plugin. m_IGTLMessageProvider->RegisterAsMicroservice(); m_ImageToIGTLMsgFilter = mitk::ImageToIGTLMessageFilter::New(); m_ImageToIGTLMsgFilter->ConnectTo(this); // set the name of this filter to identify it easier m_ImageToIGTLMsgFilter->SetName(this->GetName()); // register this filter as micro service. The message provider looks for // provided IGTLMessageSources, once it found this microservice and someone // requested this data type then the provider will connect with this filter // automatically. m_ImageToIGTLMsgFilter->RegisterAsMicroservice(); } void mitk::USDevice::Deactivate() { if (!this->GetIsActive()) { MITK_WARN("mitkUSDevice") << "Cannot deactivate a device which is not activae."; return; } if (!OnDeactivation()) { return; } DisableOIGTL(); m_DeviceState = State_Connected; this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_ISACTIVE, false); this->UpdateServiceProperty( mitk::USDevice::GetPropertyKeys().US_PROPKEY_LABEL, this->GetServicePropertyLabel()); } void mitk::USDevice::DisableOIGTL() { // TODO: This seems not to be enough cleanup to catch all cases. For example, if the device is disconnected // from the OIGTL GUI, this won't get cleaned up correctly. m_IGTLServer->CloseConnection(); m_IGTLMessageProvider->UnRegisterMicroservice(); m_ImageToIGTLMsgFilter->UnRegisterMicroservice(); } void mitk::USDevice::SetIsFreezed(bool freeze) { if (!this->GetIsActive()) { MITK_WARN("mitkUSDevice") << "Cannot freeze or unfreeze if device is not active."; return; } this->OnFreeze(freeze); if (freeze) { m_IsFreezed = true; } else { m_IsFreezed = false; // wake up the image acquisition thread m_FreezeBarrier->Signal(); } } bool mitk::USDevice::GetIsFreezed() { /* if (!this->GetIsActive()) { MITK_WARN("mitkUSDevice")("mitkUSTelemedDevice") << "Cannot get freeze state if the hardware interface is not ready. " "Returning false..."; return false; }*/ return m_IsFreezed; } void mitk::USDevice::PushFilter(AbstractOpenCVImageFilter::Pointer filter) { mitk::USImageSource::Pointer imageSource = this->GetUSImageSource(); if (imageSource.IsNull()) { MITK_ERROR << "ImageSource must not be null when pushing a filter."; mitkThrow() << "ImageSource must not be null when pushing a filter."; } imageSource->PushFilter(filter); } void mitk::USDevice::PushFilterIfNotPushedBefore( AbstractOpenCVImageFilter::Pointer filter) { mitk::USImageSource::Pointer imageSource = this->GetUSImageSource(); if (imageSource.IsNull()) { MITK_ERROR << "ImageSource must not be null when pushing a filter."; mitkThrow() << "ImageSource must not be null when pushing a filter."; } if (!imageSource->GetIsFilterInThePipeline(filter)) { imageSource->PushFilter(filter); } } bool mitk::USDevice::RemoveFilter(AbstractOpenCVImageFilter::Pointer filter) { mitk::USImageSource::Pointer imageSource = this->GetUSImageSource(); if (imageSource.IsNull()) { MITK_ERROR << "ImageSource must not be null when pushing a filter."; mitkThrow() << "ImageSource must not be null when removing a filter."; } return imageSource->RemoveFilter(filter); } void mitk::USDevice::UpdateServiceProperty(std::string key, std::string value) { m_ServiceProperties[key] = value; m_ServiceRegistration.SetProperties(m_ServiceProperties); // send event to notify listeners about the changed property m_PropertyChangedMessage(key, value); } void mitk::USDevice::UpdateServiceProperty(std::string key, double value) { std::stringstream stream; stream << value; this->UpdateServiceProperty(key, stream.str()); } void mitk::USDevice::UpdateServiceProperty(std::string key, bool value) { this->UpdateServiceProperty( key, value ? std::string("true") : std::string("false")); } /** mitk::Image* mitk::USDevice::GetOutput() { if (this->GetNumberOfOutputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetPrimaryOutput()); } mitk::Image* mitk::USDevice::GetOutput(unsigned int idx) { if (this->GetNumberOfOutputs() < 1) return nullptr; return static_cast(this->ProcessObject::GetOutput(idx)); } void mitk::USDevice::GraftOutput(itk::DataObject *graft) { this->GraftNthOutput(0, graft); } void mitk::USDevice::GraftNthOutput(unsigned int idx, itk::DataObject *graft) { if ( idx >= this->GetNumberOfOutputs() ) { itkExceptionMacro(<<"Requested to graft output " << idx << " but this filter only has " << this->GetNumberOfOutputs() << " Outputs."); } if ( !graft ) { itkExceptionMacro(<<"Requested to graft output with a nullptr pointer object" ); } itk::DataObject* output = this->GetOutput(idx); if ( !output ) { itkExceptionMacro(<<"Requested to graft output that is a nullptr pointer" ); } // Call Graft on USImage to copy member data output->Graft( graft ); } */ void mitk::USDevice::GrabImage() { std::vector image = this->GetUSImageSource()->GetNextImage(); m_ImageMutex->Lock(); this->SetImageVector(image); m_ImageMutex->Unlock(); } //########### GETTER & SETTER ##################// bool mitk::USDevice::GetIsInitialized() { return m_DeviceState == State_Initialized; } bool mitk::USDevice::GetIsActive() { return m_DeviceState == State_Activated; } bool mitk::USDevice::GetIsConnected() { return m_DeviceState == State_Connected; } std::string mitk::USDevice::GetDeviceManufacturer() { return m_Manufacturer; } std::string mitk::USDevice::GetDeviceModel() { return m_Name; } std::string mitk::USDevice::GetDeviceComment() { return m_Comment; } void mitk::USDevice::SetSpacing(double xSpacing, double ySpacing) { m_Spacing[0] = xSpacing; m_Spacing[1] = ySpacing; m_Spacing[2] = 1; if( m_ImageVector.size() > 0 ) { for( size_t index = 0; index < m_ImageVector.size(); ++index ) { auto& image = m_ImageVector[index]; if( image.IsNotNull() && image->IsInitialized() ) { image->GetGeometry()->SetSpacing(m_Spacing); } } this->Modified(); } MITK_INFO << "Spacing: " << m_Spacing; } void mitk::USDevice::GenerateData() { m_ImageMutex->Lock(); for (unsigned int i = 0; i < m_ImageVector.size() && i < this->GetNumberOfIndexedOutputs(); ++i) { auto& image = m_ImageVector[i]; if (image.IsNull() || !image->IsInitialized()) { // skip image } else { mitk::Image::Pointer output = this->GetOutput(i); if (!output->IsInitialized() || output->GetDimension(0) != image->GetDimension(0) || output->GetDimension(1) != image->GetDimension(1) || output->GetDimension(2) != image->GetDimension(2) || output->GetPixelType() != image->GetPixelType()) { output->Initialize(image->GetPixelType(), image->GetDimension(), image->GetDimensions()); } // copy contents of the given image into the member variable mitk::ImageReadAccessor inputReadAccessor(image); output->SetImportVolume(inputReadAccessor.GetData()); output->SetGeometry(image->GetGeometry()); } } m_ImageMutex->Unlock(); }; std::string mitk::USDevice::GetServicePropertyLabel() { std::string isActive; if (this->GetIsActive()) { isActive = " (Active)"; } else { isActive = " (Inactive)"; } // e.g.: Zonare MyLab5 (Active) return m_Manufacturer + " " + m_Name + isActive; } ITK_THREAD_RETURN_TYPE mitk::USDevice::Acquire(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct* pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; mitk::USDevice* device = (mitk::USDevice*)pInfo->UserData; while (device->GetIsActive()) { // lock this thread when ultrasound device is freezed if (device->m_IsFreezed) { itk::SimpleMutexLock* mutex = &(device->m_FreezeMutex); mutex->Lock(); if (device->m_FreezeBarrier.IsNotNull()) { device->m_FreezeBarrier->Wait(mutex); } } device->GrabImage(); } return ITK_THREAD_RETURN_VALUE; } ITK_THREAD_RETURN_TYPE mitk::USDevice::ConnectThread(void* pInfoStruct) { /* extract this pointer from Thread Info structure */ struct itk::MultiThreader::ThreadInfoStruct* pInfo = (struct itk::MultiThreader::ThreadInfoStruct*)pInfoStruct; mitk::USDevice* device = (mitk::USDevice*)pInfo->UserData; device->Connect(); return ITK_THREAD_RETURN_VALUE; } void mitk::USDevice::ProbeChanged(std::string probename) { this->UpdateServiceProperty(mitk::USDevice::GetPropertyKeys().US_PROPKEY_PROBES_SELECTED, probename); } void mitk::USDevice::DepthChanged(double depth) { this->UpdateServiceProperty(mitk::USDevice::GetPropertyKeys().US_PROPKEY_BMODE_DEPTH, depth); } diff --git a/Modules/US/USModel/mitkUSDevice.h b/Modules/US/USModel/mitkUSDevice.h index b54f67c583..095f3fbf1b 100644 --- a/Modules/US/USModel/mitkUSDevice.h +++ b/Modules/US/USModel/mitkUSDevice.h @@ -1,490 +1,489 @@ /*=================================================================== 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 MITKUSDevice_H_HEADER_INCLUDED_ #define MITKUSDevice_H_HEADER_INCLUDED_ // STL #include // MitkUS #include "mitkUSProbe.h" #include #include "mitkUSImageSource.h" // MitkIGTL #include "mitkIGTLMessageProvider.h" #include "mitkIGTLServer.h" #include "mitkIGTLDeviceSource.h" #include "mitkImageToIGTLMessageFilter.h" // MITK #include #include #include // ITK #include #include // Microservices #include #include #include // DEPRECATED #include "mitkUSImageMetadata.h" namespace itk { template class SmartPointer; } namespace mitk { class USAbstractControlInterface; class USControlInterfaceBMode; class USControlInterfaceProbes; class USControlInterfaceDoppler; /** * \brief A device holds information about it's model, make and the connected probes. It is the * common super class for all devices and acts as an image source for mitkUSImages. It is the base class * for all US Devices, and every new device should extend it. * * US Devices support output of calibrated images, i.e. images that include a specific geometry. * To achieve this, call SetCalibration, and make sure that the subclass also calls apply * transformation at some point (The USDevice does not automatically apply the transformation to the image) * * Note that USDevices will be removed from micro servive when their * destructor is called. Registering into micro service is done when * mitk::USDevice::Initialize() is called. * * \ingroup US */ class MITKUS_EXPORT USDevice : public mitk::ImageSource { public: enum DeviceStates { State_NoState, State_Initialized, State_Connected, State_Activated }; mitkClassMacro(USDevice, mitk::ImageSource); itkSetMacro(SpawnAcquireThread, bool); itkGetMacro(SpawnAcquireThread, bool); struct USImageCropArea { int cropLeft; int cropRight; int cropBottom; int cropTop; }; /** * \brief These constants are used in conjunction with Microservices. * The constants aren't defined as static member attributes to avoid the * "static initialization order fiasco", which would occur when objects of * this class are used in module activators (for restoring stored device, * for example). */ struct PropertyKeys { const std::string US_INTERFACE_NAME; // Common Interface name of all US Devices. Used to refer to this device via Microservices const std::string US_PROPKEY_MANUFACTURER; const std::string US_PROPKEY_NAME; const std::string US_PROPKEY_COMMENT; const std::string US_PROPKEY_LABEL; // Human readable text represntation of this device const std::string US_PROPKEY_ISCONNECTED; // Whether this device is connected or not. const std::string US_PROPKEY_ISACTIVE; // Whether this device is active or not. const std::string US_PROPKEY_CLASS; // Class Name of this Object const std::string US_PROPKEY_PROBES_SELECTED; const std::string US_PROPKEY_BMODE_FREQUENCY; const std::string US_PROPKEY_BMODE_POWER; const std::string US_PROPKEY_BMODE_DEPTH; const std::string US_PROPKEY_BMODE_GAIN; const std::string US_PROPKEY_BMODE_REJECTION; const std::string US_PROPKEY_BMODE_DYNAMIC_RANGE; PropertyKeys() : US_INTERFACE_NAME("org.mitk.services.UltrasoundDevice"), US_PROPKEY_MANUFACTURER(US_INTERFACE_NAME + ".manufacturer"), US_PROPKEY_NAME(US_INTERFACE_NAME + ".name"), US_PROPKEY_COMMENT(US_INTERFACE_NAME + ".comment"), US_PROPKEY_LABEL(US_INTERFACE_NAME + ".label"), US_PROPKEY_ISCONNECTED(US_INTERFACE_NAME + ".isConnected"), US_PROPKEY_ISACTIVE(US_INTERFACE_NAME + ".isActive"), US_PROPKEY_CLASS(US_INTERFACE_NAME + ".class"), US_PROPKEY_PROBES_SELECTED(US_INTERFACE_NAME + ".probes.selected"), US_PROPKEY_BMODE_FREQUENCY(US_INTERFACE_NAME + ".bmode.frequency"), US_PROPKEY_BMODE_POWER(US_INTERFACE_NAME + ".bmode.power"), US_PROPKEY_BMODE_DEPTH(US_INTERFACE_NAME + ".bmode.depth"), US_PROPKEY_BMODE_GAIN(US_INTERFACE_NAME + ".bmode.gain"), US_PROPKEY_BMODE_REJECTION(US_INTERFACE_NAME + ".bmode.rejection"), US_PROPKEY_BMODE_DYNAMIC_RANGE(US_INTERFACE_NAME + ".bmode.dynamicRange") {} }; /** * \brief Event for being notified about changes of the micro service properties. * This event can be used if no micro service context is available. */ mitkNewMessage2Macro(PropertyChanged, const std::string&, const std::string&) - /** - * \return keys for the microservice properties of ultrasound devices - */ - static mitk::USDevice::PropertyKeys GetPropertyKeys(); + /** + * \return keys for the microservice properties of ultrasound devices + */ + static mitk::USDevice::PropertyKeys GetPropertyKeys(); /** * \brief Default getter for the custom control interface. * Has to be implemented in a subclass if a custom control interface is * available. Default implementation returns null. * * \return null pointer */ virtual itk::SmartPointer GetControlInterfaceCustom(); /** * \brief Default getter for the b mode control interface. * Has to be implemented in a subclass if a b mode control interface is * available. Default implementation returns null. * * \return null pointer */ virtual itk::SmartPointer GetControlInterfaceBMode(); /** * \brief Default getter for the probes control interface. * Has to be implemented in a subclass if a probes control interface is * available. Default implementation returns null. * * \return null pointer */ virtual itk::SmartPointer GetControlInterfaceProbes(); /** * \brief Default getter for the doppler control interface. * Has to be implemented in a subclass if a doppler control interface is * available. Default implementation returns null. * * \return null pointer */ virtual itk::SmartPointer GetControlInterfaceDoppler(); /** * \brief Changes device state to mitk::USDevice::State_Initialized. * During initialization the virtual method * mitk::USDevice::OnInitialization will be called. If this method * returns false the initialization process will be canceled. Otherwise * the mitk::USDevice is registered in a micro service. */ bool Initialize(); /** * \brief Connects this device. A connected device is ready to deliver images (i.e. be Activated). A Connected Device can be active. A disconnected Device cannot be active. * Internally calls onConnect and then registers the device with the service. A device usually should * override the OnConnection() method, but never the Connect() method, since this will possibly exclude the device * from normal service management. The exact flow of events is: * 0. Check if the device is already connected. If yes, return true anyway, but don't do anything. * 1. Call OnConnection() Here, a device should establish it's connection with the hardware Afterwards, it should be ready to start transmitting images at any time. * 2. If OnConnection() returns true ("successful"), then the device is registered with the service. * 3. if not, it the method itself returns false or may throw an expection, depeneding on the device implementation. * */ bool Connect(); void ConnectAsynchron(); /** * \brief Works analogously to mitk::USDevice::Connect(). Don't override this Method, but onDisconnection instead. */ bool Disconnect(); /** * \brief Activates this device. * After the activation process, the device will start to produce images. * This Method will fail, if the device is not connected. */ bool Activate(); /** * \brief Deactivates this device. * After the deactivation process, the device will no longer produce * images, but still be connected. */ void Deactivate(); /** * \brief Can toggle if ultrasound image is currently updated or freezed. * * \param freeze true to stop updating the ultrasound image, false to start updating again */ virtual void SetIsFreezed(bool freeze); /** * \return true if device is currently freezed (no image update is done), false otherwise */ virtual bool GetIsFreezed(); void PushFilter(AbstractOpenCVImageFilter::Pointer filter); void PushFilterIfNotPushedBefore(AbstractOpenCVImageFilter::Pointer filter); bool RemoveFilter(AbstractOpenCVImageFilter::Pointer filter); /** * @brief To be called when the used probe changed. Will update the service properties * @param probename of the now used probe */ void ProbeChanged(std::string probename); /** * @brief To be called when the scanning depth of the probe changed. Will update the service properties * @param depth that is now used */ void DepthChanged(double depth); /** * \brief Given property is updated in the device micro service. * This method is mainly for being used by the control interface * superclasses. You do not need to call it by yoursefs in your * concrete control interface classes. */ void UpdateServiceProperty(std::string key, std::string value); void UpdateServiceProperty(std::string key, double value); void UpdateServiceProperty(std::string key, bool value); //########### GETTER & SETTER ##################// /** * \brief Returns the Class of the Device. This Method must be reimplemented by every Inheriting Class. */ virtual std::string GetDeviceClass() = 0; /** * \brief True, if the device object is created and initialized, false otherwise. */ bool GetIsInitialized(); /** * \brief True, if the device is currently generating image data, false otherwise. */ bool GetIsActive(); /** * \brief True, if the device is currently ready to start transmitting image data or is already * transmitting image data. A disconnected device cannot be activated. */ bool GetIsConnected(); /* @return Returns the area that will be cropped from the US image. Is disabled / [0,0,0,0] by default. */ mitk::USDevice::USImageCropArea GetCropArea(); /* @return Returns the size of the m_ImageVector of the ultrasound device.*/ unsigned int GetSizeOfImageVector(); /** @return Returns the current image source of this device. */ virtual USImageSource::Pointer GetUSImageSource() = 0; /** \brief Deprecated -> use GetManufacturer() instead */ DEPRECATED(std::string GetDeviceManufacturer()); /** \brief Deprecated -> use GetName() instead */ DEPRECATED(std::string GetDeviceModel()); /** \brief Deprecated -> use GetCommend() instead */ DEPRECATED(std::string GetDeviceComment()); itkGetMacro(Manufacturer, std::string); itkGetMacro(Name, std::string); itkGetMacro(Comment, std::string); void SetManufacturer(std::string manufacturer); void SetName(std::string name); void SetComment(std::string comment); itkGetMacro(DeviceState, DeviceStates) - itkGetMacro(ServiceProperties, us::ServiceProperties) + itkGetMacro(ServiceProperties, us::ServiceProperties) - void GrabImage(); + void GrabImage(); virtual void SetSpacing(double xSpacing, double ySpacing); protected: // Threading-Related itk::ConditionVariable::Pointer m_FreezeBarrier; itk::SimpleMutexLock m_FreezeMutex; itk::MultiThreader::Pointer m_MultiThreader; ///< itk::MultiThreader used for thread handling itk::FastMutexLock::Pointer m_ImageMutex; ///< mutex for images provided by the image source int m_ThreadID; ///< ID of the started thread virtual void SetImageVector(std::vector vec) { if (this->m_ImageVector != vec) { this->m_ImageVector = vec; this->Modified(); } } static ITK_THREAD_RETURN_TYPE Acquire(void* pInfoStruct); static ITK_THREAD_RETURN_TYPE ConnectThread(void* pInfoStruct); std::vector m_ImageVector; - //mitk::Image::Pointer m_OutputImage; // Variables to determine if spacing was calibrated and needs to be applied to the incoming images mitk::Vector3D m_Spacing; /** * \brief Registers an OpenIGTLink device as a microservice so that we can send the images of * this device via the network. */ void ProvideViaOIGTL(); /** * \brief Deregisters the microservices for OpenIGTLink. */ void DisableOIGTL(); mitk::IGTLServer::Pointer m_IGTLServer; mitk::IGTLMessageProvider::Pointer m_IGTLMessageProvider; mitk::ImageToIGTLMessageFilter::Pointer m_ImageToIGTLMsgFilter; bool m_IsFreezed; DeviceStates m_DeviceState; /* @brief defines the area that should be cropped from the US image */ USImageCropArea m_CropArea; /** * \brief This Method constructs the service properties which can later be used to * register the object with the Microservices * Return service properties */ us::ServiceProperties ConstructServiceProperties(); /** * \brief Remove this device from the micro service. */ void UnregisterOnService(); /** * \brief Is called during the initialization process. * Override this method in a subclass to handle the actual initialization. * If it returns false, the initialization process will be canceled. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnInitialization() = 0; /** * \brief Is called during the connection process. * Override this method in a subclass to handle the actual connection. * If it returns false, the connection process will be canceled. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnConnection() = 0; /** * \brief Is called during the disconnection process. * Override this method in a subclass to handle the actual disconnection. * If it returns false, the disconnection process will be canceled. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnDisconnection() = 0; /** * \brief Is called during the activation process. * After this method is finished, the device should be generating images. * If it returns false, the activation process will be canceled. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnActivation() = 0; /** * \brief Is called during the deactivation process. * After a call to this method the device should still be connected, * but not producing images anymore. * * \return true if successful and false if unsuccessful * \throw mitk::Exception implementation may throw an exception to clarify what went wrong */ virtual bool OnDeactivation() = 0; /** * \brief Called when mitk::USDevice::SetIsFreezed() is called. * Subclasses can overwrite this method to do additional actions. Default * implementation does noting. */ virtual void OnFreeze(bool) { } /** * \brief Enforces minimal Metadata to be set. */ USDevice(std::string manufacturer, std::string model); /** * \brief Constructs a device with the given Metadata. Make sure the Metadata contains meaningful content! * \deprecated Use USDevice(std::string manufacturer, std::string model) instead. */ USDevice(mitk::USImageMetadata::Pointer metadata); ~USDevice() override; /** * \brief Grabs the next frame from the Video input. * This method is called internally, whenever Update() is invoked by an Output. */ void GenerateData() override; std::string GetServicePropertyLabel(); unsigned int m_NumberOfOutputs; /** * \brief Properties of the device's Microservice. */ us::ServiceProperties m_ServiceProperties; /** * \brief The device's ServiceRegistration object that allows to modify it's Microservice registraton details. */ us::ServiceRegistration m_ServiceRegistration; private: std::string m_Manufacturer; std::string m_Name; std::string m_Comment; bool m_SpawnAcquireThread; bool m_UnregisteringStarted; }; } // namespace mitk // This is the microservice declaration. Do not meddle! MITK_DECLARE_SERVICE_INTERFACE(mitk::USDevice, "org.mitk.services.UltrasoundDevice") #endif // MITKUSDevice_H_HEADER_INCLUDED_ diff --git a/Modules/US/USModel/mitkUSDevicePersistence.cpp b/Modules/US/USModel/mitkUSDevicePersistence.cpp index faf69c1c47..00920465ea 100644 --- a/Modules/US/USModel/mitkUSDevicePersistence.cpp +++ b/Modules/US/USModel/mitkUSDevicePersistence.cpp @@ -1,345 +1,343 @@ /*=================================================================== 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 "mitkUSDevicePersistence.h" //Microservices #include #include #include #include #include mitk::USDevicePersistence::USDevicePersistence() : m_devices("MITK US", "Device Settings") { } void mitk::USDevicePersistence::StoreCurrentDevices() { us::ModuleContext* thisContext = us::GetModuleContext(); std::vector > services = thisContext->GetServiceReferences(); MITK_INFO << "Trying to save " << services.size() << " US devices."; int numberOfSavedDevices = 0; for (std::vector >::iterator it = services.begin(); it != services.end(); ++it) { mitk::USDevice::Pointer currentDevice = thisContext->GetService(*it); //check if it is a USVideoDevice if (currentDevice->GetDeviceClass() == "org.mitk.modules.us.USVideoDevice") { mitk::USVideoDevice::Pointer currentVideoDevice = dynamic_cast(currentDevice.GetPointer()); QString identifier = "device" + QString::number(numberOfSavedDevices); m_devices.setValue(identifier, USVideoDeviceToString(currentVideoDevice)); numberOfSavedDevices++; } else { MITK_WARN << "Saving of US devices of the type " << currentDevice->GetDeviceClass() << " is not supported at the moment. Skipping device."; } } m_devices.setValue("numberOfSavedDevices", numberOfSavedDevices); MITK_INFO << "Successfully saved " << numberOfSavedDevices << " US devices."; } std::vector mitk::USDevicePersistence::RestoreLastDevices() { std::vector devices; int numberOfSavedDevices = m_devices.value("numberOfSavedDevices").toInt(); for (int i = 0; i < numberOfSavedDevices; i++) { // Try each device. If an exception occurs: Ignore device and notify user try { QString currentString = m_devices.value("device" + QString::number(i)).toString(); mitk::USDevice::Pointer currentDevice = dynamic_cast(StringToUSVideoDevice(currentString).GetPointer()); //currentDevice->Initialize(); devices.push_back(currentDevice.GetPointer()); } catch (...) { MITK_ERROR << "Error occured while loading a USVideoDevice from persistence. Device assumed corrupt, will be deleted."; //QMessageBox::warning(nullptr, "Could not load device" ,"A stored ultrasound device is corrupted and could not be loaded. The device will be deleted."); } } MITK_INFO << "Restoring " << numberOfSavedDevices << " US devices."; return devices; } QString mitk::USDevicePersistence::USVideoDeviceToString(mitk::USVideoDevice::Pointer d) { QString manufacturer = d->GetManufacturer().c_str(); QString model = d->GetName().c_str(); QString comment = d->GetComment().c_str(); int source = d->GetDeviceID(); std::string file = d->GetFilePath(); if (!d->GetIsSourceFile()) file = "none"; //if GetIsSourceFile is true, the device plays back a file mitk::USImageVideoSource::Pointer imageSource = dynamic_cast(d->GetUSImageSource().GetPointer()); if (!imageSource) { MITK_ERROR << "There is no USImageVideoSource at the current device."; mitkThrow() << "There is no USImageVideoSource at the current device."; } int greyscale = imageSource->GetIsGreyscale(); int resOverride = imageSource->GetResolutionOverride(); int resWidth = imageSource->GetResolutionOverrideWidth(); int resHight = imageSource->GetResolutionOverrideHeight(); - mitk::USImageVideoSource::USImageRoi roi = imageSource->GetRegionOfInterest(); - QString probes = ""; //ACV$100%1%1%0$120%2%2%0$140%2%2%5!BDW$90%1%1%2$100%1%1%8!CSV$50%1%2%3$60%2%2%5 char probesSeperator = '!'; std::vector allProbesOfDevice = d->GetAllProbes(); if (allProbesOfDevice.size() > 0) { for (std::vector::iterator it = allProbesOfDevice.begin(); it != allProbesOfDevice.end(); it++) { if (it == allProbesOfDevice.begin()) { // if it is the first element there is no need for the probes seperator probes = probes + USProbeToString(*it); } else { probes = probes + probesSeperator + USProbeToString(*it); } } } char seperator = '|'; QString returnValue = manufacturer + seperator + model + seperator + comment + seperator + QString::number(source) + seperator + file.c_str() + seperator + QString::number(greyscale) + seperator + QString::number(resOverride) + seperator + QString::number(resWidth) + seperator + QString::number(resHight) + seperator + probes ; MITK_INFO << "Output String: " << returnValue.toStdString(); return returnValue; } QString mitk::USDevicePersistence::USProbeToString(mitk::USProbe::Pointer p) { QString probe = QString::fromStdString(p->GetName()); QString croppingSeparator = QString(","); probe = probe + croppingSeparator + QString::number(p->GetProbeCropping().top) + croppingSeparator + QString::number(p->GetProbeCropping().right) + croppingSeparator + QString::number(p->GetProbeCropping().bottom) + croppingSeparator + QString::number(p->GetProbeCropping().left) + croppingSeparator; char depthSeperator = '$'; char spacingSeperator = '%'; std::map depthsAndSpacing = p->GetDepthsAndSpacing(); if (depthsAndSpacing.size() > 0) { for (std::map::iterator it = depthsAndSpacing.begin(); it != depthsAndSpacing.end(); it++){ probe = probe + depthSeperator + QString::number(it->first) + spacingSeperator + QString::number(it->second[0]) + spacingSeperator + QString::number(it->second[1]) + spacingSeperator + QString::number(it->second[2]); } } return probe; } mitk::USVideoDevice::Pointer mitk::USDevicePersistence::StringToUSVideoDevice(QString s) { MITK_INFO << "Input String: " << s.toStdString(); std::vector data; std::string seperators = "|"; std::string text = s.toStdString(); split(text, seperators, data); if (data.size() != 10) { MITK_ERROR << "Cannot parse US device! (Size: " << data.size() << ")"; return mitk::USVideoDevice::New("INVALID", "INVALID", "INVALID"); } std::string manufacturer = data.at(0); std::string model = data.at(1); std::string comment = data.at(2); int source = (QString(data.at(3).c_str())).toInt(); std::string file = data.at(4); bool greyscale = (QString(data.at(5).c_str())).toInt(); bool resOverride = (QString(data.at(6).c_str())).toInt(); int resWidth = (QString(data.at(7).c_str())).toInt(); int resHight = (QString(data.at(8).c_str())).toInt(); // Create Device mitk::USVideoDevice::Pointer returnValue; if (file == "none") { returnValue = mitk::USVideoDevice::New(source, manufacturer, model); returnValue->SetComment(comment); } else { returnValue = mitk::USVideoDevice::New(file, manufacturer, model); returnValue->SetComment(comment); } mitk::USImageVideoSource::Pointer imageSource = dynamic_cast(returnValue->GetUSImageSource().GetPointer()); if (!imageSource) { MITK_ERROR << "There is no USImageVideoSource at the current device."; mitkThrow() << "There is no USImageVideoSource at the current device."; } // Set Video Options imageSource->SetColorOutput(!greyscale); // If Resolution override is activated, apply it if (resOverride) { imageSource->OverrideResolution(resWidth, resHight); imageSource->SetResolutionOverride(true); } std::string probes = data.at(9); std::string probesSeperator = "!"; std::vector probesVector; split(probes, probesSeperator, probesVector); for (std::vector::iterator it = probesVector.begin(); it != probesVector.end(); it++) { mitk::USProbe::Pointer probe = StringToUSProbe(*it); returnValue->AddNewProbe(probe); } return returnValue; } mitk::USProbe::Pointer mitk::USDevicePersistence::StringToUSProbe(std::string s) { mitk::USProbe::Pointer probe = mitk::USProbe::New(); std::string croppingSeparator = ","; std::string spacingSeperator = "%"; std::string depthSeperator = "$"; std::vector probeCropping; split(s, croppingSeparator, probeCropping); std::vector depthsWithSpacings; split(s, depthSeperator, depthsWithSpacings); //The first entry of the probeCropping vector is the name of the ultrasound probe: std::string probeName = probeCropping.at(0); probe->SetName(probeName); //The entries 1, 2, 3 and 4 of the probeCropping vector are the cropping top, // right, bottom and left: if( probeCropping.size() >= 6 ) { QString top = QString::fromStdString(probeCropping.at(1)); QString right = QString::fromStdString(probeCropping.at(2)); QString bottom = QString::fromStdString(probeCropping.at(3)); QString left = QString::fromStdString(probeCropping.at(4)); probe->SetProbeCropping(top.toUInt(), bottom.toUInt(), left.toUInt(), right.toUInt()); } for (std::vector::iterator it = depthsWithSpacings.begin(); it != depthsWithSpacings.end(); it++) { //The first element is the name of the probe and the cropping entries. //other elements are the scanning depths of the probe and the spacing if (it != depthsWithSpacings.begin()) { std::vector spacings; split(*it, spacingSeperator, spacings); mitk::Vector3D spacing; double x; double y; double z; int depth; try { x = spacingToDouble(spacings.at(1)); y = spacingToDouble(spacings.at(2)); z = spacingToDouble(spacings.at(3)); } catch (const mitk::Exception& e) { MITK_ERROR << e.GetDescription() << "Spacing of " << probe->GetName() << " at depth " << spacings.at(0) << " will be set to default value 1,1,0."; x = 1; y = 1; z = 1; } spacing[0] = x; spacing[1] = y; spacing[2] = z; try { depth = depthToInt(spacings.at(0)); } catch (const mitk::Exception& e) { MITK_ERROR << probe->GetName() << ": " << e.GetDescription(); continue; } probe->SetDepthAndSpacing(depth, spacing); } } return probe; } void mitk::USDevicePersistence::split(std::string& text, std::string& separators, std::vector& words) { int n = text.length(); int start, stop; start = text.find_first_not_of(separators); while ((start >= 0) && (start < n)) { stop = text.find_first_of(separators, start); if ((stop < 0) || (stop > n)) stop = n; words.push_back(text.substr(start, stop - start)); start = text.find_first_not_of(separators, stop + 1); } } double mitk::USDevicePersistence::spacingToDouble(std::string s) { std::istringstream i(s); double x; if (!(i >> x)) { //something went wrong because the string contains characters which can not be convertet into double mitkThrow() << "An error occured while trying to recover the spacing."; } return x; } int mitk::USDevicePersistence::depthToInt(std::string s) { std::istringstream i(s); int x; if (!(i >> x)) { //something went wrong because the string contains characters which can not be convertet into int mitkThrow() << "An error occured while trying to recover the scanning depth. " << s << " is not a valid scanning depth. "; } return x; } diff --git a/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp b/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp index 8b72ad79a4..7c3dcfdbb3 100644 --- a/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp +++ b/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.cpp @@ -1,811 +1,811 @@ /*=================================================================== 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. ===================================================================*/ //#define _USE_MATH_DEFINES #include // QT headers #include #include // mitk headers // itk headers #include #include const std::string QmitkUSNewVideoDeviceWidget::VIEW_ID = "org.mitk.views.QmitkUSNewVideoDeviceWidget"; QmitkUSNewVideoDeviceWidget::QmitkUSNewVideoDeviceWidget(QWidget* parent, Qt::WindowFlags f) : QWidget(parent, f) { m_Controls = nullptr; CreateQtPartControl(this); } QmitkUSNewVideoDeviceWidget::~QmitkUSNewVideoDeviceWidget() {} //////////////////// INITIALIZATION ///////////////////// void QmitkUSNewVideoDeviceWidget::CreateQtPartControl(QWidget* parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkUSNewVideoDeviceWidgetControls; m_Controls->setupUi(parent); this->CreateConnections(); } } void QmitkUSNewVideoDeviceWidget::CreateConnections() { if (m_Controls) { // connect(m_Controls->m_BtnDone, SIGNAL(clicked()), this, // SLOT(OnClickedDone())); connect(m_Controls->m_BtnCancel, SIGNAL(clicked()), this, SLOT(OnClickedCancel())); connect(m_Controls->m_RadioDeviceSource, SIGNAL(clicked()), this, SLOT(OnDeviceTypeSelection())); connect(m_Controls->m_RadioFileSource, SIGNAL(clicked()), this, SLOT(OnDeviceTypeSelection())); connect(m_Controls->m_RadioOIGTLClientSource, SIGNAL(clicked()), this, SLOT(OnDeviceTypeSelection())); connect(m_Controls->m_RadioOIGTLServerSource, SIGNAL(clicked()), this, SLOT(OnDeviceTypeSelection())); connect(m_Controls->m_OpenFileButton, SIGNAL(clicked()), this, SLOT(OnOpenFileButtonClicked())); connect(m_Controls->m_BtnSave, SIGNAL(clicked()), this, SLOT(OnSaveButtonClicked())); connect(m_Controls->m_BtnLoadConfiguration, SIGNAL(clicked()), this, SLOT(OnLoadConfigurationButtonClicked())); //Connect buttons and functions for editing of probes connect(m_Controls->m_AddNewProbePushButton, SIGNAL(clicked()), this, SLOT(OnAddNewProbeClicked())); connect(m_Controls->m_BtnRemoveProbe, SIGNAL(clicked()), this, SLOT(OnClickedRemoveProbe())); connect(m_Controls->m_BtnRemoveDepth, SIGNAL(clicked()), this, SLOT(OnClickedRemoveDepth())); connect(m_Controls->m_BtnAddDepths, SIGNAL(clicked()), this, SLOT(OnClickedAddDepths())); connect(m_Controls->m_Probes, SIGNAL(currentTextChanged(const QString &)), this, SLOT(OnProbeChanged(const QString &))); connect(m_Controls->m_Depths, SIGNAL(currentTextChanged(const QString &)), this, SLOT(OnDepthChanged(const QString &))); connect(m_Controls->m_XSpacingSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnXSpacingSpinBoxChanged(double))); connect(m_Controls->m_YSpacingSpinBox, SIGNAL(valueChanged(double)), this, SLOT(OnYSpacingSpinBoxChanged(double))); connect(m_Controls->m_CroppingTopSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnCroppingTopSpinBoxChanged(int))); connect(m_Controls->m_CroppingRightSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnCroppingRightSpinBoxChanged(int))); connect(m_Controls->m_CroppingBottomSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnCroppingBottomSpinBoxChanged(int))); connect(m_Controls->m_CroppingLeftSpinBox, SIGNAL(valueChanged(int)), this, SLOT(OnCroppingLeftSpinBoxChanged(int))); } } ///////////// Methods & Slots Handling Direct Interaction ///////////////// void QmitkUSNewVideoDeviceWidget::OnClickedDone() { m_Active = false; // Create Device mitk::USVideoDevice::Pointer newDevice; if (m_Controls->m_RadioDeviceSource->isChecked()) { newDevice = mitk::USVideoDevice::New( m_Controls->m_DeviceSelector->value(), m_Controls->m_Manufacturer->text().toStdString(), m_Controls->m_Model->text().toStdString()); newDevice->SetComment(m_Controls->m_Comment->text().toStdString()); } else if (m_Controls->m_RadioFileSource->isChecked()) { newDevice = mitk::USVideoDevice::New( m_Controls->m_FilePathSelector->text().toStdString(), m_Controls->m_Manufacturer->text().toStdString(), m_Controls->m_Model->text().toStdString()); newDevice->SetComment(m_Controls->m_Comment->text().toStdString()); } else if (m_Controls->m_RadioOIGTLClientSource->isChecked()) { std::string host = m_Controls->m_OIGTLClientHost->text().toStdString(); int port = m_Controls->m_OIGTLClientPort->value(); // Create a new USIGTLDevice. The last parameter tells the device that it should be a client. mitk::USIGTLDevice::Pointer device = mitk::USIGTLDevice::New(m_Controls->m_Manufacturer->text().toStdString(), m_Controls->m_Model->text().toStdString(), host, port, false); device->Initialize(); emit Finished(); // The rest of this method does stuff that is specific to USVideoDevices, // which we don't need. So we return directly. return; } else { std::string host = m_Controls->m_OIGTLServerHost->text().toStdString(); int port = m_Controls->m_OIGTLServerPort->value(); // Create a new USIGTLDevice. The last parameter tells the device that it should be a server. mitk::USIGTLDevice::Pointer device = mitk::USIGTLDevice::New(m_Controls->m_Manufacturer->text().toStdString(), m_Controls->m_Model->text().toStdString(), host, port, true); device->Initialize(); emit Finished(); // The rest of this method does stuff that is specific to USVideoDevices, // which we don't need. So we return directly. return; } // get USImageVideoSource from new device mitk::USImageVideoSource::Pointer imageSource = dynamic_cast( newDevice->GetUSImageSource().GetPointer()); if (!imageSource) { MITK_ERROR << "There is no USImageVideoSource at the current device."; mitkThrow() << "There is no USImageVideoSource at the current device."; } // Set Video Options imageSource->SetColorOutput(!m_Controls->m_CheckGreyscale->isChecked()); // If Resolution override is activated, apply it if (m_Controls->m_CheckResolutionOverride->isChecked()) { int width = m_Controls->m_ResolutionWidth->value(); int height = m_Controls->m_ResolutionHeight->value(); imageSource->OverrideResolution(width, height); imageSource->SetResolutionOverride(true); } if (m_Controls->m_Probes->count() != 0 ) //there are informations about the probes of the device, so create the probes { this->AddProbesToDevice(newDevice); } else //no information about the probes of the device, so set default value { mitk::USProbe::Pointer probe = mitk::USProbe::New("default"); probe->SetDepth(0); newDevice->DeleteAllProbes(); newDevice->AddNewProbe(probe); } newDevice->Initialize(); CleanUpAfterCreatingNewDevice(); emit Finished(); } void QmitkUSNewVideoDeviceWidget::OnClickedFinishedEditing() { m_Active = false; m_TargetDevice->SetManufacturer(m_Controls->m_Manufacturer->text().toStdString()); m_TargetDevice->SetName(m_Controls->m_Model->text().toStdString()); m_TargetDevice->SetComment(m_Controls->m_Comment->text().toStdString()); if (m_Controls->m_Probes->count() != 0) //there are informations about the probes of the device, so create the probes { this->AddProbesToDevice(m_TargetDevice); } else //no information about the probes of the device, so set default value { mitk::USProbe::Pointer probe = mitk::USProbe::New("default"); probe->SetDepth(0); m_TargetDevice->DeleteAllProbes(); m_TargetDevice->AddNewProbe(probe); } mitk::USImageVideoSource::Pointer imageSource = dynamic_cast( m_TargetDevice->GetUSImageSource().GetPointer()); if (!imageSource) { MITK_ERROR << "There is no USImageVideoSource at the current device."; mitkThrow() << "There is no USImageVideoSource at the current device."; } // Set Video Options imageSource->SetColorOutput(!m_Controls->m_CheckGreyscale->isChecked()); // If Resolution override is activated, apply it if (m_Controls->m_CheckResolutionOverride->isChecked()) { int width = m_Controls->m_ResolutionWidth->value(); int height = m_Controls->m_ResolutionHeight->value(); imageSource->OverrideResolution(width, height); imageSource->SetResolutionOverride(true); } CleanUpAfterEditingOfDevice(); MITK_INFO << "Finished Editing"; emit Finished(); } void QmitkUSNewVideoDeviceWidget::OnClickedCancel() { m_TargetDevice = nullptr; m_Active = false; CleanUpAfterCreatingNewDevice(); CleanUpAfterEditingOfDevice(); emit Finished(); } void QmitkUSNewVideoDeviceWidget::OnDeviceTypeSelection() { m_Controls->m_FilePathSelector->setEnabled( m_Controls->m_RadioFileSource->isChecked()); m_Controls->m_DeviceSelector->setEnabled( m_Controls->m_RadioDeviceSource->isChecked()); m_Controls->m_OIGTLClientHost->setEnabled( m_Controls->m_RadioOIGTLClientSource->isChecked()); m_Controls->m_OIGTLClientPort->setEnabled( m_Controls->m_RadioOIGTLClientSource->isChecked()); m_Controls->m_OIGTLServerHost->setEnabled( m_Controls->m_RadioOIGTLServerSource->isChecked()); m_Controls->m_OIGTLServerPort->setEnabled( m_Controls->m_RadioOIGTLServerSource->isChecked()); } void QmitkUSNewVideoDeviceWidget::OnOpenFileButtonClicked() { QString fileName = QFileDialog::getOpenFileName(nullptr, "Open Video File"); if (fileName.isNull()) { return; } // user pressed cancel m_Controls->m_FilePathSelector->setText(fileName); m_Controls->m_RadioFileSource->setChecked(true); this->OnDeviceTypeSelection(); } ///////////////// Methods & Slots Handling Logic ////////////////////////// void QmitkUSNewVideoDeviceWidget::EditDevice(mitk::USDevice::Pointer device) { // If no VideoDevice is given, throw an exception if (device->GetDeviceClass().compare("org.mitk.modules.us.USVideoDevice") != 0) { // TODO Alert if bad path mitkThrow() << "NewVideoDeviceWidget recieved an incompatible device type " "to edit. Type was: " << device->GetDeviceClass(); } m_TargetDevice = static_cast(device.GetPointer()); m_Active = true; m_ConfigProbes.clear(); m_ConfigProbes = m_TargetDevice->GetAllProbes(); ChangeUIEditingUSVideoDevice(); } void QmitkUSNewVideoDeviceWidget::CreateNewDevice() { //Toggle functionality of Btn_Done connect(m_Controls->m_BtnDone, SIGNAL(clicked()), this, SLOT(OnClickedDone())); m_Controls->m_BtnDone->setText("Add Video Device"); //Fill Metadata with default information m_Controls->m_Manufacturer->setText("Unknown Manufacturer"); m_Controls->m_Model->setText("Unknown Model"); m_Controls->m_Comment->setText("None"); m_TargetDevice = nullptr; m_ConfigProbes.clear(); m_Active = true; } /////////////////////// HOUSEHOLDING CODE /////////////////////////////// QListWidgetItem* QmitkUSNewVideoDeviceWidget::ConstructItemFromDevice( mitk::USDevice::Pointer device) { QListWidgetItem* result = new QListWidgetItem; std::string text = device->GetManufacturer() + "|" + device->GetName(); result->setText(text.c_str()); return result; } void QmitkUSNewVideoDeviceWidget::ChangeUIEditingUSVideoDevice() { for (std::vector::iterator it = m_ConfigProbes.begin(); it != m_ConfigProbes.end(); it++) { std::string probeName = (*it)->GetName(); m_Controls->m_Probes->addItem(QString::fromUtf8(probeName.data(), probeName.size())); } OnProbeChanged(m_Controls->m_Probes->currentText()); //Toggle functionality of Btn_Done m_Controls->m_BtnDone->setText("Apply Changes"); connect(m_Controls->m_BtnDone, SIGNAL(clicked()), this, SLOT(OnClickedFinishedEditing())); //Fill Metadata with Information provided by the Device selected to edit m_Controls->m_Manufacturer->setText(m_TargetDevice->GetManufacturer().c_str()); m_Controls->m_Model->setText(m_TargetDevice->GetName().c_str()); m_Controls->m_Comment->setText(m_TargetDevice->GetComment().c_str()); } void QmitkUSNewVideoDeviceWidget::OnClickedAddDepths() { if (!m_Controls->m_Probes->currentText().isEmpty()) { QString depths = m_Controls->m_AddDepths->text(); if( depths.isEmpty() ) return; std::string probename = m_Controls->m_Probes->currentText().toStdString(); mitk::USProbe::Pointer currentProbe = this->CheckIfProbeExistsAlready(probename); QStringList singleDepths = depths.split(','); for (int i = 0; i < singleDepths.size(); i++) { currentProbe->SetDepth(singleDepths.at(i).toInt()); } m_Controls->m_AddDepths->clear(); m_Controls->m_Depths->setEnabled(true); m_Controls->m_BtnRemoveDepth->setEnabled(true); OnProbeChanged(m_Controls->m_Probes->currentText()); } } void QmitkUSNewVideoDeviceWidget::OnClickedRemoveDepth() { if (!m_Controls->m_Probes->currentText().isEmpty() && !m_Controls->m_Depths->currentText().isEmpty()) { std::string probename = m_Controls->m_Probes->currentText().toStdString(); int indexOfDepthToRemove = m_Controls->m_Depths->currentIndex(); mitk::USProbe::Pointer currentProbe = this->CheckIfProbeExistsAlready(probename); currentProbe->RemoveDepth(m_Controls->m_Depths->currentText().toInt()); m_Controls->m_Depths->removeItem(indexOfDepthToRemove); if (m_Controls->m_Depths->count() == 0) { m_Controls->m_Depths->setEnabled(false); m_Controls->m_BtnRemoveDepth->setEnabled(false); this->EnableDisableSpacingAndCropping(false); } } } void QmitkUSNewVideoDeviceWidget::OnClickedRemoveProbe() { if (!m_Controls->m_Probes->currentText().isEmpty()) { std::string probename = m_Controls->m_Probes->currentText().toStdString(); int indexOfProbeToRemove = m_Controls->m_Probes->currentIndex(); m_ConfigProbes.erase(m_ConfigProbes.begin() + indexOfProbeToRemove); m_Controls->m_Probes->removeItem(indexOfProbeToRemove); if( m_Controls->m_Probes->count() == 0 ) { m_Controls->m_Probes->setEnabled(false); m_Controls->m_BtnRemoveProbe->setEnabled(false); m_Controls->m_BtnAddDepths->setEnabled(false); m_Controls->m_AddDepths->setEnabled(false); m_Controls->m_Depths->setEnabled(false); m_Controls->m_BtnRemoveDepth->setEnabled(false); this->EnableDisableSpacingAndCropping(false); } } } void QmitkUSNewVideoDeviceWidget::OnProbeChanged(const QString & probename) { if (!probename.isEmpty()) { std::string name = probename.toStdString(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(name); if( probe.IsNotNull() ) { std::map depths = probe->GetDepthsAndSpacing(); m_Controls->m_Depths->clear(); for (std::map::iterator it = depths.begin(); it != depths.end(); it++) { m_Controls->m_Depths->addItem(QString::number(it->first)); } this->OnDepthChanged(m_Controls->m_Depths->currentText().toInt(), probe); } } else { m_Controls->m_Depths->clear(); m_Controls->m_Depths->setEnabled(false); m_Controls->m_BtnRemoveDepth->setEnabled(false); } } -void QmitkUSNewVideoDeviceWidget::OnDepthChanged(int depth, mitk::USProbe* probe) +void QmitkUSNewVideoDeviceWidget::OnDepthChanged(int depth, mitk::USProbe::Pointer probe) { if (m_Controls->m_Depths->count() == 0) { m_Controls->m_Depths->setEnabled(false); m_Controls->m_BtnRemoveDepth->setEnabled(false); this->EnableDisableSpacingAndCropping(false); return; } - if (probe != nullptr) + if (probe.IsNotNull()) { mitk::Vector3D spacing = probe->GetSpacingForGivenDepth(depth); m_Controls->m_XSpacingSpinBox->setValue(spacing[0]); m_Controls->m_YSpacingSpinBox->setValue(spacing[1]); mitk::USProbe::USProbeCropping cropping = probe->GetProbeCropping(); m_Controls->m_CroppingTopSpinBox->setValue(cropping.top); m_Controls->m_CroppingRightSpinBox->setValue(cropping.right); m_Controls->m_CroppingBottomSpinBox->setValue(cropping.bottom); m_Controls->m_CroppingLeftSpinBox->setValue(cropping.left); this->EnableDisableSpacingAndCropping(true); m_Controls->m_Depths->setEnabled(true); m_Controls->m_BtnRemoveDepth->setEnabled(true); m_Controls->m_AddDepths->setEnabled(true); m_Controls->m_BtnAddDepths->setEnabled(true); m_Controls->m_Probes->setEnabled(true); m_Controls->m_BtnRemoveProbe->setEnabled(true); } } void QmitkUSNewVideoDeviceWidget::OnDepthChanged(const QString &depth) { MITK_INFO << "OnDepthChanged(int, mitk::USProbe)"; if( depth.isEmpty() ) { this->EnableDisableSpacingAndCropping(false); return; } QString probeName = m_Controls->m_Probes->currentText(); this->OnDepthChanged(depth.toInt(), this->CheckIfProbeExistsAlready(probeName.toStdString()) ); } void QmitkUSNewVideoDeviceWidget::OnSaveButtonClicked() { QString fileName = QFileDialog::getSaveFileName(nullptr, "Save Configuration ...", "", "XML files (*.xml)"); if( fileName.isNull() ) { return; } // user pressed cancel mitk::USDeviceWriterXML deviceWriter; deviceWriter.SetFilename(fileName.toStdString()); mitk::USDeviceReaderXML::USVideoDeviceConfigData config; this->CollectUltrasoundVideoDeviceConfigInformation(config); if (!deviceWriter.WriteUltrasoundVideoDeviceConfiguration(config)) { QMessageBox msgBox; msgBox.setText("Error when writing the configuration to the selected file. Could not write device information."); msgBox.exec(); return; } } void QmitkUSNewVideoDeviceWidget::OnLoadConfigurationButtonClicked() { QString fileName = QFileDialog::getOpenFileName(this, "Open ultrasound device configuration ..."); if (fileName.isNull()) { return; } // user pressed cancel mitk::USDeviceReaderXML deviceReader; deviceReader.SetFilename(fileName.toStdString()); if (!deviceReader.ReadUltrasoundDeviceConfiguration()) { QMessageBox msgBox; msgBox.setText("Error when parsing the selected file. Could not load stored device information."); msgBox.exec(); return; } mitk::USDeviceReaderXML::USVideoDeviceConfigData config = deviceReader.GetUSVideoDeviceConfigData(); if( config.fileversion == 1.0 ) { if (config.deviceType.compare("video") == 0) { //Fill info in metadata groupbox: m_Controls->m_DeviceName->setText(QString::fromStdString(config.deviceName)); m_Controls->m_Manufacturer->setText(QString::fromStdString(config.manufacturer)); m_Controls->m_Model->setText(QString::fromStdString(config.model)); m_Controls->m_Comment->setText(QString::fromStdString(config.comment)); //Fill info about video source: m_Controls->m_DeviceSelector->setValue(config.sourceID); m_Controls->m_FilePathSelector->setText(QString::fromStdString(config.filepathVideoSource)); //Fill video options: m_Controls->m_CheckGreyscale->setChecked(config.useGreyscale); //Fill override options: m_Controls->m_CheckResolutionOverride->setChecked(config.useResolutionOverride); m_Controls->m_ResolutionWidth->setValue(config.resolutionWidth); m_Controls->m_ResolutionHeight->setValue(config.resolutionHeight); //Fill information about probes: m_ConfigProbes.clear(); m_ConfigProbes = config.probes; m_Controls->m_Probes->clear(); m_Controls->m_ProbeNameLineEdit->clear(); m_Controls->m_AddDepths->clear(); m_Controls->m_Depths->clear(); for( size_t index = 0; index < m_ConfigProbes.size(); ++index) { m_Controls->m_Probes->addItem(QString::fromStdString(config.probes.at(index)->GetName())); } this->OnProbeChanged(m_Controls->m_Probes->currentText()); } else { MITK_WARN << "Unknown device type detected. The device type must be of type |video|"; } } else { MITK_WARN << "Unknown fileversion. Only fileversion 1.0 is known to the system."; } } void QmitkUSNewVideoDeviceWidget::OnAddNewProbeClicked() { QString probeName = m_Controls->m_ProbeNameLineEdit->text(); probeName = probeName.trimmed(); if (probeName.isEmpty()) { m_Controls->m_ProbeNameLineEdit->clear(); return; } if( this->CheckIfProbeExistsAlready(probeName.toStdString() ) != nullptr ) { QMessageBox msgBox; msgBox.setText("Probe name already exists. Please choose another name for the probe."); msgBox.exec(); m_Controls->m_ProbeNameLineEdit->clear(); } else { mitk::USProbe::Pointer newProbe = mitk::USProbe::New(probeName.toStdString()); m_ConfigProbes.push_back(newProbe); m_Controls->m_Probes->addItem(QString::fromStdString(probeName.toStdString())); m_Controls->m_Probes->setEnabled(true); m_Controls->m_BtnRemoveProbe->setEnabled(true); m_Controls->m_BtnAddDepths->setEnabled(true); m_Controls->m_AddDepths->setEnabled(true); m_Controls->m_ProbeNameLineEdit->clear(); } } void QmitkUSNewVideoDeviceWidget::OnXSpacingSpinBoxChanged(double value) { MITK_INFO << "Changing x-spacing to: " << value; QString probeName = m_Controls->m_Probes->currentText(); int depth = m_Controls->m_Depths->currentText().toInt(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(probeName.toStdString()); if (probe.IsNull()) { QMessageBox msgBox; msgBox.setText("An error occurred when changing the spacing. \ The specified probe does not exist. \ Please restart the configuration process."); msgBox.exec(); return; } mitk::Vector3D spacing = probe->GetSpacingForGivenDepth(depth); spacing[0] = value; probe->SetSpacingForGivenDepth(depth, spacing); } void QmitkUSNewVideoDeviceWidget::OnYSpacingSpinBoxChanged(double value) { MITK_INFO << "Changing y-spacing to: " << value; QString probeName = m_Controls->m_Probes->currentText(); int depth = m_Controls->m_Depths->currentText().toInt(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(probeName.toStdString()); if (probe.IsNull()) { QMessageBox msgBox; msgBox.setText("An error occurred when changing the spacing. \ The specified probe does not exist. \ Please restart the configuration process."); msgBox.exec(); return; } mitk::Vector3D spacing = probe->GetSpacingForGivenDepth(depth); spacing[1] = value; probe->SetSpacingForGivenDepth(depth, spacing); } void QmitkUSNewVideoDeviceWidget::OnCroppingTopSpinBoxChanged(int value) { MITK_INFO << "Changing cropping top to: " << value; QString probeName = m_Controls->m_Probes->currentText(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(probeName.toStdString()); if (probe.IsNull()) { QMessageBox msgBox; msgBox.setText("An error occurred when changing the probe cropping. \ The specified probe does not exist. \ Please restart the configuration process."); msgBox.exec(); return; } mitk::USProbe::USProbeCropping cropping = probe->GetProbeCropping(); probe->SetProbeCropping(value, cropping.bottom, cropping.left, cropping.right); } void QmitkUSNewVideoDeviceWidget::OnCroppingRightSpinBoxChanged(int value) { MITK_INFO << "Changing cropping right to: " << value; QString probeName = m_Controls->m_Probes->currentText(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(probeName.toStdString()); if (probe.IsNull()) { QMessageBox msgBox; msgBox.setText("An error occurred when changing the probe cropping. \ The specified probe does not exist. \ Please restart the configuration process."); msgBox.exec(); return; } mitk::USProbe::USProbeCropping cropping = probe->GetProbeCropping(); probe->SetProbeCropping(cropping.top, cropping.bottom, cropping.left, value); } void QmitkUSNewVideoDeviceWidget::OnCroppingBottomSpinBoxChanged(int value) { MITK_INFO << "Changing cropping bottom to: " << value; QString probeName = m_Controls->m_Probes->currentText(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(probeName.toStdString()); if (probe.IsNull()) { QMessageBox msgBox; msgBox.setText("An error occurred when changing the probe cropping. \ The specified probe does not exist. \ Please restart the configuration process."); msgBox.exec(); return; } mitk::USProbe::USProbeCropping cropping = probe->GetProbeCropping(); probe->SetProbeCropping(cropping.top, value, cropping.left, cropping.right); } void QmitkUSNewVideoDeviceWidget::OnCroppingLeftSpinBoxChanged(int value) { MITK_INFO << "Changing cropping left to: " << value; QString probeName = m_Controls->m_Probes->currentText(); mitk::USProbe::Pointer probe = this->CheckIfProbeExistsAlready(probeName.toStdString()); if (probe.IsNull()) { QMessageBox msgBox; msgBox.setText("An error occurred when changing the probe cropping. \ The specified probe does not exist. \ Please restart the configuration process."); msgBox.exec(); return; } mitk::USProbe::USProbeCropping cropping = probe->GetProbeCropping(); probe->SetProbeCropping(cropping.top, cropping.bottom, value, cropping.right); } void QmitkUSNewVideoDeviceWidget::CleanUpAfterCreatingNewDevice() { disconnect(m_Controls->m_BtnDone, SIGNAL(clicked()), this, SLOT(OnClickedDone())); m_Controls->m_Probes->clear(); m_Controls->m_Depths->clear(); m_Controls->m_AddDepths->clear(); m_Controls->m_ProbeNameLineEdit->clear(); m_ConfigProbes.clear(); } void QmitkUSNewVideoDeviceWidget::CleanUpAfterEditingOfDevice() { disconnect(m_Controls->m_BtnDone, SIGNAL(clicked()), this, SLOT(OnClickedFinishedEditing())); m_Controls->m_Probes->clear(); m_Controls->m_Depths->clear(); m_Controls->m_AddDepths->clear(); m_ConfigProbes.clear(); } void QmitkUSNewVideoDeviceWidget::AddProbesToDevice(mitk::USVideoDevice::Pointer device) { device->DeleteAllProbes(); for( std::vector::iterator it = m_ConfigProbes.begin(); it != m_ConfigProbes.end(); it++) { if ((*it)->IsDepthAndSpacingEmpty()) { (*it)->SetDepth(0); } device->AddNewProbe((*it)); } } -mitk::USProbe::Pointer QmitkUSNewVideoDeviceWidget::CheckIfProbeExistsAlready(std::string &probeName) +mitk::USProbe::Pointer QmitkUSNewVideoDeviceWidget::CheckIfProbeExistsAlready(const std::string &probeName) { for( std::vector::iterator it = m_ConfigProbes.begin(); it != m_ConfigProbes.end(); it++ ) { if( probeName.compare((*it)->GetName()) == 0) return (*it); } return nullptr; //no matching probe was found so nullptr is returned } void QmitkUSNewVideoDeviceWidget::CollectUltrasoundVideoDeviceConfigInformation(mitk::USDeviceReaderXML::USVideoDeviceConfigData &config) { config.fileversion = 1.0; config.deviceType = "video"; //Fill info in metadata groupbox: config.deviceName = m_Controls->m_DeviceName->text().toStdString(); config.manufacturer = m_Controls->m_Manufacturer->text().toStdString(); config.model = m_Controls->m_Model->text().toStdString(); config.comment = m_Controls->m_Comment->text().toStdString(); //Fill info about video source: config.sourceID = m_Controls->m_DeviceSelector->value(); config.filepathVideoSource = m_Controls->m_FilePathSelector->text().toStdString(); //Fill video options: config.useGreyscale = m_Controls->m_CheckGreyscale->isChecked(); //Fill override options: config.useResolutionOverride = m_Controls->m_CheckResolutionOverride->isChecked(); config.resolutionWidth = m_Controls->m_ResolutionWidth->value(); config.resolutionHeight = m_Controls->m_ResolutionHeight->value(); //Fill information about probes: config.probes = m_ConfigProbes; } void QmitkUSNewVideoDeviceWidget::EnableDisableSpacingAndCropping(bool enable) { m_Controls->m_XSpacingSpinBox->setEnabled(enable); m_Controls->m_YSpacingSpinBox->setEnabled(enable); m_Controls->m_XSpacingLabel->setEnabled(enable); m_Controls->m_YSpacingLabel->setEnabled(enable); m_Controls->m_CroppingTopSpinBox->setEnabled(enable); m_Controls->m_CroppingRightSpinBox->setEnabled(enable); m_Controls->m_CroppingBottomSpinBox->setEnabled(enable); m_Controls->m_CroppingLeftSpinBox->setEnabled(enable); m_Controls->m_CroppingTopLabel->setEnabled(enable); m_Controls->m_CroppingBottomLabel->setEnabled(enable); m_Controls->m_CroppingLeftLabel->setEnabled(enable); m_Controls->m_CroppingRightLabel->setEnabled(enable); } diff --git a/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.h b/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.h index 531d3a342b..6c7aef6b49 100644 --- a/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.h +++ b/Modules/USUI/Qmitk/QmitkUSNewVideoDeviceWidget.h @@ -1,169 +1,169 @@ /*=================================================================== 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 _QmitkUSNewVideoDeviceWidget_H_INCLUDED #define _QmitkUSNewVideoDeviceWidget_H_INCLUDED #include "MitkUSUIExports.h" #include "ui_QmitkUSNewVideoDeviceWidgetControls.h" #include "mitkUSVideoDevice.h" #include "mitkUSIGTLDevice.h" #include "mitkUSDeviceReaderXML.h" //QT headers #include #include //mitk header /** * @brief This Widget enables the USer to create and connect Video Devices. * * @ingroup USUI */ class MITKUSUI_EXPORT QmitkUSNewVideoDeviceWidget :public QWidget { //this is needed for all Qt objects that should have a MOC object (everything that derives from QObject) Q_OBJECT public: static const std::string VIEW_ID; QmitkUSNewVideoDeviceWidget(QWidget* p = nullptr, Qt::WindowFlags f1 = nullptr); ~QmitkUSNewVideoDeviceWidget() override; /* @brief This method is part of the widget an needs not to be called seperately. */ virtual void CreateQtPartControl(QWidget *parent); /* @brief This method is part of the widget an needs not to be called seperately. (Creation of the connections of main and control widget.)*/ virtual void CreateConnections(); signals: void Finished(); public slots: /* \brief Activates the widget and displays the given device's Data to edit. */ void EditDevice(mitk::USDevice::Pointer device); /* \brief Activates the widget with fields empty. */ void CreateNewDevice(); protected slots: /* \brief Called, when the the user clicks the "Done" button (Labeled either "Add Device" or "Edit Device", depending on the situation. */ void OnClickedDone(); void OnClickedFinishedEditing(); /* \brief Called, when the button "Cancel" was clicked */ void OnClickedCancel(); /* \brief Called, when the Use selects one of the Radiobuttons */ void OnDeviceTypeSelection(); void OnOpenFileButtonClicked(); void OnClickedRemoveProbe(); void OnClickedRemoveDepth(); void OnClickedAddDepths(); void OnProbeChanged(const QString & probename); - void OnDepthChanged(int depth, mitk::USProbe* probe); + void OnDepthChanged(int depth, mitk::USProbe::Pointer probe); void OnDepthChanged(const QString &depth); void OnSaveButtonClicked(); void OnLoadConfigurationButtonClicked(); void OnAddNewProbeClicked(); void OnXSpacingSpinBoxChanged(double value); void OnYSpacingSpinBoxChanged(double value); void OnCroppingTopSpinBoxChanged(int value); void OnCroppingRightSpinBoxChanged(int value); void OnCroppingBottomSpinBoxChanged(int value); void OnCroppingLeftSpinBoxChanged(int value); protected: Ui::QmitkUSNewVideoDeviceWidgetControls* m_Controls; ///< member holding the UI elements of this widget /* \brief Constructs a ListItem from the given device for display in the list of active devices */ QListWidgetItem* ConstructItemFromDevice(mitk::USDevice::Pointer device); void ChangeUIEditingUSVideoDevice(); void CleanUpAfterEditingOfDevice(); void CleanUpAfterCreatingNewDevice(); void AddProbesToDevice(mitk::USVideoDevice::Pointer device); - mitk::USProbe::Pointer CheckIfProbeExistsAlready(std::string &probe); + mitk::USProbe::Pointer CheckIfProbeExistsAlready(const std::string &probe); void CollectUltrasoundVideoDeviceConfigInformation(mitk::USDeviceReaderXML::USVideoDeviceConfigData &config); /** * \brief Enables or disables the GUI elements of the spacing and cropping options. * \param enable If true: the GUI elements are enabled. If false: elements are disabled. */ void EnableDisableSpacingAndCropping(bool enable); /* \brief Displays whether this widget is active or not. It gets activated by either sending a Signal to * the "CreateNewDevice" Slot or to the "EditDevice" Slot. If the user finishes editing the device, a * "EditingComplete" Signal is sent, and the widget is set to inactive again. Clicking Cancel also * deactivates it. */ bool m_Active; /** * \brief This is the device to edit. It is either the device transmitted in the "EditDevice" signal, or a new one * if the "CreateNewDevice slot was called. */ mitk::USVideoDevice::Pointer m_TargetDevice; /** * \brief The config probes are used to have a possibility to configure ultrasound probes without having an existing * created USVideoDevice yet. */ std::vector m_ConfigProbes; }; #endif // _QmitkUSNewVideoDeviceWidget_H_INCLUDED diff --git a/Plugins/PluginList.cmake b/Plugins/PluginList.cmake index 03f3de6e54..ecfb25c700 100644 --- a/Plugins/PluginList.cmake +++ b/Plugins/PluginList.cmake @@ -1,102 +1,103 @@ # Plug-ins must be ordered according to their dependencies set(MITK_PLUGINS org.blueberry.core.runtime:ON org.blueberry.core.expressions:OFF org.blueberry.core.commands:OFF org.blueberry.core.jobs:OFF org.blueberry.ui.qt:OFF org.blueberry.ui.qt.help:ON org.blueberry.ui.qt.log:ON org.blueberry.ui.qt.objectinspector:OFF #org.blueberry.test:ON #org.blueberry.uitest:ON #Testing/org.blueberry.core.runtime.tests:ON #Testing/org.blueberry.osgi.tests:ON org.mitk.core.services:ON org.mitk.gui.common:ON org.mitk.planarfigure:ON org.mitk.core.ext:OFF org.mitk.core.jobs:OFF org.mitk.gui.qt.application:ON org.mitk.gui.qt.coreapplication:OFF org.mitk.gui.qt.ext:OFF org.mitk.gui.qt.extapplication:OFF org.mitk.gui.qt.common:ON org.mitk.gui.qt.stdmultiwidgeteditor:ON org.mitk.gui.qt.common.legacy:OFF org.mitk.gui.qt.cmdlinemodules:OFF org.mitk.gui.qt.diffusionimagingapp:OFF org.mitk.gui.qt.datamanager:ON org.mitk.gui.qt.datamanagerlight:OFF + org.mitk.gui.qt.datastorageviewertest:OFF org.mitk.gui.qt.properties:ON org.mitk.gui.qt.basicimageprocessing:OFF org.mitk.gui.qt.dicom:OFF org.mitk.gui.qt.dicominspector:OFF org.mitk.gui.qt.diffusionimaging:OFF org.mitk.gui.qt.diffusionimaging.connectomics:OFF org.mitk.gui.qt.diffusionimaging.denoising:OFF org.mitk.gui.qt.diffusionimaging.fiberfox:OFF org.mitk.gui.qt.diffusionimaging.fiberprocessing:OFF org.mitk.gui.qt.diffusionimaging.ivim:OFF org.mitk.gui.qt.diffusionimaging.odfpeaks:OFF org.mitk.gui.qt.diffusionimaging.partialvolume:OFF org.mitk.gui.qt.diffusionimaging.preprocessing:OFF org.mitk.gui.qt.diffusionimaging.reconstruction:OFF org.mitk.gui.qt.diffusionimaging.registration:OFF org.mitk.gui.qt.diffusionimaging.tbss:OFF org.mitk.gui.qt.diffusionimaging.tractography:OFF org.mitk.gui.qt.diffusionimaging.python:OFF org.mitk.gui.qt.dosevisualization:OFF org.mitk.gui.qt.geometrytools:OFF org.mitk.gui.qt.igtexamples:OFF org.mitk.gui.qt.igttracking:OFF org.mitk.gui.qt.lasercontrol:OFF org.mitk.gui.qt.openigtlink:OFF org.mitk.gui.qt.imagecropper:OFF org.mitk.gui.qt.imagenavigator:ON org.mitk.gui.qt.viewnavigator:OFF org.mitk.gui.qt.materialeditor:OFF org.mitk.gui.qt.measurementtoolbox:OFF org.mitk.gui.qt.moviemaker:OFF org.mitk.gui.qt.pointsetinteraction:OFF org.mitk.gui.qt.pointsetinteractionmultispectrum:OFF org.mitk.gui.qt.python:OFF org.mitk.gui.qt.remeshing:OFF org.mitk.gui.qt.segmentation:OFF org.mitk.gui.qt.aicpregistration:OFF org.mitk.gui.qt.renderwindowmanager:OFF org.mitk.gui.qt.toftutorial:OFF org.mitk.gui.qt.tofutil:OFF org.mitk.gui.qt.tubegraph:OFF org.mitk.gui.qt.ugvisualization:OFF org.mitk.gui.qt.photoacoustics.pausviewer:OFF org.mitk.gui.qt.photoacoustics.imageprocessing:OFF org.mitk.gui.qt.photoacoustics.simulation:OFF org.mitk.gui.qt.ultrasound:OFF org.mitk.gui.qt.volumevisualization:OFF org.mitk.gui.qt.eventrecorder:OFF org.mitk.gui.qt.xnat:OFF org.mitk.gui.qt.igt.app.echotrack:OFF org.mitk.gui.qt.spectrocamrecorder:OFF org.mitk.gui.qt.classificationsegmentation:OFF org.mitk.gui.qt.overlaymanager:OFF org.mitk.gui.qt.igt.app.hummelprotocolmeasurements:OFF org.mitk.gui.qt.multilabelsegmentation:OFF org.mitk.matchpoint.core.helper:OFF org.mitk.gui.qt.matchpoint.algorithm.browser:OFF org.mitk.gui.qt.matchpoint.algorithm.control:OFF org.mitk.gui.qt.matchpoint.algorithm.batch:OFF org.mitk.gui.qt.matchpoint.mapper:OFF org.mitk.gui.qt.matchpoint.framereg:OFF org.mitk.gui.qt.matchpoint.visualizer:OFF org.mitk.gui.qt.matchpoint.evaluator:OFF org.mitk.gui.qt.matchpoint.manipulator:OFF org.mitk.gui.qt.preprocessing.resampling:OFF org.mitk.gui.qt.cest:OFF ) diff --git a/Plugins/org.blueberry.core.runtime/src/internal/berryCTKPluginActivator.cpp b/Plugins/org.blueberry.core.runtime/src/internal/berryCTKPluginActivator.cpp index 5bbc5ba678..5f2b670e5e 100755 --- a/Plugins/org.blueberry.core.runtime/src/internal/berryCTKPluginActivator.cpp +++ b/Plugins/org.blueberry.core.runtime/src/internal/berryCTKPluginActivator.cpp @@ -1,297 +1,297 @@ /*=================================================================== BlueBerry Platform 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 NOMINMAX #define NOMINMAX #endif #include "berryCTKPluginActivator.h" #include #include #include #include "berryApplicationContainer.h" #include "berryPlatform.h" #include "berryInternalPlatform.h" #include "berryErrorApplication.h" #include "berryPreferencesService.h" #include "berryExtensionRegistry.h" #include "berryRegistryConstants.h" #include "berryRegistryProperties.h" #include "berryRegistryStrategy.h" #include "berryRegistryContributor.h" #include #include namespace berry { static const QString XP_APPLICATIONS = "org.blueberry.osgi.applications"; ctkPluginContext* org_blueberry_core_runtime_Activator::context = nullptr; QScopedPointer org_blueberry_core_runtime_Activator::appContainer; const bool org_blueberry_core_runtime_Activator::DEBUG = false; void org_blueberry_core_runtime_Activator::start(ctkPluginContext* context) { this->context = context; BERRY_REGISTER_EXTENSION_CLASS(ErrorApplication, context) RegistryProperties::SetContext(context); //ProcessCommandLine(); this->startRegistry(); preferencesService.reset(new PreferencesService(context->getDataFile("").absolutePath())); prefServiceReg = context->registerService(preferencesService.data()); // // register a listener to catch new plugin installations/resolutions. // pluginListener.reset(new CTKPluginListener(m_ExtensionPointService)); // context->connectPluginListener(pluginListener.data(), SLOT(pluginChanged(ctkPluginEvent)), Qt::DirectConnection); // // populate the registry with all the currently installed plugins. // // There is a small window here while processPlugins is being // // called where the pluginListener may receive a ctkPluginEvent // // to add/remove a plugin from the registry. This is ok since // // the registry is a synchronized object and will not add the // // same bundle twice. // pluginListener->processPlugins(context->getPlugins()); this->startAppContainer(); InternalPlatform::GetInstance()->Start(context); } void org_blueberry_core_runtime_Activator::stop(ctkPluginContext* context) { InternalPlatform::GetInstance()->Stop(context); //pluginListener.reset(); //Platform::GetServiceRegistry().UnRegisterService(IExtensionPointService::SERVICE_ID); prefServiceReg.unregister(); preferencesService->ShutDown(); preferencesService.reset(); prefServiceReg = 0; this->stopRegistry(); RegistryProperties::SetContext(nullptr); stopAppContainer(); this->context = nullptr; } ctkPluginContext* org_blueberry_core_runtime_Activator::getPluginContext() { return context; } ApplicationContainer* org_blueberry_core_runtime_Activator::GetContainer() { return appContainer.data(); } -#if defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) || defined(Q_CC_MINGW) +#if defined(Q_OS_LINUX) || defined(Q_OS_DARWIN) #include QString org_blueberry_core_runtime_Activator::getPluginId(void *symbol) { if (symbol == nullptr) return QString(); Dl_info info = {nullptr,nullptr,nullptr,nullptr}; if(dladdr(symbol, &info) == 0) { return QString(); } else if(info.dli_fname) { QFile soPath(info.dli_fname); int index = soPath.fileName().lastIndexOf('.'); QString pluginId = soPath.fileName().left(index); if (pluginId.startsWith("lib")) pluginId = pluginId.mid(3); return pluginId.replace('_', '.'); } return QString(); } #elif defined(Q_CC_MSVC) #include #include #ifdef _MSC_VER # pragma warning(push) # pragma warning(disable: 4091) #endif #include #ifdef _MSC_VER # pragma warning(pop) #endif QString org_blueberry_core_runtime_Activator::getPluginId(void *symbol) { if (symbol == nullptr) return QString(); if (ctk::DebugSymInitialize()) { std::vector moduleBuffer(sizeof(IMAGEHLP_MODULE64)); PIMAGEHLP_MODULE64 pModuleInfo = (PIMAGEHLP_MODULE64)&moduleBuffer.front(); pModuleInfo->SizeOfStruct = sizeof(IMAGEHLP_MODULE64); if (SymGetModuleInfo64(GetCurrentProcess(), (DWORD64)symbol, pModuleInfo)) { QString pluginId = pModuleInfo->ModuleName; return pluginId.replace('_', '.'); } } return QString(); } #endif QSharedPointer org_blueberry_core_runtime_Activator::GetPlugin(const SmartPointer& contributor) { if (RegistryContributor::Pointer regContributor = contributor.Cast()) { bool okay = false; long id = regContributor->GetActualId().toLong(&okay); if (okay) { if (context != nullptr) { return context->getPlugin(id); } } else { // try using the name of the contributor below } } auto plugins = context->getPlugins(); //Return the first plugin that is not installed or uninstalled for (auto plugin : plugins) { if (!(plugin->getState() == ctkPlugin::INSTALLED || plugin->getState() == ctkPlugin::UNINSTALLED)) { return plugin; } } return QSharedPointer(); } org_blueberry_core_runtime_Activator::org_blueberry_core_runtime_Activator() : userRegistryKey(new QObject()) , masterRegistryKey(new QObject()) { } org_blueberry_core_runtime_Activator::~org_blueberry_core_runtime_Activator() { } void org_blueberry_core_runtime_Activator::startRegistry() { // see if the customer suppressed the creation of default registry QString property = context->getProperty(RegistryConstants::PROP_DEFAULT_REGISTRY).toString(); if (property.compare("false", Qt::CaseInsensitive) == 0) return; // check to see if we need to use null as a userToken if (context->getProperty(RegistryConstants::PROP_REGISTRY_nullptr_USER_TOKEN).toString().compare("true", Qt::CaseInsensitive) == 0) { userRegistryKey.reset(nullptr); } // Determine primary and alternative registry locations. BlueBerry extension registry cache // can be found in one of the two locations: // a) in the local configuration area (standard location passed in by the platform) -> priority // b) in the shared configuration area (typically, shared install is used) QList registryLocations; QList readOnlyLocations; RegistryStrategy* strategy = nullptr; //Location configuration = OSGIUtils.getDefault().getConfigurationLocation(); QString configuration = context->getDataFile("").absoluteFilePath(); if (configuration.isEmpty()) { RegistryProperties::SetProperty(RegistryConstants::PROP_NO_REGISTRY_CACHE, "true"); RegistryProperties::SetProperty(RegistryConstants::PROP_NO_LAZY_REGISTRY_CACHE_LOADING, "true"); strategy = new RegistryStrategy(QList(), QList(), masterRegistryKey.data()); } else { //File primaryDir = new File(configuration.getURL().getPath() + '/' + STORAGE_DIR); //bool primaryReadOnly = configuration.isReadOnly(); QString primaryDir = configuration; bool primaryReadOnly = false; //Location parentLocation = configuration.getParentLocation(); QString parentLocation; if (!parentLocation.isEmpty()) { // File secondaryDir = new File(parentLocation.getURL().getFile() + '/' + IRegistryConstants.RUNTIME_NAME); // registryLocations << primaryDir << secondaryDir; // readOnlyLocations << primaryReadOnly << true; // secondary BlueBerry location is always read only } else { registryLocations << primaryDir; readOnlyLocations << primaryReadOnly; } strategy = new RegistryStrategy(registryLocations, readOnlyLocations, masterRegistryKey.data()); } auto registry = new ExtensionRegistry(strategy, masterRegistryKey.data(), userRegistryKey.data()); defaultRegistry.reset(registry); registryServiceReg = context->registerService(registry); //commandRegistration = EquinoxUtils.registerCommandProvider(Activator.getContext()); } void org_blueberry_core_runtime_Activator::stopRegistry() { if (!defaultRegistry.isNull()) { registryServiceReg.unregister(); defaultRegistry->Stop(masterRegistryKey.data()); } // if (!commandRegistration.isNull()) // { // commandRegistration.unregister(); // } } void org_blueberry_core_runtime_Activator::startAppContainer() { appContainer.reset(new ApplicationContainer(context, defaultRegistry.data())); appContainer->Start(); } void org_blueberry_core_runtime_Activator::stopAppContainer() { appContainer->Stop(); } } diff --git a/Plugins/org.blueberry.ui.qt.help/resources/help.svg b/Plugins/org.blueberry.ui.qt.help/resources/help.svg index 2eea8fafba..13b270ac75 100644 --- a/Plugins/org.blueberry.ui.qt.help/resources/help.svg +++ b/Plugins/org.blueberry.ui.qt.help/resources/help.svg @@ -1,54 +1,54 @@ image/svg+xml diff --git a/Plugins/org.blueberry.ui.qt.help/resources/helpIndex.svg b/Plugins/org.blueberry.ui.qt.help/resources/helpIndex.svg index 1bd9d6cf2d..df07bbce39 100644 --- a/Plugins/org.blueberry.ui.qt.help/resources/helpIndex.svg +++ b/Plugins/org.blueberry.ui.qt.help/resources/helpIndex.svg @@ -1,62 +1,62 @@ image/svg+xml diff --git a/Plugins/org.blueberry.ui.qt.help/resources/helpSearch.svg b/Plugins/org.blueberry.ui.qt.help/resources/helpSearch.svg index 63c3cd84db..3f27badd40 100644 --- a/Plugins/org.blueberry.ui.qt.help/resources/helpSearch.svg +++ b/Plugins/org.blueberry.ui.qt.help/resources/helpSearch.svg @@ -1,59 +1,59 @@ image/svg+xml diff --git a/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpContentView.cpp b/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpContentView.cpp index 28f7a8bd23..e20b40a77f 100644 --- a/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpContentView.cpp +++ b/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpContentView.cpp @@ -1,229 +1,222 @@ /*=================================================================== BlueBerry Platform 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. ===================================================================*/ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include "berryHelpContentView.h" #include "berryHelpPluginActivator.h" #include "berryHelpEditor.h" #include "berryHelpEditorInput.h" #include "berryHelpWebView.h" #include "berryQHelpEngineWrapper.h" #include #include #include #include #include #include #include namespace berry { HelpContentWidget::HelpContentWidget() : QTreeView(nullptr) , m_SortModel(new QSortFilterProxyModel(this)) , m_SourceModel(nullptr) { header()->hide(); setUniformRowHeights(true); connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(showLink(QModelIndex))); connect(this, SIGNAL(clicked(QModelIndex)), this, SLOT(showLink(QModelIndex))); m_SortModel->setDynamicSortFilter(true); QTreeView::setModel(m_SortModel); } QModelIndex HelpContentWidget::indexOf(const QUrl &link) { QHelpContentModel *contentModel = qobject_cast(m_SourceModel); if (!contentModel || link.scheme() != QLatin1String("qthelp")) return QModelIndex(); m_syncIndex = QModelIndex(); for (int i=0; irowCount(); ++i) { QHelpContentItem *itm = contentModel->contentItemAt(contentModel->index(i, 0)); if (itm && itm->url().host() == link.host()) { QString path = link.path(); if (path.startsWith(QLatin1Char('/'))) path = path.mid(1); if (searchContentItem(contentModel, contentModel->index(i, 0), path)) { return m_syncIndex; } } } return QModelIndex(); } void HelpContentWidget::setModel(QAbstractItemModel *model) { m_SourceModel = model; m_SortModel->setSourceModel(model); } bool HelpContentWidget::searchContentItem(QHelpContentModel *model, const QModelIndex &parent, const QString &path) { QHelpContentItem *parentItem = model->contentItemAt(parent); if (!parentItem) return false; if (QDir::cleanPath(parentItem->url().path()) == path) { m_syncIndex = m_SortModel->mapFromSource(parent); return true; } for (int i=0; ichildCount(); ++i) { if (searchContentItem(model, model->index(i, 0, parent), path)) return true; } return false; } QUrl HelpContentWidget::GetUrl(const QModelIndex &index) { QHelpContentModel *contentModel = qobject_cast(m_SourceModel); if (!contentModel) return QUrl(); QHelpContentItem *item = contentModel->contentItemAt(m_SortModel->mapToSource(index)); if (!item) return QUrl(); QUrl url = item->url(); if (url.isValid()) return url; return QUrl(); } void HelpContentWidget::showLink(const QModelIndex &index) { QHelpContentModel *contentModel = qobject_cast(m_SourceModel); if (!contentModel) return; QHelpContentItem *item = contentModel->contentItemAt(m_SortModel->mapToSource(index)); if (!item) return; QUrl url = item->url(); if (url.isValid()) emit linkActivated(url); } HelpContentView::HelpContentView() : m_ContentWidget(nullptr) { } HelpContentView::~HelpContentView() { } void HelpContentView::CreateQtPartControl(QWidget* parent) { if (m_ContentWidget == nullptr) { auto verticalLayout = new QVBoxLayout(parent); verticalLayout->setSpacing(0); verticalLayout->setContentsMargins(0, 0, 0, 0); QHelpEngineWrapper& helpEngine = HelpPluginActivator::getInstance()->getQHelpEngine(); m_ContentWidget = new HelpContentWidget(); m_ContentWidget->setModel(helpEngine.contentModel()); m_ContentWidget->sortByColumn(0, Qt::AscendingOrder); connect(helpEngine.contentModel(), SIGNAL(contentsCreationStarted()), this, SLOT(setContentsWidgetBusy())); connect(helpEngine.contentModel(), SIGNAL(contentsCreated()), this, SLOT(unsetContentsWidgetBusy())); verticalLayout->addWidget(m_ContentWidget); m_ContentWidget->setContextMenuPolicy(Qt::CustomContextMenu); connect(m_ContentWidget, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); connect(m_ContentWidget, SIGNAL(linkActivated(QUrl)), this, SLOT(linkActivated(QUrl))); } } void HelpContentView::linkActivated(const QUrl &link) { IWorkbenchPage::Pointer page = this->GetSite()->GetPage(); HelpPluginActivator::linkActivated(page, link); } void HelpContentView::showContextMenu(const QPoint &pos) { if (!m_ContentWidget->indexAt(pos).isValid()) return; QModelIndex index = m_ContentWidget->indexAt(pos); QUrl url = m_ContentWidget->GetUrl(index); QMenu menu; QAction *curTab = menu.addAction(tr("Open Link")); QAction *newTab = menu.addAction(tr("Open Link in New Tab")); if (!HelpWebView::canOpenPage(url.path())) newTab->setEnabled(false); menu.move(m_ContentWidget->mapToGlobal(pos)); QAction *action = menu.exec(); if (curTab == action) { linkActivated(url); } else if (newTab == action) { IEditorInput::Pointer input(new HelpEditorInput(url)); this->GetSite()->GetPage()->OpenEditor(input, HelpEditor::EDITOR_ID); } } void HelpContentView::SetFocus() { m_ContentWidget->setFocus(); } void HelpContentView::setContentsWidgetBusy() { m_ContentWidget->setCursor(Qt::WaitCursor); } void HelpContentView::unsetContentsWidgetBusy() { m_ContentWidget->unsetCursor(); QHelpEngineWrapper& helpEngine = HelpPluginActivator::getInstance()->getQHelpEngine(); m_ContentWidget->setModel(helpEngine.contentModel()); m_ContentWidget->sortByColumn(0, Qt::AscendingOrder); } } diff --git a/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpIndexView.cpp b/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpIndexView.cpp index f19380e5c1..6fa491ea8e 100644 --- a/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpIndexView.cpp +++ b/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpIndexView.cpp @@ -1,321 +1,314 @@ /*=================================================================== BlueBerry Platform 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. ===================================================================*/ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include "berryHelpIndexView.h" #include "berryHelpPluginActivator.h" #include "berryHelpEditor.h" #include "berryHelpEditorInput.h" #include "berryQHelpEngineWrapper.h" #include "berryHelpTopicChooser.h" #include #include #include #include #include #include #include namespace berry { HelpIndexWidget::HelpIndexWidget() : QListView(nullptr) { setEditTriggers(QAbstractItemView::NoEditTriggers); setUniformItemSizes(true); connect(this, SIGNAL(activated(QModelIndex)), this, SLOT(showLink(QModelIndex))); } void HelpIndexWidget::showLink(const QModelIndex &index) { if (!index.isValid()) return; QHelpIndexModel *indexModel = qobject_cast(model()); if (!indexModel) return; QVariant v = indexModel->data(index, Qt::DisplayRole); QString name; if (v.isValid()) name = v.toString(); QMap links = indexModel->linksForKeyword(name); if (links.count() == 1) { emit linkActivated(links.constBegin().value(), name); } else if (links.count() > 1) { emit linksActivated(links, name); } } void HelpIndexWidget::activateCurrentItem() { showLink(currentIndex()); } void HelpIndexWidget::filterIndices(const QString &filter, const QString &wildcard) { QHelpIndexModel *indexModel = qobject_cast(model()); if (!indexModel) return; QModelIndex idx = indexModel->filter(filter, wildcard); if (idx.isValid()) setCurrentIndex(idx); } HelpIndexView::HelpIndexView() : m_IndexWidget(nullptr) { } HelpIndexView::~HelpIndexView() { } void HelpIndexView::CreateQtPartControl(QWidget* parent) { if (m_IndexWidget == nullptr) { auto layout = new QVBoxLayout(parent); //QLabel *l = new QLabel(tr("&Look for:")); //layout->addWidget(l); m_SearchLineEdit = new ctkSearchBox(parent); m_SearchLineEdit->setClearIcon(QIcon(":/org.blueberry.ui.qt.help/clear.png")); m_SearchLineEdit->setPlaceholderText("Filter..."); m_SearchLineEdit->setContentsMargins(2,2,2,0); //l->setBuddy(m_SearchLineEdit); connect(m_SearchLineEdit, SIGNAL(textChanged(QString)), this, SLOT(filterIndices(QString))); m_SearchLineEdit->installEventFilter(this); layout->setMargin(0); layout->setSpacing(2); layout->addWidget(m_SearchLineEdit); QHelpEngineWrapper& helpEngine = HelpPluginActivator::getInstance()->getQHelpEngine(); m_IndexWidget = new HelpIndexWidget(); m_IndexWidget->setModel(helpEngine.indexModel()); connect(helpEngine.indexModel(), SIGNAL(indexCreationStarted()), this, SLOT(setIndexWidgetBusy())); connect(helpEngine.indexModel(), SIGNAL(indexCreated()), this, SLOT(unsetIndexWidgetBusy())); m_IndexWidget->installEventFilter(this); connect(helpEngine.indexModel(), SIGNAL(indexCreationStarted()), this, SLOT(disableSearchLineEdit())); connect(helpEngine.indexModel(), SIGNAL(indexCreated()), this, SLOT(enableSearchLineEdit())); connect(m_IndexWidget, SIGNAL(linkActivated(QUrl,QString)), this, SLOT(linkActivated(QUrl))); connect(m_IndexWidget, SIGNAL(linksActivated(QMap,QString)), this, SLOT(linksActivated(QMap,QString))); connect(m_SearchLineEdit, SIGNAL(returnPressed()), m_IndexWidget, SLOT(activateCurrentItem())); layout->addWidget(m_IndexWidget); m_IndexWidget->viewport()->installEventFilter(this); } } void HelpIndexView::SetFocus() { if (!(m_IndexWidget->hasFocus() || m_SearchLineEdit->hasFocus())) { m_SearchLineEdit->setFocus(); } } void HelpIndexView::filterIndices(const QString &filter) { if (filter.contains(QLatin1Char('*'))) m_IndexWidget->filterIndices(filter, filter); else m_IndexWidget->filterIndices(filter, QString()); } bool HelpIndexView::eventFilter(QObject *obj, QEvent *e) { if (obj == m_SearchLineEdit && e->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(e); QModelIndex idx = m_IndexWidget->currentIndex(); switch (ke->key()) { case Qt::Key_Up: idx = m_IndexWidget->model()->index(idx.row()-1, idx.column(), idx.parent()); if (idx.isValid()) { m_IndexWidget->setCurrentIndex(idx); return true; } break; case Qt::Key_Down: idx = m_IndexWidget->model()->index(idx.row()+1, idx.column(), idx.parent()); if (idx.isValid()) { m_IndexWidget->setCurrentIndex(idx); return true; } break; default: ; // stop complaining } } else if (obj == m_IndexWidget && e->type() == QEvent::ContextMenu) { QContextMenuEvent *ctxtEvent = static_cast(e); QModelIndex idx = m_IndexWidget->indexAt(ctxtEvent->pos()); if (idx.isValid()) { QMenu menu; QAction *curTab = menu.addAction(tr("Open Link")); QAction *newTab = menu.addAction(tr("Open Link in New Tab")); menu.move(m_IndexWidget->mapToGlobal(ctxtEvent->pos())); QAction *action = menu.exec(); if (curTab == action) m_IndexWidget->activateCurrentItem(); else if (newTab == action) { open(m_IndexWidget, idx); } } } else if (m_IndexWidget && obj == m_IndexWidget->viewport() && e->type() == QEvent::MouseButtonRelease) { QMouseEvent *mouseEvent = static_cast(e); QModelIndex idx = m_IndexWidget->indexAt(mouseEvent->pos()); if (idx.isValid()) { Qt::MouseButtons button = mouseEvent->button(); if (((button == Qt::LeftButton) && (mouseEvent->modifiers() & Qt::ControlModifier)) || (button == Qt::MidButton)) { open(m_IndexWidget, idx); } } } #ifdef Q_OS_MAC else if (obj == m_IndexWidget && e->type() == QEvent::KeyPress) { QKeyEvent *ke = static_cast(e); if (ke->key() == Qt::Key_Return || ke->key() == Qt::Key_Enter) m_IndexWidget->activateCurrentItem(); } #endif return QObject::eventFilter(obj, e); } void HelpIndexView::enableSearchLineEdit() { m_SearchLineEdit->setDisabled(false); filterIndices(m_SearchLineEdit->text()); } void HelpIndexView::disableSearchLineEdit() { m_SearchLineEdit->setDisabled(true); } void HelpIndexView::setIndexWidgetBusy() { m_IndexWidget->setCursor(Qt::WaitCursor); } void HelpIndexView::unsetIndexWidgetBusy() { m_IndexWidget->unsetCursor(); } void HelpIndexView::setSearchLineEditText(const QString &text) { m_SearchLineEdit->setText(text); } QString HelpIndexView::searchLineEditText() const { return m_SearchLineEdit->text(); } void HelpIndexView::focusInEvent(QFocusEvent *e) { if (e->reason() != Qt::MouseFocusReason) { m_SearchLineEdit->selectAll(); m_SearchLineEdit->setFocus(); } } void HelpIndexView::open(HelpIndexWidget* indexWidget, const QModelIndex &index) { QHelpIndexModel *model = qobject_cast(indexWidget->model()); if (model) { QString keyword = model->data(index, Qt::DisplayRole).toString(); QMap links = model->linksForKeyword(keyword); QUrl url; if (links.count() > 1) { HelpTopicChooser tc(m_IndexWidget, keyword, links); if (tc.exec() == QDialog::Accepted) url = tc.link(); } else if (links.count() == 1) { url = links.constBegin().value(); } else { return; } IEditorInput::Pointer input(new HelpEditorInput(url)); this->GetSite()->GetPage()->OpenEditor(input, HelpEditor::EDITOR_ID); } } void HelpIndexView::linkActivated(const QUrl& link) { IWorkbenchPage::Pointer page = this->GetSite()->GetPage(); HelpPluginActivator::linkActivated(page, link); } void HelpIndexView::linksActivated(const QMap& links, const QString& keyword) { HelpTopicChooser tc(m_IndexWidget, keyword, links); if (tc.exec() == QDialog::Accepted) { IWorkbenchPage::Pointer page = this->GetSite()->GetPage(); HelpPluginActivator::linkActivated(page, tc.link()); } } } \ No newline at end of file diff --git a/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpSearchView.cpp b/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpSearchView.cpp index 4b42788f39..24b7692c1e 100644 --- a/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpSearchView.cpp +++ b/Plugins/org.blueberry.ui.qt.help/src/internal/berryHelpSearchView.cpp @@ -1,243 +1,236 @@ /*=================================================================== BlueBerry Platform 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. ===================================================================*/ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include "berryHelpSearchView.h" #include "berryHelpPluginActivator.h" #include "berryQHelpEngineWrapper.h" #include "berryHelpEditorInput.h" #include "berryHelpEditor.h" #include #include #include #include #include #include #include #include #include #include namespace berry { HelpSearchView::HelpSearchView() : m_ZoomCount(0) , m_Parent(nullptr) , m_SearchEngine(HelpPluginActivator::getInstance()->getQHelpEngine().searchEngine()) , m_ResultWidget(nullptr) , m_QueryWidget(nullptr) { } HelpSearchView::~HelpSearchView() { // prevent deletion of the widget m_ResultWidget->setParent(nullptr); } void HelpSearchView::CreateQtPartControl(QWidget* parent) { if (m_ResultWidget == nullptr) { m_Parent = parent; auto vLayout = new QVBoxLayout(parent); // This will be lead to strange behavior when using multiple instances of this view // because the QHelpSearchResultWidget instance is shared. The new view will // reparent the widget. m_ResultWidget = m_SearchEngine->resultWidget(); m_QueryWidget = new QHelpSearchQueryWidget(); vLayout->addWidget(m_QueryWidget); vLayout->addWidget(m_ResultWidget); connect(m_QueryWidget, SIGNAL(search()), this, SLOT(search())); connect(m_ResultWidget, SIGNAL(requestShowLink(QUrl)), this, SLOT(requestShowLink(QUrl))); connect(m_SearchEngine, SIGNAL(searchingStarted()), this, SLOT(searchingStarted())); connect(m_SearchEngine, SIGNAL(searchingFinished(int)), this, SLOT(searchingFinished(int))); QTextBrowser* browser = m_ResultWidget->findChild(); if (browser) // Will be null if QtHelp was configured not to use CLucene. { browser->viewport()->installEventFilter(this); browser->setContextMenuPolicy(Qt::CustomContextMenu); connect(browser, SIGNAL(customContextMenuRequested(QPoint)), this, SLOT(showContextMenu(QPoint))); } } } void HelpSearchView::SetFocus() { if (!(m_ResultWidget->hasFocus())) { m_QueryWidget->setFocus(); } } void HelpSearchView::zoomIn() { QTextBrowser* browser = m_ResultWidget->findChild(); if (browser && m_ZoomCount != 10) { m_ZoomCount++; browser->zoomIn(); } } void HelpSearchView::zoomOut() { QTextBrowser* browser = m_ResultWidget->findChild(); if (browser && m_ZoomCount != -5) { m_ZoomCount--; browser->zoomOut(); } } void HelpSearchView::resetZoom() { if (m_ZoomCount == 0) return; QTextBrowser* browser = m_ResultWidget->findChild(); if (browser) { browser->zoomOut(m_ZoomCount); m_ZoomCount = 0; } } void HelpSearchView::search() const { QList query = m_QueryWidget->query(); m_SearchEngine->search(query); } void HelpSearchView::searchingStarted() { m_Parent->setCursor(QCursor(Qt::WaitCursor)); } void HelpSearchView::searchingFinished(int hits) { Q_UNUSED(hits) m_Parent->unsetCursor(); //qApp->restoreOverrideCursor(); } void HelpSearchView::requestShowLink(const QUrl &link) { HelpPluginActivator::linkActivated(this->GetSite()->GetPage(), link); } bool HelpSearchView::eventFilter(QObject* o, QEvent *e) { QTextBrowser* browser = m_ResultWidget->findChild(); if (browser && o == browser->viewport() && e->type() == QEvent::MouseButtonRelease) { QMouseEvent* me = static_cast(e); QUrl link = m_ResultWidget->linkAt(me->pos()); if (!link.isEmpty() || link.isValid()) { bool controlPressed = me->modifiers() & Qt::ControlModifier; if((me->button() == Qt::LeftButton && controlPressed) || (me->button() == Qt::MidButton)) { IEditorInput::Pointer input(new HelpEditorInput(link)); this->GetSite()->GetPage()->OpenEditor(input, HelpEditor::EDITOR_ID); } } } return QObject::eventFilter(o,e); } void HelpSearchView::showContextMenu(const QPoint& point) { QMenu menu; QTextBrowser* browser = m_ResultWidget->findChild(); if (!browser) return; // QPoint point = browser->mapFromGlobal(pos); // if (!browser->rect().contains(point, true)) // return; QUrl link = browser->anchorAt(point); QKeySequence keySeq(QKeySequence::Copy); QAction *copyAction = menu.addAction(tr("&Copy") + QLatin1String("\t") + keySeq.toString(QKeySequence::NativeText)); copyAction->setEnabled(QTextCursor(browser->textCursor()).hasSelection()); QAction *copyAnchorAction = menu.addAction(tr("Copy &Link Location")); copyAnchorAction->setEnabled(!link.isEmpty() && link.isValid()); keySeq = QKeySequence(Qt::CTRL); QAction *newTabAction = menu.addAction(tr("Open Link in New Tab") + QLatin1String("\t") + keySeq.toString(QKeySequence::NativeText) + QLatin1String("LMB")); newTabAction->setEnabled(!link.isEmpty() && link.isValid()); menu.addSeparator(); keySeq = QKeySequence::SelectAll; QAction *selectAllAction = menu.addAction(tr("Select All") + QLatin1String("\t") + keySeq.toString(QKeySequence::NativeText)); QAction *usedAction = menu.exec(browser->mapToGlobal(point)); if (usedAction == copyAction) { QTextCursor cursor = browser->textCursor(); if (!cursor.isNull() && cursor.hasSelection()) { QString selectedText = cursor.selectedText(); auto data = new QMimeData(); data->setText(selectedText); QApplication::clipboard()->setMimeData(data); } } else if (usedAction == copyAnchorAction) { QApplication::clipboard()->setText(link.toString()); } else if (usedAction == newTabAction) { IEditorInput::Pointer input(new HelpEditorInput(link)); this->GetSite()->GetPage()->OpenEditor(input, HelpEditor::EDITOR_ID); } else if (usedAction == selectAllAction) { browser->selectAll(); } } } diff --git a/Plugins/org.blueberry.ui.qt.log/resources/logging.svg b/Plugins/org.blueberry.ui.qt.log/resources/logging.svg index bf7e60d22b..2b9894f8f8 100644 --- a/Plugins/org.blueberry.ui.qt.log/resources/logging.svg +++ b/Plugins/org.blueberry.ui.qt.log/resources/logging.svg @@ -1,74 +1,74 @@ image/svg+xml diff --git a/Plugins/org.blueberry.ui.qt.log/src/internal/berryLogView.cpp b/Plugins/org.blueberry.ui.qt.log/src/internal/berryLogView.cpp index e46cb44865..b2afc1fdbe 100644 --- a/Plugins/org.blueberry.ui.qt.log/src/internal/berryLogView.cpp +++ b/Plugins/org.blueberry.ui.qt.log/src/internal/berryLogView.cpp @@ -1,50 +1,43 @@ /*=================================================================== BlueBerry Platform 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. ===================================================================*/ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include "berryLogView.h" #include "berryQtLogView.h" #include namespace berry { LogView::LogView() { } void LogView::CreateQtPartControl(QWidget* parent) { auto layout = new QHBoxLayout(parent); layout->setContentsMargins(0,0,0,0); auto logView = new QtLogView(parent); layout->addWidget(logView); } void LogView::SetFocus() { } } diff --git a/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtLogView.cpp b/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtLogView.cpp index 953221cda4..0a7367dfbf 100644 --- a/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtLogView.cpp +++ b/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtLogView.cpp @@ -1,171 +1,164 @@ /*=================================================================== BlueBerry Platform 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. ===================================================================*/ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include "berryQtLogView.h" #include "berryQtLogPlugin.h" #include #include #include #include #include #include #include namespace berry { QtLogView::QtLogView(QWidget *parent) : QWidget(parent) { berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); berry::IBerryPreferences::Pointer prefs = (prefService->GetSystemPreferences()->Node("org_blueberry_ui_qt_log")) .Cast(); prefs->PutBool("ShowAdvancedFields", false); prefs->PutBool("ShowCategory", true); bool showAdvancedFields = false; ui.setupUi(this); model = QtLogPlugin::GetInstance()->GetLogModel(); model->SetShowAdvancedFiels( showAdvancedFields ); filterModel = new QSortFilterProxyModel(this); filterModel->setSourceModel(model); filterModel->setFilterKeyColumn(-1); #ifdef __APPLE__ QFont fnt = ui.tableView->font(); fnt.setPointSize(11); ui.tableView->setFont(fnt); #endif ui.tableView->setModel(filterModel); ui.tableView->verticalHeader()->setVisible(false); ui.tableView->horizontalHeader()->setStretchLastSection(true); connect( ui.filterContent, SIGNAL( textChanged( const QString& ) ), this, SLOT( slotFilterChange( const QString& ) ) ); connect( filterModel, SIGNAL( rowsInserted ( const QModelIndex &, int, int ) ), this, SLOT( slotRowAdded( const QModelIndex &, int , int ) ) ); connect( ui.SaveToClipboard, SIGNAL( clicked()),this, SLOT(on_SaveToClipboard_clicked())); ui.ShowAdvancedFields->setChecked( showAdvancedFields ); #if QT_VERSION >= QT_VERSION_CHECK(5, 2, 0) ui.filterContent->setClearButtonEnabled(true); #endif } QtLogView::~QtLogView() { } void QtLogView::slotScrollDown( ) { ui.tableView->scrollToBottom(); } void QtLogView::slotFilterChange( const QString& q ) { filterModel->setFilterRegExp(QRegExp(q, Qt::CaseInsensitive, QRegExp::FixedString)); } void QtLogView::slotRowAdded ( const QModelIndex & /*parent*/, int /*start*/, int /*end*/ ) { ui.tableView->setVisible(false); ui.tableView->resizeRowsToContents(); //only resize columns when first entry is added static bool first = true; if(first) { ui.tableView->resizeColumnsToContents(); first = false; } ui.tableView->setVisible(true); QTimer::singleShot(0,this,SLOT( slotScrollDown() ) ); } void QtLogView::showEvent( QShowEvent * /*event*/ ) { ui.tableView->setVisible(false); ui.tableView->resizeColumnsToContents(); ui.tableView->resizeRowsToContents(); ui.tableView->setVisible(true); } void QtLogView::on_ShowAdvancedFields_clicked( bool checked ) { ui.tableView->setVisible(false); QtLogPlugin::GetInstance()->GetLogModel()->SetShowAdvancedFiels( checked ); ui.tableView->resizeColumnsToContents(); ui.tableView->setVisible(true); berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); berry::IBerryPreferences::Pointer prefs = (prefService->GetSystemPreferences()->Node("org_blueberry_ui_qt_log")) .Cast(); prefs->PutBool("ShowAdvancedFields", checked); prefs->Flush(); } void QtLogView::on_ShowCategory_clicked( bool checked ) { ui.tableView->setVisible(false); QtLogPlugin::GetInstance()->GetLogModel()->SetShowCategory( checked ); ui.tableView->resizeColumnsToContents(); ui.tableView->setVisible(true); berry::IPreferencesService* prefService = berry::Platform::GetPreferencesService(); berry::IBerryPreferences::Pointer prefs = (prefService->GetSystemPreferences()->Node("org_blueberry_ui_qt_log")) .Cast(); prefs->PutBool("ShowCategory", checked); prefs->Flush(); } void QtLogView::on_SaveToClipboard_clicked() { QClipboard *clipboard = QApplication::clipboard(); QString loggingMessagesAsText = QString(""); for (int i=0; imodel()->rowCount(); i++) { for (int j=0; jmodel()->columnCount(); j++) { QModelIndex index = ui.tableView->model()->index(i, j); loggingMessagesAsText += ui.tableView->model()->data(index, Qt::DisplayRole).toString() + " "; } loggingMessagesAsText += "\n"; } clipboard->setText(loggingMessagesAsText); } } diff --git a/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtPlatformLogModel.cpp b/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtPlatformLogModel.cpp index 5e2f93f7e8..ea8aa056d9 100644 --- a/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtPlatformLogModel.cpp +++ b/Plugins/org.blueberry.ui.qt.log/src/internal/berryQtPlatformLogModel.cpp @@ -1,346 +1,339 @@ /*=================================================================== BlueBerry Platform 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. ===================================================================*/ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include "berryQtPlatformLogModel.h" #include "berryQtLogPlugin.h" #include "berryPlatform.h" #include "mbilogLoggingTypes.h" #include #include #include #include #include #include #include #include namespace berry { const QString QtPlatformLogModel::Error = QString("Error"); const QString QtPlatformLogModel::Warn = QString("Warning"); const QString QtPlatformLogModel::Fatal = QString("Fatal"); const QString QtPlatformLogModel::Info = QString("Info"); const QString QtPlatformLogModel::Debug = QString("Debug"); void QtPlatformLogModel::slotFlushLogEntries() { m_Mutex.lock(); QList *tmp=m_Active; m_Active=m_Pending; m_Pending=tmp; m_Mutex.unlock(); int num = static_cast(m_Pending->size()); if (num > 0) { int row = static_cast(m_Entries.size()); this->beginInsertRows(QModelIndex(), row, row+num-1); do { m_Entries.push_back(m_Pending->front()); m_Pending->pop_front(); } while(--num); this->endInsertRows(); } } void QtPlatformLogModel::addLogEntry(const mbilog::LogMessage &msg) { m_Mutex.lock(); //mbilog::BackendCout::FormatSmart(msg); FormatSmart is not static any more. So commented out this statement. Todo: fix m_Active->push_back(ExtendedLogMessage(msg)); m_Mutex.unlock(); emit signalFlushLogEntries(); } void QtPlatformLogModel::SetShowAdvancedFiels( bool showAdvancedFiels ) { if( m_ShowAdvancedFiels != showAdvancedFiels ) { m_ShowAdvancedFiels = showAdvancedFiels; this->beginResetModel(); this->endResetModel(); } } void QtPlatformLogModel::SetShowCategory( bool showCategory ) { if( m_ShowCategory != showCategory ) { m_ShowCategory = showCategory; this->beginResetModel(); this->endResetModel(); } } void QtPlatformLogModel::addLogEntry(const ctkPluginFrameworkEvent& event) { int level = mbilog::Info; if (event.getType() == ctkPluginFrameworkEvent::PLUGIN_ERROR) { level = mbilog::Error; } else if (event.getType() == ctkPluginFrameworkEvent::FRAMEWORK_WAIT_TIMEDOUT || event.getType() == ctkPluginFrameworkEvent::PLUGIN_WARNING) { level = mbilog::Warn; } mbilog::LogMessage msg(level,"n/a",-1,"n/a"); QString str; QDebug dbg(&str); dbg << event; msg.message = str.toStdString(); //msg.moduleName = event.getPlugin()->getSymbolicName().toStdString(); addLogEntry(msg); } QtPlatformLogModel::QtPlatformLogModel(QObject* parent) : QAbstractTableModel(parent), m_ShowAdvancedFiels(false), m_ShowCategory(true) { m_Active=new QList; m_Pending=new QList; connect(this, SIGNAL(signalFlushLogEntries()), this, SLOT( slotFlushLogEntries() ), Qt::QueuedConnection ); QtLogPlugin::GetInstance()->GetContext()->connectFrameworkListener(this, SLOT(addLogEntry(ctkPluginFrameworkEvent))); myBackend = new QtLogBackend(this); } QtPlatformLogModel::~QtPlatformLogModel() { disconnect(this, SIGNAL(signalFlushLogEntries()), this, SLOT( slotFlushLogEntries() )); QtLogPlugin::GetInstance()->GetContext()->disconnectFrameworkListener(this); // dont delete and unregister backend, only deactivate it to avoid thread syncronization issues cause mbilog::UnregisterBackend is not threadsafe // will be fixed. // delete myBackend; // delete m_Active; // delete m_Pending; m_Mutex.lock(); myBackend->Deactivate(); m_Mutex.unlock(); } // QT Binding int QtPlatformLogModel::rowCount(const QModelIndex&) const { return static_cast(m_Entries.size()); } int QtPlatformLogModel::columnCount(const QModelIndex&) const { int returnValue = 2; if( m_ShowAdvancedFiels ) returnValue += 7; if( m_ShowCategory ) returnValue += 1; return returnValue; } /* struct LogEntry { LogEntry(const std::string& msg, const std::string& src, std::time_t t) : message(msg.c_str()), moduleName(src.c_str()),time(std::clock()) { } QString message; clock_t time; QString level; QString filePath; QString lineNumber; QString moduleName; QString category; QString function; LogEntry(const mbilog::LogMessage &msg) { message = msg.message.c_str(); filePath = msg.filePath; std::stringstream out; out << msg.lineNumber; lineNumber = out.str().c_str(); moduleName = msg.moduleName; category = msg.category.c_str(); function = msg.functionName; time=std::clock(); } }; */ QVariant QtPlatformLogModel::data(const QModelIndex& index, int role) const { const ExtendedLogMessage *msg = &m_Entries[index.row()]; if (role == Qt::DisplayRole) { switch (index.column()) { case 0: if (m_ShowAdvancedFiels) return msg->getTime(); else return msg->getLevel(); case 1: if (m_ShowAdvancedFiels) return msg->getLevel(); else return msg->getMessage(); case 2: if (m_ShowAdvancedFiels) return msg->getMessage(); else return msg->getCategory(); case 3: if (m_ShowAdvancedFiels && m_ShowCategory) return msg->getCategory(); else if (m_ShowAdvancedFiels && !m_ShowCategory) return msg->getModuleName(); else break; case 4: if (m_ShowAdvancedFiels && m_ShowCategory) return msg->getModuleName(); else if (m_ShowAdvancedFiels && !m_ShowCategory) return msg->getFunctionName(); else break; case 5: if (m_ShowAdvancedFiels && m_ShowCategory) return msg->getFunctionName(); else if (m_ShowAdvancedFiels && !m_ShowCategory) return msg->getPath(); else break; case 6: if (m_ShowAdvancedFiels && m_ShowCategory) return msg->getPath(); else if (m_ShowAdvancedFiels && !m_ShowCategory) return msg->getLine(); else break; case 7: if (m_ShowAdvancedFiels && m_ShowCategory) return msg->getLine(); else break; } } else if( role == Qt::DecorationRole ) { if ( (m_ShowAdvancedFiels && index.column()==1) || (!m_ShowAdvancedFiels && index.column()==0) ) { QString file ( ":/org_blueberry_ui_qt_log/information.png" ); if( msg->message.level == mbilog::Error ) file = ":/org_blueberry_ui_qt_log/error.png"; else if( msg->message.level == mbilog::Warn ) file = ":/org_blueberry_ui_qt_log/warning.png"; else if( msg->message.level == mbilog::Debug ) file = ":/org_blueberry_ui_qt_log/debug.png"; else if( msg->message.level == mbilog::Fatal ) file = ":/org_blueberry_ui_qt_log/fatal.png"; QIcon icon(file); return QVariant(icon); } } return QVariant(); } QVariant QtPlatformLogModel::headerData(int section, Qt::Orientation orientation, int role) const { if (role == Qt::DisplayRole && orientation == Qt::Horizontal) { if( m_ShowAdvancedFiels && m_ShowCategory ) { switch (section) { case 0: return QVariant(" Time "); case 1: return QVariant(" Level "); case 2: return QVariant(" Message "); case 3: return QVariant(" Category "); case 4: return QVariant(" Module "); case 5: return QVariant(" Function "); case 6: return QVariant(" File "); case 7: return QVariant(" Line "); } } else if (m_ShowAdvancedFiels && !m_ShowCategory) { switch (section) { case 0: return QVariant(" Time "); case 1: return QVariant(" Level "); case 2: return QVariant(" Message "); case 3: return QVariant(" Module "); case 4: return QVariant(" Function "); case 5: return QVariant(" File "); case 6: return QVariant(" Line "); } } else //!m_ShowAdvancedFiels, m_ShowCategory is not handled seperately because it only activates case 2 { switch (section) { case 0: return QVariant(" Level "); case 1: return QVariant(" Message "); case 2: return QVariant(" Category "); } } } return QVariant(); } QVariant QtPlatformLogModel::ExtendedLogMessage::getTime() const { std::stringstream ss; std::locale C("C"); ss.imbue(C); ss << std::setw(7) << std::setprecision(3) << std::fixed << ((double)this->time)/CLOCKS_PER_SEC; return QVariant(QString(ss.str().c_str())); } QString QtPlatformLogModel::GetDataAsString() { QString returnValue(""); for (int message=0; messagerowCount(QModelIndex()); message++) { for (int column=0; columncolumnCount(QModelIndex()); column++) { returnValue += " " + this->data(this->index(message,column),Qt::DisplayRole).toString(); } returnValue += "\n"; } return returnValue; } } diff --git a/Plugins/org.blueberry.ui.qt.objectinspector/src/internal/berryObjectBrowserView.cpp b/Plugins/org.blueberry.ui.qt.objectinspector/src/internal/berryObjectBrowserView.cpp index ec23ed453c..29eb9e885a 100644 --- a/Plugins/org.blueberry.ui.qt.objectinspector/src/internal/berryObjectBrowserView.cpp +++ b/Plugins/org.blueberry.ui.qt.objectinspector/src/internal/berryObjectBrowserView.cpp @@ -1,271 +1,264 @@ /*=================================================================== BlueBerry Platform 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. ===================================================================*/ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include #include #include #include #include "berryObjectBrowserView.h" #include "berryDebugUtil.h" #include "berryDebugBreakpointManager.h" namespace berry { const std::string ObjectBrowserView::VIEW_ID = "objectbrowser"; ObjectBrowserView::ObjectBrowserView() : m_ActionToggleBreakpoint(this), m_ActionEnableBreakpoint(this), m_ActionDisableBreakpoint(this) { #ifdef BLUEBERRY_DEBUG_SMARTPOINTER m_Useful = true; #else m_Useful = false; #endif } void ObjectBrowserView::Init(IViewSite::Pointer site, IMemento::Pointer memento) { QtViewPart::Init(site, memento); m_StateMemento = memento; } void ObjectBrowserView::CreateQtPartControl(QWidget* parent) { if (m_Useful) { m_Controls.setupUi(parent); m_ProxyModel = new QSortFilterProxyModel(m_Controls.m_TreeView); m_ObjectModel = new QtObjectTableModel(m_ProxyModel); m_ProxyModel->setSourceModel(m_ObjectModel); m_Controls.m_TreeView->setModel(m_ProxyModel); m_Controls.m_TreeView->setSortingEnabled(true); m_Controls.m_TreeView->setContextMenuPolicy(Qt::CustomContextMenu); m_ActionToggleBreakpoint.setText(QString("Toggle Breakpoint")); m_ActionToggleBreakpoint.setCheckable(true); m_ContextMenu.addAction(&m_ActionToggleBreakpoint); auto toolbar = new QToolBar(parent); QAction* resetAction = toolbar->addAction("Reset"); toolbar->addAction("Show Breakpoints Only"); connect(resetAction, SIGNAL(triggered(bool)), this, SLOT(ResetAction(bool))); connect(m_Controls.m_TreeView->selectionModel(), SIGNAL(selectionChanged(const QItemSelection&, const QItemSelection&)), this, SLOT(SelectionChanged(const QItemSelection&, const QItemSelection&))); connect(m_Controls.m_TreeView, SIGNAL(customContextMenuRequested(const QPoint&)), this, SLOT(ContextMenuRequested(const QPoint&))); // context menu actions connect(&m_ActionToggleBreakpoint, SIGNAL(triggered(bool)), this, SLOT(ToggleBreakpoint(bool))); parent->layout()->setMenuBar(toolbar); RestoreGuiState(m_StateMemento); m_StateMemento = nullptr; } else { auto layout = new QVBoxLayout(parent); auto label = new QLabel(parent); label->setText( "Set the CMake variable BLUEBERRY_DEBUG_SMARTPOINTER to ON for a useful object browser."); label->setWordWrap(true); label->setAlignment(Qt::AlignTop); layout->addWidget(label); } } void ObjectBrowserView::RestoreGuiState(IMemento::Pointer memento) { if (memento) { IMemento::Pointer columnWidths = memento->GetChild("columnWidths"); if (columnWidths) { int colWidth = 0; if (columnWidths->GetInteger("column0", colWidth)) { m_Controls.m_TreeView->setColumnWidth(0, colWidth); } if (columnWidths->GetInteger("column1", colWidth)) { m_Controls.m_TreeView->setColumnWidth(1, colWidth); } } IMemento::Pointer splitter = memento->GetChild("splitter"); if (splitter) { QList sizes; int size = 200; splitter->GetInteger("first", size); sizes.push_back(size); splitter->GetInteger("second", size); sizes.push_back(size); m_Controls.m_Splitter->setSizes(sizes); } } } void ObjectBrowserView::ResetAction(bool /*checked*/) { m_ObjectModel->ResetData(); } void ObjectBrowserView::SelectionChanged(const QItemSelection& selected, const QItemSelection& /*deselected*/) { QList indexes = selected.indexes(); if (indexes.empty()) { m_Controls.m_DetailsView->clear(); return; } QModelIndex index = indexes.front(); if (!index.parent().isValid()) { m_Controls.m_DetailsView->clear(); } QVariant data = m_ProxyModel->data(index, Qt::UserRole); if (data.isValid()) { const ObjectItem* item = static_cast (data.value ()); if (item) { const Object* obj = nullptr; if (item->type == ObjectItem::INSTANCE) obj = item->obj; else if (item->type == ObjectItem::SMARTPOINTER) { const ObjectItem* item = static_cast (m_ProxyModel->data(index.parent(), Qt::UserRole).value ()); if (item) obj = item->obj; } if (obj) { QString str; QDebug ss(&str); obj->Print(ss); m_Controls.m_DetailsView->setPlainText(str); } else { m_Controls.m_DetailsView->setPlainText(QString("0")); } } else { m_Controls.m_DetailsView->setPlainText(QString("0")); } } } void ObjectBrowserView::ContextMenuRequested(const QPoint& p) { QModelIndex index = m_Controls.m_TreeView->selectionModel()->currentIndex(); if (index.isValid()) { QVariant data = m_ProxyModel->data(index, Qt::UserRole); if (!data.isValid()) return; const ObjectItem* item = static_cast (data.value ()); if (item->type == ObjectItem::CLASS) return; m_ContextMenu.exec(m_Controls.m_TreeView->mapToGlobal(p)); } } void ObjectBrowserView::ToggleBreakpoint(bool checked) { QModelIndex index = m_Controls.m_TreeView->selectionModel()->currentIndex(); if (index.isValid()) { QVariant data = m_ProxyModel->data(index, Qt::UserRole); if (!data.isValid()) return; const ObjectItem* item = static_cast (data.value ()); if (item->type == ObjectItem::INSTANCE) { #ifdef BLUEBERRY_DEBUG_SMARTPOINTER if (checked) DebugUtil::GetBreakpointManager()->AddObjectBreakpoint(item->obj->GetTraceId()); else DebugUtil::GetBreakpointManager()->RemoveObjectBreakpoint(item->obj->GetTraceId()); #endif } else if (item->type == ObjectItem::SMARTPOINTER) { if (checked) DebugUtil::GetBreakpointManager()->AddSmartpointerBreakpoint(item->spId); else DebugUtil::GetBreakpointManager()->RemoveSmartpointerBreakpoint( item->spId); } } } void ObjectBrowserView::SetFocus() { if (m_Useful) { m_Controls.m_TreeView->setFocus(); } } void ObjectBrowserView::SaveState(IMemento::Pointer memento) { if (!m_Useful) return; IMemento::Pointer cols = memento->CreateChild("columnWidths"); cols->PutInteger("column0", m_Controls.m_TreeView->columnWidth(0)); cols->PutInteger("column1", m_Controls.m_TreeView->columnWidth(1)); QList sizes(m_Controls.m_Splitter->sizes()); IMemento::Pointer splitter = memento->CreateChild("splitter"); splitter->PutInteger("first", sizes[0]); splitter->PutInteger("second", sizes[1]); // delete the tree view here in order to delete the underlying model // which in turn unregisters the object listener. Otherwise, we get // notifications of deleted objects during workbench shutdown which // leads to segmentation faults m_Controls.m_TreeView->deleteLater(); } } //namespace berry diff --git a/Plugins/org.blueberry.ui.qt/resources/dark/tab_close_grey.svg b/Plugins/org.blueberry.ui.qt/resources/dark/tab_close_grey.svg index 579aeb2abe..2d55a20f8c 100644 --- a/Plugins/org.blueberry.ui.qt/resources/dark/tab_close_grey.svg +++ b/Plugins/org.blueberry.ui.qt/resources/dark/tab_close_grey.svg @@ -1,74 +1,74 @@ image/svg+xml diff --git a/Plugins/org.blueberry.ui.qt/resources/dark/tab_close_grey_active.svg b/Plugins/org.blueberry.ui.qt/resources/dark/tab_close_grey_active.svg index 32dda23c66..4582f8cfae 100644 --- a/Plugins/org.blueberry.ui.qt/resources/dark/tab_close_grey_active.svg +++ b/Plugins/org.blueberry.ui.qt/resources/dark/tab_close_grey_active.svg @@ -1,79 +1,79 @@ image/svg+xml diff --git a/Plugins/org.blueberry.ui.qt/resources/tab_close.svg b/Plugins/org.blueberry.ui.qt/resources/tab_close.svg index 7a3bdfb95a..8e9ca2109d 100644 --- a/Plugins/org.blueberry.ui.qt/resources/tab_close.svg +++ b/Plugins/org.blueberry.ui.qt/resources/tab_close.svg @@ -1,56 +1,56 @@ image/svg+xml diff --git a/Plugins/org.blueberry.ui.qt/src/actions/berryContributionItemFactory.h b/Plugins/org.blueberry.ui.qt/src/actions/berryContributionItemFactory.h index 6cd54e8dda..656bcc835d 100644 --- a/Plugins/org.blueberry.ui.qt/src/actions/berryContributionItemFactory.h +++ b/Plugins/org.blueberry.ui.qt/src/actions/berryContributionItemFactory.h @@ -1,134 +1,136 @@ /*=================================================================== BlueBerry Platform 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 BERRYCONTRIBUTIONITEMFACTORY_H #define BERRYCONTRIBUTIONITEMFACTORY_H #include #include #include namespace berry { struct IContributionItem; struct IWorkbenchWindow; /** * Access to standard contribution items provided by the workbench. *

* Most of the functionality of this class is provided by * static methods and fields. * Example usage: *

  * MenuManager menu = ...;
  * IContributionItem::Pointer reEdit
  *     = ContributionItemFactory::REOPEN_EDITORS->Create(window);
  * menu->Add(reEdit);
  * 
*

*

* Clients may declare subclasses that provide additional application-specific * contribution item factories. *

*/ class BERRY_UI_QT ContributionItemFactory { private: /** * Id of contribution items created by this factory. */ const QString contributionItemId; protected: /** * Creates a new workbench contribution item factory with the given id. * * @param contributionItemId the id of contribution items created by this factory */ ContributionItemFactory(const QString& contributionItemId); public: /** * Creates a new standard contribution item for the given workbench window. *

* A typical contribution item automatically registers listeners against the * workbench window so that it can keep its enablement state up to date. * Ordinarily, the window's references to these listeners will be dropped * automatically when the window closes. However, if the client needs to get * rid of a contribution item while the window is still open, the client must * call IContributionItem#dispose to give the item an * opportunity to deregister its listeners and to perform any other cleanup. *

* * @param window the workbench window * @return the workbench contribution item */ virtual SmartPointer Create(IWorkbenchWindow* window) = 0; /** * Returns the id of this contribution item factory. * * @return the id of contribution items created by this factory */ QString GetId() const; /** * Workbench contribution item (id "openWindows"): A list of windows * currently open in the workbench. Selecting one of the items makes the * corresponding window the active window. * This action dynamically maintains the list of windows. */ static const QScopedPointer OPEN_WINDOWS; /** * Workbench contribution item (id "viewsShortlist"): A list of views * available to be opened in the window, arranged as a shortlist of * promising views and an "Other" subitem. Selecting * one of the items opens the corresponding view in the active window. * This action dynamically maintains the view shortlist. */ static const QScopedPointer VIEWS_SHORTLIST; /** * Workbench contribution item (id "reopenEditors"): A list of recent * editors (with inputs) available to be reopened in the window. Selecting * one of the items reopens the corresponding editor on its input in the * active window. This action dynamically maintains the list of editors. */ static const QScopedPointer REOPEN_EDITORS; /** * Workbench contribution item (id "perspectivesShortlist"): A list of * perspectives available to be opened, arranged as a shortlist of * promising perspectives and an "Other" subitem. Selecting * one of the items makes the corresponding perspective active. Should a * new perspective need to be opened, a workbench user preference controls * whether the prespective is opened in the active window or a new window. * This action dynamically maintains the perspectives shortlist. */ static const QScopedPointer PERSPECTIVES_SHORTLIST; + virtual ~ContributionItemFactory() = default; + }; } #endif // BERRYCONTRIBUTIONITEMFACTORY_H diff --git a/Plugins/org.blueberry.ui.qt/src/berryIElementFactory.h b/Plugins/org.blueberry.ui.qt/src/berryIElementFactory.h index a3a821e884..8e22b87dd9 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryIElementFactory.h +++ b/Plugins/org.blueberry.ui.qt/src/berryIElementFactory.h @@ -1,75 +1,75 @@ /*=================================================================== BlueBerry Platform 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 BERRYIELEMENTFACTORY_H #define BERRYIELEMENTFACTORY_H #include #include namespace berry { struct IAdaptable; struct IMemento; /** * A factory for re-creating objects from a previously saved memento. *

* Clients should implement this interface and include the name of their class * in an extension to the platform extension point named * "org.blueberry.ui.elementFactories". * For example, the plug-in's XML markup might contain: *

  * <extension point="org.blueberry.ui.elementFactories">
  *    <factory id="com.example.myplugin.MyFactory" class="MyFactory" />
  * </extension>
  * 
*

* * @see IPersistableElement * @see IMemento * @see IWorkbench#GetElementFactory */ struct BERRY_UI_QT IElementFactory { - ~IElementFactory(); + virtual ~IElementFactory(); /** * Re-creates and returns an object from the state captured within the given * memento. *

* If the result is not null, it should be persistable; that is, *

    * result.getAdapter(org.eclipse.ui.IPersistableElement.class)
    * 
* should not return null. The caller takes ownership of the * result and must delete it when it is not needed any more. *

* * @param memento * a memento containing the state for the object * @return an object, or nullptr if the element could not be * created */ virtual IAdaptable* CreateElement(const SmartPointer& memento) = 0; }; } Q_DECLARE_INTERFACE(berry::IElementFactory, "org.blueberry.ui.IElementFactory") #endif // BERRYIELEMENTFACTORY_H diff --git a/Plugins/org.blueberry.ui.qt/src/berryIQtPreferencePage.h b/Plugins/org.blueberry.ui.qt/src/berryIQtPreferencePage.h index e764cfcabb..756f0a6d6d 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryIQtPreferencePage.h +++ b/Plugins/org.blueberry.ui.qt/src/berryIQtPreferencePage.h @@ -1,57 +1,50 @@ /*=================================================================== BlueBerry Platform 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 BERRYIQTPREFERENCEPAGE_H_ #define BERRYIQTPREFERENCEPAGE_H_ -#ifdef __MINGW32__ -// We need to include winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include #include "berryIPreferencePage.h" #include namespace berry { /** * \ingroup org_blueberry_ui_qt * */ struct BERRY_UI_QT IQtPreferencePage : public IPreferencePage { berryObjectMacro(berry::IQtPreferencePage); virtual void CreateQtControl(QWidget* parent) = 0; virtual QWidget* GetQtControl() const = 0; protected: void CreateControl(void* parent) override; void* GetControl() const override; }; } #endif /*BERRYIQTPREFERENCEPAGE_H_*/ diff --git a/Plugins/org.blueberry.ui.qt/src/berryQtViewPart.h b/Plugins/org.blueberry.ui.qt/src/berryQtViewPart.h index ac6c5e9398..9a099b5368 100644 --- a/Plugins/org.blueberry.ui.qt/src/berryQtViewPart.h +++ b/Plugins/org.blueberry.ui.qt/src/berryQtViewPart.h @@ -1,53 +1,46 @@ /*=================================================================== BlueBerry Platform 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 BERRYQTVIEWPART_H_ #define BERRYQTVIEWPART_H_ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include #include #include namespace berry { class BERRY_UI_QT QtViewPart : public ViewPart { public: berryObjectMacro(QtViewPart) void CreatePartControl(QWidget* parent) override; protected: virtual void CreateQtPartControl(QWidget* parent) = 0; }; } #endif /*BERRYQTVIEWPART_H_*/ diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryQtDisplay.h b/Plugins/org.blueberry.ui.qt/src/internal/berryQtDisplay.h index 756605c8fd..52feaf2168 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryQtDisplay.h +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryQtDisplay.h @@ -1,78 +1,71 @@ /*=================================================================== BlueBerry Platform 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 BERRYQTDISPLAY_H_ #define BERRYQTDISPLAY_H_ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include #include #include namespace berry { class QtDisplay: public QObject, public Display { Q_OBJECT public: QtDisplay(); bool InDisplayThread() override; void AsyncExec(Poco::Runnable*) override; void SyncExec(Poco::Runnable*) override; int RunEventLoop() override; void ExitEventLoop(int code) override; signals: void NewAsyncRunnable(Poco::Runnable*); void NewSyncRunnable(Poco::Runnable*); protected: /** * This method must be called from within the UI thread * and should create the Display instance and initialize * variables holding implementation specific thread data. */ void CreateDisplay() override; protected slots: void ExecuteRunnable(Poco::Runnable*); private: QThread * displayThread; }; } #endif /* BERRYQTDISPLAY_H_ */ diff --git a/Plugins/org.blueberry.ui.qt/src/internal/berryQtShowViewAction.h b/Plugins/org.blueberry.ui.qt/src/internal/berryQtShowViewAction.h index 681b436200..2e14d881e0 100644 --- a/Plugins/org.blueberry.ui.qt/src/internal/berryQtShowViewAction.h +++ b/Plugins/org.blueberry.ui.qt/src/internal/berryQtShowViewAction.h @@ -1,62 +1,55 @@ /*=================================================================== BlueBerry Platform 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 BERRYQTSHOWVIEWACTION_H_ #define BERRYQTSHOWVIEWACTION_H_ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include #include #include //TODO should be removed later #include namespace berry { class BERRY_UI_QT QtShowViewAction : public QAction { Q_OBJECT private: IWorkbenchWindow* m_Window; IViewDescriptor::Pointer m_Desc; public: QtShowViewAction(IWorkbenchWindow::Pointer window, IViewDescriptor::Pointer desc) ; protected slots: /** * Implementation of method defined on IAction. */ void Run(); }; } #endif /*BERRYQTSHOWVIEWACTION_H_*/ diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkCloseProjectAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkCloseProjectAction.h index 110b154660..e8512b7c92 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkCloseProjectAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkCloseProjectAction.h @@ -1,56 +1,49 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ #ifndef QmitkCloseProjectAction_H_ #define QmitkCloseProjectAction_H_ -#ifdef __MINGW32__ -// We need to include winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include #include #include namespace berry { struct IWorkbenchWindow; } /** * \ingroup org_mitk_gui_qt_application */ class MITK_QT_APP QmitkCloseProjectAction : public QAction { Q_OBJECT public: QmitkCloseProjectAction(berry::SmartPointer window); QmitkCloseProjectAction(berry::IWorkbenchWindow* window); QmitkCloseProjectAction(const QIcon & icon, berry::SmartPointer window); QmitkCloseProjectAction(const QIcon & icon, berry::IWorkbenchWindow* window); protected slots: void Run(); private: void init(berry::IWorkbenchWindow* window); berry::IWorkbenchWindow* m_Window; }; #endif /*QmitkCloseProjectAction_H_*/ diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkFileOpenAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkFileOpenAction.h index 3e92569cf5..79675eb528 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkFileOpenAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkFileOpenAction.h @@ -1,63 +1,56 @@ /*=================================================================== 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 QMITKFILEOPENACTION_H_ #define QMITKFILEOPENACTION_H_ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include #include #include #include #include class QmitkFileOpenActionPrivate; /** * \ingroup org_mitk_gui_qt_application */ class MITK_QT_APP QmitkFileOpenAction : public QAction { Q_OBJECT public: QmitkFileOpenAction(berry::IWorkbenchWindow::Pointer window); QmitkFileOpenAction(const QIcon & icon, berry::IWorkbenchWindow::Pointer window); QmitkFileOpenAction(const QIcon & icon, berry::IWorkbenchWindow* window); ~QmitkFileOpenAction() override; protected slots: virtual void Run(); private: const QScopedPointer d; }; #endif /*QMITKFILEOPENACTION_H_*/ diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkRedoAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkRedoAction.h index 0df462d853..0ba700c582 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkRedoAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkRedoAction.h @@ -1,61 +1,54 @@ /*=================================================================== 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 QmitkRedoAction_H_ #define QmitkRedoAction_H_ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include #include #include #include #include class QmitkRedoActionPrivate; /** * \ingroup org_mitk_gui_qt_application */ class MITK_QT_APP QmitkRedoAction : public QAction { Q_OBJECT public: QmitkRedoAction(berry::IWorkbenchWindow::Pointer window); QmitkRedoAction(const QIcon & icon, berry::IWorkbenchWindow::Pointer window); QmitkRedoAction(const QIcon & icon, berry::IWorkbenchWindow* window); ~QmitkRedoAction() override; protected slots: virtual void Run(); private: const QScopedPointer d; }; #endif /*QmitkRedoAction_H_*/ diff --git a/Plugins/org.mitk.gui.qt.application/src/QmitkUndoAction.h b/Plugins/org.mitk.gui.qt.application/src/QmitkUndoAction.h index e10c9f0db6..65e93ce0fe 100644 --- a/Plugins/org.mitk.gui.qt.application/src/QmitkUndoAction.h +++ b/Plugins/org.mitk.gui.qt.application/src/QmitkUndoAction.h @@ -1,61 +1,54 @@ /*=================================================================== 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 QmitkUndoAction_H_ #define QmitkUndoAction_H_ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include #include #include #include #include class QmitkUndoActionPrivate; /** * \ingroup org_mitk_gui_qt_application */ class MITK_QT_APP QmitkUndoAction : public QAction { Q_OBJECT public: QmitkUndoAction(berry::IWorkbenchWindow::Pointer window); QmitkUndoAction(const QIcon & icon, berry::IWorkbenchWindow::Pointer window); QmitkUndoAction(const QIcon & icon, berry::IWorkbenchWindow* window); ~QmitkUndoAction() override; protected slots: virtual void Run(); private: const QScopedPointer d; }; #endif /*QmitkUndoAction_H_*/ diff --git a/Plugins/org.mitk.gui.qt.basicimageprocessing/plugin.xml b/Plugins/org.mitk.gui.qt.basicimageprocessing/plugin.xml index ffc671d614..bb84a730ad 100644 --- a/Plugins/org.mitk.gui.qt.basicimageprocessing/plugin.xml +++ b/Plugins/org.mitk.gui.qt.basicimageprocessing/plugin.xml @@ -1,47 +1,47 @@ - + Perform basic image operations like add, subtract etc.. diff --git a/Plugins/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingViewControls.ui b/Plugins/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingViewControls.ui index 179daf05a9..b6a6c4dd2b 100644 --- a/Plugins/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.basicimageprocessing/src/internal/QmitkBasicImageProcessingViewControls.ui @@ -1,473 +1,428 @@ QmitkBasicImageProcessingViewControls 0 0 448 980 Form - true + false - - 0 - - - 6 - - - 0 - - - 6 - Filters (One Image) true Arithmetic (Two Images) - Select an Image in Data Manager + Select an image in the Data Manager true false Output image will be 3D Choose time step if 4D (Slider for both images) false false Output image will be 3D true - - true - - - false - false - - 0 - - - 6 - - - 0 - - - 0 - false Select second image: false m_ImageSelector2 false false E&xecute false Select an operation: false cbWhat2 false Qt::Vertical 254 403 - - true - - - 0 - - - 6 - - - 0 - - - 0 - false Select an operation: false cbWhat1 false false ... and parameters: false false Parameter 1: false sbParam1 false Parameter 2: false sbParam2 false &Execute false Hide Original Image true false Parameter 3: false Parameter 4: false 0 0 false 0 0 Qt::LeftToRight Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 4 -999999999.000000000000000 999999999.000000000000000 false 0 0 4 -999999999.000000000000000 999999999.000000000000000 false 0 0 4 -999999999.000000000000000 999999999.000000000000000 false 0 0 -999999999 999999999 false 0 0 -999999999 999999999 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
QmitkSliderNavigatorWidget QWidget
QmitkSliderNavigatorWidget.h
diff --git a/Plugins/org.mitk.gui.qt.cest/src/internal/org_mitk_gui_qt_cest_Activator.cpp b/Plugins/org.mitk.gui.qt.cest/src/internal/org_mitk_gui_qt_cest_Activator.cpp index 028e8bbd7e..2445710d76 100644 --- a/Plugins/org.mitk.gui.qt.cest/src/internal/org_mitk_gui_qt_cest_Activator.cpp +++ b/Plugins/org.mitk.gui.qt.cest/src/internal/org_mitk_gui_qt_cest_Activator.cpp @@ -1,40 +1,27 @@ /*=================================================================== 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 "org_mitk_gui_qt_cest_Activator.h" - -#include - #include "QmitkCESTStatisticsView.h" -namespace mitk { - -void org_mitk_gui_qt_cest_Activator::start(ctkPluginContext* context) +void mitk::org_mitk_gui_qt_cest_Activator::start(ctkPluginContext* context) { BERRY_REGISTER_EXTENSION_CLASS(QmitkCESTStatisticsView, context) } -void org_mitk_gui_qt_cest_Activator::stop(ctkPluginContext* context) +void mitk::org_mitk_gui_qt_cest_Activator::stop(ctkPluginContext*) { - Q_UNUSED(context) } - -} - -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - Q_EXPORT_PLUGIN2(org_mitk_gui_qt_cest, mitk::org_mitk_gui_qt_cest_Activator) -#endif diff --git a/Plugins/org.mitk.gui.qt.cest/src/internal/org_mitk_gui_qt_cest_Activator.h b/Plugins/org.mitk.gui.qt.cest/src/internal/org_mitk_gui_qt_cest_Activator.h index 856780972d..f7060b83bc 100644 --- a/Plugins/org.mitk.gui.qt.cest/src/internal/org_mitk_gui_qt_cest_Activator.h +++ b/Plugins/org.mitk.gui.qt.cest/src/internal/org_mitk_gui_qt_cest_Activator.h @@ -1,43 +1,36 @@ /*=================================================================== 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 org_mitk_gui_qt_cest_Activator_h #define org_mitk_gui_qt_cest_Activator_h #include -namespace mitk { - -class org_mitk_gui_qt_cest_Activator : - public QObject, public ctkPluginActivator +namespace mitk { - Q_OBJECT -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) - Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_cest") -#endif - Q_INTERFACES(ctkPluginActivator) - -public: - - void start(ctkPluginContext* context); - void stop(ctkPluginContext* context); - -}; // org_mitk_gui_qt_cest_Activator - + class org_mitk_gui_qt_cest_Activator : public QObject, public ctkPluginActivator + { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_cest") + Q_INTERFACES(ctkPluginActivator) + + public: + void start(ctkPluginContext* context); + void stop(ctkPluginContext* context); + }; } -#endif // org_mitk_gui_qt_cest_Activator_h +#endif diff --git a/Plugins/org.mitk.gui.qt.common.legacy/src/QmitkFunctionality.h b/Plugins/org.mitk.gui.qt.common.legacy/src/QmitkFunctionality.h index 517c36af04..7e46c84b1a 100755 --- a/Plugins/org.mitk.gui.qt.common.legacy/src/QmitkFunctionality.h +++ b/Plugins/org.mitk.gui.qt.common.legacy/src/QmitkFunctionality.h @@ -1,407 +1,400 @@ /*=================================================================== 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 QMITKFUNCTIONALITY_H_ #define QMITKFUNCTIONALITY_H_ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - //# blueberry stuff #include #include #include #include //# mitk stuff #include #include "mitkDataNodeSelection.h" #include #include #include #include // CTK Includes #include //# forward declarations namespace mitk { class DataNode; struct IDataStorageService; } namespace berry { struct IBerryPreferences; } class QmitkFunctionalitySelectionProvider; /// /// \ingroup org_mitk_gui_qt_common_legacy /// /// \class QmitkFunctionality /// /// \brief The base class of all MITK related blueberry views (~ in the old version of MITK, this was called "Functionality") /// /// QmitkFunctionality provides several convenience methods that eases the introduction of a new view: /// ///
    ///
  1. Access to the DataStorage (~ the shared data repository) ///
  2. Access to the StdMultiWidget (the 2x2 RenderWindow arrangement) ///
  3. Access to and update notification for the functionality/view preferences ///
  4. Access to and update notification for the current DataNode selection / to DataNode selection events send through the SelectionService ///
  5. Methods to send DataNode selections through the SelectionService ///
  6. Some events for unproblematic inter-View communication (e.g. when to add/remove interactors) ///
  7. Some minor important convenience methods (like changing the mouse cursor/exception handling) ///
/// /// Please use the Activated/Deactivated method to add/remove interactors, disabling multiwidget crosshair or anything which may /// "affect" other functionalities. For further reading please have a look at QmitkFunctionality::IsExclusiveFunctionality(). /// class MITK_QT_COMMON_LEGACY QmitkFunctionality : public berry::QtViewPart { //# public virtual methods which can be overwritten public: /// /// Creates smartpointer typedefs /// berryObjectMacro(QmitkFunctionality); /// /// Nothing to do in the standard ctor. Initiliaze your GUI in CreateQtPartControl(QWidget*) /// \see berry::QtViewPart::CreateQtPartControl(QWidget*) /// QmitkFunctionality(); /// /// Disconnects all standard event listeners /// virtual ~QmitkFunctionality(); /// /// Called, when the WorkbenchPart gets closed /// by the user directly or by closing the whole /// app (e.g. for removing event listeners) /// virtual void ClosePart(); /// /// Called when the selection in the workbench changed /// virtual void OnSelectionChanged(std::vector /*nodes*/); /// /// Called when the preferences object of this view changed. /// \see GetPreferences() /// virtual void OnPreferencesChanged(const berry::IBerryPreferences*); /// /// Make this view manage multiple DataStorage. If set to true GetDataStorage() /// will return the currently active DataStorage (and not the default one). /// \see GetDataStorage() /// void SetHandleMultipleDataStorages(bool multiple); /// /// \return true if this view handles multiple DataStorages, false otherwise /// bool HandlesMultipleDataStorages() const; /// /// Called when a StdMultiWidget is available. Should not be used anymore, see GetActiveStdMultiWidget() /// \see GetActiveStdMultiWidget() /// virtual void StdMultiWidgetAvailable(QmitkStdMultiWidget& stdMultiWidget); /// /// Called when a StdMultiWidget is available. Should not be used anymore, see GetActiveStdMultiWidget() /// \see GetActiveStdMultiWidget() /// virtual void StdMultiWidgetClosed(QmitkStdMultiWidget& stdMultiWidget); /// /// Called when no StdMultiWidget is available anymore. Should not be used anymore, see GetActiveStdMultiWidget() /// \see GetActiveStdMultiWidget() /// virtual void StdMultiWidgetNotAvailable(); /// /// Only called when IsExclusiveFunctionality() returns true. /// \see IsExclusiveFunctionality() /// virtual void Activated(); /// /// \return true if this view is currently activated, false otherwise /// bool IsActivated() const; /// /// Only called when IsExclusiveFunctionality() returns true. /// \see IsExclusiveFunctionality() /// virtual void Deactivated(); /// /// Some functionalities need to add special interactors, removes the crosshair from the stdmultiwidget, etc. /// In this case the functionality has to tidy up when changing to another functionality /// which also wants to change the "default configuration". In the old Qt3-based /// version of MITK, two functionalities could never be opened at the same time so that the /// methods Activated() and Deactivated() were the right place for the functionalitites to /// add/remove their interactors, etc. This is still true for the new MITK Workbench, /// but as there can be several functionalities visible at the same time, the behaviour concerning /// when Activated() and Deactivated() are called has changed: /// /// 1. Activated() and Deactivated() are only called if IsExclusiveFunctionality() returns true /// /// 2. If only one standalone functionality is or becomes visible, Activated() will be called on that functionality /// /// 3. If two or more standalone functionalities are visible, /// Activated() will be called on the functionality that receives focus, Deactivated() will be called /// on the one that looses focus, gets hidden or closed /// /// /// As a consequence of 1. if you overwrite IsExclusiveFunctionality() and let it return false, you /// signalize the MITK Workbench that this functionality does nothing to the "default configuration" /// and can easily be visible while other functionalities are also visible. /// /// By default the method returns true. /// /// \return true if this functionality is meant to work as a standalone view, false otherwise /// virtual bool IsExclusiveFunctionality() const; /// /// Informs other parts of the workbench that node is selected via the blueberry selection service. /// void FireNodeSelected(mitk::DataNode* node); /// /// Informs other parts of the workbench that the nodes are selected via the blueberry selection service. /// void FireNodesSelected(std::vector nodes); /// /// Called when this functionality becomes visible ( no matter what IsExclusiveFunctionality() returns ) /// virtual void Visible(); /// /// \return true if this view is currently visible, false otherwise /// bool IsVisible() const; /// /// Called when this functionality is hidden ( no matter what IsExclusiveFunctionality() returns ) /// virtual void Hidden(); //# protected virtual methods which can be overwritten protected: /// /// Called when a DataStorage Add event was thrown. May be reimplemented /// by deriving classes. /// virtual void NodeAdded(const mitk::DataNode* node); /// /// Called when a DataStorage Changed event was thrown. May be reimplemented /// by deriving classes. /// virtual void NodeChanged(const mitk::DataNode* /*node*/); /// /// Called when a DataStorage Remove event was thrown. May be reimplemented /// by deriving classes. /// virtual void NodeRemoved(const mitk::DataNode* node); /// /// Called when a DataStorage add *or* remove *or* change event was thrown. May be reimplemented /// by deriving classes. /// virtual void DataStorageChanged(); /// /// \return the selection of the currently active part of the workbench or an empty vector /// if nothing is selected /// std::vector GetCurrentSelection() const; /// /// Returns the current selection made in the datamanager bundle or an empty vector /// if nothing`s selected or if the bundle does not exist /// std::vector GetDataManagerSelection() const; /// /// Returns the Preferences object for this Functionality. /// Important: When refering to this preferences, e.g. in a PreferencePage: The ID /// for this preferences object is "/", e.g. "/org.mitk.views.datamanager" /// berry::IPreferences::Pointer GetPreferences() const; /// /// Returns the default or the currently active DataStorage if m_HandlesMultipleDataStorages /// is set to true /// \see SetHandleMultipleDataStorages(bool) /// \see HandlesMultipleDataStorages() /// mitk::DataStorage::Pointer GetDataStorage() const; /// /// \return always returns the default DataStorage /// mitk::DataStorage::Pointer GetDefaultDataStorage() const; mitk::IDataStorageReference::Pointer GetDataStorageReference() const; /// /// Returns the default and active StdMultiWidget. /// \param reCreateWidget a boolean flag to en-/disable the attept to re-create the StdWidget /// If there is not StdMultiWidget yet a new one is /// created in this method when called with default parameter! /// QmitkStdMultiWidget* GetActiveStdMultiWidget( bool reCreateWidget = true); /// /// Outputs an error message to the console and displays a message box containing /// the exception description. /// \param e the exception which should be handled /// \param showDialog controls, whether additionally a message box should be /// displayed to inform the user that something went wrong /// void HandleException( std::exception& e, QWidget* parent = nullptr, bool showDialog = true ) const; /// /// Calls HandleException ( std::exception&, QWidget*, bool ) internally /// \see HandleException ( std::exception&, QWidget*, bool ) /// void HandleException( const char* str, QWidget* parent = nullptr, bool showDialog = true ) const; /// /// Convenient method to set and reset a wait cursor ("hourglass") /// void WaitCursorOn(); /// /// Convenient method to restore the standard cursor /// void WaitCursorOff(); /// /// Convenient method to set and reset a busy cursor /// void BusyCursorOn(); /// /// Convenient method to restore the standard cursor /// void BusyCursorOff(); /// /// Convenient method to restore the standard cursor /// void RestoreOverrideCursor(); //# other public methods which should not be overwritten public: /// /// Creates a scroll area for this view and calls CreateQtPartControl then /// void CreatePartControl(QWidget* parent) override; /// /// Called when this view receives the focus. Same as Activated() /// \see Activated() /// void SetFocus() override; /// /// Called when a DataStorage Add Event was thrown. Sets /// m_InDataStorageChanged to true and calls NodeAdded afterwards. /// \see m_InDataStorageChanged /// void NodeAddedProxy(const mitk::DataNode* node); /// /// Called when a DataStorage remove event was thrown. Sets /// m_InDataStorageChanged to true and calls NodeRemoved afterwards. /// \see m_InDataStorageChanged /// void NodeRemovedProxy(const mitk::DataNode* node); /// /// Called when a DataStorage changed event was thrown. Sets /// m_InDataStorageChanged to true and calls NodeChanged afterwards. /// \see m_InDataStorageChanged /// void NodeChangedProxy(const mitk::DataNode* node); /// /// Toggles the visible flag m_Visible /// void SetVisible(bool visible); /// /// Toggles the activated flag m_Activated /// void SetActivated(bool activated); /// /// Called, when the WorkbenchPart gets closed for removing event listeners /// Internally this method calls ClosePart after it removed the listeners registered /// by QmitkFunctionality. By having this proxy method the user does not have to /// call QmitkFunctionality::ClosePart() when overwriting ClosePart() /// void ClosePartProxy(); //# other protected methods which should not be overwritten (or which are deprecated) protected: /// /// Called immediately after CreateQtPartControl(). /// Here standard event listeners for a QmitkFunctionality are registered /// void AfterCreateQtPartControl(); /// /// code to activate the last visible functionality /// void ActivateLastVisibleFunctionality(); /// /// reactions to selection events from data manager (and potential other senders) /// void BlueBerrySelectionChanged(const berry::IWorkbenchPart::Pointer& sourcepart, const berry::ISelection::ConstPointer& selection); /// /// Converts a mitk::DataNodeSelection to a std::vector (possibly empty /// std::vector DataNodeSelectionToVector(mitk::DataNodeSelection::ConstPointer currentSelection) const; //# protected fields protected: /// /// helper stuff to observe BlueBerry selections /// friend struct berry::SelectionChangedAdapter; /// /// Saves the parent of this view (this is the scrollarea created in CreatePartControl(QWidget*) /// \see CreatePartControl(QWidget*) /// QWidget* m_Parent; /// /// Saves if this view is the currently active one. /// bool m_Active; /// /// Saves if this view is visible /// bool m_Visible; //# private fields: private: /// /// Holds the current selection (selection made by this Functionality !!!) /// QmitkFunctionalitySelectionProvider* m_SelectionProvider; /// /// object to observe BlueBerry selections /// QScopedPointer m_BlueBerrySelectionListener; ctkServiceTracker m_DataStorageServiceTracker; /// /// Saves if this view handles multiple datastorages /// bool m_HandlesMultipleDataStorages; /// /// Saves if this class is currently working on DataStorage changes. /// This is a protector variable to avoid recursive calls on event listener functions. bool m_InDataStorageChanged; /// /// saves all visible functionalities /// std::set m_VisibleFunctionalities; }; #endif /*QMITKFUNCTIONALITY_H_*/ diff --git a/Plugins/org.mitk.gui.qt.common/files.cmake b/Plugins/org.mitk.gui.qt.common/files.cmake index 2564418383..850134fb4e 100755 --- a/Plugins/org.mitk.gui.qt.common/files.cmake +++ b/Plugins/org.mitk.gui.qt.common/files.cmake @@ -1,38 +1,62 @@ set(SRC_CPP_FILES QmitkAbstractRenderEditor.cpp QmitkAbstractView.cpp QmitkDataNodeSelectionProvider.cpp QmitkDnDFrameWidget.cpp + QmitkSelectionServiceConnector.cpp QmitkSliceNavigationListener.cpp + QmitkSingleNodeSelectionWidget.cpp + QmitkNodeSelectionDialog.cpp + QmitkAbstractNodeSelectionWidget.cpp + QmitkMultiNodeSelectionWidget.cpp + QmitkNodeSelectionPreferenceHelper.cpp + QmitkNodeSelectionButton.cpp ) set(INTERNAL_CPP_FILES QmitkCommonActivator.cpp QmitkDataNodeItemModel.cpp QmitkDataNodeSelection.cpp QmitkViewCoordinator.cpp + QmitkNodeSelectionConstants.cpp + QmitkNodeSelectionPreferencePage.cpp +) + +set(UI_FILES + src/QmitkSingleNodeSelectionWidget.ui + src/QmitkMultiNodeSelectionWidget.ui + src/QmitkNodeSelectionDialog.ui + src/internal/QmitkNodeSelectionPreferencePage.ui ) set(MOC_H_FILES src/QmitkAbstractRenderEditor.h src/QmitkDnDFrameWidget.h + src/QmitkSelectionServiceConnector.h src/QmitkSliceNavigationListener.h - + src/QmitkSingleNodeSelectionWidget.h + src/QmitkNodeSelectionDialog.h + src/QmitkAbstractNodeSelectionWidget.h + src/QmitkMultiNodeSelectionWidget.h + src/QmitkNodeSelectionButton.h src/internal/QmitkCommonActivator.h + src/internal/QmitkNodeSelectionPreferencePage.h ) set(CACHED_RESOURCE_FILES + plugin.xml + resources/times.svg ) set(QRC_FILES ) set(CPP_FILES ) foreach(file ${SRC_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/${file}) endforeach(file ${SRC_CPP_FILES}) foreach(file ${INTERNAL_CPP_FILES}) set(CPP_FILES ${CPP_FILES} src/internal/${file}) endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.common/plugin.xml b/Plugins/org.mitk.gui.qt.common/plugin.xml new file mode 100644 index 0000000000..e81a484d36 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/plugin.xml @@ -0,0 +1,6 @@ + + + + + + diff --git a/Plugins/org.mitk.gui.qt.common/resources/times.svg b/Plugins/org.mitk.gui.qt.common/resources/times.svg new file mode 100644 index 0000000000..571a32a122 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/resources/times.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.cpp new file mode 100644 index 0000000000..669c0b128f --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.cpp @@ -0,0 +1,114 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical and Biological Informatics. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + + +#include "QmitkAbstractNodeSelectionWidget.h" + +#include +#include + +QmitkAbstractNodeSelectionWidget::QmitkAbstractNodeSelectionWidget(QWidget* parent) : QWidget(parent), m_InvalidInfo("Error. Select data."), +m_EmptyInfo("Empty. Make a selection."), m_PopUpTitel("Select a data node"), m_PopUpHint(""), +m_IsOptional(false), m_SelectOnlyVisibleNodes(true) +{ +} + +void QmitkAbstractNodeSelectionWidget::SetDataStorage(mitk::DataStorage* dataStorage) +{ + if (m_DataStorage != dataStorage) + { + m_DataStorage = dataStorage; + } +}; + +void QmitkAbstractNodeSelectionWidget::SetNodePredicate(mitk::NodePredicateBase* nodePredicate) +{ + if (m_NodePredicate != nodePredicate) + { + m_NodePredicate = nodePredicate; + + this->OnNodePredicateChanged(nodePredicate); + this->UpdateInfo(); + } +}; + +mitk::NodePredicateBase* QmitkAbstractNodeSelectionWidget::GetNodePredicate() const +{ + return m_NodePredicate; +} + +QString QmitkAbstractNodeSelectionWidget::GetInvalidInfo() const +{ + return m_InvalidInfo; +}; + +QString QmitkAbstractNodeSelectionWidget::GetEmptyInfo() const +{ + return m_EmptyInfo; +}; + +QString QmitkAbstractNodeSelectionWidget::GetPopUpTitel() const +{ + return m_PopUpTitel; +}; + +QString QmitkAbstractNodeSelectionWidget::GetPopUpHint() const +{ + return m_PopUpHint; +}; + +bool QmitkAbstractNodeSelectionWidget::GetSelectionIsOptional() const +{ + return m_IsOptional; +}; + +bool QmitkAbstractNodeSelectionWidget::GetSelectOnlyVisibleNodes() const +{ + return m_SelectOnlyVisibleNodes; +}; + +void QmitkAbstractNodeSelectionWidget::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) +{ + m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; +}; + +void QmitkAbstractNodeSelectionWidget::SetInvalidInfo(QString info) +{ + m_InvalidInfo = info; + this->UpdateInfo(); +}; + +void QmitkAbstractNodeSelectionWidget::SetEmptyInfo(QString info) +{ + m_EmptyInfo = info; + this->UpdateInfo(); +}; + +void QmitkAbstractNodeSelectionWidget::SetPopUpTitel(QString info) +{ + m_PopUpTitel = info; +}; + +void QmitkAbstractNodeSelectionWidget::SetPopUpHint(QString info) +{ + m_PopUpHint = info; +}; + +void QmitkAbstractNodeSelectionWidget::SetSelectionIsOptional(bool isOptional) +{ + m_IsOptional = isOptional; + this->UpdateInfo(); +}; diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.h b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.h new file mode 100644 index 0000000000..0292dca521 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractNodeSelectionWidget.h @@ -0,0 +1,149 @@ +/*=================================================================== + +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 QMITK_ABSTRACT_NODE_SELECTION_WIDGET_H +#define QMITK_ABSTRACT_NODE_SELECTION_WIDGET_H + +#include + +#include +#include +#include + +#include "org_mitk_gui_qt_common_Export.h" + +#include + +class QmitkAbstractDataStorageModel; +class QAbstractItemVew; + +/** +* \class QmitkAbstractNodeSelectionWidget +* \brief Abstract base class for the selection of data from a data storage. +*/ +class MITK_QT_COMMON QmitkAbstractNodeSelectionWidget : public QWidget +{ + Q_OBJECT + +public: + explicit QmitkAbstractNodeSelectionWidget(QWidget* parent = nullptr); + + /** + * @brief Sets the data storage that will be used /monitored by widget. + * + * @par dataStorage A pointer to the data storage to set. + */ + void SetDataStorage(mitk::DataStorage* dataStorage); + + /** + * Sets the node predicate and updates the widget, according to the node predicate. + * Implement OnNodePredicateChange() for custom actualization of a derived widget class. + * + * @par nodePredicate A pointer to node predicate. + */ + void SetNodePredicate(mitk::NodePredicateBase* nodePredicate); + + mitk::NodePredicateBase* GetNodePredicate() const; + + QString GetInvalidInfo() const; + QString GetEmptyInfo() const; + QString GetPopUpTitel() const; + QString GetPopUpHint() const; + + bool GetSelectionIsOptional() const; + + bool GetSelectOnlyVisibleNodes() const; + + using NodeList = QList; + +Q_SIGNALS: + /* + * @brief A signal that will be emitted if the selected node has changed. + * + * @par nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(QList nodes); + +public Q_SLOTS: + /* + * @brief Change the selection modus of the item view's selection model. + * + * If true, an incoming selection will be filtered (reduced) to only those nodes that are visible by the current view. + * An outgoing selection can then at most contain the filtered nodes. + * If false, the incoming non-visible selection will be stored and later added to the outgoing selection, + * to include the original selection that could not be modified. + * The part of the original selection, that is non-visible are the nodes that are not + * + * @par selectOnlyVisibleNodes The bool value to define the selection modus. + */ + virtual void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes); + + /* + * @brief Transform a list of data nodes into a model selection and set this as a new selection of the + * selection model of the private member item view. + * + * The function filters the given list of nodes according to the 'm_SelectOnlyVisibleNodes' member variable. If + * necessary, the non-visible nodes are stored. This is done if 'm_SelectOnlyVisibleNodes' is false: In this case + * the selection may be filtered and only a subset of the selected nodes may be visible and therefore (de-)selectable + * in the data storage viewer. By storing the non-visible nodes it is possible to send the new, modified selection + * but also include the selected nodes from the original selection that could not be modified (see 'SetSelectOnlyVisibleNodes'). + * + * @par nodes A list of data nodes that should be newly selected. + */ + virtual void SetCurrentSelection(NodeList selectedNodes) = 0; + + /** Set the info text that should be displayed if no (valid) node is selected, + * but a selection is mandatory. + * The string can contain HTML code. if wanted*/ + void SetInvalidInfo(QString info); + + /** Set the info text that should be displayed if no (valid) node is selected, + * but a selection is optional. + * The string can contain HTML code. if wanted*/ + void SetEmptyInfo(QString info); + + /** Set the caption of the popup that is displayed to alter the selection. + * The string can contain HTML code. if wanted*/ + void SetPopUpTitel(QString info); + + /** Set the hint text of the popup that is displayed to alter the selection. + * The string can contain HTML code. if wanted*/ + void SetPopUpHint(QString info); + + /** Set the widget into an optional mode. Optional means that the selection of no valid + node does not mean an invalid state. Thus no node is a valid "node" selection too.*/ + void SetSelectionIsOptional(bool isOptional); + +protected: + /**Member is called if the display of the selected nodes should be updated.*/ + virtual void UpdateInfo() = 0; + + /**Member is called if the predicate has changed. Thus the selection might change to.*/ + virtual void OnNodePredicateChanged(mitk::NodePredicateBase* newPredicate) = 0; + + mitk::WeakPointer m_DataStorage; + mitk::NodePredicateBase::Pointer m_NodePredicate; + + QString m_InvalidInfo; + QString m_EmptyInfo; + QString m_PopUpTitel; + QString m_PopUpHint; + + bool m_IsOptional; + bool m_SelectOnlyVisibleNodes; +}; +#endif // QmitkAbstractNodeSelectionWidget_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractView.h b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractView.h index 947b82e1bb..d92f6560ad 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractView.h +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkAbstractView.h @@ -1,391 +1,384 @@ /*=================================================================== 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 QMITKABSTRACTVIEW_H_ #define QMITKABSTRACTVIEW_H_ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - //# blueberry stuff #include #include #include #include //# mitk stuff #include #include "mitkDataNodeSelection.h" #include "mitkIRenderWindowPart.h" #include #include #include #include namespace mitk { class DataNode; } namespace berry { struct IBerryPreferences; } class QmitkAbstractViewPrivate; class QmitkAbstractViewSelectionProvider; /** * \ingroup org_mitk_gui_qt_common * * \brief A convenient base class for MITK related BlueBerry Views. * * QmitkAbstractView provides several convenience methods that ease the introduction of a new view: * *
    *
  1. Access to the DataStorage (~ the shared data repository) *
  2. Access to the active IRenderWindowPart *
  3. Access to and update notification for the view's preferences *
  4. Access to and update notification for the current DataNode selection / to DataNode selection events send through the SelectionService *
  5. Access to and update notification for DataNode events (added/removed/modified) *
  6. Methods to send DataNode selections through the SelectionService *
  7. Some minor important convenience methods (like changing the mouse cursor/exception handling) *
* * Usually all MITK Views inherit from QmitkAbstractView to achieve a consistent Workbench behavior. * * When inheriting from QmitkAbstractView, you must implement the following methods: *
    *
  • void CreateQtPartControl(QWidget* parent) *
  • void SetFocus() *
* * You may reimplement the following private virtual methods to customize your View's behavior: *
    *
  • void SetSelectionProvider() *
  • QItemSelectionModel* GetDataNodeSelectionModel() const *
* * You may reimplement the following private virtual methods to be notified about certain changes: *
    *
  • void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes) *
  • void OnNullSelection(berry::IWorkbenchPart::Pointer part) *
  • void OnPreferencesChanged(const berry::IBerryPreferences*) *
  • void NodeAdded(const mitk::DataNode* node) *
  • void NodeChanged(const mitk::DataNode* node) *
  • void NodeRemoved(const mitk::DataNode* node) *
  • void DataStorageModified() *
  • void DataStorageChanged(mitk::IDataStorageReference::Pointer dsRef) *
* * \see mitk::ILifecycleAwarePart * \see mitk::IZombieViewPart * \see mitk::IRenderWindowPartListener */ class MITK_QT_COMMON QmitkAbstractView : public berry::QtViewPart { public: /** * Describes the strategies to be used for getting a mitk::IRenderWindowPart * instance. */ enum IRenderWindowPartStrategy { /** Do nothing. */ NONE = 0x00000000, /** Bring the most recently activated mitk::IRenderWindowPart instance to the front. */ BRING_TO_FRONT = 0x00000001, /** Activate a mitk::IRenderWindowPart part (implies bringing it to the front). */ ACTIVATE = 0x00000002, /** Create a mitk::IRenderWindowPart if none is alredy opened. */ OPEN = 0x00000004 }; Q_DECLARE_FLAGS(IRenderWindowPartStrategies, IRenderWindowPartStrategy) /** * Creates smartpointer typedefs */ berryObjectMacro(QmitkAbstractView); /** * Nothing to do in the standard ctor. Initiliaze your GUI in CreateQtPartControl(QWidget*) * \see berry::QtViewPart::CreateQtPartControl(QWidget*) */ QmitkAbstractView(); /** * Disconnects all standard event listeners */ ~QmitkAbstractView() override; protected: /** * Informs other parts of the workbench that node is selected via the blueberry selection service. * * \note This method should not be used if you have set your own selection provider via * SetSelectionProvider() or your own QItemSelectionModel via GetDataNodeSelectionModel(). */ void FireNodeSelected(mitk::DataNode::Pointer node); /** * Informs other parts of the workbench that the nodes are selected via the blueberry selection service. * * \note This method should not be used if you have set your own selection provider via * SetSelectionProvider() or your own QItemSelectionModel via GetDataNodeSelectionModel(). */ virtual void FireNodesSelected(const QList& nodes); /** * \return The selection of the currently active part of the workbench or an empty list * if there is no selection or if it is empty. * * \see IsCurrentSelectionValid */ QList GetCurrentSelection() const; /** * Queries the state of the current selection. * * \return If the current selection is nullptr, this method returns * false and true otherwise. */ bool IsCurrentSelectionValid() const; /** * Returns the current selection made in the datamanager bundle or an empty list * if there is no selection or if it is empty. * * \see IsDataManagerSelectionValid */ QList GetDataManagerSelection() const; /** * Queries the state of the current selection of the data manager view. * * \return If the current data manager selection is nullptr, this method returns * false and true otherwise. */ bool IsDataManagerSelectionValid() const; /** * Sets the selection of the data manager view if available. * * \param selection The new selection for the data manager. * \param flags The Qt selection flags for controlling the way how the selection is updated. */ void SetDataManagerSelection(const berry::ISelection::ConstPointer& selection, QItemSelectionModel::SelectionFlags flags = QItemSelectionModel::ClearAndSelect) const; /** * Takes the current selection and sets it on the data manager. Only matching nodes in the * data manager view will be selected. */ void SynchronizeDataManagerSelection() const; /** * Returns the Preferences object for this View. * Important: When refering to this preferences, e.g. in a PreferencePage: The ID * for this preferences object is "/", e.g. "/org.mitk.views.datamanager" */ berry::IPreferences::Pointer GetPreferences() const; /** * Returns a reference to the currently active DataStorage. */ mitk::IDataStorageReference::Pointer GetDataStorageReference() const; /** * Returns the currently active DataStorage. */ mitk::DataStorage::Pointer GetDataStorage() const; /** * Returns the currently active mitk::IRenderWindowPart. * * \param strategies Strategies for returning a mitk::IRenderWindowPart instance if there * is currently no active one. * \return The active mitk::IRenderWindowPart. */ mitk::IRenderWindowPart* GetRenderWindowPart(IRenderWindowPartStrategies strategies = NONE) const; /** * Request an update of all render windows of the currently active IRenderWindowPart. * * \param requestType Specifies the type of render windows for which an update * will be requested. */ void RequestRenderWindowUpdate(mitk::RenderingManager::RequestType requestType = mitk::RenderingManager::REQUEST_UPDATE_ALL); /** * Outputs an error message to the console and displays a message box containing * the exception description. * \param e the exception which should be handled * \param showDialog controls, whether additionally a message box should be * displayed to inform the user that something went wrong */ void HandleException( std::exception& e, QWidget* parent = nullptr, bool showDialog = true ) const; /** * Calls HandleException ( std::exception&, QWidget*, bool ) internally * \see HandleException ( std::exception&, QWidget*, bool ) */ void HandleException( const char* str, QWidget* parent = nullptr, bool showDialog = true ) const; /** * Convenient method to set and reset a wait cursor ("hourglass") */ void WaitCursorOn(); /** * Convenient method to restore the standard cursor */ void WaitCursorOff(); /** * Convenient method to set and reset a busy cursor */ void BusyCursorOn(); /** * Convenient method to restore the standard cursor */ void BusyCursorOff(); /** * Convenient method to restore the standard cursor */ void RestoreOverrideCursor(); private: /** * Reimplement this method to set a custom selection provider. This method is * called once after CreateQtPartControl(). * * The default implementation registers a QmitkDataNodeSelectionProvider with * a QItemSelectionModel returned by GetDataNodeSelectionModel(). */ virtual void SetSelectionProvider(); /** * Reimplement this method to supply a custom Qt selection model. The custom * model will be used with the default selection provider QmitkDataNodeSelectionProvider * to inform the MITK Workbench about selection changes. * * If you reimplement this method, the methods FireNodeSelected() and FireNodesSelected() * will have no effect. Use your custom selection model to notify the MITK Workbench * about selection changes. * * The Qt item model used with the custom selection model must return mitk::DataNode::Pointer * objects for model indexes when the role is QmitkDataNodeRole. */ virtual QItemSelectionModel* GetDataNodeSelectionModel() const; /** * Called when the selection in the workbench changed. * May be reimplemented by deriving classes. * * \param part The source part responsible for the selection change. * \param nodes A list of selected nodes. * * \see OnNullSelection */ virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList &nodes); /** * Called when a nullptr selection occurs. * * \param part The source part responsible for the selection change. */ virtual void OnNullSelection(berry::IWorkbenchPart::Pointer part); /** * Called when the preferences object of this view changed. * May be reimplemented by deriving classes. * * \see GetPreferences() */ virtual void OnPreferencesChanged(const berry::IBerryPreferences*); /** * Called when a DataStorage Add event was thrown. May be reimplemented * by deriving classes. */ virtual void NodeAdded(const mitk::DataNode* node); /** * Called when a DataStorage Changed event was thrown. May be reimplemented * by deriving classes. */ virtual void NodeChanged(const mitk::DataNode* node); /** * Called when a DataStorage Remove event was thrown. May be reimplemented * by deriving classes. */ virtual void NodeRemoved(const mitk::DataNode* node); /** * Called when a DataStorage add *or* remove *or* change event from the currently active * data storage is thrown. * * May be reimplemented by deriving classes. */ virtual void DataStorageModified(); /** * Called when the currently active DataStorage changed. * May be reimplemented by deriving classes. * * \param dsRef A reference to the new active DataStorage. */ virtual void DataStorageChanged(mitk::IDataStorageReference::Pointer dsRef); /** * Creates a scroll area for this view and calls CreateQtPartControl then */ void CreatePartControl(QWidget* parent) override; /** * Called immediately after CreateQtPartControl(). * Here standard event listeners for a QmitkAbstractView are registered */ void AfterCreateQtPartControl(); private: friend class QmitkAbstractViewPrivate; friend class QmitkViewCoordinator; Q_DISABLE_COPY(QmitkAbstractView) const QScopedPointer d; }; Q_DECLARE_OPERATORS_FOR_FLAGS(QmitkAbstractView::IRenderWindowPartStrategies) #endif /*QMITKABSTRACTVIEW_H_*/ diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkDnDFrameWidget.h b/Plugins/org.mitk.gui.qt.common/src/QmitkDnDFrameWidget.h index e9d2aa17c8..acc5620398 100644 --- a/Plugins/org.mitk.gui.qt.common/src/QmitkDnDFrameWidget.h +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkDnDFrameWidget.h @@ -1,61 +1,54 @@ /*=================================================================== 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 QmitkDndFrameWidget_h #define QmitkDndFrameWidget_h -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include #include //drag&drop class QDragEnterEvent; class QDropEvent; class QMouseEvent; class QmitkDnDFrameWidgetPrivate; /** * \ingroup org_mitk_gui_qt_common * * \brief Enables loading data into a MITK application via Drag'n Drop. * * You can use this class inside your MITK View as a container for your widgets * if you want the user to be able to load data by dropping files onto your view. */ class MITK_QT_COMMON QmitkDnDFrameWidget : public QWidget { Q_OBJECT public: QmitkDnDFrameWidget(QWidget *parent); ~QmitkDnDFrameWidget() override; private: void dragEnterEvent( QDragEnterEvent *event ) override; void dropEvent( QDropEvent * event ) override; const QScopedPointer d; }; #endif diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.cpp new file mode 100644 index 0000000000..47b5f1d2cc --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.cpp @@ -0,0 +1,167 @@ +/*=================================================================== + +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 "QmitkMultiNodeSelectionWidget.h" + +#include +#include +#include + +QmitkMultiNodeSelectionWidget::QmitkMultiNodeSelectionWidget(QWidget* parent) : QmitkAbstractNodeSelectionWidget(parent) +{ + m_Controls.setupUi(this); + + this->UpdateList(); + this->UpdateInfo(); + + connect(m_Controls.btnChange, SIGNAL(clicked(bool)), this, SLOT(OnEditSelection())); +} + +QmitkMultiNodeSelectionWidget::NodeList QmitkMultiNodeSelectionWidget::CompileEmitSelection() const +{ + NodeList result; + + for (int i = 0; i < m_Controls.list->count(); ++i) + { + QListWidgetItem* item = m_Controls.list->item(i); + + auto node = item->data(Qt::UserRole).value(); + result.append(node); + } + + + if (!m_SelectOnlyVisibleNodes) + { + for (auto node : m_CurrentSelection) + { + if (!result.contains(node)) + { + result.append(node); + } + } + } + + return result; +} + +void QmitkMultiNodeSelectionWidget::OnNodePredicateChanged(mitk::NodePredicateBase* /*newPredicate*/) +{ + this->UpdateInfo(); + this->UpdateList(); +}; + +QmitkMultiNodeSelectionWidget::NodeList QmitkMultiNodeSelectionWidget::GetSelectedNodes() const +{ + return m_CurrentSelection; +}; + +void QmitkMultiNodeSelectionWidget::OnEditSelection() +{ + QmitkNodeSelectionDialog* dialog = new QmitkNodeSelectionDialog(this, m_PopUpTitel, m_PopUpHint); + + dialog->SetDataStorage(m_DataStorage.Lock()); + dialog->SetNodePredicate(m_NodePredicate); + dialog->SetCurrentSelection(this->CompileEmitSelection()); + dialog->SetSelectOnlyVisibleNodes(m_SelectOnlyVisibleNodes); + dialog->SetSelectionMode(QAbstractItemView::MultiSelection); + + m_Controls.btnChange->setChecked(true); + if (dialog->exec()) + { + auto lastEmission = this->CompileEmitSelection(); + + m_CurrentSelection = dialog->GetSelectedNodes(); + this->UpdateList(); + this->UpdateInfo(); + + auto newEmission = this->CompileEmitSelection(); + + if (!EqualNodeSelections(lastEmission, newEmission)) + { + emit CurrentSelectionChanged(newEmission); + } + } + m_Controls.btnChange->setChecked(false); + + delete dialog; +}; + +void QmitkMultiNodeSelectionWidget::UpdateInfo() +{ + m_Controls.infoLabel->setVisible(m_Controls.list->count()==0); + + if (!m_Controls.list->count()) + { + if (m_IsOptional) + { + m_Controls.infoLabel->setText(m_EmptyInfo); + } + else + { + m_Controls.infoLabel->setText(m_InvalidInfo); + } + } +}; + +void QmitkMultiNodeSelectionWidget::UpdateList() +{ + m_Controls.list->clear(); + + for (auto node : m_CurrentSelection) + { + if (m_NodePredicate.IsNull() || m_NodePredicate->CheckNode(node)) + { + QListWidgetItem *newItem = new QListWidgetItem; + newItem->setText(QString::fromStdString(node->GetName())); + newItem->setData(Qt::UserRole, QVariant::fromValue(node)); + + m_Controls.list->addItem(newItem); + } + } +}; + +void QmitkMultiNodeSelectionWidget::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) +{ + auto lastEmission = this->CompileEmitSelection(); + + m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; + + auto newEmission = this->CompileEmitSelection(); + + if (!EqualNodeSelections(lastEmission, newEmission)) + { + emit CurrentSelectionChanged(newEmission); + this->UpdateList(); + this->UpdateInfo(); + } +}; + +void QmitkMultiNodeSelectionWidget::SetCurrentSelection(NodeList selectedNodes) +{ + auto lastEmission = this->CompileEmitSelection(); + + m_CurrentSelection = selectedNodes; + this->UpdateList(); + + auto newEmission = this->CompileEmitSelection(); + + if (!EqualNodeSelections(lastEmission, newEmission)) + { + emit CurrentSelectionChanged(newEmission); + this->UpdateInfo(); + } +}; diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.h b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.h new file mode 100644 index 0000000000..d1f736be51 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.h @@ -0,0 +1,76 @@ +/*=================================================================== + +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 QMITK_MULTI_NODE_SELECTION_WIDGET_H +#define QMITK_MULTI_NODE_SELECTION_WIDGET_H + +#include + +#include +#include +#include + +#include "org_mitk_gui_qt_common_Export.h" + +#include "ui_QmitkMultiNodeSelectionWidget.h" + +#include + +class QmitkAbstractDataStorageModel; +class QAbstractItemVew; + +/** +* \class QmitkMultiNodeSelectionWidget +* \brief Widget that allows to show and edit the content of an mitk::IsoDoseLevel instance. +*/ +class MITK_QT_COMMON QmitkMultiNodeSelectionWidget : public QmitkAbstractNodeSelectionWidget +{ + Q_OBJECT + +public: + explicit QmitkMultiNodeSelectionWidget(QWidget* parent = nullptr); + + using NodeList = QmitkAbstractNodeSelectionWidget::NodeList; + + NodeList GetSelectedNodes() const; + +Q_SIGNALS: + /* + * @brief A signal that will be emitted if the selected node has changed. + * + * @par nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(QList nodes); + + public Q_SLOTS: + virtual void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) override; + virtual void SetCurrentSelection(NodeList selectedNodes) override; + void OnEditSelection(); + +protected: + NodeList CompileEmitSelection() const; + + virtual void UpdateInfo() override; + virtual void UpdateList(); + + virtual void OnNodePredicateChanged(mitk::NodePredicateBase* newPredicate); + + NodeList m_CurrentSelection; + + Ui_QmitkMultiNodeSelectionWidget m_Controls; +}; +#endif // QmitkMultiNodeSelectionWidget_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.ui b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.ui new file mode 100644 index 0000000000..87eae80c7e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkMultiNodeSelectionWidget.ui @@ -0,0 +1,92 @@ + + + QmitkMultiNodeSelectionWidget + + + + 0 + 0 + 391 + 265 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QAbstractItemView::NoEditTriggers + + + false + + + QAbstractItemView::NoDragDrop + + + Qt::MoveAction + + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + + + + TextLabel + + + true + + + + + + + Change selection + + + true + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.cpp new file mode 100644 index 0000000000..fa21db2d4b --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.cpp @@ -0,0 +1,163 @@ +/*=================================================================== + +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 "QmitkNodeSelectionButton.h" + +#include "QPainter" +#include "QTextDocument" + +#include +#include + + +// mitk core +#include +#include +#include +#include +#include +#include + +// vtk +#include + +QPixmap GetPixmapFromImageNode(const mitk::DataNode* dataNode, int height) +{ + if (nullptr == dataNode) + { + return QPixmap(); + } + + const mitk::Image* image = dynamic_cast(dataNode->GetData()); + if ((nullptr == image || !image->IsInitialized()) || // -> must be an image + (image->GetPixelType().GetNumberOfComponents() != 1)) // -> for now only single component are allowed + { + auto descManager = QmitkNodeDescriptorManager::GetInstance(); + auto desc = descManager->GetDescriptor(dataNode); + auto icon = desc->GetIcon(dataNode); + auto fallBackMap = icon.pixmap(height, height); + return fallBackMap; + } + + mitk::PlaneGeometry::Pointer planeGeometry = mitk::PlaneGeometry::New(); + int sliceNumber = image->GetDimension(2) / 2; + planeGeometry->InitializeStandardPlane(image->GetGeometry(), mitk::PlaneGeometry::Axial, sliceNumber); + + mitk::ExtractSliceFilter::Pointer extractSliceFilter = mitk::ExtractSliceFilter::New(); + extractSliceFilter->SetInput(image); + extractSliceFilter->SetInterpolationMode(mitk::ExtractSliceFilter::RESLICE_CUBIC); + extractSliceFilter->SetResliceTransformByGeometry(image->GetGeometry()); + extractSliceFilter->SetWorldGeometry(planeGeometry); + extractSliceFilter->SetOutputDimensionality(2); + extractSliceFilter->SetVtkOutputRequest(true); + extractSliceFilter->Update(); + + vtkImageData* imageData = extractSliceFilter->GetVtkOutput(); + + mitk::LevelWindow levelWindow; + dataNode->GetLevelWindow(levelWindow); + vtkSmartPointer lookupTable = vtkSmartPointer::New(); + lookupTable->SetRange(levelWindow.GetLowerWindowBound(), levelWindow.GetUpperWindowBound()); + lookupTable->SetSaturationRange(0.0, 0.0); + lookupTable->SetValueRange(0.0, 1.0); + lookupTable->SetHueRange(0.0, 0.0); + lookupTable->SetRampToLinear(); + + vtkSmartPointer levelWindowFilter = vtkSmartPointer::New(); + levelWindowFilter->SetLookupTable(lookupTable); + levelWindowFilter->SetInputData(imageData); + levelWindowFilter->SetMinOpacity(0.0); + levelWindowFilter->SetMaxOpacity(1.0); + int dims[3]; + imageData->GetDimensions(dims); + double clippingBounds[] = { 0.0, static_cast(dims[0]), 0.0, static_cast(dims[1]) }; + levelWindowFilter->SetClippingBounds(clippingBounds); + levelWindowFilter->Update(); + imageData = levelWindowFilter->GetOutput(); + + QImage thumbnailImage(reinterpret_cast(imageData->GetScalarPointer()), dims[0], dims[1], QImage::Format_ARGB32); + + thumbnailImage = thumbnailImage.scaledToHeight(height,Qt::SmoothTransformation).rgbSwapped(); + return QPixmap::fromImage(thumbnailImage); +} + +QmitkNodeSelectionButton::QmitkNodeSelectionButton(QWidget *parent) + : QPushButton(parent), m_OutDatedThumpNail(true) +{ } + +QmitkNodeSelectionButton::~QmitkNodeSelectionButton() +{ + this->m_SelectedNode = nullptr; +} + +void QmitkNodeSelectionButton::SetSelectedNode(mitk::DataNode* node) +{ + if (m_SelectedNode != node) + { + this->m_SelectedNode = node; //mitk::WeakPointer(node); + this->m_OutDatedThumpNail = true; + } + + this->update(); +}; + +void QmitkNodeSelectionButton::SetNodeInfo(QString info) +{ + this->m_Info = info; + this->update(); +}; + +void QmitkNodeSelectionButton::paintEvent(QPaintEvent *p) +{ + QPushButton::paintEvent(p); + + QPainter painter(this); + + QTextDocument td; + + auto widgetSize = this->size(); + QPoint origin = QPoint(5, 5); + + if (this->m_SelectedNode) + { + auto iconLength = widgetSize.height() - 10; + auto node = this->m_SelectedNode; // .Lock(); + + if (this->m_OutDatedThumpNail) + { + this->m_ThumpNail = GetPixmapFromImageNode(node, iconLength); + this->m_OutDatedThumpNail = false; + } + + painter.drawPixmap(origin, m_ThumpNail); + origin.setX(origin.x() + iconLength + 5); + + td.setHtml(QString::fromStdString(node->GetName())); + } + else + { + td.setHtml(m_Info); + } + + auto textSize = td.size(); + + origin.setY( (widgetSize.height() - textSize.height()) / 2.); + + painter.translate(origin); + td.drawContents(&painter); + +} diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.h b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.h new file mode 100644 index 0000000000..74ea357652 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionButton.h @@ -0,0 +1,56 @@ +/*=================================================================== + +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 QMITK_NODE_SELECTION_BUTTON_H +#define QMITK_NODE_SELECTION_BUTTON_H + +#include +#include + +#include "org_mitk_gui_qt_common_Export.h" + +#include "QPushButton" +#include "QPixmap" + + +/** Button class that can be used to display informations about a passed node. + * If the passed node is a null ptr the node info text will be shown. + * In difference to the normal push button text property. The node info can + * be formated text (e.g. HTML code; like the tooltip text).*/ +class MITK_QT_COMMON QmitkNodeSelectionButton : public QPushButton +{ + Q_OBJECT + +public: + explicit QmitkNodeSelectionButton(QWidget *parent = nullptr); + ~QmitkNodeSelectionButton(); + +public Q_SLOTS : + virtual void SetSelectedNode(mitk::DataNode* node); + virtual void SetNodeInfo(QString info); + +protected: + void paintEvent(QPaintEvent *p) override; + + mitk::DataNode::Pointer m_SelectedNode; + QString m_Info; + bool m_OutDatedThumpNail; + QPixmap m_ThumpNail; +}; + + +#endif // QmitkSingleNodeSelectionWidget_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.cpp new file mode 100644 index 0000000000..702baa98c9 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.cpp @@ -0,0 +1,185 @@ +/*=================================================================== + +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 "QmitkNodeSelectionDialog.h" + +#include +#include +#include + +QmitkNodeSelectionDialog::QmitkNodeSelectionDialog(QWidget* parent, QString title, QString hint) : QDialog(parent), m_NodePredicate(nullptr), m_SelectOnlyVisibleNodes(false) +{ + m_Controls.setupUi(this); + + auto providers = QmitkDataStorageInspectorGenerator::GetProviders(); + auto visibleProviders = mitk::GetVisibleDataStorageInspectors(); + auto favoriteID = mitk::GetFavoriteDataStorageInspector(); + + if (visibleProviders.empty()) + { + MITK_DEBUG << "No presets for visible node selection inspectors available. Use fallback (show all available inspectors)"; + unsigned int order = 0; + for (auto proIter : providers) + { + visibleProviders.insert(std::make_pair(order, proIter.first)); + } + } + + int favIndex = 0; + bool favoriteFound = false; + for (auto proIter : visibleProviders) + { + auto finding = providers.find(proIter.second); + if (finding != providers.end()) + { + auto inspector = finding->second->CreateInspector(); + QString name = QString::fromStdString(finding->second->GetInspectorDisplayName()); + QString desc = QString::fromStdString(finding->second->GetInspectorDescription()); + AddPanel(inspector, name, desc); + + favoriteFound = favoriteFound || proIter.second == favoriteID; + if (!favoriteFound) + { + ++favIndex; + } + } + else + { + MITK_DEBUG << "No provider registered for inspector that is defined as visible in the preferences. Illegal inspector ID: " << proIter.second; + } + } + + m_Controls.tabWidget->setCurrentIndex(favIndex); + this->setWindowTitle(title); + this->setToolTip(hint); + + m_Controls.hint->setText(hint); + m_Controls.hint->setVisible(!hint.isEmpty()); + + connect(m_Controls.buttonBox, SIGNAL(accepted()), this, SLOT(OnOK())); + connect(m_Controls.buttonBox, SIGNAL(rejected()), this, SLOT(OnCancel())); +} + +void QmitkNodeSelectionDialog::SetDataStorage(mitk::DataStorage* dataStorage) +{ + if (m_DataStorage != dataStorage) + { + m_DataStorage = dataStorage; + + if (!m_DataStorage.IsExpired()) + { + for (auto panel : m_Panels) + { + panel->SetDataStorage(dataStorage); + } + } + } +}; + +void QmitkNodeSelectionDialog::SetNodePredicate(mitk::NodePredicateBase* nodePredicate) +{ + if (m_NodePredicate != nodePredicate) + { + m_NodePredicate = nodePredicate; + + for (auto panel : m_Panels) + { + panel->SetNodePredicate(m_NodePredicate); + } + } +}; + +mitk::NodePredicateBase* QmitkNodeSelectionDialog::GetNodePredicate() const +{ + return m_NodePredicate; +} + +QmitkNodeSelectionDialog::NodeList QmitkNodeSelectionDialog::GetSelectedNodes() const +{ + return m_SelectedNodes; +}; + +void QmitkNodeSelectionDialog::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) +{ + if (m_SelectOnlyVisibleNodes != selectOnlyVisibleNodes) + { + m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; + + for (auto panel : m_Panels) + { + panel->SetSelectOnlyVisibleNodes(m_SelectOnlyVisibleNodes); + } + } +}; + +void QmitkNodeSelectionDialog::SetCurrentSelection(NodeList selectedNodes) +{ + m_SelectedNodes = selectedNodes; + for (auto panel : m_Panels) + { + panel->SetCurrentSelection(selectedNodes); + } +}; + +void QmitkNodeSelectionDialog::OnSelectionChanged(NodeList selectedNodes) +{ + SetCurrentSelection(selectedNodes); + emit CurrentSelectionChanged(selectedNodes); +}; + +void QmitkNodeSelectionDialog::AddPanel(QmitkAbstractDataStorageInspector* view, QString name, QString desc) +{ + view->setParent(this); + view->SetSelectionMode(m_SelectionMode); + + auto tabPanel = new QWidget(); + tabPanel->setObjectName(QString("tab_")+name); + tabPanel->setToolTip(desc); + m_Controls.tabWidget->insertTab(m_Controls.tabWidget->count(), tabPanel, name); + + auto verticalLayout = new QVBoxLayout(tabPanel); + verticalLayout->setSpacing(0); + verticalLayout->setContentsMargins(0, 0, 0, 0); + verticalLayout->addWidget(view); + + m_Panels.push_back(view); + connect(view, &QmitkAbstractDataStorageInspector::CurrentSelectionChanged, this, &QmitkNodeSelectionDialog::OnSelectionChanged); +}; + +void QmitkNodeSelectionDialog::OnOK() +{ + this->accept(); +}; + +void QmitkNodeSelectionDialog::OnCancel() +{ + this->reject(); +}; + +void QmitkNodeSelectionDialog::SetSelectionMode(SelectionMode mode) +{ + m_SelectionMode = mode; + for (auto panel : m_Panels) + { + panel->SetSelectionMode(mode); + } +}; + +QmitkNodeSelectionDialog::SelectionMode QmitkNodeSelectionDialog::GetSelectionMode() const +{ + return m_SelectionMode; +} diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.h b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.h new file mode 100644 index 0000000000..02f828bcc5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.h @@ -0,0 +1,127 @@ +/*=================================================================== + +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 QMITK_NODE_SELECTION_DIALOG_H +#define QMITK_NODE_SELECTION_DIALOG_H + + +#include +#include +#include + +#include + +#include "org_mitk_gui_qt_common_Export.h" + +#include "ui_QmitkNodeSelectionDialog.h" + +#include + +/** +* \class QmitkNodeSelectionDialog +* \brief Widget that allows to show and edit the content of an mitk::IsoDoseLevel instance. +*/ +class MITK_QT_COMMON QmitkNodeSelectionDialog : public QDialog +{ + Q_OBJECT + +public: + explicit QmitkNodeSelectionDialog(QWidget* parent = nullptr, QString caption = "", QString hint = ""); + + /* + * @brief Sets the data storage that will be used /monitored by widget. + * + * @param dataStorage A pointer to the data storage to set. + */ + void SetDataStorage(mitk::DataStorage* dataStorage); + + /* + * @brief Sets the node predicate and updates the widget, according to the node predicate. + * + * @param nodePredicate A pointer to node predicate. + */ + virtual void SetNodePredicate(mitk::NodePredicateBase* nodePredicate); + + mitk::NodePredicateBase* GetNodePredicate() const; + + using NodeList = QList; + + NodeList GetSelectedNodes() const; + + bool GetSelectOnlyVisibleNodes() const; + + using SelectionMode = QAbstractItemView::SelectionMode; + void SetSelectionMode(SelectionMode mode); + SelectionMode GetSelectionMode() const; + +Q_SIGNALS: + /* + * @brief A signal that will be emitted if the selected node has changed. + * + * @param nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(NodeList nodes); + + public Q_SLOTS: + /* + * @brief Change the selection modus of the item view's selection model. + * + * If true, an incoming selection will be filtered (reduced) to only those nodes that are visible by the current view. + * An outgoing selection can then at most contain the filtered nodes. + * If false, the incoming non-visible selection will be stored and later added to the outgoing selection, + * to include the original selection that could not be modified. + * The part of the original selection, that is non-visible are the nodes that are not + * + * @param selectOnlyVisibleNodes The bool value to define the selection modus. + */ + void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes); + + /* + * @brief Transform a list of data nodes into a model selection and set this as a new selection of the + * selection model of the private member item view. + * + * The function filters the given list of nodes according to the 'm_SelectOnlyVisibleNodes' member variable. If + * necessary, the non-visible nodes are stored. This is done if 'm_SelectOnlyVisibleNodes' is false: In this case + * the selection may be filtered and only a subset of the selected nodes may be visible and therefore (de-)selectable + * in the data storage viewer. By storing the non-visible nodes it is possible to send the new, modified selection + * but also include the selected nodes from the original selection that could not be modified (see 'SetSelectOnlyVisibleNodes'). + * + * @param nodes A list of data nodes that should be newly selected. + */ + void SetCurrentSelection(NodeList selectedNodes); + +protected Q_SLOTS: + void OnSelectionChanged(NodeList selectedNodes); + void OnOK(); + void OnCancel(); + +protected: + void AddPanel(QmitkAbstractDataStorageInspector* view, QString name, QString desc); + + mitk::WeakPointer m_DataStorage; + mitk::NodePredicateBase::Pointer m_NodePredicate; + bool m_SelectOnlyVisibleNodes; + NodeList m_SelectedNodes; + + SelectionMode m_SelectionMode; + + using PanelVectorType = std::vector; + PanelVectorType m_Panels; + + Ui_QmitkNodeSelectionDialog m_Controls; +}; +#endif // QmitkNodeSelectionDialog_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.ui b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.ui new file mode 100644 index 0000000000..190293767e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionDialog.ui @@ -0,0 +1,82 @@ + + + QmitkNodeSelectionDialog + + + + 0 + 0 + 596 + 539 + + + + Dialog + + + true + + + true + + + + 5 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + 6 + + + 6 + + + 6 + + + + + QFrame::NoFrame + + + Info text ... + + + true + + + + + + + + + -1 + + + + + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.cpp new file mode 100644 index 0000000000..1e739cc705 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.cpp @@ -0,0 +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. + +===================================================================*/ + +#include "QmitkNodeSelectionPreferenceHelper.h" + +#include + +#include + +#include +#include +#include + + +#include "mitkExceptionMacro.h" + +void mitk::PutVisibleDataStorageInspectors(const VisibleDataStorageInspectorMapType &inspectors) +{ + berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); + berry::IPreferences::Pointer prefNode = + prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); + berry::IPreferences::Pointer visNode = + prefNode->Node(mitk::NodeSelectionConstants::VISIBLE_INSPECTORS_NODE_ID.c_str()); + + visNode->RemoveNode(); + prefNode->Flush(); + + // new empty preset node + visNode = prefNode->Node(mitk::NodeSelectionConstants::VISIBLE_INSPECTORS_NODE_ID.c_str()); + + // store map in new node + for (const auto &inspector : inspectors) + { + std::ostringstream sstr; + sstr << inspector.first; + berry::IPreferences::Pointer aNode = visNode->Node(QString::fromStdString(sstr.str())); + + aNode->Put(mitk::NodeSelectionConstants::VISIBLE_INSPECTOR_ID.c_str(), inspector.second.c_str()); + aNode->Flush(); + } + + visNode->Flush(); +} + +mitk::VisibleDataStorageInspectorMapType mitk::GetVisibleDataStorageInspectors() +{ + berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = + prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); + berry::IPreferences::Pointer visNode = + prefNode->Node(mitk::NodeSelectionConstants::VISIBLE_INSPECTORS_NODE_ID.c_str()); + + typedef QStringList NamesType; + NamesType names = visNode->ChildrenNames(); + + VisibleDataStorageInspectorMapType visMap; + + if (!names.empty()) + { + for (NamesType::const_iterator pos = names.begin(); pos != names.end(); ++pos) + { + berry::IPreferences::Pointer aNode = visNode->Node(*pos); + + if (aNode.IsNull()) + { + mitkThrow() << "Error in preference interface. Cannot find preset node under given name. Name: " + << (*pos).toStdString(); + } + + std::istringstream isstr(pos->toStdString()); + unsigned int order = 0; + isstr >> order; + + auto id = aNode->Get(mitk::NodeSelectionConstants::VISIBLE_INSPECTOR_ID.c_str(), ""); + if (id.isEmpty()) + { + mitkThrow() << "Error in preference interface. ID of visible inspector is not set. Inspector position: " + << order; + } + + visMap.insert(std::make_pair(order, id.toStdString())); + } + } + return visMap; +} + +mitk::DataStorageInspectorIDType mitk::GetFavoriteDataStorageInspector() +{ + berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = + prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); + + auto id = prefNode->Get(mitk::NodeSelectionConstants::FAVORITE_INSPECTOR_ID.c_str(), ""); + + mitk::DataStorageInspectorIDType result = id.toStdString(); + return result; +} + +void mitk::PutFavoriteDataStorageInspector(const DataStorageInspectorIDType &id) +{ + berry::IPreferencesService *prefService = berry::Platform::GetPreferencesService(); + + berry::IPreferences::Pointer prefNode = + prefService->GetSystemPreferences()->Node(mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID.c_str()); + + prefNode->Put(mitk::NodeSelectionConstants::FAVORITE_INSPECTOR_ID.c_str(), id.c_str()); + prefNode->Flush(); +} diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.h b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.h new file mode 100644 index 0000000000..09bc4a719c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkNodeSelectionPreferenceHelper.h @@ -0,0 +1,44 @@ +/*=================================================================== + +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 __QMITK_NODE_SELECTION_PREFERENCE_HELPER_H +#define __QMITK_NODE_SELECTION_PREFERENCE_HELPER_H + +#include +#include + +namespace mitk +{ + using DataStorageInspectorIDType = std::string; + + using VisibleDataStorageInspectorMapType = std::map; + + /** Stores the given ID as favorite inspector.*/ + void PutFavoriteDataStorageInspector(const DataStorageInspectorIDType& id); + + /** Gets the ID of the current favorite data storage inspector. + * If empty string is returned, no favorite is set.*/ + DataStorageInspectorIDType GetFavoriteDataStorageInspector(); + + /** Stores the given map of visible inspectors.*/ + void PutVisibleDataStorageInspectors(const VisibleDataStorageInspectorMapType& inspectors); + + /** Gets the map of current visible inspectors.*/ + VisibleDataStorageInspectorMapType GetVisibleDataStorageInspectors(); +} + +#endif diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.cpp new file mode 100644 index 0000000000..10a89c0be3 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.cpp @@ -0,0 +1,130 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +// mitk gui qt common plugin +#include "QmitkSelectionServiceConnector.h" +#include "internal/QmitkDataNodeSelection.h" + +// qt widgets module +#include "QmitkCustomVariants.h" +#include "QmitkEnums.h" + +// blueberry ui qt plugin +#include + +QmitkSelectionServiceConnector::QmitkSelectionServiceConnector() + : m_SelectionService(nullptr) + , m_SelectionProvider(nullptr) +{ + m_DataNodeItemModel = std::make_shared(); + m_DataNodeSelectionModel = std::make_shared(m_DataNodeItemModel.get()); +} + +QmitkSelectionServiceConnector::~QmitkSelectionServiceConnector() +{ + RemovePostSelectionListener(); + RemoveAsSelectionProvider(); +} + +void QmitkSelectionServiceConnector::AddPostSelectionListener(berry::ISelectionService* selectionService) +{ + if (nullptr == selectionService) + { + return; + } + + m_SelectionService = selectionService; + m_BerrySelectionListener.reset(new berry::NullSelectionChangedAdapter(this, &QmitkSelectionServiceConnector::OnServiceSelectionChanged)); + m_SelectionService->AddPostSelectionListener(m_BerrySelectionListener.get()); +} + +void QmitkSelectionServiceConnector::RemovePostSelectionListener() +{ + if (nullptr == m_SelectionService) + { + return; + } + + m_SelectionService->RemovePostSelectionListener(m_BerrySelectionListener.get()); + m_SelectionService = nullptr; +} + +void QmitkSelectionServiceConnector::SetAsSelectionProvider(QmitkDataNodeSelectionProvider* selectionProvider) +{ + m_SelectionProvider = selectionProvider; +} + +void QmitkSelectionServiceConnector::RemoveAsSelectionProvider() +{ + m_SelectionProvider = nullptr; +} + +void QmitkSelectionServiceConnector::ChangeServiceSelection(QList nodes) +{ + if (nullptr == m_SelectionProvider) + { + return; + } + + m_SelectionProvider->SetItemSelectionModel(m_DataNodeSelectionModel.get()); + + if (nodes.empty()) + { + m_DataNodeSelectionModel->clearSelection(); + m_DataNodeItemModel->clear(); + } + else + { + m_DataNodeItemModel->clear(); + // fill the temporary helper data node item model with the nodes to select + for (const auto& node : nodes) + { + m_DataNodeItemModel->AddDataNode(node); + } + + m_DataNodeSelectionModel->select(QItemSelection(m_DataNodeItemModel->index(0, 0), m_DataNodeItemModel->index(nodes.size() - 1, 0)), QItemSelectionModel::ClearAndSelect); + } +} + +void QmitkSelectionServiceConnector::OnServiceSelectionChanged(const berry::IWorkbenchPart::Pointer& sourcePart, const berry::ISelection::ConstPointer& selection) +{ + if (sourcePart.IsNull()) + { + return; + } + + QList nodes; + if (selection.IsNull()) + { + // propagate an empty list + nodes = QList(); + } + + // transform valid selection to DataNodeSelection, which allows to retrieve the selected nodes + mitk::DataNodeSelection::ConstPointer dataNodeSelection = selection.Cast(); + if (dataNodeSelection.IsNull()) + { + // propagate an empty list + nodes = QList(); + } + else + { + nodes = QList::fromStdList(dataNodeSelection->GetSelectedDataNodes()); + } + + // send new (possibly empty) list of selected nodes + emit ServiceSelectionChanged(nodes); +} diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.h b/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.h new file mode 100644 index 0000000000..21c1f8f7f1 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSelectionServiceConnector.h @@ -0,0 +1,133 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKSELECTIONSERVICECONNECTOR_H +#define QMITKSELECTIONSERVICECONNECTOR_H + +#include + +// qt widgets module +#include + +// mitk gui qt common plugin +#include "QmitkDataNodeSelectionProvider.h" +#include "internal/QmitkDataNodeItemModel.h" + + // blueberry ui qt plugin +#include + +/* +* @brief The 'QmitkSelectionServiceConnector' is used to handle the selections of the global selection bus (selection service). +* +* The selection service connector can listen to a selection service. This should be done by using 'AddPostSelectionListener' +* with the existing selection service of the surrounding 'QmitkAbstractView'. +* The selection service connector can provide selections. This should be done by using 'SetAsSelectionProvider' +* with the existing selection provider of the surrounding 'QmitkAbstractView'. +* +* The 'QmitkSelectionServiceConnector' offers a public slot and signal that can be used to propagate the selected +* nodes from or to the global selection bus: +* The 'ChangeServiceSelection'-slot transforms the given list of selected nodes into a QItemSelection of a temporary +* data node selection model. This data node selection model is set as the item selection model of the member selection provider. +* So by temporary adding a new data node selection model and changing its selection the selection provider sends a new selection +* that can be received at any place in the workbench. +* +* The 'ServiceSelectionChanged'-signal sends a list of selected nodes to it's local environment (e.g. containing widget). +* The 'ServiceSelectionChanged'-signal is emitted by the 'ServiceSelectionChanged'-function, which transforms the +* berry selection of the selection into a data node list. The 'ServiceSelectionChanged'-function is called whenever +* the selection service sends a selection changed event. +* +* In order to connect the 'QmitkSelectionServiceConnector' with a model-view pair, a 'QmitkModelViewSelectionConnector' needs to be used: +* The 'QmitkModelViewSelectionConnector' offers a 'SetCurrentSelection'-slot that can be connected with the +* 'ServiceSelectionChanged'-signal of this class. +* The 'QmitkModelViewSelectionConnector' offers a 'CurrentSelectionChanged'-signal that can be connected with the +* 'ChangeServiceSelection'-slot of this class. +*/ +class MITK_QT_COMMON QmitkSelectionServiceConnector : public QObject +{ + Q_OBJECT + +public: + + QmitkSelectionServiceConnector(); + ~QmitkSelectionServiceConnector(); + + /* + * @brief Create a selection listener and add it to the list of selection listener of the given selection service. + * + * The selection listener is connected to the 'ServiceSelectionChanged' member function, which is + * called if a berry selection is changed in the workbench. + */ + void AddPostSelectionListener(berry::ISelectionService* selectionService); + /* + * @brief Remove a selection listener from the list of selection listener of the selection service member. + */ + void RemovePostSelectionListener(); + /* + * @brief Store the given selection provider as a private member. + * In order to use the public slot 'ChangeServiceSelection'-function, the selection provider member had to be + * previously set. + */ + void SetAsSelectionProvider(QmitkDataNodeSelectionProvider* selectionProvider); + /* + * @brief Set the selection provider member to a nullptr. This will prevent the public slot + * 'ChangeServiceSelection'-function from working. + */ + void RemoveAsSelectionProvider(); + +Q_SIGNALS: + /* + * @brief A signal that will be emitted by the private 'ServiceSelectionChanged'-function. This happens if a selection is changed + * via the selection service. + * + * @par nodes A list of data nodes that are newly selected. + */ + void ServiceSelectionChanged(QList nodes); + +public Q_SLOTS: + /* + * @brief Send new selections to the selection service via the private selection provider member. + * + * This slot-function is called whenever a local selection is changed in the surrounding widget and a selection provider was set. + * The newly selected data nodes are added temporary to a 'QmitkDataNodeItemModel', which is then used to define + * the indices to select. + * The 'QItemSelectionModel' is set as the item selection model of the selection provider member and its items are + * selected by the indices previously defined by the 'QmitkDataNodeItemModel'. + */ + void ChangeServiceSelection(QList nodes); + +private: + + std::unique_ptr m_BerrySelectionListener; + berry::ISelectionService* m_SelectionService; + QmitkDataNodeSelectionProvider* m_SelectionProvider; + std::shared_ptr m_DataNodeItemModel; + std::shared_ptr m_DataNodeSelectionModel; + + /* + * @brief Handle a selection received from the selection service. + * + * This function is called whenever a berry selection of the selection service is changed in the workbench. + * The new selection is transformed into a data node selection and the contained data nodes are propagated + * as the new current selection of the item view member. + * + * @par sourcePart The workbench part containing the selection. + * @par selection The current selection. + */ + void OnServiceSelectionChanged(const berry::IWorkbenchPart::Pointer& sourcePart, const berry::ISelection::ConstPointer& selection); + +}; + +#endif // QMITKSELECTIONSERVICECONNECTOR_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.cpp b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.cpp new file mode 100644 index 0000000000..7bfe3d420c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.cpp @@ -0,0 +1,212 @@ +/*=================================================================== + +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 "QmitkSingleNodeSelectionWidget.h" + +#include +#include + +#include "QPainter" +#include "QTextDocument" + +QmitkSingleNodeSelectionWidget::QmitkSingleNodeSelectionWidget(QWidget* parent) : QmitkAbstractNodeSelectionWidget(parent) +{ + m_Controls.setupUi(this); + + m_Controls.btnSelect->installEventFilter(this); + m_Controls.btnSelect->setVisible(true); + m_Controls.btnClear->setVisible(false); + + this->UpdateInfo(); + + connect(m_Controls.btnClear, SIGNAL(clicked(bool)), this, SLOT(OnClearSelection())); +} + +QmitkSingleNodeSelectionWidget::~QmitkSingleNodeSelectionWidget() +{ +} + +mitk::DataNode::Pointer QmitkSingleNodeSelectionWidget::ExtractCurrentValidSelection(const NodeList& nodes) const +{ + mitk::DataNode::Pointer result = nullptr; + + for (auto node : nodes) + { + bool valid = true; + if (m_NodePredicate.IsNotNull()) + { + valid = m_NodePredicate->CheckNode(node); + } + if (valid) + { + result = node; + break; + } + } + + return result; +} + +QmitkSingleNodeSelectionWidget::NodeList QmitkSingleNodeSelectionWidget::CompileEmitSelection() const +{ + NodeList result; + + if (!m_SelectOnlyVisibleNodes) + { + result = m_ExternalSelection; + } + + if (m_SelectedNode.IsNotNull() && !result.contains(m_SelectedNode)) + { + result.append(m_SelectedNode); + } + + return result; +} + +void QmitkSingleNodeSelectionWidget::OnNodePredicateChanged(mitk::NodePredicateBase* /*newPredicate*/) +{ + m_SelectedNode = this->ExtractCurrentValidSelection(m_ExternalSelection); +}; + +void QmitkSingleNodeSelectionWidget::OnClearSelection() +{ + if (m_IsOptional) + { + NodeList emptyList; + this->SetCurrentSelection(emptyList); + } + + this->UpdateInfo(); +} + +mitk::DataNode::Pointer QmitkSingleNodeSelectionWidget::GetSelectedNode() const +{ + return m_SelectedNode; +}; + +bool QmitkSingleNodeSelectionWidget::eventFilter(QObject *obj, QEvent *ev) +{ + if (obj == m_Controls.btnSelect) + { + if (ev->type() == QEvent::MouseButtonRelease) + { + this->EditSelection(); + return true; + } + } + + return false; +} + +void QmitkSingleNodeSelectionWidget::EditSelection() +{ + QmitkNodeSelectionDialog* dialog = new QmitkNodeSelectionDialog(this, m_PopUpTitel, m_PopUpHint); + + dialog->SetDataStorage(m_DataStorage.Lock()); + dialog->SetNodePredicate(m_NodePredicate); + NodeList list; + if (m_SelectedNode.IsNotNull()) + { + list.append(m_SelectedNode); + } + dialog->SetCurrentSelection(list); + dialog->SetSelectOnlyVisibleNodes(m_SelectOnlyVisibleNodes); + dialog->SetSelectionMode(QAbstractItemView::SingleSelection); + + m_Controls.btnSelect->setChecked(true); + + if (dialog->exec()) + { + auto lastEmission = this->CompileEmitSelection(); + + auto nodes = dialog->GetSelectedNodes(); + if (nodes.empty()) + { + m_SelectedNode = nullptr; + } + else + { + m_SelectedNode = nodes.first(); + } + + auto newEmission = this->CompileEmitSelection(); + + if (!EqualNodeSelections(lastEmission, newEmission)) + { + emit CurrentSelectionChanged(newEmission); + this->UpdateInfo(); + } + } + + m_Controls.btnSelect->setChecked(false); + + delete dialog; +}; + +void QmitkSingleNodeSelectionWidget::UpdateInfo() +{ + if (m_SelectedNode.IsNull()) + { + if (m_IsOptional) + { + m_Controls.btnSelect->SetNodeInfo(m_EmptyInfo); + } + else + { + m_Controls.btnSelect->SetNodeInfo(m_InvalidInfo); + } + m_Controls.btnClear->setVisible(false); + } + else + { + m_Controls.btnClear->setVisible(m_IsOptional); + } + + m_Controls.btnSelect->SetSelectedNode(m_SelectedNode); +}; + +void QmitkSingleNodeSelectionWidget::SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) +{ + auto lastEmission = this->CompileEmitSelection(); + + m_SelectOnlyVisibleNodes = selectOnlyVisibleNodes; + + auto newEmission = this->CompileEmitSelection(); + + if (!EqualNodeSelections(lastEmission, newEmission)) + { + emit CurrentSelectionChanged(newEmission); + this->UpdateInfo(); + } +}; + +void QmitkSingleNodeSelectionWidget::SetCurrentSelection(NodeList selectedNodes) +{ + auto lastEmission = this->CompileEmitSelection(); + + m_ExternalSelection = selectedNodes; + m_SelectedNode = this->ExtractCurrentValidSelection(selectedNodes); + + auto newEmission = this->CompileEmitSelection(); + + if (!EqualNodeSelections(lastEmission, newEmission)) + { + emit CurrentSelectionChanged(newEmission); + this->UpdateInfo(); + } +}; diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.h b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.h new file mode 100644 index 0000000000..9fbe2c040d --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.h @@ -0,0 +1,84 @@ +/*=================================================================== + +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 QMITK_SINGLE_NODE_SELECTION_WIDGET_H +#define QMITK_SINGLE_NODE_SELECTION_WIDGET_H + +#include + +#include +#include +#include + +#include "org_mitk_gui_qt_common_Export.h" + +#include "ui_QmitkSingleNodeSelectionWidget.h" + +#include +#include + +class QmitkAbstractDataStorageModel; + +/** +* \class QmitkSingleNodeSelectionWidget +* \brief Widget that that represents a node selection. It acts like a button. Clicking on it +* allows to change the selection. +*/ +class MITK_QT_COMMON QmitkSingleNodeSelectionWidget : public QmitkAbstractNodeSelectionWidget +{ + Q_OBJECT + +public: + explicit QmitkSingleNodeSelectionWidget(QWidget* parent = nullptr); + ~QmitkSingleNodeSelectionWidget(); + + mitk::DataNode::Pointer GetSelectedNode() const; + + using NodeList = QmitkAbstractNodeSelectionWidget::NodeList; + +Q_SIGNALS: + /* + * @brief A signal that will be emitted if the selected node has changed. + * + * @param nodes A list of data nodes that are newly selected. + */ + void CurrentSelectionChanged(QList nodes); + +public Q_SLOTS: + virtual void SetSelectOnlyVisibleNodes(bool selectOnlyVisibleNodes) override; + virtual void SetCurrentSelection(NodeList selectedNodes) override; + +protected Q_SLOTS: + virtual void OnClearSelection(); + +protected: + mitk::DataNode::Pointer ExtractCurrentValidSelection(const NodeList& nodes) const; + NodeList CompileEmitSelection() const; + + virtual bool eventFilter(QObject *obj, QEvent *ev) override; + void EditSelection(); + virtual void UpdateInfo() override; + + virtual void OnNodePredicateChanged(mitk::NodePredicateBase* newPredicate); + + NodeList m_ExternalSelection; + mitk::DataNode::Pointer m_SelectedNode; + + Ui_QmitkSingleNodeSelectionWidget m_Controls; +}; + +#endif // QmitkSingleNodeSelectionWidget_H diff --git a/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.ui b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.ui new file mode 100644 index 0000000000..7a13c0bbe2 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/QmitkSingleNodeSelectionWidget.ui @@ -0,0 +1,121 @@ + + + QmitkSingleNodeSelectionWidget + + + + 0 + 0 + 348 + 25 + + + + + 0 + 0 + + + + + 0 + 25 + + + + + 16777215 + 40 + + + + Form + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + + + true + + + + + + + + 0 + 0 + + + + + 0 + 25 + + + + + 25 + 16777215 + + + + Press to remove the current selection. + + + + + + + :/org.mitk.gui.qt.common/resources/times.svg:/org.mitk.gui.qt.common/resources/times.svg + + + + 19 + 19 + + + + + + + + + QmitkNodeSelectionButton + QPushButton +
QmitkNodeSelectionButton.h
+
+
+ + +
diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkCommonActivator.cpp b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkCommonActivator.cpp index 8116c685e3..188d1d6738 100644 --- a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkCommonActivator.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkCommonActivator.cpp @@ -1,70 +1,73 @@ /*=================================================================== 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 "QmitkCommonActivator.h" #include #include +#include "QmitkNodeSelectionPreferencePage.h" QmitkCommonActivator* QmitkCommonActivator::m_Instance = nullptr; ctkPluginContext* QmitkCommonActivator::m_Context = nullptr; ctkPluginContext* QmitkCommonActivator::GetContext() { return m_Context; } QmitkCommonActivator* QmitkCommonActivator::GetInstance() { return m_Instance; } berry::IPreferencesService* QmitkCommonActivator::GetPreferencesService() { return m_PrefServiceTracker->getService(); } void QmitkCommonActivator::start(ctkPluginContext* context) { this->m_Instance = this; this->m_Context = context; this->m_PrefServiceTracker.reset(new ctkServiceTracker(context)); if(berry::PlatformUI::IsWorkbenchRunning()) { m_ViewCoordinator.reset(new QmitkViewCoordinator); m_ViewCoordinator->Start(); } else { MITK_ERROR << "BlueBerry Workbench not running!"; } + + BERRY_REGISTER_EXTENSION_CLASS(QmitkNodeSelectionPreferencePage, context) } void QmitkCommonActivator::stop(ctkPluginContext* context) { Q_UNUSED(context) m_ViewCoordinator->Stop(); m_ViewCoordinator.reset(); this->m_PrefServiceTracker.reset(); this->m_Context = nullptr; this->m_Instance = nullptr; } diff --git a/Modules/Core/test/mitkImageDataItemTest.cpp b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.cpp similarity index 55% copy from Modules/Core/test/mitkImageDataItemTest.cpp copy to Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.cpp index b332e9eca7..2f6a3ceaf1 100644 --- a/Modules/Core/test/mitkImageDataItemTest.cpp +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.cpp @@ -1,32 +1,22 @@ /*=================================================================== 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 "mitkImage.h" -#include "mitkImageDataItem.h" +#include "QmitkNodeSelectionConstants.h" -#include -int mitkImageDataItemTest(int /*argc*/, char * /*argv*/ []) -{ - auto pixels = new unsigned long[100]; - void *data = pixels; - - std::cout << "Testing pseudo-type independent deleting: "; - delete[](unsigned char *) data; - std::cout << "[PASSED]" << std::endl; - - std::cout << "[TEST DONE]" << std::endl; - return EXIT_SUCCESS; -} +const std::string mitk::NodeSelectionConstants::ROOT_PREFERENCE_NODE_ID = "/NODESELECTION/UI"; +const std::string mitk::NodeSelectionConstants::VISIBLE_INSPECTORS_NODE_ID = "visibleInspectors"; +const std::string mitk::NodeSelectionConstants::FAVORITE_INSPECTOR_ID = "inspectorID"; +const std::string mitk::NodeSelectionConstants::VISIBLE_INSPECTOR_ID = "inspectorID"; diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.h b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.h new file mode 100644 index 0000000000..170ec1840c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionConstants.h @@ -0,0 +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. + +===================================================================*/ + +#ifndef _QMITK_NODE_SELECTION_CONSTANTS_H_ +#define _QMITK_NODE_SELECTION_CONSTANTS_H_ + +#include + +#include "org_mitk_gui_qt_common_Export.h" + +#ifdef _MSC_VER +# pragma warning(push) +# pragma warning(disable:4251) +#endif + +namespace mitk +{ +struct MITK_QT_COMMON NodeSelectionConstants +{ + /** ID/Path of main preference node for node selections. */ + static const std::string ROOT_PREFERENCE_NODE_ID; + + /** ID of main preference node where all visible inspectors are stored (e.g. ROOT_PREFERENCE_NODE_ID+"/"+VISIBLE_INSPECTORS_NODE_ID+"/[orderering #]"). + The sub node naming encodes the ordering number of the visible inspector.*/ + static const std::string VISIBLE_INSPECTORS_NODE_ID; + /** ID for the value that stores the favorite inspector ID in the root preference node.*/ + static const std::string FAVORITE_INSPECTOR_ID; + /** ID for the value that stores the inspector ID in the preference node.*/ + static const std::string VISIBLE_INSPECTOR_ID; +}; + +} + +#ifdef _MSC_VER +# pragma warning(pop) +#endif + +#endif diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.cpp b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.cpp new file mode 100644 index 0000000000..86fe16b1de --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.cpp @@ -0,0 +1,198 @@ +/*=================================================================== + +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 "QmitkNodeSelectionPreferencePage.h" + +#include "QmitkNodeSelectionPreferenceHelper.h" + +//----------------------------------------------------------------------------- +QmitkNodeSelectionPreferencePage::QmitkNodeSelectionPreferencePage() + : m_MainControl(0), m_Controls(0) +{ + +} + + +//----------------------------------------------------------------------------- +QmitkNodeSelectionPreferencePage::~QmitkNodeSelectionPreferencePage() +{ + delete m_Controls; +} + + +//----------------------------------------------------------------------------- +void QmitkNodeSelectionPreferencePage::Init(berry::IWorkbench::Pointer ) +{ + +} + + +//----------------------------------------------------------------------------- +void QmitkNodeSelectionPreferencePage::CreateQtControl(QWidget* parent) +{ + m_MainControl = new QWidget(parent); + m_Controls = new Ui::QmitkNodeSelectionPreferencePage; + m_Controls->setupUi( m_MainControl ); + + connect(m_Controls->comboFavorite, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateWidgets())); + connect(m_Controls->btnUp, SIGNAL(clicked(bool)), this, SLOT(MoveUp())); + connect(m_Controls->btnDown, SIGNAL(clicked(bool)), this, SLOT(MoveDown())); + connect(m_Controls->listInspectors, SIGNAL(itemSelectionChanged()), this, SLOT(UpdateWidgets())); + + this->Update(); +} + + +//----------------------------------------------------------------------------- +QWidget* QmitkNodeSelectionPreferencePage::GetQtControl() const +{ + return m_MainControl; +} + +//----------------------------------------------------------------------------- +bool QmitkNodeSelectionPreferencePage::PerformOk() +{ + //store favorite + auto id = m_Controls->comboFavorite->currentData().toString(); + mitk::PutFavoriteDataStorageInspector(id.toStdString()); + + //store visible + mitk::VisibleDataStorageInspectorMapType visibles; + + unsigned int visiblePos = 0; + + for (int i = 0; i < m_Controls->listInspectors->count(); ++i) + { + auto item = m_Controls->listInspectors->item(i); + if (item->checkState() == Qt::Checked) + { + visibles.insert(std::make_pair(visiblePos++, item->data(Qt::UserRole).toString().toStdString())); + } + } + mitk::PutVisibleDataStorageInspectors(visibles); + + return true; +} + + +//----------------------------------------------------------------------------- +void QmitkNodeSelectionPreferencePage::PerformCancel() +{ +} + + +//----------------------------------------------------------------------------- +void QmitkNodeSelectionPreferencePage::Update() +{ + m_Providers = QmitkDataStorageInspectorGenerator::GetProviders(); + + auto visibleProviders = mitk::GetVisibleDataStorageInspectors(); + auto allProviders = QmitkDataStorageInspectorGenerator::GetProviders(); + auto favorite = mitk::GetFavoriteDataStorageInspector(); + + auto finding = m_Providers.find(favorite); + if (finding == m_Providers.cend()) + { + favorite = m_Providers.begin()->first; + } + + //fill favorite combo + int index = 0; + int currentIndex = 0; + m_Controls->comboFavorite->clear(); + for (auto iter : m_Providers) + { + m_Controls->comboFavorite->addItem(QString::fromStdString(iter.second->GetInspectorDisplayName()),QVariant::fromValue(QString::fromStdString(iter.first))); + if (iter.first == favorite) + { + currentIndex = index; + }; + ++index; + } + m_Controls->comboFavorite->setCurrentIndex(currentIndex); + + //fill inspector list + m_Controls->listInspectors->clear(); + for (const auto iter : allProviders) + { + auto currentID = iter.first; + QListWidgetItem* item = new QListWidgetItem; + item->setText(QString::fromStdString(iter.second->GetInspectorDisplayName())); + item->setData(Qt::UserRole, QVariant::fromValue(QString::fromStdString(currentID))); + item->setToolTip(QString::fromStdString(iter.second->GetInspectorDescription())); + + auto finding = std::find_if(visibleProviders.cbegin(), visibleProviders.cend(), [¤tID](auto v) {return v.second == currentID; }); + if (finding == visibleProviders.cend()) + { + item->setCheckState(Qt::Unchecked); + m_Controls->listInspectors->addItem(item); + } + else + { + item->setCheckState(Qt::Checked); + m_Controls->listInspectors->insertItem(finding->first, item); + } + } + + this->UpdateWidgets(); +} + +void QmitkNodeSelectionPreferencePage::UpdateWidgets() +{ + int currentIndex = m_Controls->listInspectors->currentRow(); + m_Controls->btnUp->setEnabled(!m_Controls->listInspectors->selectedItems().empty() && currentIndex > 0); + m_Controls->btnDown->setEnabled(!m_Controls->listInspectors->selectedItems().empty() && currentIndex + 1 < m_Controls->listInspectors->count()); + + for (int i = 0; i < m_Controls->listInspectors->count(); ++i) + { + auto item = m_Controls->listInspectors->item(i); + if (item->data(Qt::UserRole).toString() == m_Controls->comboFavorite->currentData().toString()) + { + //favorites are always visible. + item->setCheckState(Qt::Checked); + item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled); + } + else + { + item->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsUserCheckable); + } + } +}; + +void QmitkNodeSelectionPreferencePage::MoveDown() +{ + int currentIndex = m_Controls->listInspectors->currentRow(); + if (currentIndex+1 < m_Controls->listInspectors->count()) + { + QListWidgetItem *currentItem = m_Controls->listInspectors->takeItem(currentIndex); + m_Controls->listInspectors->insertItem(currentIndex + 1, currentItem); + m_Controls->listInspectors->setCurrentRow(currentIndex + 1); + } + this->UpdateWidgets(); +}; + +void QmitkNodeSelectionPreferencePage::MoveUp() +{ + int currentIndex = m_Controls->listInspectors->currentRow(); + if (currentIndex > 0) + { + QListWidgetItem *currentItem = m_Controls->listInspectors->takeItem(currentIndex); + m_Controls->listInspectors->insertItem(currentIndex - 1, currentItem); + m_Controls->listInspectors->setCurrentRow(currentIndex - 1); + } + this->UpdateWidgets(); +}; diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.h b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.h new file mode 100644 index 0000000000..2e959c43c5 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.h @@ -0,0 +1,91 @@ +/*=================================================================== + +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 __QMITK_NODE_SELECTION_PREFERENCE_PAGE_H +#define __QMITK_NODE_SELECTION_PREFERENCE_PAGE_H + +#include "berryIQtPreferencePage.h" +#include "berryIPreferences.h" + +#include "QmitkDataStorageInspectorGenerator.h" + +#include "ui_QmitkNodeSelectionPreferencePage.h" + +class QWidget; + +/** +* \class QmitkNodeSelectionPreferencePage +* \brief Preference page for general node selection settings. +*/ +class QmitkNodeSelectionPreferencePage : public QObject, public berry::IQtPreferencePage +{ + Q_OBJECT + Q_INTERFACES(berry::IPreferencePage) + +public: + QmitkNodeSelectionPreferencePage(); + ~QmitkNodeSelectionPreferencePage(); + + /** + * \brief Called by framework to initialize this preference page, but currently does nothing. + * \param workbench The workbench. + */ + void Init(berry::IWorkbench::Pointer workbench); + + /** + * \brief Called by framework to create the GUI, and connect signals and slots. + * \param widget The Qt widget that acts as parent to all GUI components, as this class itself is not derived from QWidget. + */ + void CreateQtControl(QWidget* widget); + + /** + * \brief Required by framework to get hold of the GUI. + * \return QWidget* the top most QWidget for the GUI. + */ + QWidget* GetQtControl() const; + + /** + * \see IPreferencePage::PerformOk + */ + virtual bool PerformOk(); + + /** + * \see IPreferencePage::PerformCancel + */ + virtual void PerformCancel(); + + /** + * \see IPreferencePage::Update + */ + virtual void Update(); + +protected slots: + + void UpdateWidgets(); + void MoveDown(); + void MoveUp(); + +protected: + + QWidget *m_MainControl; + Ui::QmitkNodeSelectionPreferencePage* m_Controls; + + QmitkDataStorageInspectorGenerator::ProviderMapType m_Providers; + +}; + +#endif diff --git a/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.ui b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.ui new file mode 100644 index 0000000000..c88f7330f2 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.common/src/internal/QmitkNodeSelectionPreferencePage.ui @@ -0,0 +1,145 @@ + + + QmitkNodeSelectionPreferencePage + + + + 0 + 0 + 715 + 713 + + + + Form + + + + + + + + Up + + + + + + + Down + + + + + + + + + Favorite inspector: + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 20 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + <html><head/><body><p>The favorite inspector is always visible.</p><p>Additionally the favorite inspector has always the focus when opening a node selection dialoge.</p></body></html> + + + + Neues Element + + + + + 2 + + + + + + + + <html><head/><body><p><span style=" font-weight:600;">Instruction:</span><br/>Only checked inspectors will be shown in node selection dialogs.<br/>You may change the order in the inspector list, to change the order of the tabs in the node selection dialog.</p></body></html> + + + true + + + + + + + + + Inspector visiblitiy and order: + + + + + + + + 16777215 + 16777215 + + + + List of all available inspectors. Checked inspectores will be display + + + + TreeInspector + + + ffffff + + + Checked + + + + + List + + + Checked + + + + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.coreapplication/src/internal/QmitkWorkbenchAdvisor.h b/Plugins/org.mitk.gui.qt.coreapplication/src/internal/QmitkWorkbenchAdvisor.h index 27976d24dc..931ee761bd 100644 --- a/Plugins/org.mitk.gui.qt.coreapplication/src/internal/QmitkWorkbenchAdvisor.h +++ b/Plugins/org.mitk.gui.qt.coreapplication/src/internal/QmitkWorkbenchAdvisor.h @@ -1,45 +1,37 @@ /*=================================================================== 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 QMITKWORKBENCHADVISOR_H_ #define QMITKWORKBENCHADVISOR_H_ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include - class QmitkWorkbenchAdvisor : public berry::QtWorkbenchAdvisor { public: static const QString DEFAULT_PERSPECTIVE_ID; // = org.mitk.coreapp.defaultperspective void Initialize(berry::IWorkbenchConfigurer::Pointer configurer) override; berry::WorkbenchWindowAdvisor* CreateWorkbenchWindowAdvisor( berry::IWorkbenchWindowConfigurer::Pointer configurer) override; QString GetInitialWindowPerspectiveId() override; }; #endif /*QMITKWORKBENCHADVISOR_H_*/ diff --git a/Plugins/org.mitk.gui.qt.datamanager/resources/data-manager.svg b/Plugins/org.mitk.gui.qt.datamanager/resources/data-manager.svg index 0e4b601122..82a332cdab 100644 --- a/Plugins/org.mitk.gui.qt.datamanager/resources/data-manager.svg +++ b/Plugins/org.mitk.gui.qt.datamanager/resources/data-manager.svg @@ -1,55 +1,55 @@ image/svg+xml diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/CMakeLists.txt b/Plugins/org.mitk.gui.qt.datastorageviewertest/CMakeLists.txt new file mode 100644 index 0000000000..add23310bd --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/CMakeLists.txt @@ -0,0 +1,7 @@ +project(org_mitk_gui_qt_datastorageviewertest) + +mitk_create_plugin( + EXPORT_DIRECTIVE DATASTORAGEVIEWERTEST_EXPORT + EXPORTED_INCLUDE_SUFFIXES src + MODULE_DEPENDS MitkQtWidgets +) diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/files.cmake b/Plugins/org.mitk.gui.qt.datastorageviewertest/files.cmake new file mode 100644 index 0000000000..7346b84a06 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/files.cmake @@ -0,0 +1,32 @@ +set(SRC_CPP_FILES +) + +set(INTERNAL_CPP_FILES + mitkPluginActivator.cpp + QmitkDataStorageViewerTestView.cpp +) + +set(UI_FILES + src/internal/QmitkDataStorageViewerTestControls.ui +) + +set(MOC_H_FILES + src/internal/mitkPluginActivator.h + src/internal/QmitkDataStorageViewerTestView.h +) + +set(CACHED_RESOURCE_FILES + resources/DataStorageViewer_48.png + plugin.xml +) + +set(QRC_FILES +) + +foreach(file ${SRC_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/${file}) +endforeach(file ${SRC_CPP_FILES}) + +foreach(file ${INTERNAL_CPP_FILES}) + set(CPP_FILES ${CPP_FILES} src/internal/${file}) +endforeach(file ${INTERNAL_CPP_FILES}) diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/manifest_headers.cmake b/Plugins/org.mitk.gui.qt.datastorageviewertest/manifest_headers.cmake new file mode 100644 index 0000000000..3189816295 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/manifest_headers.cmake @@ -0,0 +1,5 @@ +set(Plugin-Name "MITK Data storage viewer test") +set(Plugin-Version "0.1") +set(Plugin-Vendor "DKFZ") +set(Plugin-ContactAddress "http://www.mitk.org") +set(Require-Plugin org.mitk.gui.qt.common) diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/plugin.xml b/Plugins/org.mitk.gui.qt.datastorageviewertest/plugin.xml new file mode 100644 index 0000000000..9b1f6fd52c --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/plugin.xml @@ -0,0 +1,11 @@ + + + + + + + + diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/resources/DataStorageViewer_48.png b/Plugins/org.mitk.gui.qt.datastorageviewertest/resources/DataStorageViewer_48.png new file mode 100644 index 0000000000..d297828a0d Binary files /dev/null and b/Plugins/org.mitk.gui.qt.datastorageviewertest/resources/DataStorageViewer_48.png differ diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestControls.ui b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestControls.ui new file mode 100644 index 0000000000..66866a9712 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestControls.ui @@ -0,0 +1,158 @@ + + + QmitkDataStorageViewerTestControls + + + + 0 + 0 + 945 + 728 + + + + + 0 + 0 + + + + Data storage viewer test + + + + + + + + + + + + Set as selection provider + + + + + + + Set as selection provider + + + + + + + Set as selection listener + + + + + + + Set as selection listener + + + + + + + + 0 + 40 + + + + + + + + + + + Set as selection provider + + + + + + + Set as selection listner + + + + + + + Only valid nodes + + + + + + + Allow only images + + + + + + + Is Optional + + + + + + + Set as selection provider + + + + + + + Set as selection listner + + + + + + + Only valid nodes + + + + + + + Allow only images + + + + + + + Is Optional + + + + + + + + QmitkSingleNodeSelectionWidget + QWidget +
QmitkSingleNodeSelectionWidget.h
+ 1 +
+ + QmitkMultiNodeSelectionWidget + QWidget +
QmitkMultiNodeSelectionWidget.h
+ 1 +
+
+ + +
diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.cpp b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.cpp new file mode 100644 index 0000000000..dbe3bd1cc8 --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.cpp @@ -0,0 +1,247 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +// data storage viewer test plugin +#include "QmitkDataStorageViewerTestView.h" + +#include "mitkNodePredicateDataType.h" + +// berry +#include + +// qt +#include + +const std::string QmitkDataStorageViewerTestView::VIEW_ID = "org.mitk.views.datastorageviewertest"; + +void QmitkDataStorageViewerTestView::SetFocus() +{ + // nothing here +} + +void QmitkDataStorageViewerTestView::CreateQtPartControl(QWidget* parent) +{ + // create GUI widgets + m_Controls.setupUi(parent); + + m_DataStorageDefaultListModel = new QmitkDataStorageDefaultListModel(this); + m_DataStorageDefaultListModel->SetDataStorage(GetDataStorage()); + m_Controls.selectionListView->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_Controls.selectionListView->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.selectionListView->setAlternatingRowColors(true); + m_Controls.selectionListView->setModel(m_DataStorageDefaultListModel); + + m_DataStorageDefaultListModel2 = new QmitkDataStorageDefaultListModel(this); + m_DataStorageDefaultListModel2->SetDataStorage(GetDataStorage()); + m_Controls.selectionListView2->setSelectionMode(QAbstractItemView::ExtendedSelection); + m_Controls.selectionListView2->setSelectionBehavior(QAbstractItemView::SelectRows); + m_Controls.selectionListView2->setAlternatingRowColors(true); + m_Controls.selectionListView2->setModel(m_DataStorageDefaultListModel2); + + m_Controls.singleSlot->SetDataStorage(GetDataStorage()); + m_Controls.singleSlot->SetEmptyInfo(QString("EmptyInfo: Set this to display info in empty state")); + m_Controls.singleSlot->SetInvalidInfo(QString("InvalidInfo: is displayed for invalid states")); + m_Controls.singleSlot->SetPopUpTitel(QString("This is the definable caption. Choose your data now!")); + m_Controls.singleSlot->SetPopUpHint(QString("I am an optional hint, that can be set by the developer

If not set the widget is invisible.")); + + m_Controls.multiSlot->SetDataStorage(GetDataStorage()); + m_Controls.multiSlot->SetEmptyInfo(QString("EmptyInfo: Set this to display info in empty state")); + m_Controls.multiSlot->SetInvalidInfo(QString("InvalidInfo: is displayed for invalid states")); + m_Controls.multiSlot->SetPopUpTitel(QString("This is the definable caption. Choose your data now!")); + m_Controls.multiSlot->SetPopUpHint(QString("I am an optional hint, that can be set by the developer

If not set the widget is invisible.")); + + m_ModelViewSelectionConnector = std::make_unique(); + try + { + m_ModelViewSelectionConnector->SetView(m_Controls.selectionListView); + } + catch (mitk::Exception& e) + { + mitkReThrow(e) << "Cannot connect the model-view pair signals and slots."; + } + m_SelectionServiceConnector = std::make_unique(); + + m_ModelViewSelectionConnector2 = std::make_unique(); + try + { + m_ModelViewSelectionConnector2->SetView(m_Controls.selectionListView2); + } + catch (mitk::Exception& e) + { + mitkReThrow(e) << "Cannot connect the model-view pair signals and slots."; + } + m_SelectionServiceConnector2 = std::make_unique(); + + m_SelectionServiceConnector3 = std::make_unique(); + m_SelectionServiceConnector4 = std::make_unique(); + + connect(m_Controls.selectionProviderCheckBox, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionProvider1(bool))); + connect(m_Controls.selectionProviderCheckBox2, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionProvider2(bool))); + + connect(m_Controls.selectionListenerCheckBox, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionListener1(bool))); + connect(m_Controls.selectionListenerCheckBox2, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionListener2(bool))); + + connect(m_Controls.selectionProviderCheckBox3, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionProvider3(bool))); + connect(m_Controls.selectionListenerCheckBox3, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionListener3(bool))); + + connect(m_Controls.checkOnlyVisible, SIGNAL(toggled(bool)), m_Controls.singleSlot, SLOT(SetSelectOnlyVisibleNodes(bool))); + connect(m_Controls.checkOptional, SIGNAL(toggled(bool)), m_Controls.singleSlot, SLOT(SetSelectionIsOptional(bool))); + connect(m_Controls.checkOnlyImages, SIGNAL(toggled(bool)), this, SLOT(OnOnlyImages(bool))); + + connect(m_Controls.selectionProviderCheckBox4, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionProvider4(bool))); + connect(m_Controls.selectionListenerCheckBox4, SIGNAL(toggled(bool)), this, SLOT(SetAsSelectionListener4(bool))); + + connect(m_Controls.checkOnlyVisible_2, SIGNAL(toggled(bool)), m_Controls.multiSlot, SLOT(SetSelectOnlyVisibleNodes(bool))); + connect(m_Controls.checkOptional_2, SIGNAL(toggled(bool)), m_Controls.multiSlot, SLOT(SetSelectionIsOptional(bool))); + connect(m_Controls.checkOnlyImages_2, SIGNAL(toggled(bool)), this, SLOT(OnOnlyImages2(bool))); +} + +void QmitkDataStorageViewerTestView::SetAsSelectionProvider1(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); + connect(m_ModelViewSelectionConnector.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector.get(), SLOT(ChangeServiceSelection(QList))); + } + else + { + m_SelectionServiceConnector->RemoveAsSelectionProvider(); + disconnect(m_ModelViewSelectionConnector.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector.get(), SLOT(ChangeServiceSelection(QList))); + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionListener1(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); + connect(m_SelectionServiceConnector.get(), SIGNAL(ServiceSelectionChanged(QList)), m_ModelViewSelectionConnector.get(), SLOT(SetCurrentSelection(QList))); + } + else + { + m_SelectionServiceConnector->RemovePostSelectionListener(); + disconnect(m_SelectionServiceConnector.get(), SIGNAL(ServiceSelectionChanged(QList)), m_ModelViewSelectionConnector.get(), SLOT(SetCurrentSelection(QList))); + + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionProvider2(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector2->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); + connect(m_ModelViewSelectionConnector2.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector2.get(), SLOT(ChangeServiceSelection(QList))); + } + else + { + m_SelectionServiceConnector2->RemoveAsSelectionProvider(); + disconnect(m_ModelViewSelectionConnector2.get(), SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector2.get(), SLOT(ChangeServiceSelection(QList))); + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionListener2(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector2->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); + connect(m_SelectionServiceConnector2.get(), SIGNAL(ServiceSelectionChanged(QList)), m_ModelViewSelectionConnector2.get(), SLOT(SetCurrentSelection(QList))); + } + else + { + m_SelectionServiceConnector2->RemovePostSelectionListener(); + disconnect(m_SelectionServiceConnector2.get(), SIGNAL(ServiceSelectionChanged(QList)), m_ModelViewSelectionConnector2.get(), SLOT(SetCurrentSelection(QList))); + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionProvider3(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector3->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); + connect(m_Controls.singleSlot, SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector3.get(), SLOT(ChangeServiceSelection(QList))); + } + else + { + m_SelectionServiceConnector3->RemoveAsSelectionProvider(); + disconnect(m_Controls.singleSlot, SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector3.get(), SLOT(ChangeServiceSelection(QList))); + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionListener3(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector3->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); + connect(m_SelectionServiceConnector3.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.singleSlot, &QmitkSingleNodeSelectionWidget::SetCurrentSelection); + } + else + { + m_SelectionServiceConnector3->RemovePostSelectionListener(); + disconnect(m_SelectionServiceConnector3.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.singleSlot, &QmitkSingleNodeSelectionWidget::SetCurrentSelection); + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionProvider4(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector4->SetAsSelectionProvider(GetSite()->GetSelectionProvider().Cast().GetPointer()); + connect(m_Controls.multiSlot, SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector4.get(), SLOT(ChangeServiceSelection(QList))); + } + else + { + m_SelectionServiceConnector4->RemoveAsSelectionProvider(); + disconnect(m_Controls.multiSlot, SIGNAL(CurrentSelectionChanged(QList)), m_SelectionServiceConnector4.get(), SLOT(ChangeServiceSelection(QList))); + } +} + +void QmitkDataStorageViewerTestView::SetAsSelectionListener4(bool checked) +{ + if (checked) + { + m_SelectionServiceConnector4->AddPostSelectionListener(GetSite()->GetWorkbenchWindow()->GetSelectionService()); + connect(m_SelectionServiceConnector4.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.multiSlot, &QmitkMultiNodeSelectionWidget::SetCurrentSelection); + } + else + { + m_SelectionServiceConnector4->RemovePostSelectionListener(); + disconnect(m_SelectionServiceConnector4.get(), &QmitkSelectionServiceConnector::ServiceSelectionChanged, m_Controls.multiSlot, &QmitkMultiNodeSelectionWidget::SetCurrentSelection); + } +} + +void QmitkDataStorageViewerTestView::OnOnlyImages(bool checked) +{ + if (checked) + { + m_Controls.singleSlot->SetNodePredicate(mitk::NodePredicateDataType::New("Image")); + } + else + { + m_Controls.singleSlot->SetNodePredicate(nullptr); + } +}; + +void QmitkDataStorageViewerTestView::OnOnlyImages2(bool checked) +{ + if (checked) + { + m_Controls.multiSlot->SetNodePredicate(mitk::NodePredicateDataType::New("Image")); + } + else + { + m_Controls.multiSlot->SetNodePredicate(nullptr); + } +}; diff --git a/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.h b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.h new file mode 100644 index 0000000000..ce4042ae3e --- /dev/null +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/QmitkDataStorageViewerTestView.h @@ -0,0 +1,77 @@ +/*=================================================================== + +The Medical Imaging Interaction Toolkit (MITK) + +Copyright (c) German Cancer Research Center, +Division of Medical Image Computing. +All rights reserved. + +This software is distributed WITHOUT ANY WARRANTY; without +even the implied warranty of MERCHANTABILITY or FITNESS FOR +A PARTICULAR PURPOSE. + +See LICENSE.txt or http://www.mitk.org for details. + +===================================================================*/ + +#ifndef QMITKDATASTORAGEVIEWERTESTVIEW_H +#define QMITKDATASTORAGEVIEWERTESTVIEW_H + +// mitk gui qt common plugin +#include +#include "QmitkModelViewSelectionConnector.h" +#include "QmitkSelectionServiceConnector.h" + +// data storage viewer test plugin +#include "ui_QmitkDataStorageViewerTestControls.h" + +// qt widgets module +#include "QmitkDataStorageDefaultListModel.h" + +/** +* @brief DataStorageViewerTestView +*/ +class QmitkDataStorageViewerTestView : public QmitkAbstractView +{ + Q_OBJECT + +public: + + static const std::string VIEW_ID; + +protected: + + virtual void SetFocus() override; + + virtual void CreateQtPartControl(QWidget* parent) override; + +private Q_SLOTS: + + void SetAsSelectionProvider1(bool checked); + void SetAsSelectionProvider2(bool checked); + void SetAsSelectionProvider3(bool checked); + void SetAsSelectionProvider4(bool checked); + void SetAsSelectionListener1(bool checked); + void SetAsSelectionListener2(bool checked); + void SetAsSelectionListener3(bool checked); + void SetAsSelectionListener4(bool checked); + + void OnOnlyImages(bool checked); + void OnOnlyImages2(bool checked); + +private: + + Ui::QmitkDataStorageViewerTestControls m_Controls; + QmitkDataStorageDefaultListModel* m_DataStorageDefaultListModel; + QmitkDataStorageDefaultListModel* m_DataStorageDefaultListModel2; + + std::unique_ptr m_ModelViewSelectionConnector; + std::unique_ptr m_SelectionServiceConnector; + std::unique_ptr m_ModelViewSelectionConnector2; + std::unique_ptr m_SelectionServiceConnector2; + + std::unique_ptr m_SelectionServiceConnector3; + std::unique_ptr m_SelectionServiceConnector4; +}; + +#endif // QMITKDATASTORAGEVIEWERTESTVIEW_H diff --git a/Modules/Core/test/mitkImageDataItemTest.cpp b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.cpp similarity index 50% copy from Modules/Core/test/mitkImageDataItemTest.cpp copy to Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.cpp index b332e9eca7..deb5df0dc0 100644 --- a/Modules/Core/test/mitkImageDataItemTest.cpp +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.cpp @@ -1,32 +1,28 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. +Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ -#include "mitkImage.h" -#include "mitkImageDataItem.h" +#include "mitkPluginActivator.h" +#include "QmitkDataStorageViewerTestView.h" -#include -int mitkImageDataItemTest(int /*argc*/, char * /*argv*/ []) +namespace mitk { - auto pixels = new unsigned long[100]; - void *data = pixels; + void DataStorageViewerTestActivator::start(ctkPluginContext *context) + { + BERRY_REGISTER_EXTENSION_CLASS(QmitkDataStorageViewerTestView, context) + } - std::cout << "Testing pseudo-type independent deleting: "; - delete[](unsigned char *) data; - std::cout << "[PASSED]" << std::endl; - - std::cout << "[TEST DONE]" << std::endl; - return EXIT_SUCCESS; + void DataStorageViewerTestActivator::stop(ctkPluginContext *context) { Q_UNUSED(context) } } diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.h b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.h similarity index 58% copy from Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.h copy to Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.h index b2fe5addce..080450ba33 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.h +++ b/Plugins/org.mitk.gui.qt.datastorageviewertest/src/internal/mitkPluginActivator.h @@ -1,44 +1,37 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, -Division of Medical and Biological Informatics. +Division of Medical Image Computing. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ + #ifndef MITKPLUGINACTIVATOR_H #define MITKPLUGINACTIVATOR_H -// Parent classes -#include #include namespace mitk { - class PluginActivator : public QObject, public ctkPluginActivator + class DataStorageViewerTestActivator : public QObject, public ctkPluginActivator { Q_OBJECT -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) - Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_multilabelsegmentation") -#endif + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_datastorageviewertest") Q_INTERFACES(ctkPluginActivator) public: - void start(ctkPluginContext *context); - void stop(ctkPluginContext *context); - - static ctkPluginContext* getContext(); + void start(ctkPluginContext* context) override; + void stop(ctkPluginContext* context) override; - private: - static ctkPluginContext* m_Context; }; } -#endif +#endif // MITKPLUGINACTIVATOR_H diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp index cd1848de92..aca647f8fe 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkFiberQuantificationView.cpp @@ -1,441 +1,441 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkFiberQuantificationView.h" // Qt #include // MITK #include #include #include #include #include #include #include #include // ITK #include #include #include #include -#include +#include const std::string QmitkFiberQuantificationView::VIEW_ID = "org.mitk.views.fiberquantification"; using namespace mitk; QmitkFiberQuantificationView::QmitkFiberQuantificationView() : QmitkAbstractView() , m_Controls( 0 ) , m_UpsamplingFactor(5) , m_Visible(false) { } // Destructor QmitkFiberQuantificationView::~QmitkFiberQuantificationView() { } void QmitkFiberQuantificationView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkFiberQuantificationViewControls; m_Controls->setupUi( parent ); connect( m_Controls->m_ProcessFiberBundleButton, SIGNAL(clicked()), this, SLOT(ProcessSelectedBundles()) ); connect( m_Controls->m_ExtractFiberPeaks, SIGNAL(clicked()), this, SLOT(CalculateFiberDirections()) ); m_Controls->m_TractBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isFib = mitk::TNodePredicateDataType::New(); m_Controls->m_TractBox->SetPredicate( isFib ); m_Controls->m_ImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_ImageBox->SetZeroEntryText("--"); mitk::TNodePredicateDataType::Pointer isImagePredicate = mitk::TNodePredicateDataType::New(); mitk::NodePredicateDimension::Pointer is3D = mitk::NodePredicateDimension::New(3); m_Controls->m_ImageBox->SetPredicate( mitk::NodePredicateAnd::New(isImagePredicate, is3D) ); connect( (QObject*)(m_Controls->m_TractBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); connect( (QObject*)(m_Controls->m_ImageBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); } } void QmitkFiberQuantificationView::Activated() { } void QmitkFiberQuantificationView::Deactivated() { } void QmitkFiberQuantificationView::Visible() { m_Visible = true; } void QmitkFiberQuantificationView::Hidden() { m_Visible = false; } void QmitkFiberQuantificationView::SetFocus() { m_Controls->m_ProcessFiberBundleButton->setFocus(); } void QmitkFiberQuantificationView::CalculateFiberDirections() { typedef itk::Image ItkUcharImgType; // load fiber bundle mitk::FiberBundle::Pointer inputTractogram = dynamic_cast(m_SelectedFB.back()->GetData()); itk::TractsToVectorImageFilter::Pointer fOdfFilter = itk::TractsToVectorImageFilter::New(); if (m_SelectedImage.IsNotNull()) { ItkUcharImgType::Pointer itkMaskImage = ItkUcharImgType::New(); mitk::CastToItkImage(m_SelectedImage, itkMaskImage); fOdfFilter->SetMaskImage(itkMaskImage); } // extract directions from fiber bundle fOdfFilter->SetFiberBundle(inputTractogram); fOdfFilter->SetAngularThreshold(cos(m_Controls->m_AngularThreshold->value()*itk::Math::pi/180)); switch (m_Controls->m_FiberDirNormBox->currentIndex()) { case 0: fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::GLOBAL_MAX); break; case 1: fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::SINGLE_VEC_NORM); break; case 2: fOdfFilter->SetNormalizationMethod(itk::TractsToVectorImageFilter::NormalizationMethods::MAX_VEC_NORM); break; } fOdfFilter->SetUseWorkingCopy(true); fOdfFilter->SetSizeThreshold(m_Controls->m_PeakThreshold->value()); fOdfFilter->SetMaxNumDirections(m_Controls->m_MaxNumDirections->value()); fOdfFilter->Update(); QString name = m_SelectedFB.back()->GetName().c_str(); if (m_Controls->m_NumDirectionsBox->isChecked()) { mitk::Image::Pointer mitkImage = mitk::Image::New(); mitkImage->InitializeByItk( fOdfFilter->GetNumDirectionsImage().GetPointer() ); mitkImage->SetVolume( fOdfFilter->GetNumDirectionsImage()->GetBufferPointer() ); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(mitkImage); node->SetName((name+"_NUM_DIRECTIONS").toStdString().c_str()); GetDataStorage()->Add(node, m_SelectedFB.back()); } Image::Pointer mitkImage = dynamic_cast(PeakImage::New().GetPointer()); mitk::CastToMitkImage(fOdfFilter->GetDirectionImage(), mitkImage); mitkImage->SetVolume(fOdfFilter->GetDirectionImage()->GetBufferPointer()); mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(mitkImage); node->SetName( (name+"_DIRECTIONS").toStdString().c_str()); GetDataStorage()->Add(node, m_SelectedFB.back()); } void QmitkFiberQuantificationView::UpdateGui() { m_SelectedFB.clear(); if (m_Controls->m_TractBox->GetSelectedNode().IsNotNull()) m_SelectedFB.push_back(m_Controls->m_TractBox->GetSelectedNode()); m_SelectedImage = nullptr; if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) m_SelectedImage = dynamic_cast(m_Controls->m_ImageBox->GetSelectedNode()->GetData()); m_Controls->m_ProcessFiberBundleButton->setEnabled(!m_SelectedFB.empty()); m_Controls->m_ExtractFiberPeaks->setEnabled(!m_SelectedFB.empty()); } void QmitkFiberQuantificationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& ) { UpdateGui(); } void QmitkFiberQuantificationView::ProcessSelectedBundles() { if ( m_SelectedFB.empty() ){ QMessageBox::information( nullptr, "Warning", "No fibe bundle selected!"); MITK_WARN("QmitkFiberQuantificationView") << "no fibe bundle selected"; return; } int generationMethod = m_Controls->m_GenerationBox->currentIndex(); for( unsigned int i=0; i(node->GetData())) { mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); QString name(node->GetName().c_str()); DataNode::Pointer newNode = nullptr; switch(generationMethod){ case 0: newNode = GenerateTractDensityImage(fib, false, true); name += "_TDI"; break; case 1: newNode = GenerateTractDensityImage(fib, false, false); name += "_TDI"; break; case 2: newNode = GenerateTractDensityImage(fib, true, false); name += "_envelope"; break; case 3: newNode = GenerateColorHeatmap(fib); break; case 4: newNode = GenerateFiberEndingsImage(fib); name += "_fiber_endings"; break; case 5: newNode = GenerateFiberEndingsPointSet(fib); name += "_fiber_endings"; break; } if (newNode.IsNotNull()) { newNode->SetName(name.toStdString()); GetDataStorage()->Add(newNode); } } } } // generate pointset displaying the fiber endings mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateFiberEndingsPointSet(mitk::FiberBundle::Pointer fib) { mitk::PointSet::Pointer pointSet = mitk::PointSet::New(); vtkSmartPointer fiberPolyData = fib->GetFiberPolyData(); int count = 0; int numFibers = fib->GetNumFibers(); for( int i=0; iGetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); if (numPoints>0) { double* point = points->GetPoint(0); itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; pointSet->InsertPoint(count, itkPoint); count++; } if (numPoints>2) { double* point = points->GetPoint(numPoints-1); itk::Point itkPoint; itkPoint[0] = point[0]; itkPoint[1] = point[1]; itkPoint[2] = point[2]; pointSet->InsertPoint(count, itkPoint); count++; } } mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData( pointSet ); return node; } // generate image displaying the fiber endings mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateFiberEndingsImage(mitk::FiberBundle::Pointer fib) { typedef unsigned int OutPixType; typedef itk::Image OutImageType; typedef itk::TractsToFiberEndingsImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image OutImageType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } // generate rgba heatmap from fiber bundle mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateColorHeatmap(mitk::FiberBundle::Pointer fib) { typedef itk::RGBAPixel OutPixType; typedef itk::Image OutImageType; typedef itk::TractsToRgbaImageFilter< OutImageType > ImageGeneratorType; ImageGeneratorType::Pointer generator = ImageGeneratorType::New(); generator->SetFiberBundle(fib); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { itk::Image::Pointer itkImage = itk::Image::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); return node; } // generate tract density image from fiber bundle mitk::DataNode::Pointer QmitkFiberQuantificationView::GenerateTractDensityImage(mitk::FiberBundle::Pointer fib, bool binary, bool absolute) { mitk::DataNode::Pointer node = mitk::DataNode::New(); if (binary) { typedef unsigned char OutPixType; typedef itk::Image OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetOutputAbsoluteValues(absolute); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); if (m_SelectedImage.IsNotNull()) { mitk::LabelSetImage::Pointer multilabelImage = mitk::LabelSetImage::New(); multilabelImage->InitializeByLabeledImage(img); mitk::Label::Pointer label = multilabelImage->GetActiveLabel(); label->SetName("Tractogram"); // label->SetColor(color); label->SetValue(1); // multilabelImage->GetActiveLabelSet()->AddLabel(label); multilabelImage->GetActiveLabelSet()->SetActiveLabel(1); PropertyList::Pointer dicomSegPropertyList = mitk::DICOMSegmentationPropertyHandler::GetDICOMSegmentationProperties(m_SelectedImage->GetPropertyList()); multilabelImage->GetPropertyList()->ConcatenatePropertyList(dicomSegPropertyList); mitk::DICOMSegmentationPropertyHandler::GetDICOMSegmentProperties(multilabelImage->GetActiveLabel(multilabelImage->GetActiveLayer())); // init data node node->SetData(multilabelImage); } else { // init data node node->SetData(img); } } else { typedef float OutPixType; typedef itk::Image OutImageType; itk::TractDensityImageFilter< OutImageType >::Pointer generator = itk::TractDensityImageFilter< OutImageType >::New(); generator->SetFiberBundle(fib); generator->SetBinaryOutput(binary); generator->SetOutputAbsoluteValues(absolute); generator->SetUpsamplingFactor(m_Controls->m_UpsamplingSpinBox->value()); if (m_SelectedImage.IsNotNull()) { OutImageType::Pointer itkImage = OutImageType::New(); CastToItkImage(m_SelectedImage, itkImage); generator->SetInputImage(itkImage); generator->SetUseImageGeometry(true); } //generator->SetDoFiberResampling(false); generator->Update(); // get output image typedef itk::Image OutType; OutType::Pointer outImg = generator->GetOutput(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); // init data node node->SetData(img); } return node; } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryView.cpp index 50d11a0469..99c8aa88eb 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.fiberprocessing/src/internal/QmitkTractometryView.cpp @@ -1,339 +1,339 @@ /*=================================================================== 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 "QmitkTractometryView.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include -#include +#include #include const std::string QmitkTractometryView::VIEW_ID = "org.mitk.views.tractometry"; using namespace mitk; QmitkTractometryView::QmitkTractometryView() : QmitkAbstractView() , m_Controls( nullptr ) , m_Visible(false) { } // Destructor QmitkTractometryView::~QmitkTractometryView() { } void QmitkTractometryView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkTractometryViewControls; m_Controls->setupUi( parent ); connect( m_Controls->m_SamplingPointsBox, SIGNAL(valueChanged(int)), this, SLOT(UpdateGui()) ); connect( m_Controls->m_StDevBox, SIGNAL(stateChanged(int)), this, SLOT(UpdateGui()) ); mitk::TNodePredicateDataType::Pointer imageP = mitk::TNodePredicateDataType::New(); mitk::NodePredicateDimension::Pointer dimP = mitk::NodePredicateDimension::New(3); m_Controls->m_ImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_ImageBox->SetPredicate(mitk::NodePredicateAnd::New(imageP, dimP)); m_Controls->m_ChartWidget->SetXAxisLabel("Tract position"); m_Controls->m_ChartWidget->SetYAxisLabel("Image Value"); } } void QmitkTractometryView::OnPageSuccessfullyLoaded() { berry::IPreferencesService* prefService = berry::WorkbenchPlugin::GetDefault()->GetPreferencesService(); berry::IPreferences::Pointer m_StylePref = prefService->GetSystemPreferences()->Node(berry::QtPreferences::QT_STYLES_NODE); QString styleName = m_StylePref->Get(berry::QtPreferences::QT_STYLE_NAME, ""); if (styleName == ":/org.blueberry.ui.qt/darkstyle.qss") { this->m_Controls->m_ChartWidget->SetTheme(QmitkChartWidget::ChartStyle::darkstyle); } else { this->m_Controls->m_ChartWidget->SetTheme(QmitkChartWidget::ChartStyle::lightstyle); } } void QmitkTractometryView::SetFocus() { } void QmitkTractometryView::UpdateGui() { berry::IWorkbenchPart::Pointer nullPart; OnSelectionChanged(nullPart, QList(m_CurrentSelection)); } bool QmitkTractometryView::Flip(vtkSmartPointer< vtkPolyData > polydata1, int i, vtkSmartPointer< vtkPolyData > ref_poly) { float d_direct = 0; float d_flipped = 0; vtkCell* cell1 = polydata1->GetCell(0); if (ref_poly!=nullptr) cell1 = ref_poly->GetCell(0); int numPoints1 = cell1->GetNumberOfPoints(); vtkPoints* points1 = cell1->GetPoints(); vtkCell* cell2 = polydata1->GetCell(i); vtkPoints* points2 = cell2->GetPoints(); for (int j=0; jGetPoint(j); double* p2 = points2->GetPoint(j); d_direct = (p1[0]-p2[0])*(p1[0]-p2[0]) + (p1[1]-p2[1])*(p1[1]-p2[1]) + (p1[2]-p2[2])*(p1[2]-p2[2]); double* p3 = points2->GetPoint(numPoints1-j-1); d_flipped = (p1[0]-p3[0])*(p1[0]-p3[0]) + (p1[1]-p3[1])*(p1[1]-p3[1]) + (p1[2]-p3[2])*(p1[2]-p3[2]); } if (d_direct>d_flipped) return true; return false; } template void QmitkTractometryView::ImageValuesAlongTract(const mitk::PixelType, mitk::Image::Pointer image, mitk::FiberBundle::Pointer fib, std::vector > &data, std::string& clipboard_string) { int num_points = m_Controls->m_SamplingPointsBox->value(); mitk::ImagePixelReadAccessor readimage(image, image->GetVolumeData(0)); mitk::FiberBundle::Pointer working_fib = fib->GetDeepCopy(); working_fib->ResampleToNumPoints(num_points); vtkSmartPointer< vtkPolyData > polydata = working_fib->GetFiberPolyData(); std::vector > all_values; std::vector< double > mean_values; for (int i=0; iGetNumFibers(); ++i) { vtkCell* cell = polydata->GetCell(i); int numPoints = cell->GetNumberOfPoints(); vtkPoints* points = cell->GetPoints(); std::vector< double > fib_vals; bool flip = false; if (i>0) flip = Flip(polydata, i); else if (m_ReferencePolyData!=nullptr) flip = Flip(polydata, 0, m_ReferencePolyData); for (int j=0; jGetPoint(numPoints - j - 1); else p = points->GetPoint(j); Point3D px; px[0] = p[0]; px[1] = p[1]; px[2] = p[2]; double pixelValue = readimage.GetPixelByWorldCoordinates(px); fib_vals.push_back(pixelValue); mean += pixelValue; if (pixelValuemax) max = pixelValue; mean_values.at(j) += pixelValue; } all_values.push_back(fib_vals); } if (m_ReferencePolyData==nullptr) m_ReferencePolyData = polydata; std::vector< double > std_values1; std::vector< double > std_values2; for (int i=0; iGetNumFibers(); double stdev = 0; for (unsigned int j=0; j(mean_values.at(i)); clipboard_string += " "; clipboard_string += boost::lexical_cast(stdev); clipboard_string += "\n"; } clipboard_string += "\n"; data.push_back(mean_values); data.push_back(std_values1); data.push_back(std_values2); MITK_INFO << "Min: " << min; MITK_INFO << "Max: " << max; MITK_INFO << "Mean: " << mean/working_fib->GetNumberOfPoints(); } void QmitkTractometryView::Activated() { } void QmitkTractometryView::Deactivated() { } void QmitkTractometryView::Visible() { m_Visible = true; QList selection = GetDataManagerSelection(); berry::IWorkbenchPart::Pointer nullPart; OnSelectionChanged(nullPart, selection); } void QmitkTractometryView::Hidden() { m_Visible = false; } std::string QmitkTractometryView::RGBToHexString(double *rgb) { std::ostringstream os; for (int i = 0; i < 3; ++i) { os << std::setw(2) << std::setfill('0') << std::hex << static_cast(rgb[i] * 255); } return os.str(); } void QmitkTractometryView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { if (!m_Visible) return; m_CurrentSelection.clear(); if(m_Controls->m_ImageBox->GetSelectedNode().IsNull()) return; std::string clipboardString = ""; m_ReferencePolyData = nullptr; mitk::Image::Pointer image = dynamic_cast(m_Controls->m_ImageBox->GetSelectedNode()->GetData()); vtkSmartPointer lookupTable = vtkSmartPointer::New(); lookupTable->SetTableRange(0.0, 1.0); lookupTable->Build(); int num_tracts = 0; for (auto node: nodes) if ( dynamic_cast(node->GetData()) ) num_tracts++; int c = 1; this->m_Controls->m_ChartWidget->Clear(); for (auto node: nodes) { if ( dynamic_cast(node->GetData()) ) { clipboardString += node->GetName() + "\n"; clipboardString += "mean stdev\n"; mitk::FiberBundle::Pointer fib = dynamic_cast(node->GetData()); m_CurrentSelection.push_back(node); std::vector< std::vector< double > > data; mitkPixelTypeMultiplex4( ImageValuesAlongTract, image->GetPixelType(), image, fib, data, clipboardString ); m_Controls->m_ChartWidget->AddData1D(data.at(0), node->GetName() + " Mean", QmitkChartWidget::ChartType::line); if (m_Controls->m_StDevBox->isChecked()) { this->m_Controls->m_ChartWidget->AddData1D(data.at(1), node->GetName() + " +STDEV", QmitkChartWidget::ChartType::line); this->m_Controls->m_ChartWidget->AddData1D(data.at(2), node->GetName() + " -STDEV", QmitkChartWidget::ChartType::line); } double color[3]; if (num_tracts>1) { float scalar_color = ( (float)c/num_tracts - 1.0/num_tracts )/(1.0-1.0/num_tracts); lookupTable->GetColor(1.0 - scalar_color, color); } else lookupTable->GetColor(0, color); this->m_Controls->m_ChartWidget->SetColor(node->GetName() + " Mean", RGBToHexString(color)); if (m_Controls->m_StDevBox->isChecked()) { color[0] *= 0.5; color[1] *= 0.5; color[2] *= 0.5; this->m_Controls->m_ChartWidget->SetColor(node->GetName() + " +STDEV", RGBToHexString(color)); this->m_Controls->m_ChartWidget->SetColor(node->GetName() + " -STDEV", RGBToHexString(color)); } this->m_Controls->m_ChartWidget->Show(true); this->m_Controls->m_ChartWidget->SetShowDataPoints(false); ++c; } } QApplication::clipboard()->setText(clipboardString.c_str(), QClipboard::Clipboard); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationView.cpp index 944e77f2d4..532072513f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.reconstruction/src/internal/QmitkDiffusionQuantificationView.cpp @@ -1,668 +1,668 @@ /*=================================================================== 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 "QmitkDiffusionQuantificationView.h" #include "mitkDiffusionImagingConfigure.h" #include "itkTimeProbe.h" #include "itkImage.h" #include "mitkNodePredicateDataType.h" #include "mitkDataNodeObject.h" #include "mitkOdfImage.h" #include #include "mitkImageCast.h" #include "mitkStatusBar.h" #include "itkDiffusionOdfGeneralizedFaImageFilter.h" #include "itkShiftScaleImageFilter.h" #include "itkTensorFractionalAnisotropyImageFilter.h" #include "itkTensorRelativeAnisotropyImageFilter.h" #include "itkTensorDerivedMeasurementsFilter.h" #include "QmitkDataStorageComboBox.h" #include #include "berryIWorkbenchWindow.h" #include "berryISelectionService.h" #include #include #include #include #include #include #include -#include +#include #include #include #include #include const std::string QmitkDiffusionQuantificationView::VIEW_ID = "org.mitk.views.diffusionquantification"; QmitkDiffusionQuantificationView::QmitkDiffusionQuantificationView() : QmitkAbstractView(), m_Controls(nullptr) { } QmitkDiffusionQuantificationView::~QmitkDiffusionQuantificationView() { } void QmitkDiffusionQuantificationView::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { // create GUI widgets m_Controls = new Ui::QmitkDiffusionQuantificationViewControls; m_Controls->setupUi(parent); this->CreateConnections(); GFACheckboxClicked(); #ifndef DIFFUSION_IMAGING_EXTENDED m_Controls->m_StandardGFACheckbox->setVisible(false); m_Controls->frame_3->setVisible(false); m_Controls->m_CurvatureButton->setVisible(false); #endif m_Controls->m_BallStickButton->setVisible(false); m_Controls->m_MultiTensorButton->setVisible(false); } } void QmitkDiffusionQuantificationView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_StandardGFACheckbox), SIGNAL(clicked()), this, SLOT(GFACheckboxClicked()) ); connect( (QObject*)(m_Controls->m_GFAButton), SIGNAL(clicked()), this, SLOT(GFA()) ); connect( (QObject*)(m_Controls->m_CurvatureButton), SIGNAL(clicked()), this, SLOT(Curvature()) ); connect( (QObject*)(m_Controls->m_FAButton), SIGNAL(clicked()), this, SLOT(FA()) ); connect( (QObject*)(m_Controls->m_RAButton), SIGNAL(clicked()), this, SLOT(RA()) ); connect( (QObject*)(m_Controls->m_ADButton), SIGNAL(clicked()), this, SLOT(AD()) ); connect( (QObject*)(m_Controls->m_RDButton), SIGNAL(clicked()), this, SLOT(RD()) ); connect( (QObject*)(m_Controls->m_MDButton), SIGNAL(clicked()), this, SLOT(MD()) ); connect( (QObject*)(m_Controls->m_MdDwiButton), SIGNAL(clicked()), this, SLOT(MD_DWI()) ); connect( (QObject*)(m_Controls->m_AdcDwiButton), SIGNAL(clicked()), this, SLOT(ADC_DWI()) ); connect( (QObject*)(m_Controls->m_ClusteringAnisotropy), SIGNAL(clicked()), this, SLOT(ClusterAnisotropy()) ); connect( (QObject*)(m_Controls->m_BallStickButton), SIGNAL(clicked()), this, SLOT(DoBallStickCalculation()) ); connect( (QObject*)(m_Controls->m_MultiTensorButton), SIGNAL(clicked()), this, SLOT(DoMultiTensorCalculation()) ); // m_Controls->m_FAButton->setIcon(QmitkStyleManager::ThemeIcon(QStringLiteral(":/org_mitk_icons/icons/awesome/scalable/actions/go-next.svg"))); m_Controls->m_ImageBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isDti = mitk::TNodePredicateDataType::New(); mitk::TNodePredicateDataType::Pointer isOdf = mitk::TNodePredicateDataType::New(); mitk::NodePredicateIsDWI::Pointer isDwi = mitk::NodePredicateIsDWI::New(); m_Controls->m_ImageBox->SetPredicate( mitk::NodePredicateOr::New(isDti, mitk::NodePredicateOr::New(isOdf, isDwi)) ); connect( (QObject*)(m_Controls->m_ImageBox), SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui())); } } void QmitkDiffusionQuantificationView::SetFocus() { m_Controls->m_ScaleImageValuesBox->setFocus(); } void QmitkDiffusionQuantificationView::UpdateGui() { bool foundOdfVolume = false; bool foundTensorVolume = false; bool foundDwVolume = false; mitk::DataNode::Pointer selNode = m_Controls->m_ImageBox->GetSelectedNode(); if( selNode.IsNotNull() && dynamic_cast(selNode->GetData()) ) foundOdfVolume = true; else if( selNode.IsNotNull() && dynamic_cast(selNode->GetData()) ) foundTensorVolume = true; else if( selNode.IsNotNull()) foundDwVolume = true; m_Controls->m_GFAButton->setEnabled(foundOdfVolume); m_Controls->m_CurvatureButton->setEnabled(foundOdfVolume); m_Controls->m_FAButton->setEnabled(foundTensorVolume); m_Controls->m_RAButton->setEnabled(foundTensorVolume); m_Controls->m_ADButton->setEnabled(foundTensorVolume); m_Controls->m_RDButton->setEnabled(foundTensorVolume); m_Controls->m_MDButton->setEnabled(foundTensorVolume); m_Controls->m_ClusteringAnisotropy->setEnabled(foundTensorVolume); m_Controls->m_AdcDwiButton->setEnabled(foundDwVolume); m_Controls->m_MdDwiButton->setEnabled(foundDwVolume); m_Controls->m_BallStickButton->setEnabled(foundDwVolume); m_Controls->m_MultiTensorButton->setEnabled(foundDwVolume); } void QmitkDiffusionQuantificationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& ) { UpdateGui(); } void QmitkDiffusionQuantificationView::ADC_DWI() { DoAdcCalculation(true); } void QmitkDiffusionQuantificationView::MD_DWI() { DoAdcCalculation(false); } void QmitkDiffusionQuantificationView::DoBallStickCalculation() { if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) { mitk::DataNode* node = m_Controls->m_ImageBox->GetSelectedNode(); mitk::Image::Pointer image = dynamic_cast(node->GetData()); typedef itk::BallAndSticksImageFilter< short, double > FilterType; ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetGradientDirections( static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); filter->SetB_value( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); filter->Update(); mitk::Image::Pointer newImage = mitk::Image::New(); newImage->InitializeByItk( filter->GetOutput() ); newImage->SetVolume( filter->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_f").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); { FilterType::PeakImageType::Pointer itkImg = filter->GetPeakImage(); mitk::Image::Pointer newImage = mitk::Image::New(); CastToMitkImage(itkImg, newImage); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_Sticks").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); } { mitk::Image::Pointer dOut = mitk::GrabItkImageMemory( filter->GetOutDwi().GetPointer() ); dOut->GetPropertyList()->ReplaceProperty( mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str(), image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ); dOut->SetProperty( mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str(), image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ); mitk::DiffusionPropertyHelper propertyHelper( dOut ); propertyHelper.InitializeImage(); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( dOut ); QString name = node->GetName().c_str(); imageNode->SetName((name+"_Estimated-DWI").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); } } } void QmitkDiffusionQuantificationView::DoMultiTensorCalculation() { if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) // for all items { mitk::DataNode* node = m_Controls->m_ImageBox->GetSelectedNode(); mitk::Image::Pointer image = dynamic_cast(node->GetData()); typedef itk::MultiTensorImageFilter< short, double > FilterType; ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetGradientDirections( static_cast ( image->GetProperty(mitk::DiffusionPropertyHelper::GRADIENTCONTAINERPROPERTYNAME.c_str()).GetPointer() ) ->GetGradientDirectionsContainer() ); filter->SetB_value( static_cast (image->GetProperty(mitk::DiffusionPropertyHelper::REFERENCEBVALUEPROPERTYNAME.c_str()).GetPointer() ) ->GetValue() ); filter->Update(); typedef mitk::TensorImage::ItkTensorImageType TensorImageType; for (int i=0; iGetTensorImages().at(i); mitk::TensorImage::Pointer image = mitk::TensorImage::New(); image->InitializeByItk( tensorImage.GetPointer() ); image->SetVolume( tensorImage->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( image ); QString name = node->GetName().c_str(); name.append("_Tensor"); name.append(boost::lexical_cast(i).c_str()); imageNode->SetName(name.toStdString().c_str()); GetDataStorage()->Add(imageNode, node); } } } void QmitkDiffusionQuantificationView::DoAdcCalculation(bool fit) { if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) { mitk::DataNode* node = m_Controls->m_ImageBox->GetSelectedNode(); mitk::Image::Pointer image = dynamic_cast(node->GetData()); typedef itk::AdcImageFilter< short, double > FilterType; ItkDwiType::Pointer itkVectorImagePointer = ItkDwiType::New(); mitk::CastToItkImage(image, itkVectorImagePointer); FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkVectorImagePointer ); filter->SetGradientDirections( mitk::DiffusionPropertyHelper::GetGradientContainer(image) ); filter->SetB_value( mitk::DiffusionPropertyHelper::GetReferenceBValue(image) ); filter->SetFitSignal(fit); filter->Update(); typedef itk::ShiftScaleImageFilter::OutputImageType, itk::AdcImageFilter< short, double >::OutputImageType> ShiftScaleFilterType; ShiftScaleFilterType::Pointer multi = ShiftScaleFilterType::New(); multi->SetShift(0.0); multi->SetScale(m_Controls->m_ScaleImageValuesBox->value()); multi->SetInput(filter->GetOutput()); multi->Update(); mitk::Image::Pointer newImage = mitk::Image::New(); newImage->InitializeByItk( multi->GetOutput() ); newImage->SetVolume( multi->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer imageNode = mitk::DataNode::New(); imageNode->SetData( newImage ); QString name = node->GetName().c_str(); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType( mitk::LookupTable::JET_TRANSPARENT ); mitk::LookupTableProperty::Pointer lut_prop = mitk::LookupTableProperty::New(); lut_prop->SetLookupTable( lut ); imageNode->SetProperty("LookupTable", lut_prop ); if (fit) imageNode->SetName((name+"_ADC").toStdString().c_str()); else imageNode->SetName((name+"_MD").toStdString().c_str()); GetDataStorage()->Add(imageNode, node); } } void QmitkDiffusionQuantificationView::GFACheckboxClicked() { m_Controls->frame_2->setVisible(m_Controls->m_StandardGFACheckbox->isChecked()); } void QmitkDiffusionQuantificationView::GFA() { if(m_Controls->m_StandardGFACheckbox->isChecked()) { OdfQuantify(13); } else { OdfQuantify(0); } } void QmitkDiffusionQuantificationView::Curvature() { OdfQuantify(12); } void QmitkDiffusionQuantificationView::FA() { TensorQuantify(0); } void QmitkDiffusionQuantificationView::RA() { TensorQuantify(1); } void QmitkDiffusionQuantificationView::AD() { TensorQuantify(2); } void QmitkDiffusionQuantificationView::RD() { TensorQuantify(3); } void QmitkDiffusionQuantificationView::ClusterAnisotropy() { TensorQuantify(4); } void QmitkDiffusionQuantificationView::MD() { TensorQuantify(5); } void QmitkDiffusionQuantificationView::OdfQuantify(int method) { OdfQuantification(method); } void QmitkDiffusionQuantificationView::TensorQuantify(int method) { TensorQuantification(method); } void QmitkDiffusionQuantificationView::OdfQuantification(int method) { QString status; if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) { mitk::DataNode* node = m_Controls->m_ImageBox->GetSelectedNode(); typedef float TOdfPixelType; typedef itk::Vector OdfVectorType; typedef itk::Image OdfVectorImgType; mitk::Image* vol = static_cast(node->GetData()); OdfVectorImgType::Pointer itkvol = OdfVectorImgType::New(); mitk::CastToItkImage(vol, itkvol); std::string nodename = node->GetName(); float p1 = m_Controls->m_ParamKEdit->text().toFloat(); float p2 = m_Controls->m_ParamPEdit->text().toFloat(); mitk::StatusBar::GetInstance()->DisplayText(status.sprintf("Computing GFA for %s", nodename.c_str()).toLatin1()); typedef itk::DiffusionOdfGeneralizedFaImageFilter GfaFilterType; GfaFilterType::Pointer gfaFilter = GfaFilterType::New(); gfaFilter->SetInput(itkvol); std::string newname; newname.append(nodename); switch(method) { case 0: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_STANDARD); newname.append("GFA"); break; } case 1: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_QUANTILES_HIGH_LOW); newname.append("01"); break; } case 2: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_QUANTILE_HIGH); newname.append("02"); break; } case 3: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_MAX_ODF_VALUE); newname.append("03"); break; } case 4: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_DECONVOLUTION_COEFFS); newname.append("04"); break; } case 5: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_MIN_MAX_NORMALIZED_STANDARD); newname.append("05"); break; } case 6: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_NORMALIZED_ENTROPY); newname.append("06"); break; } case 7: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_NEMATIC_ORDER_PARAMETER); newname.append("07"); break; } case 8: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_QUANTILES_LOW_HIGH); newname.append("08"); break; } case 9: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_QUANTILE_LOW); newname.append("09"); break; } case 10: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_MIN_ODF_VALUE); newname.append("10"); break; } case 11: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_STD_BY_MAX); newname.append("11"); break; } case 12: { p1 = m_Controls->MinAngle->text().toFloat(); p2 = m_Controls->MaxAngle->text().toFloat(); gfaFilter->SetComputationMethod(GfaFilterType::GFA_PRINCIPLE_CURVATURE); QString paramString; paramString = paramString.append("PC%1-%2").arg(p1).arg(p2); newname.append(paramString.toLatin1()); gfaFilter->SetParam1(p1); gfaFilter->SetParam2(p2); break; } case 13: { gfaFilter->SetComputationMethod(GfaFilterType::GFA_GENERALIZED_GFA); QString paramString; paramString = paramString.append("GFAK%1P%2").arg(p1).arg(p2); newname.append(paramString.toLatin1()); gfaFilter->SetParam1(p1); gfaFilter->SetParam2(p2); break; } default: { newname.append("0"); gfaFilter->SetComputationMethod(GfaFilterType::GFA_STANDARD); } } gfaFilter->Update(); typedef itk::Image ImgType; ImgType::Pointer img = ImgType::New(); img->SetSpacing( gfaFilter->GetOutput()->GetSpacing() ); // Set the image spacing img->SetOrigin( gfaFilter->GetOutput()->GetOrigin() ); // Set the image origin img->SetDirection( gfaFilter->GetOutput()->GetDirection() ); // Set the image direction img->SetLargestPossibleRegion( gfaFilter->GetOutput()->GetLargestPossibleRegion()); img->SetBufferedRegion( gfaFilter->GetOutput()->GetLargestPossibleRegion() ); img->Allocate(); itk::ImageRegionIterator ot (img, img->GetLargestPossibleRegion() ); ot.GoToBegin(); itk::ImageRegionConstIterator it (gfaFilter->GetOutput(), gfaFilter->GetOutput()->GetLargestPossibleRegion() ); for (it.GoToBegin(); !it.IsAtEnd(); ++it) { GfaFilterType::OutputImageType::PixelType val = it.Get(); ot.Set(val * m_Controls->m_ScaleImageValuesBox->value()); ++ot; } // GFA TO DATATREE mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk( img.GetPointer() ); image->SetVolume( img->GetBufferPointer() ); mitk::DataNode::Pointer new_node=mitk::DataNode::New(); new_node->SetData( image ); new_node->SetProperty( "name", mitk::StringProperty::New(newname) ); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType( mitk::LookupTable::JET_TRANSPARENT ); mitk::LookupTableProperty::Pointer lut_prop = mitk::LookupTableProperty::New(); lut_prop->SetLookupTable( lut ); new_node->SetProperty("LookupTable", lut_prop ); GetDataStorage()->Add(new_node, node); mitk::StatusBar::GetInstance()->DisplayText("Computation complete."); } this->GetRenderWindowPart()->RequestUpdate(); } void QmitkDiffusionQuantificationView::TensorQuantification(int method) { QString status; if (m_Controls->m_ImageBox->GetSelectedNode().IsNotNull()) { mitk::DataNode* node = m_Controls->m_ImageBox->GetSelectedNode(); typedef mitk::TensorImage::ScalarPixelType TTensorPixelType; typedef mitk::TensorImage::ItkTensorImageType TensorImageType; mitk::Image* vol = static_cast(node->GetData()); TensorImageType::Pointer itkvol = TensorImageType::New(); mitk::CastToItkImage(vol, itkvol); std::string nodename = node->GetName(); mitk::StatusBar::GetInstance()->DisplayText(status.sprintf("Computing FA for %s", nodename.c_str()).toLatin1()); typedef itk::Image< TTensorPixelType, 3 > FAImageType; typedef itk::ShiftScaleImageFilter ShiftScaleFilterType; ShiftScaleFilterType::Pointer multi = ShiftScaleFilterType::New(); multi->SetShift(0.0); multi->SetScale(m_Controls->m_ScaleImageValuesBox->value()); typedef itk::TensorDerivedMeasurementsFilter MeasurementsType; if(method == 0) //FA { MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(itkvol.GetPointer() ); measurementsCalculator->SetMeasure(MeasurementsType::FA); measurementsCalculator->Update(); multi->SetInput(measurementsCalculator->GetOutput()); nodename = QString(nodename.c_str()).append("_FA").toStdString(); } else if(method == 1) //RA { MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(itkvol.GetPointer() ); measurementsCalculator->SetMeasure(MeasurementsType::RA); measurementsCalculator->Update(); multi->SetInput(measurementsCalculator->GetOutput()); nodename = QString(nodename.c_str()).append("_RA").toStdString(); } else if(method == 2) // AD (Axial diffusivity) { MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(itkvol.GetPointer() ); measurementsCalculator->SetMeasure(MeasurementsType::AD); measurementsCalculator->Update(); multi->SetInput(measurementsCalculator->GetOutput()); nodename = QString(nodename.c_str()).append("_AD").toStdString(); } else if(method == 3) // RD (Radial diffusivity, (Lambda2+Lambda3)/2 { MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(itkvol.GetPointer() ); measurementsCalculator->SetMeasure(MeasurementsType::RD); measurementsCalculator->Update(); multi->SetInput(measurementsCalculator->GetOutput()); nodename = QString(nodename.c_str()).append("_RD").toStdString(); } else if(method == 4) // 1-(Lambda2+Lambda3)/(2*Lambda1) { MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(itkvol.GetPointer() ); measurementsCalculator->SetMeasure(MeasurementsType::CA); measurementsCalculator->Update(); multi->SetInput(measurementsCalculator->GetOutput()); nodename = QString(nodename.c_str()).append("_CA").toStdString(); } else if(method == 5) // MD (Mean Diffusivity, (Lambda1+Lambda2+Lambda3)/3 ) { MeasurementsType::Pointer measurementsCalculator = MeasurementsType::New(); measurementsCalculator->SetInput(itkvol.GetPointer() ); measurementsCalculator->SetMeasure(MeasurementsType::MD); measurementsCalculator->Update(); multi->SetInput(measurementsCalculator->GetOutput()); nodename = QString(nodename.c_str()).append("_MD").toStdString(); } multi->Update(); // FA TO DATATREE mitk::Image::Pointer image = mitk::Image::New(); image->InitializeByItk( multi->GetOutput() ); image->SetVolume( multi->GetOutput()->GetBufferPointer() ); mitk::DataNode::Pointer new_node=mitk::DataNode::New(); new_node->SetData( image ); new_node->SetProperty( "name", mitk::StringProperty::New(nodename) ); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType( mitk::LookupTable::JET_TRANSPARENT ); mitk::LookupTableProperty::Pointer lut_prop = mitk::LookupTableProperty::New(); lut_prop->SetLookupTable( lut ); new_node->SetProperty("LookupTable", lut_prop ); GetDataStorage()->Add(new_node, node); mitk::StatusBar::GetInstance()->DisplayText("Computation complete."); } this->GetRenderWindowPart()->RequestUpdate(); } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationView.cpp index 6c388e9c7c..fd8444008f 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tbss/src/internal/QmitkTbssSkeletonizationView.cpp @@ -1,502 +1,502 @@ /*=================================================================== 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. ===================================================================*/ // Qmitk #include "QmitkTbssSkeletonizationView.h" #include #include #include #include #include // mitk #include #include #include #include // Qt #include #include //vtk #include #include // Boost -#include +#include const std::string QmitkTbssSkeletonizationView::VIEW_ID = "org.mitk.views.tbssskeletonization"; using namespace berry; QmitkTbssSkeletonizationView::QmitkTbssSkeletonizationView() : QmitkAbstractView() , m_Controls( 0 ) , m_Activated(false) { } QmitkTbssSkeletonizationView::~QmitkTbssSkeletonizationView() { } void QmitkTbssSkeletonizationView::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { //datamanager selection changed if (!this->IsActivated()) return; bool found3dImage = false; bool found4dImage = false; this->m_Controls->m_TubularName->setText(QString("Tubular Structure Mask: ")); this->m_Controls->m_TubularName->setEnabled(false); this->m_Controls->m_MeanLabel->setText(QString("Mean: ")); this->m_Controls->m_MeanLabel->setEnabled(false); this->m_Controls->m_PatientDataLabel->setText(QString("Patient Data: ")); this->m_Controls->m_PatientDataLabel->setEnabled(false); // iterate selection for (mitk::DataNode::Pointer node: nodes) { // only look at interesting types from valid nodes mitk::BaseData* nodeData = node->GetData(); std::string name = ""; node->GetStringProperty("name", name); if(nodeData) { if(QString("Image").compare(nodeData->GetNameOfClass())==0) { mitk::Image* img = static_cast(nodeData); if(img->GetDimension() == 3) { bool isBinary(false); node->GetBoolProperty("binary", isBinary); if(isBinary) { QString label("Tubular Structure Mask: "); label.append(QString(name.c_str())); this->m_Controls->m_TubularName->setText(label); this->m_Controls->m_TubularName->setEnabled(true); } else { found3dImage = true; QString label("Mean: "); label.append(QString(name.c_str())); this->m_Controls->m_MeanLabel->setText(label); this->m_Controls->m_MeanLabel->setEnabled(true); } } else if(img->GetDimension() == 4) { found4dImage = true; QString label("Patient Data: "); label.append(QString(name.c_str())); this->m_Controls->m_PatientDataLabel->setText(label); this->m_Controls->m_PatientDataLabel->setEnabled(true); } } } } this->m_Controls->m_Skeletonize->setEnabled(found3dImage); this->m_Controls->m_Project->setEnabled(found3dImage && found4dImage); this->m_Controls->m_OutputMask->setEnabled(found3dImage && found4dImage); this->m_Controls->m_OutputDistanceMap->setEnabled(found3dImage && found4dImage); } void QmitkTbssSkeletonizationView::CreateQtPartControl( QWidget *parent ) { // build up qt view, unless already done if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkTbssSkeletonizationViewControls; m_Controls->setupUi( parent ); this->CreateConnections(); } } void QmitkTbssSkeletonizationView::SetFocus() { m_Controls->m_Skeletonize->setFocus(); } void QmitkTbssSkeletonizationView::Activated() { m_Activated = true; } void QmitkTbssSkeletonizationView::Deactivated() { m_Activated = false; } bool QmitkTbssSkeletonizationView::IsActivated() const { return m_Activated; } void QmitkTbssSkeletonizationView::Visible() { } void QmitkTbssSkeletonizationView::Hidden() { } void QmitkTbssSkeletonizationView::CreateConnections() { if ( m_Controls ) { connect( (QObject*)(m_Controls->m_Skeletonize), SIGNAL(clicked()), this, SLOT(Skeletonize() )); connect( (QObject*)(m_Controls->m_Project), SIGNAL(clicked()), this, SLOT(Project() )); } } void QmitkTbssSkeletonizationView::Skeletonize() { typedef itk::SkeletonizationFilter SkeletonisationFilterType; SkeletonisationFilterType::Pointer skeletonizer = SkeletonisationFilterType::New(); QList nodes = this->GetDataManagerSelection(); mitk::Image::Pointer meanImage = mitk::Image::New(); std::string name = ""; for (auto node: nodes) { // process only on valid nodes mitk::BaseData* nodeData = node->GetData(); if(nodeData) { if(QString("Image").compare(nodeData->GetNameOfClass())==0) { bool isBinary(false); node->GetBoolProperty("binary", isBinary); mitk::Image* img = static_cast(nodeData); if(img->GetDimension() == 3 && !isBinary) { meanImage = img; name = node->GetName(); } } } } // Calculate skeleton FloatImageType::Pointer itkImg = FloatImageType::New(); mitk::CastToItkImage(meanImage, itkImg); skeletonizer->SetInput(itkImg); skeletonizer->Update(); FloatImageType::Pointer output = skeletonizer->GetOutput(); mitk::Image::Pointer mitkOutput = mitk::Image::New(); mitk::CastToMitkImage(output, mitkOutput); name += "_skeleton"; AddToDataStorage(mitkOutput, name); } void QmitkTbssSkeletonizationView::Project() { typedef itk::SkeletonizationFilter SkeletonisationFilterType; typedef itk::ProjectionFilter ProjectionFilterType; typedef itk::DistanceMapFilter DistanceMapFilterType; SkeletonisationFilterType::Pointer skeletonizer = SkeletonisationFilterType::New(); QList nodes = this->GetDataManagerSelection(); mitk::Image::Pointer meanImage = mitk::Image::New(); mitk::Image::Pointer subjects = mitk::Image::New(); mitk::Image::Pointer tubular = mitk::Image::New(); for (auto node: nodes) { // process only on valid nodes mitk::BaseData* nodeData = node->GetData(); if(nodeData) { if(QString("Image").compare(nodeData->GetNameOfClass())==0) { mitk::Image* img = static_cast(nodeData); if(img->GetDimension() == 3) { bool isBinary(false); node->GetBoolProperty("binary", isBinary); if(isBinary) { tubular = img; } else { meanImage = img; } } else if(img->GetDimension() == 4) { subjects = img; } } } } Float4DImageType::Pointer allFA; mitkPixelTypeMultiplex2(ConvertToItk,subjects->GetChannelDescriptor().GetPixelType(),subjects, allFA); // Calculate skeleton FloatImageType::Pointer itkImg = FloatImageType::New(); mitk::CastToItkImage(meanImage, itkImg); skeletonizer->SetInput(itkImg); skeletonizer->Update(); FloatImageType::Pointer output = skeletonizer->GetOutput(); mitk::Image::Pointer mitkOutput = mitk::Image::New(); mitk::CastToMitkImage(output, mitkOutput); AddToDataStorage(mitkOutput, "mean_FA_skeletonised"); // Retrieve direction image needed later by the projection filter DirectionImageType::Pointer directionImg = skeletonizer->GetVectorImage(); // Calculate distance image DistanceMapFilterType::Pointer distanceMapFilter = DistanceMapFilterType::New(); distanceMapFilter->SetInput(output); distanceMapFilter->Update(); FloatImageType::Pointer distanceMap = distanceMapFilter->GetOutput(); if(m_Controls->m_OutputDistanceMap->isChecked()) { mitk::Image::Pointer mitkDistance = mitk::Image::New(); mitk::CastToMitkImage(distanceMap, mitkDistance); AddToDataStorage(mitkDistance, "distance map"); } // Do projection // Ask a threshold to create a skeleton mask double threshold = -1.0; while(threshold == -1.0) { threshold = QInputDialog::getDouble(m_Controls->m_Skeletonize, tr("Specify the FA threshold"), tr("Threshold:"), QLineEdit::Normal, 0.2); if(threshold < 0.0 || threshold > 1.0) { QMessageBox msgBox; msgBox.setText("Please choose a value between 0 and 1"); msgBox.exec(); threshold = -1.0; } } typedef itk::BinaryThresholdImageFilter ThresholdFilterType; ThresholdFilterType::Pointer thresholder = ThresholdFilterType::New(); thresholder->SetInput(output); thresholder->SetLowerThreshold(threshold); thresholder->SetUpperThreshold(std::numeric_limits::max()); thresholder->SetOutsideValue(0); thresholder->SetInsideValue(1); thresholder->Update(); CharImageType::Pointer thresholdedImg = thresholder->GetOutput(); if(m_Controls->m_OutputMask->isChecked()) { mitk::Image::Pointer mitkThresholded = mitk::Image::New(); mitk::CastToMitkImage(thresholdedImg, mitkThresholded); std::string maskName = "skeleton_mask_at_" + boost::lexical_cast(threshold); AddToDataStorage(mitkThresholded, maskName); } CharImageType::Pointer itkTubular = CharImageType::New(); mitk::CastToItkImage(tubular, itkTubular); ProjectionFilterType::Pointer projectionFilter = ProjectionFilterType::New(); projectionFilter->SetDistanceMap(distanceMap); projectionFilter->SetDirections(directionImg); projectionFilter->SetAllFA(allFA); projectionFilter->SetTube(itkTubular); projectionFilter->SetSkeleton(thresholdedImg); projectionFilter->Project(); Float4DImageType::Pointer projected = projectionFilter->GetProjections(); mitk::Image::Pointer mitkProjections = mitk::Image::New(); mitk::CastToMitkImage(projected, mitkProjections); AddToDataStorage(mitkProjections, "all_FA_projected"); } void QmitkTbssSkeletonizationView::AddToDataStorage(mitk::Image* img, std::string name) { mitk::DataNode::Pointer result = mitk::DataNode::New(); result->SetProperty( "name", mitk::StringProperty::New(name) ); result->SetData( img ); // add new image to data storage and set as active to ease further processing GetDataStorage()->Add( result ); } template void QmitkTbssSkeletonizationView::ConvertToItk(mitk::PixelType, mitk::Image* image, Float4DImageType::Pointer output) { output = Float4DImageType::New(); mitk::BaseGeometry* geo = image->GetGeometry(); mitk::Vector3D mitkSpacing = geo->GetSpacing(); mitk::Point3D mitkOrigin = geo->GetOrigin(); Float4DImageType::SpacingType spacing; spacing[0] = mitkSpacing[0]; spacing[1] = mitkSpacing[1]; spacing[2] = mitkSpacing[2]; spacing[3] = 1.0; // todo: check if spacing has length 4 Float4DImageType::PointType origin; origin[0] = mitkOrigin[0]; origin[1] = mitkOrigin[1]; origin[2] = mitkOrigin[2]; origin[3] = 0; Float4DImageType::SizeType size; size[0] = image->GetDimension(0); size[1] = image->GetDimension(1); size[2] = image->GetDimension(2); size[3] = image->GetDimension(3); Float4DImageType::DirectionType dir; vtkLinearTransform* lin = geo->GetVtkTransform(); vtkMatrix4x4 *m = lin->GetMatrix(); dir.Fill(0.0); for(int x=0; x<3; x++) { for(int y=0; y<3; y++) { dir[x][y] = m->GetElement(x,y); } } dir[3][3] = 1; output->SetSpacing(spacing); output->SetOrigin(origin); output->SetRegions(size); output->SetDirection(dir); output->Allocate(); if(image->GetDimension() == 4) { unsigned int timesteps = image->GetDimension(3); try{ // REPLACE THIS METHODE()ConvertToItk) WITH mitk::CastToItk // iterate through the subjects and copy data to output for(unsigned int t=0; t inAcc(image,image->GetVolumeData(t)); for(unsigned int x=0; xGetDimension(0); x++) { for(unsigned int y=0; yGetDimension(1); y++) { for(unsigned int z=0; zGetDimension(2); z++) { itk::Index<3> ix = {{x, y, z}}; itk::Index<4> ix4 = {{x, y, z, t}}; output->SetPixel(ix4, inAcc.GetPixelByIndex(ix)); } } } } } catch(const std::exception & e) { MITK_INFO << e.what(); } } } diff --git a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp index 94b0c2aea0..58a19d4aa9 100644 --- a/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp +++ b/Plugins/org.mitk.gui.qt.diffusionimaging.tractography/src/internal/QmitkStreamlineTrackingView.cpp @@ -1,1026 +1,1026 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include #include // Qmitk #include "QmitkStreamlineTrackingView.h" #include "QmitkStdMultiWidget.h" // Qt #include // MITK #include #include #include #include #include #include #include #include #include #include #include #include #include // VTK #include #include #include #include #include #include #include #include #include -#include +#include const std::string QmitkStreamlineTrackingView::VIEW_ID = "org.mitk.views.streamlinetracking"; const std::string id_DataManager = "org.mitk.views.datamanager"; using namespace berry; QmitkStreamlineTrackingWorker::QmitkStreamlineTrackingWorker(QmitkStreamlineTrackingView* view) : m_View(view) { } void QmitkStreamlineTrackingWorker::run() { m_View->m_Tracker->Update(); m_View->m_TrackingThread.quit(); } QmitkStreamlineTrackingView::QmitkStreamlineTrackingView() : m_TrackingWorker(this) , m_Controls(nullptr) , m_FirstTensorProbRun(true) , m_FirstInteractiveRun(true) , m_TrackingHandler(nullptr) , m_ThreadIsRunning(false) , m_DeleteTrackingHandler(false) , m_Visible(false) , m_LastPrior("") , m_TrackingPriorHandler(nullptr) { m_TrackingWorker.moveToThread(&m_TrackingThread); connect(&m_TrackingThread, SIGNAL(started()), this, SLOT(BeforeThread())); connect(&m_TrackingThread, SIGNAL(started()), &m_TrackingWorker, SLOT(run())); connect(&m_TrackingThread, SIGNAL(finished()), this, SLOT(AfterThread())); m_TrackingTimer = new QTimer(this); } // Destructor QmitkStreamlineTrackingView::~QmitkStreamlineTrackingView() { if (m_Tracker.IsNull()) return; m_Tracker->SetStopTracking(true); m_TrackingThread.wait(); } void QmitkStreamlineTrackingView::CreateQtPartControl( QWidget *parent ) { if ( !m_Controls ) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkStreamlineTrackingViewControls; m_Controls->setupUi( parent ); m_Controls->m_FaImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_SeedImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_MaskImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_TargetImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_PriorImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_StopImageBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_ForestBox->SetDataStorage(this->GetDataStorage()); m_Controls->m_ExclusionImageBox->SetDataStorage(this->GetDataStorage()); mitk::TNodePredicateDataType::Pointer isPeakImagePredicate = mitk::TNodePredicateDataType::New(); mitk::TNodePredicateDataType::Pointer isImagePredicate = mitk::TNodePredicateDataType::New(); mitk::TNodePredicateDataType::Pointer isTractographyForest = mitk::TNodePredicateDataType::New(); mitk::NodePredicateProperty::Pointer isBinaryPredicate = mitk::NodePredicateProperty::New("binary", mitk::BoolProperty::New(true)); mitk::NodePredicateNot::Pointer isNotBinaryPredicate = mitk::NodePredicateNot::New( isBinaryPredicate ); mitk::NodePredicateAnd::Pointer isNotABinaryImagePredicate = mitk::NodePredicateAnd::New( isImagePredicate, isNotBinaryPredicate ); mitk::NodePredicateDimension::Pointer dimensionPredicate = mitk::NodePredicateDimension::New(3); m_Controls->m_ForestBox->SetPredicate(isTractographyForest); m_Controls->m_FaImageBox->SetPredicate( mitk::NodePredicateAnd::New(isNotABinaryImagePredicate, dimensionPredicate) ); m_Controls->m_FaImageBox->SetZeroEntryText("--"); m_Controls->m_SeedImageBox->SetPredicate( mitk::NodePredicateAnd::New(isImagePredicate, dimensionPredicate) ); m_Controls->m_SeedImageBox->SetZeroEntryText("--"); m_Controls->m_MaskImageBox->SetPredicate( mitk::NodePredicateAnd::New(isImagePredicate, dimensionPredicate) ); m_Controls->m_MaskImageBox->SetZeroEntryText("--"); m_Controls->m_StopImageBox->SetPredicate( mitk::NodePredicateAnd::New(isImagePredicate, dimensionPredicate) ); m_Controls->m_StopImageBox->SetZeroEntryText("--"); m_Controls->m_TargetImageBox->SetPredicate( mitk::NodePredicateAnd::New(isImagePredicate, dimensionPredicate) ); m_Controls->m_TargetImageBox->SetZeroEntryText("--"); m_Controls->m_PriorImageBox->SetPredicate( isPeakImagePredicate ); m_Controls->m_PriorImageBox->SetZeroEntryText("--"); m_Controls->m_ExclusionImageBox->SetPredicate( mitk::NodePredicateAnd::New(isImagePredicate, dimensionPredicate) ); m_Controls->m_ExclusionImageBox->SetZeroEntryText("--"); connect( m_TrackingTimer, SIGNAL(timeout()), this, SLOT(TimerUpdate()) ); connect( m_Controls->commandLinkButton_2, SIGNAL(clicked()), this, SLOT(StopTractography()) ); connect( m_Controls->commandLinkButton, SIGNAL(clicked()), this, SLOT(DoFiberTracking()) ); connect( m_Controls->m_InteractiveBox, SIGNAL(stateChanged(int)), this, SLOT(ToggleInteractive()) ); connect( m_Controls->m_ModeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(UpdateGui()) ); connect( m_Controls->m_FaImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(DeleteTrackingHandler()) ); connect( m_Controls->m_ModeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(DeleteTrackingHandler()) ); connect( m_Controls->m_OutputProbMap, SIGNAL(stateChanged(int)), this, SLOT(OutputStyleSwitched()) ); connect( m_Controls->m_SeedImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_ModeBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_StopImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_TargetImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_PriorImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_ExclusionImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_MaskImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FaImageBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_ForestBox, SIGNAL(currentIndexChanged(int)), this, SLOT(ForestSwitched()) ); connect( m_Controls->m_ForestBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_SeedsPerVoxelBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_NumFibersBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_ScalarThresholdBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_OdfCutoffBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_StepSizeBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_SamplingDistanceBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_AngularThresholdBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_MinTractLengthBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_fBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_gBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_NumSamplesBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_SeedRadiusBox, SIGNAL(editingFinished()), this, SLOT(InteractiveSeedChanged()) ); connect( m_Controls->m_NumSeedsBox, SIGNAL(editingFinished()), this, SLOT(InteractiveSeedChanged()) ); connect( m_Controls->m_OutputProbMap, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_SharpenOdfsBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_InterpolationBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_MaskInterpolationBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FlipXBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FlipYBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FlipZBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_FrontalSamplesBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_StopVotesBox, SIGNAL(stateChanged(int)), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_LoopCheckBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_TrialsPerSeedBox, SIGNAL(editingFinished()), this, SLOT(OnParameterChanged()) ); connect( m_Controls->m_EpConstraintsBox, SIGNAL(currentIndexChanged(int)), this, SLOT(OnParameterChanged()) ); m_Controls->m_SeedsPerVoxelBox->editingFinished(); m_Controls->m_NumFibersBox->editingFinished(); m_Controls->m_ScalarThresholdBox->editingFinished(); m_Controls->m_OdfCutoffBox->editingFinished(); m_Controls->m_StepSizeBox->editingFinished(); m_Controls->m_SamplingDistanceBox->editingFinished(); m_Controls->m_AngularThresholdBox->editingFinished(); m_Controls->m_MinTractLengthBox->editingFinished(); m_Controls->m_fBox->editingFinished(); m_Controls->m_gBox->editingFinished(); m_Controls->m_NumSamplesBox->editingFinished(); m_Controls->m_SeedRadiusBox->editingFinished(); m_Controls->m_NumSeedsBox->editingFinished(); m_Controls->m_LoopCheckBox->editingFinished(); m_Controls->m_TrialsPerSeedBox->editingFinished(); StartStopTrackingGui(false); } UpdateGui(); } void QmitkStreamlineTrackingView::StopTractography() { if (m_Tracker.IsNull()) return; m_Tracker->SetStopTracking(true); } void QmitkStreamlineTrackingView::TimerUpdate() { if (m_Tracker.IsNull()) return; QString status_text(m_Tracker->GetStatusText().c_str()); m_Controls->m_StatusTextBox->setText(status_text); } void QmitkStreamlineTrackingView::BeforeThread() { m_TrackingTimer->start(1000); } void QmitkStreamlineTrackingView::AfterThread() { m_TrackingTimer->stop(); if (!m_Tracker->GetUseOutputProbabilityMap()) { vtkSmartPointer fiberBundle = m_Tracker->GetFiberPolyData(); if (!m_Controls->m_InteractiveBox->isChecked() && fiberBundle->GetNumberOfLines() == 0) { QMessageBox warnBox; warnBox.setWindowTitle("Warning"); warnBox.setText("No fiberbundle was generated!"); warnBox.setDetailedText("No fibers were generated using the chosen parameters. Typical reasons are:\n\n- Cutoff too high. Some images feature very low FA/GFA/peak size. Try to lower this parameter.\n- Angular threshold too strict. Try to increase this parameter.\n- A small step sizes also means many steps to go wrong. Especially in the case of probabilistic tractography. Try to adjust the angular threshold."); warnBox.setIcon(QMessageBox::Warning); warnBox.exec(); if (m_InteractivePointSetNode.IsNotNull()) m_InteractivePointSetNode->SetProperty("color", mitk::ColorProperty::New(1,1,1)); StartStopTrackingGui(false); if (m_DeleteTrackingHandler) DeleteTrackingHandler(); UpdateGui(); return; } mitk::FiberBundle::Pointer fib = mitk::FiberBundle::New(fiberBundle); fib->SetReferenceGeometry(dynamic_cast(m_ParentNode->GetData())->GetGeometry()); if (m_Controls->m_ResampleFibersBox->isChecked() && fiberBundle->GetNumberOfLines()>0) fib->Compress(m_Controls->m_FiberErrorBox->value()); fib->ColorFibersByOrientation(); m_Tracker->SetDicomProperties(fib); if (m_Controls->m_InteractiveBox->isChecked()) { if (m_InteractiveNode.IsNull()) { m_InteractiveNode = mitk::DataNode::New(); QString name("Interactive"); m_InteractiveNode->SetName(name.toStdString()); GetDataStorage()->Add(m_InteractiveNode); } m_InteractiveNode->SetData(fib); m_InteractiveNode->SetFloatProperty("Fiber2DSliceThickness", m_Tracker->GetMinVoxelSize()/2); if (auto renderWindowPart = this->GetRenderWindowPart()) renderWindowPart->RequestUpdate(); } else { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(fib); QString name("FiberBundle_"); name += m_ParentNode->GetName().c_str(); name += "_Streamline"; node->SetName(name.toStdString()); node->SetFloatProperty("Fiber2DSliceThickness", m_Tracker->GetMinVoxelSize()/2); GetDataStorage()->Add(node, m_ParentNode); } } else { TrackerType::ItkDoubleImgType::Pointer outImg = m_Tracker->GetOutputProbabilityMap(); mitk::Image::Pointer img = mitk::Image::New(); img->InitializeByItk(outImg.GetPointer()); img->SetVolume(outImg->GetBufferPointer()); if (m_Controls->m_InteractiveBox->isChecked()) { if (m_InteractiveNode.IsNull()) { m_InteractiveNode = mitk::DataNode::New(); QString name("Interactive"); m_InteractiveNode->SetName(name.toStdString()); GetDataStorage()->Add(m_InteractiveNode); } m_InteractiveNode->SetData(img); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType(mitk::LookupTable::JET_TRANSPARENT); mitk::LookupTableProperty::Pointer lut_prop = mitk::LookupTableProperty::New(); lut_prop->SetLookupTable(lut); m_InteractiveNode->SetProperty("LookupTable", lut_prop); m_InteractiveNode->SetProperty("opacity", mitk::FloatProperty::New(0.5)); m_InteractiveNode->SetFloatProperty("Fiber2DSliceThickness", m_Tracker->GetMinVoxelSize()/2); if (auto renderWindowPart = this->GetRenderWindowPart()) renderWindowPart->RequestUpdate(); } else { mitk::DataNode::Pointer node = mitk::DataNode::New(); node->SetData(img); QString name("ProbabilityMap_"); name += m_ParentNode->GetName().c_str(); node->SetName(name.toStdString()); mitk::LookupTable::Pointer lut = mitk::LookupTable::New(); lut->SetType(mitk::LookupTable::JET_TRANSPARENT); mitk::LookupTableProperty::Pointer lut_prop = mitk::LookupTableProperty::New(); lut_prop->SetLookupTable(lut); node->SetProperty("LookupTable", lut_prop); node->SetProperty("opacity", mitk::FloatProperty::New(0.5)); GetDataStorage()->Add(node, m_ParentNode); } } if (m_InteractivePointSetNode.IsNotNull()) m_InteractivePointSetNode->SetProperty("color", mitk::ColorProperty::New(1,1,1)); StartStopTrackingGui(false); if (m_DeleteTrackingHandler) DeleteTrackingHandler(); UpdateGui(); } void QmitkStreamlineTrackingView::InteractiveSeedChanged(bool posChanged) { if(!CheckAndStoreLastParams(sender()) && !posChanged) return; if (m_ThreadIsRunning || !m_Visible) return; if (!posChanged && (!m_Controls->m_InteractiveBox->isChecked() || !m_Controls->m_ParamUpdateBox->isChecked()) ) return; std::srand(std::time(0)); m_SeedPoints.clear(); itk::Point world_pos = this->GetRenderWindowPart()->GetSelectedPosition(); m_SeedPoints.push_back(world_pos); float radius = m_Controls->m_SeedRadiusBox->value(); int num = m_Controls->m_NumSeedsBox->value(); mitk::PointSet::Pointer pointset = mitk::PointSet::New(); pointset->InsertPoint(0, world_pos); m_InteractivePointSetNode->SetProperty("pointsize", mitk::FloatProperty::New(radius*2)); m_InteractivePointSetNode->SetProperty("point 2D size", mitk::FloatProperty::New(radius*2)); m_InteractivePointSetNode->SetData(pointset); for (int i=1; i p; p[0] = rand()%1000-500; p[1] = rand()%1000-500; p[2] = rand()%1000-500; p.Normalize(); p *= radius; m_SeedPoints.push_back(world_pos+p); } m_InteractivePointSetNode->SetProperty("color", mitk::ColorProperty::New(1,0,0)); DoFiberTracking(); } bool QmitkStreamlineTrackingView::CheckAndStoreLastParams(QObject* obj) { if (obj!=nullptr) { std::string new_val = ""; if(qobject_cast(obj)!=nullptr) new_val = boost::lexical_cast(qobject_cast(obj)->value()); else if (qobject_cast(obj)!=nullptr) new_val = boost::lexical_cast(qobject_cast(obj)->value()); if (m_LastTractoParams.find(obj->objectName())==m_LastTractoParams.end()) { m_LastTractoParams[obj->objectName()] = new_val; return false; } else if (m_LastTractoParams.at(obj->objectName()) != new_val) { m_LastTractoParams[obj->objectName()] = new_val; return true; } else if (m_LastTractoParams.at(obj->objectName()) == new_val) return false; } return true; } void QmitkStreamlineTrackingView::OnParameterChanged() { UpdateGui(); if(!CheckAndStoreLastParams(sender())) return; if (m_Controls->m_InteractiveBox->isChecked() && m_Controls->m_ParamUpdateBox->isChecked()) DoFiberTracking(); } void QmitkStreamlineTrackingView::ToggleInteractive() { UpdateGui(); m_Controls->m_SeedsPerVoxelBox->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); m_Controls->m_SeedsPerVoxelLabel->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); m_Controls->m_SeedImageBox->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); m_Controls->label_6->setEnabled(!m_Controls->m_InteractiveBox->isChecked()); if ( m_Controls->m_InteractiveBox->isChecked() ) { if (m_FirstInteractiveRun) { QMessageBox::information(nullptr, "Information", "Place and move a spherical seed region anywhere in the image by left-clicking and dragging. If the seed region is colored red, tracking is in progress. If the seed region is colored white, tracking is finished.\nPlacing the seed region for the first time in a newly selected dataset might cause a short delay, since the tracker needs to be initialized."); m_FirstInteractiveRun = false; } QApplication::setOverrideCursor(Qt::PointingHandCursor); QApplication::processEvents(); m_InteractivePointSetNode = mitk::DataNode::New(); m_InteractivePointSetNode->SetProperty("color", mitk::ColorProperty::New(1,1,1)); m_InteractivePointSetNode->SetName("InteractiveSeedRegion"); mitk::PointSetShapeProperty::Pointer shape_prop = mitk::PointSetShapeProperty::New(); shape_prop->SetValue(mitk::PointSetShapeProperty::PointSetShape::CIRCLE); m_InteractivePointSetNode->SetProperty("Pointset.2D.shape", shape_prop); GetDataStorage()->Add(m_InteractivePointSetNode); m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); connect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); } else { QApplication::restoreOverrideCursor(); QApplication::processEvents(); m_InteractiveNode = nullptr; m_InteractivePointSetNode = nullptr; m_SliceChangeListener.RenderWindowPartActivated(this->GetRenderWindowPart()); disconnect(&m_SliceChangeListener, SIGNAL(SliceChanged()), this, SLOT(OnSliceChanged())); } } void QmitkStreamlineTrackingView::Activated() { } void QmitkStreamlineTrackingView::Deactivated() { } void QmitkStreamlineTrackingView::Visible() { m_Visible = true; } void QmitkStreamlineTrackingView::Hidden() { m_Visible = false; m_Controls->m_InteractiveBox->setChecked(false); ToggleInteractive(); } void QmitkStreamlineTrackingView::OnSliceChanged() { InteractiveSeedChanged(true); } void QmitkStreamlineTrackingView::SetFocus() { } void QmitkStreamlineTrackingView::DeleteTrackingHandler() { if (!m_ThreadIsRunning && m_TrackingHandler != nullptr) { delete m_TrackingHandler; m_TrackingHandler = nullptr; m_DeleteTrackingHandler = false; m_LastPrior = ""; if (m_TrackingPriorHandler != nullptr) delete m_TrackingPriorHandler; } else if (m_ThreadIsRunning) { m_DeleteTrackingHandler = true; } } void QmitkStreamlineTrackingView::ForestSwitched() { DeleteTrackingHandler(); } void QmitkStreamlineTrackingView::OutputStyleSwitched() { if (m_InteractiveNode.IsNotNull()) GetDataStorage()->Remove(m_InteractiveNode); m_InteractiveNode = nullptr; } void QmitkStreamlineTrackingView::OnSelectionChanged( berry::IWorkbenchPart::Pointer , const QList& nodes ) { std::vector< mitk::DataNode::Pointer > last_nodes = m_InputImageNodes; m_InputImageNodes.clear(); m_InputImages.clear(); m_AdditionalInputImages.clear(); bool retrack = false; for( auto node : nodes ) { if( node.IsNotNull() && dynamic_cast(node->GetData()) ) { if( dynamic_cast(node->GetData()) ) { m_InputImageNodes.push_back(node); m_InputImages.push_back(dynamic_cast(node->GetData())); retrack = true; } else if ( dynamic_cast(node->GetData()) ) { m_InputImageNodes.push_back(node); m_InputImages.push_back(dynamic_cast(node->GetData())); retrack = true; } else if ( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(node->GetData())) ) { m_InputImageNodes.push_back(node); m_InputImages.push_back(dynamic_cast(node->GetData())); retrack = true; } else { mitk::Image* img = dynamic_cast(node->GetData()); if (img!=nullptr) { int dim = img->GetDimension(); unsigned int* dimensions = img->GetDimensions(); if (dim==4 && dimensions[3]%3==0) { m_InputImageNodes.push_back(node); m_InputImages.push_back(dynamic_cast(node->GetData())); retrack = true; } else if (dim==3) { m_AdditionalInputImages.push_back(dynamic_cast(node->GetData())); } } } } } // sometimes the OnSelectionChanged event is sent twice and actually no selection has changed for the first event. We need to catch that. if (last_nodes.size() == m_InputImageNodes.size()) { bool same_nodes = true; for (unsigned int i=0; im_TensorImageLabel->setText("select in data-manager"); m_Controls->m_fBox->setEnabled(false); m_Controls->m_fLabel->setEnabled(false); m_Controls->m_gBox->setEnabled(false); m_Controls->m_gLabel->setEnabled(false); m_Controls->m_FaImageBox->setEnabled(true); m_Controls->mFaImageLabel->setEnabled(true); m_Controls->m_OdfCutoffBox->setEnabled(false); m_Controls->m_OdfCutoffLabel->setEnabled(false); m_Controls->m_SharpenOdfsBox->setEnabled(false); m_Controls->m_ForestBox->setVisible(false); m_Controls->m_ForestLabel->setVisible(false); m_Controls->commandLinkButton->setEnabled(false); m_Controls->m_TrialsPerSeedBox->setEnabled(false); m_Controls->m_TrialsPerSeedLabel->setEnabled(false); m_Controls->m_TargetImageBox->setEnabled(false); m_Controls->m_TargetImageLabel->setEnabled(false); if (m_Controls->m_InteractiveBox->isChecked()) { m_Controls->m_InteractiveSeedingFrame->setVisible(true); m_Controls->m_StaticSeedingFrame->setVisible(false); m_Controls->commandLinkButton_2->setVisible(false); m_Controls->commandLinkButton->setVisible(false); } else { m_Controls->m_InteractiveSeedingFrame->setVisible(false); m_Controls->m_StaticSeedingFrame->setVisible(true); m_Controls->commandLinkButton_2->setVisible(m_ThreadIsRunning); m_Controls->commandLinkButton->setVisible(!m_ThreadIsRunning); } if (m_Controls->m_EpConstraintsBox->currentIndex()>0) { m_Controls->m_TargetImageBox->setEnabled(true); m_Controls->m_TargetImageLabel->setEnabled(true); } // trials per seed are only important for probabilistic tractography if (m_Controls->m_ModeBox->currentIndex()==1) { m_Controls->m_TrialsPerSeedBox->setEnabled(true); m_Controls->m_TrialsPerSeedLabel->setEnabled(true); } if(!m_InputImageNodes.empty()) { if (m_InputImageNodes.size()>1) m_Controls->m_TensorImageLabel->setText( ( std::to_string(m_InputImageNodes.size()) + " images selected").c_str() ); else m_Controls->m_TensorImageLabel->setText(m_InputImageNodes.at(0)->GetName().c_str()); m_Controls->commandLinkButton->setEnabled(!m_Controls->m_InteractiveBox->isChecked() && !m_ThreadIsRunning); m_Controls->m_ScalarThresholdBox->setEnabled(true); m_Controls->m_FaThresholdLabel->setEnabled(true); if ( dynamic_cast(m_InputImageNodes.at(0)->GetData()) ) { m_Controls->m_fBox->setEnabled(true); m_Controls->m_fLabel->setEnabled(true); m_Controls->m_gBox->setEnabled(true); m_Controls->m_gLabel->setEnabled(true); } else if ( dynamic_cast(m_InputImageNodes.at(0)->GetData()) ) { m_Controls->m_OdfCutoffBox->setEnabled(true); m_Controls->m_OdfCutoffLabel->setEnabled(true); m_Controls->m_SharpenOdfsBox->setEnabled(true); } else if ( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(m_InputImageNodes.at(0)->GetData())) ) { m_Controls->m_ForestBox->setVisible(true); m_Controls->m_ForestLabel->setVisible(true); m_Controls->m_ScalarThresholdBox->setEnabled(false); m_Controls->m_FaThresholdLabel->setEnabled(false); } } } void QmitkStreamlineTrackingView::StartStopTrackingGui(bool start) { m_ThreadIsRunning = start; if (!m_Controls->m_InteractiveBox->isChecked()) { m_Controls->commandLinkButton_2->setVisible(start); m_Controls->commandLinkButton->setVisible(!start); m_Controls->m_InteractiveBox->setEnabled(!start); m_Controls->m_StatusTextBox->setVisible(start); } } void QmitkStreamlineTrackingView::DoFiberTracking() { if (m_InputImages.empty()) { QMessageBox::information(nullptr, "Information", "Please select an input image in the datamaneger (tensor, ODF, peak or dMRI image)!"); return; } if (m_ThreadIsRunning || !m_Visible) return; if (m_Controls->m_InteractiveBox->isChecked() && m_SeedPoints.empty()) return; StartStopTrackingGui(true); m_Tracker = TrackerType::New(); if( dynamic_cast(m_InputImageNodes.at(0)->GetData()) ) { if (m_Controls->m_ModeBox->currentIndex()==1) { if (m_InputImages.size()>1) { QMessageBox::information(nullptr, "Information", "Probabilistic tensor tractography is only implemented for single-tensor mode!"); StartStopTrackingGui(false); return; } if (m_TrackingHandler==nullptr) { m_TrackingHandler = new mitk::TrackingHandlerOdf(); mitk::TensorImage::ItkTensorImageType::Pointer itkImg = mitk::TensorImage::ItkTensorImageType::New(); mitk::CastToItkImage(m_InputImages.at(0), itkImg); typedef itk::TensorImageToOdfImageFilter< float, float > FilterType; FilterType::Pointer filter = FilterType::New(); filter->SetInput( itkImg ); filter->Update(); dynamic_cast(m_TrackingHandler)->SetOdfImage(filter->GetOutput()); if (m_Controls->m_FaImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer itkImg = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_FaImageBox->GetSelectedNode()->GetData()), itkImg); dynamic_cast(m_TrackingHandler)->SetGfaImage(itkImg); } } dynamic_cast(m_TrackingHandler)->SetGfaThreshold(m_Controls->m_ScalarThresholdBox->value()); dynamic_cast(m_TrackingHandler)->SetOdfThreshold(0); dynamic_cast(m_TrackingHandler)->SetSharpenOdfs(true); dynamic_cast(m_TrackingHandler)->SetIsOdfFromTensor(true); } else { if (m_TrackingHandler==nullptr) { m_TrackingHandler = new mitk::TrackingHandlerTensor(); for (int i=0; i<(int)m_InputImages.size(); i++) { typedef mitk::ImageToItk< mitk::TrackingHandlerTensor::ItkTensorImageType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(m_InputImages.at(i)); caster->Update(); mitk::TrackingHandlerTensor::ItkTensorImageType::ConstPointer itkImg = caster->GetOutput(); dynamic_cast(m_TrackingHandler)->AddTensorImage(itkImg); } if (m_Controls->m_FaImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer itkImg = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_FaImageBox->GetSelectedNode()->GetData()), itkImg); dynamic_cast(m_TrackingHandler)->SetFaImage(itkImg); } } dynamic_cast(m_TrackingHandler)->SetFaThreshold(m_Controls->m_ScalarThresholdBox->value()); dynamic_cast(m_TrackingHandler)->SetF((float)m_Controls->m_fBox->value()); dynamic_cast(m_TrackingHandler)->SetG((float)m_Controls->m_gBox->value()); } } else if ( dynamic_cast(m_InputImageNodes.at(0)->GetData()) ) { if (m_TrackingHandler==nullptr) { m_TrackingHandler = new mitk::TrackingHandlerOdf(); mitk::TrackingHandlerOdf::ItkOdfImageType::Pointer itkImg = mitk::TrackingHandlerOdf::ItkOdfImageType::New(); mitk::CastToItkImage(m_InputImages.at(0), itkImg); dynamic_cast(m_TrackingHandler)->SetOdfImage(itkImg); if (m_Controls->m_FaImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer itkImg = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_FaImageBox->GetSelectedNode()->GetData()), itkImg); dynamic_cast(m_TrackingHandler)->SetGfaImage(itkImg); } } dynamic_cast(m_TrackingHandler)->SetGfaThreshold(m_Controls->m_ScalarThresholdBox->value()); dynamic_cast(m_TrackingHandler)->SetOdfThreshold(m_Controls->m_OdfCutoffBox->value()); dynamic_cast(m_TrackingHandler)->SetSharpenOdfs(m_Controls->m_SharpenOdfsBox->isChecked()); } else if ( mitk::DiffusionPropertyHelper::IsDiffusionWeightedImage( dynamic_cast(m_InputImageNodes.at(0)->GetData())) ) { if ( m_Controls->m_ForestBox->GetSelectedNode().IsNull() ) { QMessageBox::information(nullptr, "Information", "Not random forest for machine learning based tractography (raw dMRI tractography) selected. Did you accidentally select the raw diffusion-weighted image in the datamanager?"); StartStopTrackingGui(false); return; } if (m_TrackingHandler==nullptr) { mitk::TractographyForest::Pointer forest = dynamic_cast(m_Controls->m_ForestBox->GetSelectedNode()->GetData()); mitk::Image::Pointer dwi = dynamic_cast(m_InputImageNodes.at(0)->GetData()); std::vector< std::vector< ItkFloatImageType::Pointer > > additionalFeatureImages; additionalFeatureImages.push_back(std::vector< ItkFloatImageType::Pointer >()); for (auto img : m_AdditionalInputImages) { ItkFloatImageType::Pointer itkimg = ItkFloatImageType::New(); mitk::CastToItkImage(img, itkimg); additionalFeatureImages.at(0).push_back(itkimg); } bool forest_valid = false; if (forest->GetNumFeatures()>=100) { int num_previous_directions = (forest->GetNumFeatures() - (100 + additionalFeatureImages.at(0).size()))/3; m_TrackingHandler = new mitk::TrackingHandlerRandomForest<6, 100>(); dynamic_cast*>(m_TrackingHandler)->AddDwi(dwi); dynamic_cast*>(m_TrackingHandler)->SetAdditionalFeatureImages(additionalFeatureImages); dynamic_cast*>(m_TrackingHandler)->SetForest(forest); dynamic_cast*>(m_TrackingHandler)->SetNumPreviousDirections(num_previous_directions); forest_valid = dynamic_cast*>(m_TrackingHandler)->IsForestValid(); } else { int num_previous_directions = (forest->GetNumFeatures() - (28 + additionalFeatureImages.at(0).size()))/3; m_TrackingHandler = new mitk::TrackingHandlerRandomForest<6, 28>(); dynamic_cast*>(m_TrackingHandler)->AddDwi(dwi); dynamic_cast*>(m_TrackingHandler)->SetAdditionalFeatureImages(additionalFeatureImages); dynamic_cast*>(m_TrackingHandler)->SetForest(forest); dynamic_cast*>(m_TrackingHandler)->SetNumPreviousDirections(num_previous_directions); forest_valid = dynamic_cast*>(m_TrackingHandler)->IsForestValid(); } if (!forest_valid) { QMessageBox::information(nullptr, "Information", "Random forest is invalid. The forest signatue does not match the parameters of TrackingHandlerRandomForest."); StartStopTrackingGui(false); return; } } } else { if (m_Controls->m_ModeBox->currentIndex()==1) { QMessageBox::information(nullptr, "Information", "Probabilstic tractography is not implemented for peak images."); StartStopTrackingGui(false); return; } try { if (m_TrackingHandler==nullptr) { typedef mitk::ImageToItk< mitk::TrackingHandlerPeaks::PeakImgType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(m_InputImages.at(0)); caster->SetCopyMemFlag(true); caster->Update(); mitk::TrackingHandlerPeaks::PeakImgType::Pointer itkImg = caster->GetOutput(); m_TrackingHandler = new mitk::TrackingHandlerPeaks(); dynamic_cast(m_TrackingHandler)->SetPeakImage(itkImg); } dynamic_cast(m_TrackingHandler)->SetPeakThreshold(m_Controls->m_ScalarThresholdBox->value()); } catch(...) { QMessageBox::information(nullptr, "Error", "Peak tracker could not be initialized. Is your input image in the correct format (4D float image, peaks in the 4th dimension)?"); StartStopTrackingGui(false); return; } } m_TrackingHandler->SetFlipX(m_Controls->m_FlipXBox->isChecked()); m_TrackingHandler->SetFlipY(m_Controls->m_FlipYBox->isChecked()); m_TrackingHandler->SetFlipZ(m_Controls->m_FlipZBox->isChecked()); m_TrackingHandler->SetInterpolate(m_Controls->m_InterpolationBox->isChecked()); switch (m_Controls->m_ModeBox->currentIndex()) { case 0: m_TrackingHandler->SetMode(mitk::TrackingDataHandler::MODE::DETERMINISTIC); break; case 1: m_TrackingHandler->SetMode(mitk::TrackingDataHandler::MODE::PROBABILISTIC); break; default: m_TrackingHandler->SetMode(mitk::TrackingDataHandler::MODE::DETERMINISTIC); } if (m_Controls->m_InteractiveBox->isChecked()) { m_Tracker->SetSeedPoints(m_SeedPoints); } else if (m_Controls->m_SeedImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer mask = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_SeedImageBox->GetSelectedNode()->GetData()), mask); m_Tracker->SetSeedImage(mask); } if (m_Controls->m_MaskImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer mask = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_MaskImageBox->GetSelectedNode()->GetData()), mask); m_Tracker->SetMaskImage(mask); } if (m_Controls->m_StopImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer mask = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_StopImageBox->GetSelectedNode()->GetData()), mask); m_Tracker->SetStoppingRegions(mask); } if (m_Controls->m_TargetImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer mask = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_TargetImageBox->GetSelectedNode()->GetData()), mask); m_Tracker->SetTargetRegions(mask); } if (m_Controls->m_PriorImageBox->GetSelectedNode().IsNotNull()) { if (m_LastPrior!=m_Controls->m_PriorImageBox->GetSelectedNode()->GetUID() || m_TrackingPriorHandler==nullptr) { typedef mitk::ImageToItk< mitk::TrackingHandlerPeaks::PeakImgType > CasterType; CasterType::Pointer caster = CasterType::New(); caster->SetInput(dynamic_cast(m_Controls->m_PriorImageBox->GetSelectedNode()->GetData())); caster->SetCopyMemFlag(true); caster->Update(); mitk::TrackingHandlerPeaks::PeakImgType::Pointer itkImg = caster->GetOutput(); m_TrackingPriorHandler = new mitk::TrackingHandlerPeaks(); dynamic_cast(m_TrackingPriorHandler)->SetPeakImage(itkImg); dynamic_cast(m_TrackingPriorHandler)->SetPeakThreshold(0.0); m_LastPrior = m_Controls->m_PriorImageBox->GetSelectedNode()->GetUID(); } m_TrackingPriorHandler->SetInterpolate(m_Controls->m_InterpolationBox->isChecked()); m_TrackingPriorHandler->SetMode(mitk::TrackingDataHandler::MODE::DETERMINISTIC); m_Tracker->SetTrackingPriorHandler(m_TrackingPriorHandler); m_Tracker->SetTrackingPriorWeight(m_Controls->m_PriorWeightBox->value()); m_Tracker->SetTrackingPriorAsMask(m_Controls->m_PriorAsMaskBox->isChecked()); m_Tracker->SetIntroduceDirectionsFromPrior(m_Controls->m_NewDirectionsFromPriorBox->isChecked()); } else if (m_Controls->m_PriorImageBox->GetSelectedNode().IsNull()) m_Tracker->SetTrackingPriorHandler(nullptr); if (m_Controls->m_ExclusionImageBox->GetSelectedNode().IsNotNull()) { ItkFloatImageType::Pointer mask = ItkFloatImageType::New(); mitk::CastToItkImage(dynamic_cast(m_Controls->m_ExclusionImageBox->GetSelectedNode()->GetData()), mask); m_Tracker->SetExclusionRegions(mask); } // Endpoint constraints switch (m_Controls->m_EpConstraintsBox->currentIndex()) { case 0: m_Tracker->SetEndpointConstraint(itk::StreamlineTrackingFilter::EndpointConstraints::NONE); m_Tracker->SetTargetRegions(nullptr); break; case 1: m_Tracker->SetEndpointConstraint(itk::StreamlineTrackingFilter::EndpointConstraints::EPS_IN_TARGET); break; case 2: m_Tracker->SetEndpointConstraint(itk::StreamlineTrackingFilter::EndpointConstraints::EPS_IN_TARGET_LABELDIFF); break; case 3: m_Tracker->SetEndpointConstraint(itk::StreamlineTrackingFilter::EndpointConstraints::EPS_IN_SEED_AND_TARGET); break; case 4: m_Tracker->SetEndpointConstraint(itk::StreamlineTrackingFilter::EndpointConstraints::MIN_ONE_EP_IN_TARGET); break; case 5: m_Tracker->SetEndpointConstraint(itk::StreamlineTrackingFilter::EndpointConstraints::ONE_EP_IN_TARGET); break; case 6: m_Tracker->SetEndpointConstraint(itk::StreamlineTrackingFilter::EndpointConstraints::NO_EP_IN_TARGET); break; } if (m_Tracker->GetEndpointConstraint()!=itk::StreamlineTrackingFilter::EndpointConstraints::NONE && m_Controls->m_TargetImageBox->GetSelectedNode().IsNull()) { QMessageBox::information(nullptr, "Error", "Endpoint constraints are used but no target image is set!"); StartStopTrackingGui(false); return; } else if (m_Tracker->GetEndpointConstraint()==itk::StreamlineTrackingFilter::EndpointConstraints::EPS_IN_SEED_AND_TARGET && (m_Controls->m_SeedImageBox->GetSelectedNode().IsNull()|| m_Controls->m_TargetImageBox->GetSelectedNode().IsNull()) ) { QMessageBox::information(nullptr, "Error", "Endpoint constraint EPS_IN_SEED_AND_TARGET is used but no target or no seed image is set!"); StartStopTrackingGui(false); return; } m_Tracker->SetInterpolateMasks(m_Controls->m_MaskInterpolationBox->isChecked()); m_Tracker->SetVerbose(!m_Controls->m_InteractiveBox->isChecked()); m_Tracker->SetSeedsPerVoxel(m_Controls->m_SeedsPerVoxelBox->value()); m_Tracker->SetStepSize(m_Controls->m_StepSizeBox->value()); m_Tracker->SetSamplingDistance(m_Controls->m_SamplingDistanceBox->value()); m_Tracker->SetUseStopVotes(m_Controls->m_StopVotesBox->isChecked()); m_Tracker->SetOnlyForwardSamples(m_Controls->m_FrontalSamplesBox->isChecked()); m_Tracker->SetTrialsPerSeed(m_Controls->m_TrialsPerSeedBox->value()); m_Tracker->SetMaxNumTracts(m_Controls->m_NumFibersBox->value()); m_Tracker->SetNumberOfSamples(m_Controls->m_NumSamplesBox->value()); m_Tracker->SetTrackingHandler(m_TrackingHandler); m_Tracker->SetLoopCheck(m_Controls->m_LoopCheckBox->value()); m_Tracker->SetAngularThreshold(m_Controls->m_AngularThresholdBox->value()); m_Tracker->SetMinTractLength(m_Controls->m_MinTractLengthBox->value()); m_Tracker->SetUseOutputProbabilityMap(m_Controls->m_OutputProbMap->isChecked()); m_ParentNode = m_InputImageNodes.at(0); m_TrackingThread.start(QThread::LowestPriority); } diff --git a/Plugins/org.mitk.gui.qt.ext/src/QmitkExtFileSaveProjectAction.h b/Plugins/org.mitk.gui.qt.ext/src/QmitkExtFileSaveProjectAction.h index 0fc9ff2825..f1877c287a 100644 --- a/Plugins/org.mitk.gui.qt.ext/src/QmitkExtFileSaveProjectAction.h +++ b/Plugins/org.mitk.gui.qt.ext/src/QmitkExtFileSaveProjectAction.h @@ -1,58 +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. ===================================================================*/ #ifndef QmitkExtFileSaveProjectAction_H_ #define QmitkExtFileSaveProjectAction_H_ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include #include #include namespace berry { struct IWorkbenchWindow; } class MITK_QT_COMMON_EXT_EXPORT QmitkExtFileSaveProjectAction : public QAction { Q_OBJECT public: QmitkExtFileSaveProjectAction(berry::SmartPointer window); QmitkExtFileSaveProjectAction(berry::IWorkbenchWindow* window); protected slots: void Run(); private: void Init(berry::IWorkbenchWindow* window); berry::IWorkbenchWindow* m_Window; }; #endif /*QmitkExtFileSaveProjectAction_H_*/ diff --git a/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenDicomEditorAction.h b/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenDicomEditorAction.h index fbde21443b..c55518e200 100644 --- a/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenDicomEditorAction.h +++ b/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenDicomEditorAction.h @@ -1,54 +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. ===================================================================*/ #ifndef QMITKOPENDICOMEDITORACTION_H_ #define QMITKOPENDICOMEDITORACTION_H_ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include #include #include #include #include class MITK_QT_COMMON_EXT_EXPORT QmitkOpenDicomEditorAction : public QAction { Q_OBJECT public: QmitkOpenDicomEditorAction(berry::IWorkbenchWindow::Pointer window); QmitkOpenDicomEditorAction(const QIcon & icon, berry::IWorkbenchWindow::Pointer window); protected slots: void Run(); private: void init ( berry::IWorkbenchWindow::Pointer window ); berry::IWorkbenchWindow::Pointer m_Window; berry::IPreferences::WeakPtr m_GeneralPreferencesNode; }; #endif /*QMITKOPENDICOMEDITORACTION_H_*/ diff --git a/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenXnatEditorAction.h b/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenXnatEditorAction.h index cd765eeda9..db7c529507 100644 --- a/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenXnatEditorAction.h +++ b/Plugins/org.mitk.gui.qt.ext/src/QmitkOpenXnatEditorAction.h @@ -1,54 +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. ===================================================================*/ #ifndef QMITKOPENXNATEDITORACTION_H_ #define QMITKOPENXNATEDITORACTION_H_ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include #include #include #include #include class MITK_QT_COMMON_EXT_EXPORT QmitkOpenXnatEditorAction : public QAction { Q_OBJECT public: QmitkOpenXnatEditorAction(berry::IWorkbenchWindow::Pointer window); QmitkOpenXnatEditorAction(const QIcon & icon, berry::IWorkbenchWindow::Pointer window); protected slots: void Run(); private: void init ( berry::IWorkbenchWindow::Pointer window ); berry::IWorkbenchWindow::Pointer m_Window; berry::IPreferences::WeakPtr m_GeneralPreferencesNode; }; #endif /*QMITKOPENXNATEDITORACTION_H_*/ diff --git a/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtAppWorkbenchAdvisor.h b/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtAppWorkbenchAdvisor.h index 3c258118be..377264b12d 100644 --- a/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtAppWorkbenchAdvisor.h +++ b/Plugins/org.mitk.gui.qt.extapplication/src/internal/QmitkExtAppWorkbenchAdvisor.h @@ -1,44 +1,37 @@ /*=================================================================== 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 QMITKEXTAPPWORKBENCHADVISOR_H_ #define QMITKEXTAPPWORKBENCHADVISOR_H_ -#ifdef __MINGW32__ -// We need to inlclude winbase.h here in order to declare -// atomic intrinsics like InterlockedIncrement correctly. -// Otherwhise, they would be declared wrong within qatomic_windows.h . -#include -#endif - #include class QmitkExtAppWorkbenchAdvisor: public berry::QtWorkbenchAdvisor { public: static const QString DEFAULT_PERSPECTIVE_ID; // = "org.mitk.extapp.defaultperspective" void Initialize(berry::IWorkbenchConfigurer::Pointer configurer) override; berry::WorkbenchWindowAdvisor* CreateWorkbenchWindowAdvisor( berry::IWorkbenchWindowConfigurer::Pointer configurer) override; QString GetInitialWindowPerspectiveId() override; }; #endif /*QMITKEXTAPPWORKBENCHADVISOR_H_*/ diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/org_mbi_gui_qt_usnavigation_Activator.cpp b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/org_mbi_gui_qt_usnavigation_Activator.cpp index d02b7fb363..9bdb0186f7 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/org_mbi_gui_qt_usnavigation_Activator.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/org_mbi_gui_qt_usnavigation_Activator.cpp @@ -1,67 +1,57 @@ /*=================================================================== 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 "org_mbi_gui_qt_usnavigation_Activator.h" #include -#include -//#include "USNavigation.h" #include "QmitkUltrasoundCalibration.h" #include "QmitkUSNavigationMarkerPlacement.h" #include "QmitkUSNavigationPerspective.h" #include "mitkVirtualTrackingDevice.h" namespace mitk { ctkPluginContext* org_mbi_gui_qt_usnavigation_Activator::m_Context = 0; void org_mbi_gui_qt_usnavigation_Activator::start(ctkPluginContext* context) { m_Context = context; - //BERRY_REGISTER_EXTENSION_CLASS(USNavigation, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkUltrasoundCalibration, context) - BERRY_REGISTER_EXTENSION_CLASS(QmitkUSNavigationMarkerPlacement, context) - BERRY_REGISTER_EXTENSION_CLASS(QmitkUSNavigationPerspective, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkUSNavigationMarkerPlacement, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkUSNavigationPerspective, context) - // create a combined modality persistence object for loading and storing - // combined modality objects persistently - m_USCombinedModalityPersistence = mitk::USNavigationCombinedModalityPersistence::New(); + // create a combined modality persistence object for loading and storing + // combined modality objects persistently + m_USCombinedModalityPersistence = mitk::USNavigationCombinedModalityPersistence::New(); } - void org_mbi_gui_qt_usnavigation_Activator::stop(ctkPluginContext* context) + void org_mbi_gui_qt_usnavigation_Activator::stop(ctkPluginContext*) { m_USCombinedModalityPersistence = 0; - m_Context = 0; - - Q_UNUSED(context) } ctkPluginContext *org_mbi_gui_qt_usnavigation_Activator::GetContext() { return m_Context; } } -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) -Q_EXPORT_PLUGIN2(org_mitk_gui_qt_igt_app_echotrack, mitk::org_mbi_gui_qt_usnavigation_Activator) -#endif - // necessary for us::GetModuleContext() in USNavigationCombinedModalityPersistence // (see: https://www.mail-archive.com/mitk-users@lists.sourceforge.net/msg04421.html) US_INITIALIZE_MODULE diff --git a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/org_mbi_gui_qt_usnavigation_Activator.h b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/org_mbi_gui_qt_usnavigation_Activator.h index ef4140e6e1..56266b5e86 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/org_mbi_gui_qt_usnavigation_Activator.h +++ b/Plugins/org.mitk.gui.qt.igt.app.echotrack/src/internal/org_mbi_gui_qt_usnavigation_Activator.h @@ -1,55 +1,48 @@ /*=================================================================== 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 org_mbi_gui_qt_usnavigation_Activator_h #define org_mbi_gui_qt_usnavigation_Activator_h #include - #include "mitkTrackingDeviceSource.h" - #include "IO/mitkUSNavigationCombinedModalityPersistence.h" -namespace mitk { -class org_mbi_gui_qt_usnavigation_Activator : - public QObject, public ctkPluginActivator +namespace mitk { - Q_OBJECT -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) - Q_PLUGIN_METADATA(IID "org_mbi_gui_qt_usnavigation") -#endif - Q_INTERFACES(ctkPluginActivator) + class org_mbi_gui_qt_usnavigation_Activator : public QObject, public ctkPluginActivator + { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org_mbi_gui_qt_usnavigation") + Q_INTERFACES(ctkPluginActivator) -public: + public: + void start(ctkPluginContext* context); + void stop(ctkPluginContext* context); - void start(ctkPluginContext* context); - void stop(ctkPluginContext* context); + static ctkPluginContext* GetContext(); - static ctkPluginContext* GetContext(); + private: + static ctkPluginContext* m_Context; -private: - static ctkPluginContext* m_Context; + TrackingDeviceSource::Pointer m_VirtualTrackingDeviceSource; + USNavigationCombinedModalityPersistence::Pointer m_USCombinedModalityPersistence; + }; - TrackingDeviceSource::Pointer m_VirtualTrackingDeviceSource; - - USNavigationCombinedModalityPersistence::Pointer m_USCombinedModalityPersistence; -}; // org_mbi_gui_qt_usnavigation_Activator - -typedef org_mbi_gui_qt_usnavigation_Activator PluginActivator; + typedef org_mbi_gui_qt_usnavigation_Activator PluginActivator; } -#endif // org_mbi_gui_qt_usnavigation_Activator_h +#endif diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkPluginActivator.cpp index daf9692487..243f2652ef 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkPluginActivator.cpp +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkPluginActivator.cpp @@ -1,39 +1,29 @@ /*========================================================================= 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 "mitkPluginActivator.h" - -#include - #include "QmitkIGTTrackingSemiAutomaticMeasurementView.h" #include "QmitkIGTTrackingDataEvaluationView.h" -namespace mitk { - void PluginActivator::start(ctkPluginContext* context) - { - BERRY_REGISTER_EXTENSION_CLASS(QmitkIGTTrackingSemiAutomaticMeasurementView, context) - BERRY_REGISTER_EXTENSION_CLASS(QmitkIGTTrackingDataEvaluationView, context) - } - - void PluginActivator::stop(ctkPluginContext* context) - { - Q_UNUSED(context) - } +void mitk::PluginActivator::start(ctkPluginContext* context) +{ + BERRY_REGISTER_EXTENSION_CLASS(QmitkIGTTrackingSemiAutomaticMeasurementView, context) + BERRY_REGISTER_EXTENSION_CLASS(QmitkIGTTrackingDataEvaluationView, context) } -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) -Q_EXPORT_PLUGIN2(org_mitk_gui_qt_igttrackingsemiautomaticmeasurement, mitk::PluginActivator) -#endif +void mitk::PluginActivator::stop(ctkPluginContext*) +{ +} diff --git a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkPluginActivator.h b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkPluginActivator.h index 08f307e628..6c09619a44 100644 --- a/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkPluginActivator.h +++ b/Plugins/org.mitk.gui.qt.igt.app.hummelprotocolmeasurements/src/internal/mitkPluginActivator.h @@ -1,43 +1,36 @@ /*=================================================================== 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 MITKPLUGINACTIVATOR_H -#define MITKPLUGINACTIVATOR_H +#ifndef org_mitk_gui_qt_igtapphummelprotocolmeasurements_Activator_h +#define org_mitk_gui_qt_igtapphummelprotocolmeasurements_Activator_h #include -namespace mitk { - -class PluginActivator : - public QObject, public ctkPluginActivator +namespace mitk { - Q_OBJECT - #if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) - Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_igtapphummelprotocolmeasurements") - #endif - Q_INTERFACES(ctkPluginActivator) - -public: - - void start(ctkPluginContext* context); - void stop(ctkPluginContext* context); - -}; // PluginActivator - + class PluginActivator : public QObject, public ctkPluginActivator + { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_igtapphummelprotocolmeasurements") + Q_INTERFACES(ctkPluginActivator) + + public: + void start(ctkPluginContext* context); + void stop(ctkPluginContext* context); + }; } -#endif // MITKPLUGINACTIVATOR_H +#endif diff --git a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxView.cpp b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxView.cpp index f5cd6b6732..ea16dd96c0 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxView.cpp +++ b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxView.cpp @@ -1,1426 +1,1426 @@ /*=================================================================== The Medical Imaging Interaction Toolkit (MITK) Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See LICENSE.txt or http://www.mitk.org for details. ===================================================================*/ // Blueberry #include #include // Qmitk #include "QmitkMITKIGTTrackingToolboxView.h" // Qt #include #include #include // MITK #include #include #include #include #include #include #include #include #include #include //for exceptions #include #include #include "mitkPluginActivator.h" const std::string QmitkMITKIGTTrackingToolboxView::VIEW_ID = "org.mitk.views.mitkigttrackingtoolbox"; QmitkMITKIGTTrackingToolboxView::QmitkMITKIGTTrackingToolboxView() : QmitkAbstractView() , m_Controls(nullptr) , m_DeviceTypeCollection(nullptr) , m_ToolProjectionNode(nullptr) { m_TrackingLoggingTimer = new QTimer(this); m_TrackingRenderTimer = new QTimer(this); m_TimeoutTimer = new QTimer(this); m_tracking = false; m_connected = false; m_logging = false; m_ShowHideToolAxis = false; m_loggedFrames = 0; m_SimpleModeEnabled = false; m_NeedleProjectionFilter = mitk::NeedleProjectionFilter::New(); //create filename for autosaving of tool storage QString loggingPathWithoutFilename = QString(mitk::LoggingBackend::GetLogFile().c_str()); if (!loggingPathWithoutFilename.isEmpty()) //if there already is a path for the MITK logging file use this one { //extract path from path+filename (if someone knows a better way to do this feel free to change it) int lengthOfFilename = QFileInfo(QString::fromStdString(mitk::LoggingBackend::GetLogFile())).fileName().size(); loggingPathWithoutFilename.resize(loggingPathWithoutFilename.size() - lengthOfFilename); m_AutoSaveFilename = loggingPathWithoutFilename + "TrackingToolboxAutoSave.IGTToolStorage"; } else //if not: use a temporary path from IOUtil { m_AutoSaveFilename = QString(mitk::IOUtil::GetTempPath().c_str()) + "TrackingToolboxAutoSave.IGTToolStorage"; } MITK_INFO("IGT Tracking Toolbox") << "Filename for auto saving of IGT ToolStorages: " << m_AutoSaveFilename.toStdString(); //! [Thread 1] //initialize worker thread m_WorkerThread = new QThread(); m_Worker = new QmitkMITKIGTTrackingToolboxViewWorker(); //! [Thread 1] ctkPluginContext* pluginContext = mitk::PluginActivator::GetContext(); if (pluginContext) { QString interfaceName = QString::fromStdString(us_service_interface_iid()); QList serviceReference = pluginContext->getServiceReferences(interfaceName); if (serviceReference.size() > 0) { m_DeviceTypeServiceReference = serviceReference.at(0); const ctkServiceReference& r = serviceReference.at(0); m_DeviceTypeCollection = pluginContext->getService(r); } else { MITK_INFO << "No Tracking Device Collection!"; } } } QmitkMITKIGTTrackingToolboxView::~QmitkMITKIGTTrackingToolboxView() { this->StoreUISettings(); m_TrackingLoggingTimer->stop(); m_TrackingRenderTimer->stop(); m_TimeoutTimer->stop(); delete m_TrackingLoggingTimer; delete m_TrackingRenderTimer; delete m_TimeoutTimer; try { //! [Thread 2] // wait for thread to finish m_WorkerThread->terminate(); m_WorkerThread->wait(); //clean up worker thread if (m_WorkerThread) { delete m_WorkerThread; } if (m_Worker) { delete m_Worker; } //! [Thread 2] //remove the tracking volume this->GetDataStorage()->Remove(m_TrackingVolumeNode); //unregister microservices if (m_toolStorage) { m_toolStorage->UnRegisterMicroservice(); } if (m_IGTLMessageProvider.IsNotNull()){ m_IGTLMessageProvider->UnRegisterMicroservice(); } } catch (std::exception& e) { MITK_WARN << "Unexpected exception during clean up of tracking toolbox view: " << e.what(); } catch (...) { MITK_WARN << "Unexpected unknown error during clean up of tracking toolbox view!"; } //store tool storage and UI settings for persistence this->AutoSaveToolStorage(); this->StoreUISettings(); m_DeviceTypeCollection = nullptr; mitk::PluginActivator::GetContext()->ungetService(m_DeviceTypeServiceReference); } void QmitkMITKIGTTrackingToolboxView::CreateQtPartControl(QWidget *parent) { // build up qt view, unless already done if (!m_Controls) { // create GUI widgets from the Qt Designer's .ui file m_Controls = new Ui::QmitkMITKIGTTrackingToolboxViewControls; m_Controls->setupUi(parent); //create connections connect(m_Controls->m_LoadTools, SIGNAL(clicked()), this, SLOT(OnLoadTools())); connect(m_Controls->m_ConnectDisconnectButton, SIGNAL(clicked()), this, SLOT(OnConnectDisconnect())); connect(m_Controls->m_StartStopTrackingButton, SIGNAL(clicked()), this, SLOT(OnStartStopTracking())); connect(m_Controls->m_ConnectSimpleMode, SIGNAL(clicked()), this, SLOT(OnConnectDisconnect())); connect(m_Controls->m_StartTrackingSimpleMode, SIGNAL(clicked()), this, SLOT(OnStartStopTracking())); connect(m_Controls->m_FreezeUnfreezeTrackingButton, SIGNAL(clicked()), this, SLOT(OnFreezeUnfreezeTracking())); connect(m_TrackingLoggingTimer, SIGNAL(timeout()), this, SLOT(UpdateLoggingTrackingTimer())); connect(m_TrackingRenderTimer, SIGNAL(timeout()), this, SLOT(UpdateRenderTrackingTimer())); connect(m_TimeoutTimer, SIGNAL(timeout()), this, SLOT(OnTimeOut())); connect(m_Controls->m_ChooseFile, SIGNAL(clicked()), this, SLOT(OnChooseFileClicked())); connect(m_Controls->m_StartLogging, SIGNAL(clicked()), this, SLOT(StartLogging())); connect(m_Controls->m_StopLogging, SIGNAL(clicked()), this, SLOT(StopLogging())); connect(m_Controls->m_VolumeSelectionBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(OnTrackingVolumeChanged(QString))); connect(m_Controls->m_ShowTrackingVolume, SIGNAL(clicked()), this, SLOT(OnShowTrackingVolumeChanged())); connect(m_Controls->m_AutoDetectTools, SIGNAL(clicked()), this, SLOT(OnAutoDetectTools())); connect(m_Controls->m_ResetTools, SIGNAL(clicked()), this, SLOT(OnResetTools())); connect(m_Controls->m_AddSingleTool, SIGNAL(clicked()), this, SLOT(OnAddSingleTool())); connect(m_Controls->m_NavigationToolCreationWidget, SIGNAL(NavigationToolFinished()), this, SLOT(OnAddSingleToolFinished())); connect(m_Controls->m_NavigationToolCreationWidget, SIGNAL(Canceled()), this, SLOT(OnAddSingleToolCanceled())); connect(m_Controls->m_CsvFormat, SIGNAL(clicked()), this, SLOT(OnToggleFileExtension())); connect(m_Controls->m_XmlFormat, SIGNAL(clicked()), this, SLOT(OnToggleFileExtension())); connect(m_Controls->m_UseDifferentUpdateRates, SIGNAL(clicked()), this, SLOT(OnToggleDifferentUpdateRates())); connect(m_Controls->m_RenderUpdateRate, SIGNAL(valueChanged(int)), this, SLOT(OnChangeRenderUpdateRate())); connect(m_Controls->m_DisableAllTimers, SIGNAL(stateChanged(int)), this, SLOT(EnableDisableTimerButtons(int))); connect(m_Controls->m_advancedUI, SIGNAL(clicked()), this, SLOT(OnToggleAdvancedSimpleMode())); connect(m_Controls->m_SimpleUI, SIGNAL(clicked()), this, SLOT(OnToggleAdvancedSimpleMode())); connect(m_Controls->showHideToolProjectionCheckBox, SIGNAL(clicked()), this, SLOT(OnShowHideToolProjectionClicked())); connect(m_Controls->showHideToolAxisCheckBox, SIGNAL(clicked()), this, SLOT(OnShowHideToolAxisClicked())); connect(m_Controls->m_toolselector, SIGNAL(currentIndexChanged(int)), this, SLOT(SelectToolProjection(int))); //connections for the tracking device configuration widget connect(m_Controls->m_ConfigurationWidget, SIGNAL(TrackingDeviceSelectionChanged()), this, SLOT(OnTrackingDeviceChanged())); //! [Thread 3] //connect worker thread connect(m_Worker, SIGNAL(AutoDetectToolsFinished(bool, QString)), this, SLOT(OnAutoDetectToolsFinished(bool, QString))); connect(m_Worker, SIGNAL(ConnectDeviceFinished(bool, QString)), this, SLOT(OnConnectFinished(bool, QString))); connect(m_Worker, SIGNAL(StartTrackingFinished(bool, QString)), this, SLOT(OnStartTrackingFinished(bool, QString))); connect(m_Worker, SIGNAL(StopTrackingFinished(bool, QString)), this, SLOT(OnStopTrackingFinished(bool, QString))); connect(m_Worker, SIGNAL(DisconnectDeviceFinished(bool, QString)), this, SLOT(OnDisconnectFinished(bool, QString))); connect(m_WorkerThread, SIGNAL(started()), m_Worker, SLOT(ThreadFunc())); connect(m_Worker, SIGNAL(ConnectDeviceFinished(bool, QString)), m_Controls->m_ConfigurationWidget, SLOT(OnConnected(bool))); connect(m_Worker, SIGNAL(DisconnectDeviceFinished(bool, QString)), m_Controls->m_ConfigurationWidget, SLOT(OnDisconnected(bool))); connect(m_Worker, SIGNAL(StartTrackingFinished(bool, QString)), m_Controls->m_ConfigurationWidget, SLOT(OnStartTracking(bool))); connect(m_Worker, SIGNAL(StopTrackingFinished(bool, QString)), m_Controls->m_ConfigurationWidget, SLOT(OnStopTracking(bool))); //Add Listener, so that we know when the toolStorage changed. std::string m_Filter = "(" + us::ServiceConstants::OBJECTCLASS() + "=" + "org.mitk.services.NavigationToolStorage" + ")"; mitk::PluginActivator::GetContext()->connectServiceListener(this, "OnToolStorageChanged", QString(m_Filter.c_str())); //move the worker to the thread m_Worker->moveToThread(m_WorkerThread); //! [Thread 3] //initialize widgets m_Controls->m_TrackingToolsStatusWidget->SetShowPositions(true); m_Controls->m_TrackingToolsStatusWidget->SetTextAlignment(Qt::AlignLeft); m_Controls->m_simpleWidget->setVisible(false); //initialize tracking volume node m_TrackingVolumeNode = mitk::DataNode::New(); m_TrackingVolumeNode->SetName("TrackingVolume"); m_TrackingVolumeNode->SetBoolProperty("Backface Culling", true); mitk::Color red; red.SetRed(1); m_TrackingVolumeNode->SetColor(red); //initialize buttons m_Controls->m_AutoDetectTools->setVisible(false); //only visible if supported by tracking device m_Controls->m_StartStopTrackingButton->setEnabled(false); m_Controls->m_StartTrackingSimpleMode->setEnabled(false); m_Controls->m_FreezeUnfreezeTrackingButton->setEnabled(false); //initialize warning labels m_Controls->m_RenderWarningLabel->setVisible(false); m_Controls->m_TrackingFrozenLabel->setVisible(false); //Update List of available models for selected tool. std::vector Compatibles; if ((m_Controls == nullptr) || //check all these stuff for NULL, latterly this causes crashes from time to time (m_Controls->m_ConfigurationWidget == nullptr) || (m_Controls->m_ConfigurationWidget->GetTrackingDevice().IsNull())) { MITK_ERROR << "Couldn't get current tracking device or an object is nullptr, something went wrong!"; return; } else { Compatibles = m_DeviceTypeCollection->GetDeviceDataForLine(m_Controls->m_ConfigurationWidget->GetTrackingDevice()->GetType()); } m_Controls->m_VolumeSelectionBox->clear(); for (std::size_t i = 0; i < Compatibles.size(); i++) { m_Controls->m_VolumeSelectionBox->addItem(Compatibles[i].Model.c_str()); } //initialize tool storage m_toolStorage = mitk::NavigationToolStorage::New(GetDataStorage()); m_toolStorage->SetName("TrackingToolbox Default Storage"); m_toolStorage->RegisterAsMicroservice(); //set home directory as default path for logfile m_Controls->m_LoggingFileName->setText(QDir::toNativeSeparators(QDir::homePath()) + QDir::separator() + "logfile.csv"); //tracking device may be changed already by the persistence of the //QmitkTrackingDeciveConfigurationWidget this->OnTrackingDeviceChanged(); this->LoadUISettings(); //add tracking volume node only to data storage this->GetDataStorage()->Add(m_TrackingVolumeNode); if (!m_Controls->m_ShowTrackingVolume->isChecked()) m_TrackingVolumeNode->SetOpacity(0.0); else m_TrackingVolumeNode->SetOpacity(0.25); //Update List of available models for selected tool. m_Controls->m_VolumeSelectionBox->clear(); for (std::size_t i = 0; i < Compatibles.size(); i++) { m_Controls->m_VolumeSelectionBox->addItem(Compatibles[i].Model.c_str()); } } } void QmitkMITKIGTTrackingToolboxView::OnLoadTools() { //read in filename QString filename = QFileDialog::getOpenFileName(nullptr, tr("Open Tool Storage"), "/", tr("Tool Storage Files (*.IGTToolStorage)")); if (filename.isNull()) return; //read tool storage from disk std::string errorMessage = ""; mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(GetDataStorage()); // try-catch block for exceptions try { this->ReplaceCurrentToolStorage(myDeserializer->Deserialize(filename.toStdString()), filename.toStdString()); } catch (mitk::IGTException) { std::string errormessage = "Error during loading the tool storage file. Please only load tool storage files created with the NavigationToolManager view."; QMessageBox::warning(nullptr, "Tool Storage Loading Error", errormessage.c_str()); return; } if (m_toolStorage->isEmpty()) { errorMessage = myDeserializer->GetErrorMessage(); MessageBox(errorMessage); return; } //update label UpdateToolStorageLabel(filename); //update tool preview m_Controls->m_TrackingToolsStatusWidget->RemoveStatusLabels(); m_Controls->m_TrackingToolsStatusWidget->PreShowTools(m_toolStorage); //save filename for persistent storage m_ToolStorageFilename = filename; } void QmitkMITKIGTTrackingToolboxView::OnResetTools() { //remove data nodes of surfaces from data storage to clean up for (unsigned int i = 0; i < m_toolStorage->GetToolCount(); i++) { this->GetDataStorage()->Remove(m_toolStorage->GetTool(i)->GetDataNode()); } this->ReplaceCurrentToolStorage(mitk::NavigationToolStorage::New(GetDataStorage()), "TrackingToolbox Default Storage"); m_Controls->m_TrackingToolsStatusWidget->RemoveStatusLabels(); QString toolLabel = QString(""); m_Controls->m_ToolLabel->setText(toolLabel); m_ToolStorageFilename = ""; RemoveAllToolProjections(); } void QmitkMITKIGTTrackingToolboxView::OnStartStopTracking() { if (!m_connected) { MITK_WARN << "Can't start tracking if no device is connected. Aborting"; return; } if (m_tracking) { OnStopTracking(); } else { OnStartTracking(); } } void QmitkMITKIGTTrackingToolboxView::OnFreezeUnfreezeTracking() { if (m_Controls->m_FreezeUnfreezeTrackingButton->text() == "Freeze Tracking") { m_Worker->GetTrackingDeviceSource()->Freeze(); m_Controls->m_FreezeUnfreezeTrackingButton->setText("Unfreeze Tracking"); m_Controls->m_TrackingFrozenLabel->setVisible(true); } else if (m_Controls->m_FreezeUnfreezeTrackingButton->text() == "Unfreeze Tracking") { m_Worker->GetTrackingDeviceSource()->UnFreeze(); m_Controls->m_FreezeUnfreezeTrackingButton->setText("Freeze Tracking"); m_Controls->m_TrackingFrozenLabel->setVisible(false); } } void QmitkMITKIGTTrackingToolboxView::ShowToolProjection(int index) { mitk::DataNode::Pointer toolnode = m_toolStorage->GetTool(index)->GetDataNode(); QString ToolProjectionName = "ToolProjection" + QString::number(index); m_ToolProjectionNode = this->GetDataStorage()->GetNamedNode(ToolProjectionName.toStdString()); //If node does not exist, create the node for the Pointset if (m_ToolProjectionNode.IsNull()) { m_ToolProjectionNode = mitk::DataNode::New(); m_ToolProjectionNode->SetName(ToolProjectionName.toStdString()); if (index < static_cast(m_NeedleProjectionFilter->GetNumberOfInputs())) { m_NeedleProjectionFilter->SelectInput(index); m_NeedleProjectionFilter->Update(); m_ToolProjectionNode->SetData(m_NeedleProjectionFilter->GetProjection()); m_ToolProjectionNode->SetBoolProperty("show contour", true); this->GetDataStorage()->Add(m_ToolProjectionNode, toolnode); } // this->FireNodeSelected(node); } else { m_ToolProjectionNode->SetBoolProperty("show contour", true); } } void QmitkMITKIGTTrackingToolboxView::RemoveAllToolProjections() { for (size_t i = 0; i < m_toolStorage->GetToolCount(); i++) { QString toolProjectionName = "ToolProjection" + QString::number(i); mitk::DataNode::Pointer node = this->GetDataStorage()->GetNamedNode(toolProjectionName.toStdString()); //Deactivate and hide the tool projection if (!node.IsNull()) { this->GetDataStorage()->Remove(node); } } } void QmitkMITKIGTTrackingToolboxView::SelectToolProjection(int idx) { if (m_Controls->showHideToolProjectionCheckBox->isChecked()) { //Deactivate and hide the tool projection if (!m_ToolProjectionNode.IsNull()) { this->GetDataStorage()->Remove(m_ToolProjectionNode); } if (m_NeedleProjectionFilter.IsNotNull()) { m_NeedleProjectionFilter->Update(); } //Refresh the view and the status widget mitk::RenderingManager::GetInstance()->RequestUpdateAll(); // Show the tool projection for the currently selected tool ShowToolProjection(idx); } } void QmitkMITKIGTTrackingToolboxView::OnShowHideToolProjectionClicked() { int index = m_Controls->m_toolselector->currentIndex(); //Activate and show the tool projection if (m_Controls->showHideToolProjectionCheckBox->isChecked()) { ShowToolProjection(index); m_Controls->showHideToolAxisCheckBox->setEnabled(true); } else { RemoveAllToolProjections(); m_Controls->showHideToolAxisCheckBox->setEnabled(false); } if( m_NeedleProjectionFilter.IsNotNull() ) { m_NeedleProjectionFilter->Update(); } //Refresh the view and the status widget mitk::RenderingManager::GetInstance()->RequestUpdateAll(); // m_Controls->m_TrackingToolsStatusWidget->Refresh(); } void QmitkMITKIGTTrackingToolboxView::OnShowHideToolAxisClicked() { if( !m_ShowHideToolAxis ) { //Activate and show the tool axis m_NeedleProjectionFilter->ShowToolAxis(true); m_ShowHideToolAxis = true; } else { //Deactivate and hide the tool axis m_NeedleProjectionFilter->ShowToolAxis(false); m_NeedleProjectionFilter->GetProjection()->RemovePointIfExists(2); m_ShowHideToolAxis = false; } //Update the filter if( m_NeedleProjectionFilter.IsNotNull() ) { m_NeedleProjectionFilter->Update(); } //Refresh the view and the status widget mitk::RenderingManager::GetInstance()->RequestUpdateAll(); // m_Controls->m_TrackingToolsStatusWidget->Refresh(); } void QmitkMITKIGTTrackingToolboxView::OnConnectDisconnect() { if (m_connected) { OnDisconnect(); } else { OnConnect(); } } void QmitkMITKIGTTrackingToolboxView::OnConnect() { MITK_DEBUG << "Connect Clicked"; //check if everything is ready to start tracking if (this->m_toolStorage.IsNull()) { MessageBox("Error: No Tools Loaded Yet!"); return; } else if (this->m_toolStorage->GetToolCount() == 0) { MessageBox("Error: No Way To Track Without Tools!"); return; } //parse tracking device data mitk::TrackingDeviceData data = mitk::UnspecifiedTrackingTypeInformation::GetDeviceDataUnspecified(); QString qstr = m_Controls->m_VolumeSelectionBox->currentText(); if ((!qstr.isNull()) || (!qstr.isEmpty())) { std::string str = qstr.toStdString(); data = m_DeviceTypeCollection->GetDeviceDataByName(str); //Data will be set later, after device generation } //! [Thread 4] //initialize worker thread m_Worker->SetWorkerMethod(QmitkMITKIGTTrackingToolboxViewWorker::eConnectDevice); m_Worker->SetTrackingDevice(this->m_Controls->m_ConfigurationWidget->GetTrackingDevice()); m_Worker->SetInverseMode(m_Controls->m_InverseMode->isChecked()); m_Worker->SetNavigationToolStorage(this->m_toolStorage); m_Worker->SetTrackingDeviceData(data); //start worker thread m_WorkerThread->start(); //! [Thread 4] //disable buttons this->m_Controls->m_MainWidget->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::EnableDisableTimerButtons(int enable) { bool enableBool = enable; m_Controls->m_UpdateRateOptionsGroupBox->setEnabled(!enableBool); m_Controls->m_RenderWarningLabel->setVisible(enableBool); } void QmitkMITKIGTTrackingToolboxView::OnConnectFinished(bool success, QString errorMessage) { m_WorkerThread->quit(); m_WorkerThread->wait(); //enable buttons this->m_Controls->m_MainWidget->setEnabled(true); if (!success) { MITK_WARN << errorMessage.toStdString(); MessageBox(errorMessage.toStdString()); return; } //! [Thread 6] //get data from worker thread m_TrackingDeviceData = m_Worker->GetTrackingDeviceData(); m_ToolVisualizationFilter = m_Worker->GetToolVisualizationFilter(); if( m_ToolVisualizationFilter.IsNotNull() ) { //Connect the NeedleProjectionFilter to the ToolVisualizationFilter as third filter of the IGT pipeline m_NeedleProjectionFilter->ConnectTo(m_ToolVisualizationFilter); if (m_Controls->showHideToolProjectionCheckBox->isChecked()) { ShowToolProjection(m_Controls->m_toolselector->currentIndex()); } } //! [Thread 6] //enable/disable Buttons DisableOptionsButtons(); DisableTrackingConfigurationButtons(); m_Controls->m_TrackingControlLabel->setText("Status: connected"); m_Controls->m_ConnectDisconnectButton->setText("Disconnect"); m_Controls->m_ConnectSimpleMode->setText("Disconnect"); m_Controls->m_StartStopTrackingButton->setEnabled(true); m_Controls->m_StartTrackingSimpleMode->setEnabled(true); m_connected = true; //During connection, thi sourceID of the tool storage changed. However, Microservice can't be updated on a different thread. //UpdateMicroservice is necessary to use filter to get the right storage belonging to a source. //Don't do it before m_connected is true, as we don't want to call content of OnToolStorageChanged. m_toolStorage->UpdateMicroservice(); } void QmitkMITKIGTTrackingToolboxView::OnDisconnect() { m_Worker->SetWorkerMethod(QmitkMITKIGTTrackingToolboxViewWorker::eDisconnectDevice); m_WorkerThread->start(); m_Controls->m_MainWidget->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::OnDisconnectFinished(bool success, QString errorMessage) { m_WorkerThread->quit(); m_WorkerThread->wait(); m_Controls->m_MainWidget->setEnabled(true); if (!success) { MITK_WARN << errorMessage.toStdString(); MessageBox(errorMessage.toStdString()); return; } //enable/disable Buttons m_Controls->m_StartStopTrackingButton->setEnabled(false); m_Controls->m_StartTrackingSimpleMode->setEnabled(false); EnableOptionsButtons(); EnableTrackingConfigurationButtons(); m_Controls->m_TrackingControlLabel->setText("Status: disconnected"); m_Controls->m_ConnectDisconnectButton->setText("Connect"); m_Controls->m_ConnectSimpleMode->setText("Connect"); m_Controls->m_FreezeUnfreezeTrackingButton->setText("Freeze Tracking"); m_Controls->m_TrackingFrozenLabel->setVisible(false); m_connected = false; } void QmitkMITKIGTTrackingToolboxView::OnStartTracking() { //show tracking volume this->OnTrackingVolumeChanged(m_Controls->m_VolumeSelectionBox->currentText()); //Reset the view to a defined start. Do it here and not in OnStartTrackingFinished, to give other tracking devices the chance to reset the view to a different direction. this->GlobalReinit(); m_Worker->SetWorkerMethod(QmitkMITKIGTTrackingToolboxViewWorker::eStartTracking); m_WorkerThread->start(); this->m_Controls->m_MainWidget->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::OnStartTrackingFinished(bool success, QString errorMessage) { //! [Thread 5] m_WorkerThread->quit(); m_WorkerThread->wait(); //! [Thread 5] this->m_Controls->m_MainWidget->setEnabled(true); if (!success) { MessageBox(errorMessage.toStdString()); MITK_WARN << errorMessage.toStdString(); return; } if (!(m_Controls->m_DisableAllTimers->isChecked())) { if (m_Controls->m_UseDifferentUpdateRates->isChecked()) { if (m_Controls->m_RenderUpdateRate->value() != 0) m_TrackingRenderTimer->start(1000 / (m_Controls->m_RenderUpdateRate->value())); m_TrackingLoggingTimer->start(1000 / (m_Controls->m_LogUpdateRate->value())); } else { m_TrackingRenderTimer->start(1000 / (m_Controls->m_UpdateRate->value())); m_TrackingLoggingTimer->start(1000 / (m_Controls->m_UpdateRate->value())); } } m_Controls->m_TrackingControlLabel->setText("Status: tracking"); //connect the tool visualization widget for (std::size_t i = 0; i < m_Worker->GetTrackingDeviceSource()->GetNumberOfOutputs(); i++) { m_Controls->m_TrackingToolsStatusWidget->AddNavigationData(m_Worker->GetTrackingDeviceSource()->GetOutput(i)); } m_Controls->m_TrackingToolsStatusWidget->ShowStatusLabels(); if (m_Controls->m_ShowToolQuaternions->isChecked()) { m_Controls->m_TrackingToolsStatusWidget->SetShowQuaternions(true); } else { m_Controls->m_TrackingToolsStatusWidget->SetShowQuaternions(false); } //if activated enable open IGT link microservice if (m_Controls->m_EnableOpenIGTLinkMicroService->isChecked()) { //create convertion filter m_IGTLConversionFilter = mitk::NavigationDataToIGTLMessageFilter::New(); m_IGTLConversionFilter->SetName("IGT Tracking Toolbox"); QString dataModeSelection = this->m_Controls->m_OpenIGTLinkDataFormat->currentText(); if (dataModeSelection == "TDATA") { m_IGTLConversionFilter->SetOperationMode(mitk::NavigationDataToIGTLMessageFilter::ModeSendTDataMsg); } else if (dataModeSelection == "TRANSFORM") { m_IGTLConversionFilter->SetOperationMode(mitk::NavigationDataToIGTLMessageFilter::ModeSendTransMsg); } else if (dataModeSelection == "QTDATA") { m_IGTLConversionFilter->SetOperationMode(mitk::NavigationDataToIGTLMessageFilter::ModeSendQTDataMsg); } else if (dataModeSelection == "POSITION") { m_IGTLConversionFilter->SetOperationMode(mitk::NavigationDataToIGTLMessageFilter::ModeSendQTransMsg); } m_IGTLConversionFilter->ConnectTo(m_ToolVisualizationFilter); m_IGTLConversionFilter->RegisterAsMicroservice(); //create server and message provider m_IGTLServer = mitk::IGTLServer::New(false); m_IGTLServer->SetName("Tracking Toolbox IGTL Server"); m_IGTLMessageProvider = mitk::IGTLMessageProvider::New(); m_IGTLMessageProvider->SetIGTLDevice(m_IGTLServer); m_IGTLMessageProvider->RegisterAsMicroservice(); } m_tracking = true; m_Controls->m_ConnectDisconnectButton->setEnabled(false); m_Controls->m_StartStopTrackingButton->setText("Stop Tracking"); m_Controls->m_StartTrackingSimpleMode->setText("Stop\nTracking"); m_Controls->m_FreezeUnfreezeTrackingButton->setEnabled(true); } void QmitkMITKIGTTrackingToolboxView::OnStopTracking() { if (!m_tracking) return; for (unsigned int i = 0; i < m_ToolVisualizationFilter->GetNumberOfIndexedOutputs(); i++) { mitk::NavigationData::Pointer currentTool = m_ToolVisualizationFilter->GetOutput(i); if (currentTool->IsDataValid()) { this->m_toolStorage->GetTool(i)->GetDataNode()->SetColor(mitk::IGTColor_INVALID); } } //refresh view and status widget mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_TrackingRenderTimer->stop(); m_TrackingLoggingTimer->stop(); m_Worker->SetWorkerMethod(QmitkMITKIGTTrackingToolboxViewWorker::eStopTracking); m_WorkerThread->start(); m_Controls->m_MainWidget->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::OnStopTrackingFinished(bool success, QString errorMessage) { m_WorkerThread->quit(); m_WorkerThread->wait(); m_Controls->m_MainWidget->setEnabled(true); if (!success) { MessageBox(errorMessage.toStdString()); MITK_WARN << errorMessage.toStdString(); return; } m_Controls->m_TrackingControlLabel->setText("Status: connected"); if (m_logging) StopLogging(); m_Controls->m_TrackingToolsStatusWidget->RemoveStatusLabels(); m_Controls->m_TrackingToolsStatusWidget->PreShowTools(m_toolStorage); m_tracking = false; m_Controls->m_StartStopTrackingButton->setText("Start Tracking"); m_Controls->m_StartTrackingSimpleMode->setText("Start\nTracking"); m_Controls->m_ConnectDisconnectButton->setEnabled(true); m_Controls->m_FreezeUnfreezeTrackingButton->setEnabled(false); //unregister open IGT link micro service if (m_Controls->m_EnableOpenIGTLinkMicroService->isChecked()) { m_IGTLConversionFilter->UnRegisterMicroservice(); m_IGTLMessageProvider->UnRegisterMicroservice(); } } void QmitkMITKIGTTrackingToolboxView::OnTrackingDeviceChanged() { mitk::TrackingDeviceType Type; if (m_Controls->m_ConfigurationWidget->GetTrackingDevice().IsNotNull()) { Type = m_Controls->m_ConfigurationWidget->GetTrackingDevice()->GetType(); //enable controls because device is valid m_Controls->m_TrackingToolsFrame->setEnabled(true); m_Controls->m_TrackingControlsFrame->setEnabled(true); } else { Type = mitk::UnspecifiedTrackingTypeInformation::GetTrackingDeviceName(); MessageBox("Error: This tracking device is not included in this project. Please make sure that the device is installed and activated in your MITK build."); m_Controls->m_TrackingToolsFrame->setEnabled(false); m_Controls->m_TrackingControlsFrame->setEnabled(false); return; } // Code to enable/disable device specific buttons if (m_Controls->m_ConfigurationWidget->GetTrackingDevice()->AutoDetectToolsAvailable()) { m_Controls->m_AutoDetectTools->setVisible(true); } else { m_Controls->m_AutoDetectTools->setVisible(false); } m_Controls->m_AddSingleTool->setEnabled(this->m_Controls->m_ConfigurationWidget->GetTrackingDevice()->AddSingleToolIsAvailable()); // Code to select appropriate tracking volume for current type std::vector Compatibles = m_DeviceTypeCollection->GetDeviceDataForLine(Type); m_Controls->m_VolumeSelectionBox->clear(); for (std::size_t i = 0; i < Compatibles.size(); i++) { m_Controls->m_VolumeSelectionBox->addItem(Compatibles[i].Model.c_str()); } } void QmitkMITKIGTTrackingToolboxView::OnTrackingVolumeChanged(QString qstr) { if (qstr.isNull()) return; if (qstr.isEmpty()) return; mitk::TrackingVolumeGenerator::Pointer volumeGenerator = mitk::TrackingVolumeGenerator::New(); std::string str = qstr.toStdString(); mitk::TrackingDeviceData data = m_DeviceTypeCollection->GetDeviceDataByName(str); m_TrackingDeviceData = data; volumeGenerator->SetTrackingDeviceData(data); volumeGenerator->Update(); mitk::Surface::Pointer volumeSurface = volumeGenerator->GetOutput(); m_TrackingVolumeNode->SetData(volumeSurface); if (!m_Controls->m_ShowTrackingVolume->isChecked()) m_TrackingVolumeNode->SetOpacity(0.0); else m_TrackingVolumeNode->SetOpacity(0.25); GlobalReinit(); } void QmitkMITKIGTTrackingToolboxView::OnShowTrackingVolumeChanged() { if (m_Controls->m_ShowTrackingVolume->isChecked()) { OnTrackingVolumeChanged(m_Controls->m_VolumeSelectionBox->currentText()); m_TrackingVolumeNode->SetOpacity(0.25); } else { m_TrackingVolumeNode->SetOpacity(0.0); } } void QmitkMITKIGTTrackingToolboxView::OnAutoDetectTools() { if (m_Controls->m_ConfigurationWidget->GetTrackingDevice()->AutoDetectToolsAvailable()) { DisableTrackingConfigurationButtons(); m_Worker->SetWorkerMethod(QmitkMITKIGTTrackingToolboxViewWorker::eAutoDetectTools); m_Worker->SetTrackingDevice(m_Controls->m_ConfigurationWidget->GetTrackingDevice().GetPointer()); m_Worker->SetDataStorage(this->GetDataStorage()); m_WorkerThread->start(); - m_TimeoutTimer->start(7000); + m_TimeoutTimer->start(30000); //disable controls until worker thread is finished this->m_Controls->m_MainWidget->setEnabled(false); } } void QmitkMITKIGTTrackingToolboxView::OnAutoDetectToolsFinished(bool success, QString errorMessage) { //Check, if the thread is running. There might have been a timeOut inbetween and this causes crashes... if (m_WorkerThread->isRunning()) { m_TimeoutTimer->stop(); m_WorkerThread->quit(); m_WorkerThread->wait(); } //enable controls again this->m_Controls->m_MainWidget->setEnabled(true); EnableTrackingConfigurationButtons(); if (!success) { MITK_WARN << errorMessage.toStdString(); MessageBox(errorMessage.toStdString()); EnableTrackingConfigurationButtons(); return; } mitk::NavigationToolStorage::Pointer autoDetectedStorage = m_Worker->GetNavigationToolStorage(); //save detected tools std::string _autoDetectText; _autoDetectText = "Autodetected "; _autoDetectText.append(this->m_TrackingDeviceData.Line); //This is the device name as string of the current TrackingDevice. _autoDetectText.append(" Storage"); this->ReplaceCurrentToolStorage(autoDetectedStorage, _autoDetectText); //auto save the new storage to hard disc (for persistence) AutoSaveToolStorage(); //update label QString toolLabel = QString("Loaded Tools: ") + QString::number(m_toolStorage->GetToolCount()) + " Tools (Auto Detected)"; m_Controls->m_ToolLabel->setText(toolLabel); //update tool preview m_Controls->m_TrackingToolsStatusWidget->RemoveStatusLabels(); m_Controls->m_TrackingToolsStatusWidget->PreShowTools(m_toolStorage); EnableTrackingConfigurationButtons(); //print a logging message about the detected tools switch (m_toolStorage->GetToolCount()) { case 0: MITK_INFO("IGT Tracking Toolbox") << "Found no tools. Empty ToolStorage was autosaved to " << m_ToolStorageFilename.toStdString(); break; case 1: MITK_INFO("IGT Tracking Toolbox") << "Found one tool. ToolStorage was autosaved to " << m_ToolStorageFilename.toStdString(); break; default: MITK_INFO("IGT Tracking Toolbox") << "Found " << m_toolStorage->GetToolCount() << " tools. ToolStorage was autosaved to " << m_ToolStorageFilename.toStdString(); } } void QmitkMITKIGTTrackingToolboxView::MessageBox(std::string s) { QMessageBox msgBox; msgBox.setText(s.c_str()); msgBox.exec(); } void QmitkMITKIGTTrackingToolboxView::UpdateRenderTrackingTimer() { //update filter m_ToolVisualizationFilter->Update(); MITK_DEBUG << "Number of outputs ToolVisualizationFilter: " << m_ToolVisualizationFilter->GetNumberOfIndexedOutputs(); MITK_DEBUG << "Number of inputs ToolVisualizationFilter: " << m_ToolVisualizationFilter->GetNumberOfIndexedInputs(); //update tool colors to show tool status for (unsigned int i = 0; i < m_ToolVisualizationFilter->GetNumberOfIndexedOutputs(); i++) { mitk::NavigationData::Pointer currentTool = m_ToolVisualizationFilter->GetOutput(i); if (currentTool->IsDataValid()) { this->m_toolStorage->GetTool(i)->GetDataNode()->SetColor(mitk::IGTColor_VALID); } else { this->m_toolStorage->GetTool(i)->GetDataNode()->SetColor(mitk::IGTColor_WARNING); } } //Update the NeedleProjectionFilter if( m_NeedleProjectionFilter.IsNotNull() ) { m_NeedleProjectionFilter->Update(); } //refresh view and status widget mitk::RenderingManager::GetInstance()->RequestUpdateAll(); m_Controls->m_TrackingToolsStatusWidget->Refresh(); } void QmitkMITKIGTTrackingToolboxView::UpdateLoggingTrackingTimer() { //update logging if (m_logging) { this->m_loggingFilter->Update(); m_loggedFrames = this->m_loggingFilter->GetNumberOfRecordedSteps(); this->m_Controls->m_LoggedFramesLabel->setText("Logged Frames: " + QString::number(m_loggedFrames)); //check if logging stopped automatically if ((m_loggedFrames > 1) && (!m_loggingFilter->GetRecording())){ StopLogging(); } } //refresh status widget m_Controls->m_TrackingToolsStatusWidget->Refresh(); } void QmitkMITKIGTTrackingToolboxView::OnChooseFileClicked() { QDir currentPath = QFileInfo(m_Controls->m_LoggingFileName->text()).dir(); // if no path was selected (QDir would select current working dir then) or the // selected path does not exist -> use home directory if (currentPath == QDir() || !currentPath.exists()) { currentPath = QDir(QDir::homePath()); } QString filename = QFileDialog::getSaveFileName(nullptr, tr("Choose Logging File"), currentPath.absolutePath(), "*.*"); if (filename == "") return; this->m_Controls->m_LoggingFileName->setText(filename); this->OnToggleFileExtension(); } // bug-16470: toggle file extension after clicking on radio button void QmitkMITKIGTTrackingToolboxView::OnToggleFileExtension() { QString currentInputText = this->m_Controls->m_LoggingFileName->text(); QString currentFile = QFileInfo(currentInputText).baseName(); QDir currentPath = QFileInfo(currentInputText).dir(); if (currentFile.isEmpty()) { currentFile = "logfile"; } // Setting currentPath to default home path when currentPath is empty or it does not exist if (currentPath == QDir() || !currentPath.exists()) { currentPath = QDir::homePath(); } // check if csv radio button is clicked if (this->m_Controls->m_CsvFormat->isChecked()) { // you needn't add a seperator to the input text when currentpath is the rootpath if (currentPath.isRoot()) { this->m_Controls->m_LoggingFileName->setText(QDir::toNativeSeparators(currentPath.absolutePath()) + currentFile + ".csv"); } else { this->m_Controls->m_LoggingFileName->setText(QDir::toNativeSeparators(currentPath.absolutePath()) + QDir::separator() + currentFile + ".csv"); } } // check if xml radio button is clicked else if (this->m_Controls->m_XmlFormat->isChecked()) { // you needn't add a seperator to the input text when currentpath is the rootpath if (currentPath.isRoot()) { this->m_Controls->m_LoggingFileName->setText(QDir::toNativeSeparators(currentPath.absolutePath()) + currentFile + ".xml"); } else { this->m_Controls->m_LoggingFileName->setText(QDir::toNativeSeparators(currentPath.absolutePath()) + QDir::separator() + currentFile + ".xml"); } } } void QmitkMITKIGTTrackingToolboxView::OnToggleAdvancedSimpleMode() { if (m_SimpleModeEnabled) { m_Controls->m_simpleWidget->setVisible(false); m_Controls->m_MainWidget->setVisible(true); m_Controls->m_SimpleUI->setChecked(false); m_SimpleModeEnabled = false; } else { m_Controls->m_simpleWidget->setVisible(true); m_Controls->m_MainWidget->setVisible(false); m_SimpleModeEnabled = true; } } void QmitkMITKIGTTrackingToolboxView::OnToggleDifferentUpdateRates() { if (m_Controls->m_UseDifferentUpdateRates->isChecked()) { if (m_Controls->m_RenderUpdateRate->value() == 0) m_Controls->m_RenderWarningLabel->setVisible(true); else m_Controls->m_RenderWarningLabel->setVisible(false); m_Controls->m_UpdateRate->setEnabled(false); m_Controls->m_OptionsUpdateRateLabel->setEnabled(false); m_Controls->m_RenderUpdateRate->setEnabled(true); m_Controls->m_OptionsRenderUpdateRateLabel->setEnabled(true); m_Controls->m_LogUpdateRate->setEnabled(true); m_Controls->m_OptionsLogUpdateRateLabel->setEnabled(true); } else { m_Controls->m_RenderWarningLabel->setVisible(false); m_Controls->m_UpdateRate->setEnabled(true); m_Controls->m_OptionsUpdateRateLabel->setEnabled(true); m_Controls->m_RenderUpdateRate->setEnabled(false); m_Controls->m_OptionsRenderUpdateRateLabel->setEnabled(false); m_Controls->m_LogUpdateRate->setEnabled(false); m_Controls->m_OptionsLogUpdateRateLabel->setEnabled(false); } } void QmitkMITKIGTTrackingToolboxView::OnChangeRenderUpdateRate() { if (m_Controls->m_RenderUpdateRate->value() == 0) m_Controls->m_RenderWarningLabel->setVisible(true); else m_Controls->m_RenderWarningLabel->setVisible(false); } void QmitkMITKIGTTrackingToolboxView::StartLogging() { if (m_ToolVisualizationFilter.IsNull()) { MessageBox("Cannot activate logging without a connected device. Configure and connect a tracking device first."); return; } if (!m_logging) { //initialize logging filter m_loggingFilter = mitk::NavigationDataRecorder::New(); m_loggingFilter->SetRecordOnlyValidData(m_Controls->m_SkipInvalidData->isChecked()); m_loggingFilter->ConnectTo(m_ToolVisualizationFilter); if (m_Controls->m_LoggingLimit->isChecked()){ m_loggingFilter->SetRecordCountLimit(m_Controls->m_LoggedFramesLimit->value()); } //start filter with try-catch block for exceptions try { m_loggingFilter->StartRecording(); } catch (mitk::IGTException) { std::string errormessage = "Error during start recording. Recorder already started recording?"; QMessageBox::warning(nullptr, "IGTPlayer: Error", errormessage.c_str()); m_loggingFilter->StopRecording(); return; } //update labels / logging variables this->m_Controls->m_LoggingLabel->setText("Logging ON"); this->m_Controls->m_LoggedFramesLabel->setText("Logged Frames: 0"); m_loggedFrames = 0; m_logging = true; DisableLoggingButtons(); } } void QmitkMITKIGTTrackingToolboxView::StopLogging() { if (m_logging) { //stop logging m_loggingFilter->StopRecording(); m_logging = false; //update GUI this->m_Controls->m_LoggingLabel->setText("Logging OFF"); EnableLoggingButtons(); //write the results to a file if (m_Controls->m_CsvFormat->isChecked()) { mitk::IOUtil::Save(m_loggingFilter->GetNavigationDataSet(), this->m_Controls->m_LoggingFileName->text().toStdString()); } else if (m_Controls->m_XmlFormat->isChecked()) { mitk::IOUtil::Save(m_loggingFilter->GetNavigationDataSet(), this->m_Controls->m_LoggingFileName->text().toStdString()); } } } void QmitkMITKIGTTrackingToolboxView::SetFocus() { } void QmitkMITKIGTTrackingToolboxView::OnAddSingleTool() { QString Identifier = "Tool#"; QString Name = "NewTool"; if (m_toolStorage.IsNotNull()) { Identifier += QString::number(m_toolStorage->GetToolCount()); Name += QString::number(m_toolStorage->GetToolCount()); } else { Identifier += "0"; Name += "0"; } m_Controls->m_NavigationToolCreationWidget->Initialize(GetDataStorage(), Identifier.toStdString(), Name.toStdString()); m_Controls->m_NavigationToolCreationWidget->SetTrackingDeviceType(m_Controls->m_ConfigurationWidget->GetTrackingDevice()->GetType(), false); m_Controls->m_TrackingToolsWidget->setCurrentIndex(1); //disable tracking volume during tool editing lastTrackingVolumeState = m_Controls->m_ShowTrackingVolume->isChecked(); if (lastTrackingVolumeState) m_Controls->m_ShowTrackingVolume->click(); GlobalReinit(); } void QmitkMITKIGTTrackingToolboxView::OnAddSingleToolFinished() { m_Controls->m_TrackingToolsWidget->setCurrentIndex(0); if (this->m_toolStorage.IsNull()) { //this shouldn't happen! MITK_WARN << "No ToolStorage available, cannot add tool, aborting!"; return; } m_toolStorage->AddTool(m_Controls->m_NavigationToolCreationWidget->GetCreatedTool()); m_Controls->m_TrackingToolsStatusWidget->PreShowTools(m_toolStorage); m_Controls->m_ToolLabel->setText(""); //displya in tool selector // m_Controls->m_toolselector->addItem(QString::fromStdString(m_Controls->m_NavigationToolCreationWidget->GetCreatedTool()->GetToolName())); //auto save current storage for persistence MITK_INFO << "Auto saving manually added tools for persistence."; AutoSaveToolStorage(); //enable tracking volume again if (lastTrackingVolumeState) m_Controls->m_ShowTrackingVolume->click(); GlobalReinit(); } void QmitkMITKIGTTrackingToolboxView::OnAddSingleToolCanceled() { m_Controls->m_TrackingToolsWidget->setCurrentIndex(0); //enable tracking volume again if (lastTrackingVolumeState) m_Controls->m_ShowTrackingVolume->click(); GlobalReinit(); } void QmitkMITKIGTTrackingToolboxView::GlobalReinit() { // get all nodes that have not set "includeInBoundingBox" to false mitk::NodePredicateNot::Pointer pred = mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("includeInBoundingBox", mitk::BoolProperty::New(false))); mitk::DataStorage::SetOfObjects::ConstPointer rs = this->GetDataStorage()->GetSubset(pred); // calculate bounding geometry of these nodes auto bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(rs, "visible"); // initialize the views to the bounding geometry mitk::RenderingManager::GetInstance()->InitializeViews(bounds); } void QmitkMITKIGTTrackingToolboxView::DisableLoggingButtons() { m_Controls->m_StartLogging->setEnabled(false); m_Controls->m_LoggingFileName->setEnabled(false); m_Controls->m_ChooseFile->setEnabled(false); m_Controls->m_LoggingLimit->setEnabled(false); m_Controls->m_LoggedFramesLimit->setEnabled(false); m_Controls->m_CsvFormat->setEnabled(false); m_Controls->m_XmlFormat->setEnabled(false); m_Controls->m_SkipInvalidData->setEnabled(false); m_Controls->m_StopLogging->setEnabled(true); } void QmitkMITKIGTTrackingToolboxView::EnableLoggingButtons() { m_Controls->m_StartLogging->setEnabled(true); m_Controls->m_LoggingFileName->setEnabled(true); m_Controls->m_ChooseFile->setEnabled(true); m_Controls->m_LoggingLimit->setEnabled(true); m_Controls->m_LoggedFramesLimit->setEnabled(true); m_Controls->m_CsvFormat->setEnabled(true); m_Controls->m_XmlFormat->setEnabled(true); m_Controls->m_SkipInvalidData->setEnabled(true); m_Controls->m_StopLogging->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::DisableOptionsButtons() { m_Controls->m_ShowTrackingVolume->setEnabled(false); m_Controls->m_UseDifferentUpdateRates->setEnabled(false); m_Controls->m_UpdateRate->setEnabled(false); m_Controls->m_OptionsUpdateRateLabel->setEnabled(false); m_Controls->m_RenderUpdateRate->setEnabled(false); m_Controls->m_OptionsRenderUpdateRateLabel->setEnabled(false); m_Controls->m_LogUpdateRate->setEnabled(false); m_Controls->m_OptionsLogUpdateRateLabel->setEnabled(false); m_Controls->m_DisableAllTimers->setEnabled(false); m_Controls->m_OtherOptionsGroupBox->setEnabled(false); m_Controls->m_EnableOpenIGTLinkMicroService->setEnabled(false); m_Controls->m_OpenIGTLinkDataFormat->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::EnableOptionsButtons() { m_Controls->m_ShowTrackingVolume->setEnabled(true); m_Controls->m_UseDifferentUpdateRates->setEnabled(true); m_Controls->m_DisableAllTimers->setEnabled(true); m_Controls->m_OtherOptionsGroupBox->setEnabled(true); m_Controls->m_EnableOpenIGTLinkMicroService->setEnabled(true); m_Controls->m_OpenIGTLinkDataFormat->setEnabled(true); OnToggleDifferentUpdateRates(); } void QmitkMITKIGTTrackingToolboxView::EnableTrackingControls() { m_Controls->m_TrackingControlsFrame->setEnabled(true); } void QmitkMITKIGTTrackingToolboxView::DisableTrackingControls() { m_Controls->m_TrackingControlsFrame->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::EnableTrackingConfigurationButtons() { m_Controls->m_AutoDetectTools->setEnabled(true); m_Controls->m_AddSingleTool->setEnabled(this->m_Controls->m_ConfigurationWidget->GetTrackingDevice()->AddSingleToolIsAvailable()); m_Controls->m_LoadTools->setEnabled(true); m_Controls->m_ResetTools->setEnabled(true); } void QmitkMITKIGTTrackingToolboxView::DisableTrackingConfigurationButtons() { m_Controls->m_AutoDetectTools->setEnabled(false); m_Controls->m_AddSingleTool->setEnabled(false); m_Controls->m_LoadTools->setEnabled(false); m_Controls->m_ResetTools->setEnabled(false); } void QmitkMITKIGTTrackingToolboxView::ReplaceCurrentToolStorage(mitk::NavigationToolStorage::Pointer newStorage, std::string newStorageName) { //first: get rid of the old one //don't reset if there is no tool storage. BugFix #17793 if (m_toolStorage.IsNotNull()){ m_toolStorage->UnLockStorage(); //only to be sure... m_toolStorage->UnRegisterMicroservice(); m_toolStorage = nullptr; } //now: replace by the new one m_toolStorage = newStorage; m_toolStorage->SetName(newStorageName); m_toolStorage->RegisterAsMicroservice(); } void QmitkMITKIGTTrackingToolboxView::OnTimeOut() { MITK_WARN << "TimeOut. Quitting the thread..."; m_WorkerThread->quit(); //only if we can't quit use terminate. if (!m_WorkerThread->wait(1000)) { MITK_ERROR << "Can't quit the thread. Terminating... Might cause further problems, be careful!"; m_WorkerThread->terminate(); m_WorkerThread->wait(); } m_TimeoutTimer->stop(); } void QmitkMITKIGTTrackingToolboxView::OnToolStorageChanged(const ctkServiceEvent event) { //don't listen to any changes during connection, toolStorage is locked anyway, so this are only changes of e.g. sourceID which are not relevant for the widget. if (!m_connected && (event.getType() == ctkServiceEvent::MODIFIED)) { m_Controls->m_ConfigurationWidget->OnToolStorageChanged(); m_Controls->m_toolselector->clear(); for (size_t i = 0; i < m_toolStorage->GetToolCount(); i++) { m_Controls->m_toolselector->addItem(QString::fromStdString(m_toolStorage->GetTool(i)->GetToolName())); } } } //! [StoreUISettings] void QmitkMITKIGTTrackingToolboxView::StoreUISettings() { // persistence service does not directly work in plugins for now // -> using QSettings QSettings settings; settings.beginGroup(QString::fromStdString(VIEW_ID)); MITK_DEBUG << "Store UI settings"; // set the values of some widgets and attrbutes to the QSettings settings.setValue("ShowTrackingVolume", QVariant(m_Controls->m_ShowTrackingVolume->isChecked())); settings.setValue("toolStorageFilename", QVariant(m_ToolStorageFilename)); settings.setValue("VolumeSelectionBox", QVariant(m_Controls->m_VolumeSelectionBox->currentIndex())); settings.setValue("SimpleModeEnabled", QVariant(m_SimpleModeEnabled)); settings.setValue("OpenIGTLinkDataFormat", QVariant(m_Controls->m_OpenIGTLinkDataFormat->currentIndex())); settings.setValue("EnableOpenIGTLinkMicroService", QVariant(m_Controls->m_EnableOpenIGTLinkMicroService->isChecked())); settings.endGroup(); } //! [StoreUISettings] //! [LoadUISettings] void QmitkMITKIGTTrackingToolboxView::LoadUISettings() { // persistence service does not directly work in plugins for now -> using QSettings QSettings settings; settings.beginGroup(QString::fromStdString(VIEW_ID)); // set some widgets and attributes by the values from the QSettings - m_Controls->m_ShowTrackingVolume->setChecked(settings.value("ShowTrackingVolume", true).toBool()); + m_Controls->m_ShowTrackingVolume->setChecked(settings.value("ShowTrackingVolume", false).toBool()); m_Controls->m_EnableOpenIGTLinkMicroService->setChecked(settings.value("EnableOpenIGTLinkMicroService", true).toBool()); m_Controls->m_VolumeSelectionBox->setCurrentIndex(settings.value("VolumeSelectionBox", 0).toInt()); m_Controls->m_OpenIGTLinkDataFormat->setCurrentIndex(settings.value("OpenIGTLinkDataFormat", 0).toInt()); m_ToolStorageFilename = settings.value("toolStorageFilename", QVariant("")).toString(); if (settings.value("SimpleModeEnabled", false).toBool()) { this->OnToggleAdvancedSimpleMode(); } settings.endGroup(); //! [LoadUISettings] //! [LoadToolStorage] // try to deserialize the tool storage from the given tool storage file name if (!m_ToolStorageFilename.isEmpty()) { // try-catch block for exceptions try { mitk::NavigationToolStorageDeserializer::Pointer myDeserializer = mitk::NavigationToolStorageDeserializer::New(GetDataStorage()); m_toolStorage->UnRegisterMicroservice(); m_toolStorage = myDeserializer->Deserialize(m_ToolStorageFilename.toStdString()); m_toolStorage->RegisterAsMicroservice(); //update label UpdateToolStorageLabel(m_ToolStorageFilename); //update tool preview m_Controls->m_TrackingToolsStatusWidget->RemoveStatusLabels(); m_Controls->m_TrackingToolsStatusWidget->PreShowTools(m_toolStorage); } - catch (mitk::IGTException) + catch (mitk::IGTException e) { - MITK_WARN("QmitkMITKIGTTrackingToolBoxView") << "Error during restoring tools. Problems with file (" << m_ToolStorageFilename.toStdString() << "), please check the file?"; + MITK_WARN("QmitkMITKIGTTrackingToolBoxView") << "Error during restoring tools. Problems with file (" << m_ToolStorageFilename.toStdString() << "), please check the file? Error message: "<OnResetTools(); //if there where errors reset the tool storage to avoid problems later on } } //! [LoadToolStorage] } void QmitkMITKIGTTrackingToolboxView::UpdateToolStorageLabel(QString pathOfLoadedStorage) { QFileInfo myPath(pathOfLoadedStorage); //use this to seperate filename from path QString toolLabel = myPath.fileName(); if (toolLabel.size() > 45) //if the tool storage name is to long trimm the string { toolLabel.resize(40); toolLabel += "[...]"; } m_Controls->m_ToolLabel->setText(toolLabel); } void QmitkMITKIGTTrackingToolboxView::AutoSaveToolStorage() { m_ToolStorageFilename = m_AutoSaveFilename; mitk::NavigationToolStorageSerializer::Pointer mySerializer = mitk::NavigationToolStorageSerializer::New(); mySerializer->Serialize(m_ToolStorageFilename.toStdString(), m_toolStorage); } diff --git a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxViewControls.ui b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxViewControls.ui index 3d6eab8f4c..8e043ac2f8 100644 --- a/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxViewControls.ui +++ b/Plugins/org.mitk.gui.qt.igttracking/src/internal/QmitkMITKIGTTrackingToolboxViewControls.ui @@ -1,954 +1,954 @@ QmitkMITKIGTTrackingToolboxViewControls 0 0 370 739 0 0 QmitkTemplate 0 Tracking QFrame::NoFrame QFrame::Raised 0 0 QFrame::NoFrame QFrame::Raised 10 75 true true Tracking Tools Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop 0 0 ToolStorage: <none> Qt::Horizontal 40 20 0 0 Qt::Horizontal 13 49 120 0 Auto Detection 120 0 Add Single Tool 120 0 Load Tool Storage 120 0 Reset QFrame::NoFrame QFrame::Raised 10 75 true Tracking Control Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop Status: disconnected Qt::Horizontal 40 20 142 0 Connect Qt::Horizontal 40 20 142 0 Start Tracking Qt::Horizontal 40 20 <html><head/><body><p><span style=" color:#ff0000;">Tracking Frozen!</span></p></body></html> true 142 0 Freeze Tracking Qt::Vertical 20 40 Options Update Rate Options Update Rate [per second] Qt::Horizontal 40 20 100 30 Use different Render and Log Update Rates false Render Update Rate [fps] Qt::Horizontal 40 20 false 0 100 30 false Log Update Rate [per second] Qt::Horizontal 40 20 false 1 120 10 60 Other Options Show Tool Quaternions Simple UI Caution, only for backward compatibility: Inverse mode (Quaternions are stored inverse) Tracking Volume Options true Show Tracking Volume - true + false Select Model: Tool Visualization Options true Show Tool Projection false Show Tool Axis Open IGT Link Enable Open IGT Link MicroService true Select Open IGT Link Data Format: TRANSFORM QTDATA TDATA POSITION Disable All Timers true <html><head/><body><p align="right"><span style=" color:#ff0000;">Rendering Disabled!</span></p></body></html> Qt::AutoText Qt::Vertical 20 40 Logging Filename: Choose File Limit Number Of Logged Frames: Qt::Horizontal 40 20 1 9999 300 CSV format true XML format Skip invalid data Logging Status Logging OFF Logged Frames: 0 Qt::Horizontal 40 20 Start Logging Stop Logging Qt::Vertical 20 40 9 742 303 70 70 50 Connect 70 50 Start Tracking Qt::Horizontal 40 20 70 50 Advanced Mode QmitkToolTrackingStatusWidget QWidget

QmitkToolTrackingStatusWidget.h
1 QmitkTrackingDeviceConfigurationWidget QWidget
QmitkTrackingDeviceConfigurationWidget.h
1
QmitkNavigationToolCreationWidget QWidget
QmitkNavigationToolCreationWidget.h
1
diff --git a/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/Advanced_ImageCropperView.png b/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/Advanced_ImageCropperView.png index 6b31cf0297..62f78ff57a 100644 Binary files a/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/Advanced_ImageCropperView.png and b/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/Advanced_ImageCropperView.png differ diff --git a/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/Basic_ImageCropperView.png b/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/Basic_ImageCropperView.png index eb0b3ee384..7cb45a0828 100644 Binary files a/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/Basic_ImageCropperView.png and b/Plugins/org.mitk.gui.qt.imagecropper/documentation/UserManual/Basic_ImageCropperView.png differ diff --git a/Plugins/org.mitk.gui.qt.imagecropper/plugin.xml b/Plugins/org.mitk.gui.qt.imagecropper/plugin.xml index b97af3cd8e..7b2df1f616 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/plugin.xml +++ b/Plugins/org.mitk.gui.qt.imagecropper/plugin.xml @@ -1,27 +1,27 @@ Crop images to a given size - + - - - - - - + + + + + + diff --git a/Plugins/org.mitk.gui.qt.imagecropper/resources/crop.svg b/Plugins/org.mitk.gui.qt.imagecropper/resources/crop.svg index 50a086ca35..149209316f 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/resources/crop.svg +++ b/Plugins/org.mitk.gui.qt.imagecropper/resources/crop.svg @@ -1,31 +1,31 @@ + height="128" + width="128"> image/svg+xml diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/ImageCropperControls.ui b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/ImageCropperControls.ui index e45fe66627..2c0107ebed 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/ImageCropperControls.ui +++ b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/ImageCropperControls.ui @@ -1,1133 +1,1133 @@ ImageCropperControls 0 0 329 863 0 0 QmitkTemplate 3 0 0 QLabel { color: rgb(255, 0, 0) } Please select an image. 255 0 0 255 0 0 255 127 127 255 63 63 127 0 0 170 0 0 0 0 0 255 255 255 0 0 0 255 255 255 255 0 0 0 0 0 255 127 127 255 255 220 0 0 0 255 0 0 255 0 0 255 127 127 255 63 63 127 0 0 170 0 0 0 0 0 255 255 255 0 0 0 255 255 255 255 0 0 0 0 0 255 127 127 255 255 220 0 0 0 120 120 120 255 0 0 255 127 127 255 63 63 127 0 0 170 0 0 127 0 0 255 255 255 127 0 0 255 0 0 255 0 0 0 0 0 255 0 0 255 255 220 0 0 0 Please select a bounding object. false 0 0 0 90 Bounding object 0 0 16777215 16777215 0 0 - New... + New 0 0 Do Cropping Mask 0 0 Crop true 255 0 0 255 0 0 255 127 127 255 63 63 127 0 0 170 0 0 255 0 0 255 255 255 0 0 0 255 255 255 255 0 0 0 0 0 255 127 127 255 255 220 0 0 0 255 0 0 255 0 0 255 127 127 255 63 63 127 0 0 170 0 0 255 0 0 255 255 255 0 0 0 255 255 255 255 0 0 0 0 0 255 127 127 255 255 220 0 0 0 127 0 0 255 0 0 255 127 127 255 63 63 127 0 0 170 0 0 127 0 0 255 255 255 127 0 0 255 0 0 255 0 0 0 0 0 255 0 0 255 255 220 0 0 0 Image geometry is rotated, result won't be pixel-aligned. You can reinit your image to get a pixel-aligned result, though. Qt::PlainText true 0 0 0 25 Advanced settings false 100 Qt::ToolButtonTextBesideIcon false 0 0 0 120 Output image settings 0 0 Outside pixel value (masking): false 0 0 16777210 16777215 0 0 Overrride original image false 0 0 Only crop current timestep / cut off other timesteps Qt::Vertical 20 40 QmitkDataStorageComboBox QComboBox
QmitkDataStorageComboBox.h
ctkExpandButton QToolButton
ctkExpandButton.h
diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp index 42f42ff803..6618810596 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp +++ b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.cpp @@ -1,606 +1,575 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #include "QmitkImageCropper.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Includes for image casting between ITK and MITK: added after using Plugin Generator #include #include #include #include #include #include #include #include #include +#include #include #include #include #include #include #include const std::string QmitkImageCropper::VIEW_ID = "org.mitk.views.qmitkimagecropper"; QmitkImageCropper::QmitkImageCropper(QObject *) : m_ParentWidget(0), m_ImageNode(nullptr), m_CroppingObject(nullptr), m_CroppingObjectNode(nullptr), m_BoundingShapeInteractor(nullptr), m_CropOutsideValue(0), m_Advanced(0), m_Active(0), m_ScrollEnabled(true) { CreateBoundingShapeInteractor(false); } QmitkImageCropper::~QmitkImageCropper() { //delete pointer objects m_CroppingObjectNode = nullptr; m_CroppingObject = nullptr; //disable interactor if (m_BoundingShapeInteractor != nullptr) { m_BoundingShapeInteractor->SetDataNode(nullptr); m_BoundingShapeInteractor->EnableInteraction(false); } } void QmitkImageCropper::SetFocus() { m_Controls.buttonCreateNewBoundingBox->setFocus(); } void QmitkImageCropper::CreateQtPartControl(QWidget *parent) { // create GUI widgets from the Qt Designer's .ui file m_Controls.setupUi(parent); m_Controls.boundingShapeSelector->SetDataStorage(this->GetDataStorage()); m_Controls.boundingShapeSelector->SetPredicate(mitk::NodePredicateAnd::New( mitk::TNodePredicateDataType::New(), mitk::NodePredicateNot::New(mitk::NodePredicateProperty::New("helper object")))); m_CroppingObjectNode = m_Controls.boundingShapeSelector->GetSelectedNode(); connect(m_Controls.buttonCropping, SIGNAL(clicked()), this, SLOT(DoCropping())); connect(m_Controls.buttonMasking, SIGNAL(clicked()), this, SLOT(DoMasking())); connect(m_Controls.boundingShapeSelector, SIGNAL(OnSelectionChanged(const mitk::DataNode*)), this, SLOT(OnDataSelectionChanged(const mitk::DataNode*))); connect(m_Controls.buttonCreateNewBoundingBox, SIGNAL(clicked()), this, SLOT(DoCreateNewBoundingObject())); connect(m_Controls.buttonAdvancedSettings, SIGNAL(clicked()), this, SLOT(OnAdvancedSettingsButtonToggled())); connect(m_Controls.spinBoxOutsidePixelValue, SIGNAL(valueChanged(int)), this, SLOT(OnSliderValueChanged(int))); setDefaultGUI(); m_Controls.labelWarningRotation->setVisible(false); - m_BoundingObjectNames.clear(); - m_Advanced = false; this->OnAdvancedSettingsButtonToggled(); m_ParentWidget = parent; } void QmitkImageCropper::OnDataSelectionChanged(const mitk::DataNode*) { m_Controls.boundingShapeSelector->setEnabled(true); m_CroppingObjectNode = m_Controls.boundingShapeSelector->GetSelectedNode(); if (m_CroppingObjectNode.IsNotNull() && dynamic_cast(this->m_CroppingObjectNode->GetData())) { m_Controls.buttonAdvancedSettings->setEnabled(true); m_Controls.labelWarningBB->setVisible(false); m_CroppingObject = dynamic_cast(m_CroppingObjectNode->GetData()); m_Advanced = true; mitk::RenderingManager::GetInstance()->InitializeViews(); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } else { setDefaultGUI(); m_CroppingObject = nullptr; m_BoundingShapeInteractor->EnableInteraction(false); m_BoundingShapeInteractor->SetDataNode(nullptr); m_Advanced = false; this->OnAdvancedSettingsButtonToggled(); } } void QmitkImageCropper::OnAdvancedSettingsButtonToggled() { m_Controls.groupImageSettings->setVisible(m_Advanced); m_Advanced = !m_Advanced; } void QmitkImageCropper::CreateBoundingShapeInteractor(bool rotationEnabled) { if (m_BoundingShapeInteractor.IsNull()) { m_BoundingShapeInteractor = mitk::BoundingShapeInteractor::New(); m_BoundingShapeInteractor->LoadStateMachine("BoundingShapeInteraction.xml", us::ModuleRegistry::GetModule("MitkBoundingShape")); m_BoundingShapeInteractor->SetEventConfig("BoundingShapeMouseConfig.xml", us::ModuleRegistry::GetModule("MitkBoundingShape")); } m_BoundingShapeInteractor->SetRotationEnabled(rotationEnabled); } mitk::Geometry3D::Pointer QmitkImageCropper::InitializeWithImageGeometry(mitk::BaseGeometry::Pointer geometry) { // convert a basegeometry into a Geometry3D (otherwise IO is not working properly) if (geometry == nullptr) mitkThrow() << "Geometry is not valid."; auto boundingGeometry = mitk::Geometry3D::New(); boundingGeometry->SetBounds(geometry->GetBounds()); boundingGeometry->SetImageGeometry(geometry->GetImageGeometry()); boundingGeometry->SetOrigin(geometry->GetOrigin()); boundingGeometry->SetSpacing(geometry->GetSpacing()); boundingGeometry->SetIndexToWorldTransform(geometry->GetIndexToWorldTransform()); boundingGeometry->Modified(); return boundingGeometry; } -QString QmitkImageCropper::getAdaptedBoundingObjectName(const QString& name) const +QString QmitkImageCropper::AdaptBoundingObjectName(const QString& name) const { - bool nameNotTaken = false; unsigned int counter = 2; - QString newName; - while (!nameNotTaken) + QString newName = QString("%1 %2").arg(name).arg(counter); + + while (nullptr != this->GetDataStorage()->GetNode(mitk::NodePredicateFunction::New([&newName](const mitk::DataNode *node) { - newName = name + "_" + QString::number(counter); - if (!m_BoundingObjectNames.contains(newName)) - { - nameNotTaken = true; - } - ++counter; + return 0 == node->GetName().compare(newName.toStdString()); + }))) + { + newName = QString("%1 %2").arg(name).arg(++counter); } + return newName; } void QmitkImageCropper::DoCreateNewBoundingObject() { if (!m_ImageNode.IsExpired()) { auto imageNode = m_ImageNode.Lock(); + QString name = QString::fromStdString(imageNode->GetName() + " Bounding Shape"); - bool ok = false; - QString defaultName = "BoundingShape"; - if (m_BoundingObjectNames.contains(defaultName)) + auto boundingShape = this->GetDataStorage()->GetNode(mitk::NodePredicateFunction::New([&name](const mitk::DataNode *node) { - defaultName = getAdaptedBoundingObjectName(defaultName); - } - QString name = QInputDialog::getText(QApplication::activeWindow() - , "Add cropping shape...", "Enter name for the new cropping shape", QLineEdit::Normal, defaultName, &ok); - if (!ok) - return; + return 0 == node->GetName().compare(name.toStdString()); + })); - if (name == "") - { - name = "Bounding Shape"; - } - if (m_BoundingObjectNames.contains(name)) - { - name = getAdaptedBoundingObjectName(name); - QMessageBox::information(nullptr, "Information", "Bounding object name already exists. It was changed to: " + name); - } - m_BoundingObjectNames.append(name); + if (nullptr != boundingShape) + name = this->AdaptBoundingObjectName(name); m_Controls.buttonCropping->setEnabled(true); m_Controls.buttonMasking->setEnabled(true); m_Controls.boundingShapeSelector->setEnabled(true); m_Controls.groupImageSettings->setEnabled(true); // get current timestep to support 3d+t images auto renderWindowPart = this->GetRenderWindowPart(OPEN); int timeStep = renderWindowPart->GetTimeNavigationController()->GetTime()->GetPos(); mitk::BaseGeometry::Pointer imageGeometry = static_cast(imageNode->GetData()->GetGeometry(timeStep)); m_CroppingObject = mitk::GeometryData::New(); m_CroppingObject->SetGeometry(static_cast(this->InitializeWithImageGeometry(imageGeometry))); m_CroppingObjectNode = mitk::DataNode::New(); m_CroppingObjectNode->SetData(m_CroppingObject); m_CroppingObjectNode->SetProperty("name", mitk::StringProperty::New(name.toStdString())); m_CroppingObjectNode->SetProperty("color", mitk::ColorProperty::New(1.0, 1.0, 1.0)); m_CroppingObjectNode->SetProperty("opacity", mitk::FloatProperty::New(0.6)); m_CroppingObjectNode->SetProperty("layer", mitk::IntProperty::New(99)); m_CroppingObjectNode->AddProperty("handle size factor", mitk::DoubleProperty::New(1.0 / 40.0)); m_CroppingObjectNode->SetBoolProperty("pickable", true); if (!this->GetDataStorage()->Exists(m_CroppingObjectNode)) { GetDataStorage()->Add(m_CroppingObjectNode, imageNode); m_Controls.boundingShapeSelector->SetSelectedNode(m_CroppingObjectNode); m_CroppingObjectNode->SetVisibility(true); m_BoundingShapeInteractor->EnableInteraction(true); m_BoundingShapeInteractor->SetDataNode(this->m_CroppingObjectNode); this->OnDataSelectionChanged(m_CroppingObjectNode); } } // Adjust coordinate system by doing a reinit on auto tempDataStorage = mitk::DataStorage::SetOfObjects::New(); tempDataStorage->InsertElement(0, m_CroppingObjectNode); //// initialize the views to the bounding geometry //mitk::TimeGeometry::Pointer bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(tempDataStorage); //mitk::RenderingManager::GetInstance()->InitializeViews(bounds); //mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkImageCropper::setDefaultGUI() { m_Controls.labelWarningImage->setStyleSheet(" QLabel { color: rgb(255, 0, 0) }"); m_Controls.labelWarningImage->setText(QString::fromStdString("Select an image.")); m_Controls.labelWarningImage->setVisible(true); m_Controls.labelWarningBB->setStyleSheet(" QLabel { color: rgb(255, 0, 0) }"); m_Controls.labelWarningBB->setText(QString::fromStdString("Create a bounding shape below.")); m_Controls.labelWarningBB->setVisible(true); m_Controls.buttonCreateNewBoundingBox->setEnabled(false); m_Controls.labelWarningRotation->setVisible(false); m_Controls.buttonCropping->setEnabled(false); m_Controls.buttonMasking->setEnabled(false); m_Controls.boundingShapeSelector->setEnabled(false); m_Controls.buttonAdvancedSettings->setEnabled(false); m_Controls.groupImageSettings->setEnabled(false); m_Controls.checkOverwriteImage->setChecked(false); m_Controls.checkBoxCropTimeStepOnly->setChecked(false); } void QmitkImageCropper::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { bool rotationEnabled = false; if (nodes.empty()) { setDefaultGUI(); return; } m_ParentWidget->setEnabled(true); foreach(mitk::DataNode::Pointer node, nodes) { if (node.IsNotNull() && dynamic_cast(node->GetData())) { m_ImageNode = nodes[0]; m_Controls.groupBoundingObject->setEnabled(true); - m_Controls.labelWarningImage->setStyleSheet(" QLabel { color: rgb(0, 0, 0) }"); - m_Controls.labelWarningImage->setText(QString::fromStdString("File name: " + nodes[0]->GetName())); + m_Controls.labelWarningImage->setStyleSheet(""); + m_Controls.labelWarningImage->setText(QString::fromStdString("Selected image: " + nodes[0]->GetName())); m_Controls.buttonCreateNewBoundingBox->setEnabled(true); mitk::Image::Pointer image = dynamic_cast(nodes[0]->GetData()); if (image != nullptr) { if (image->GetDimension() < 3) { QMessageBox::warning(nullptr, tr("Invalid image selected"), tr("ImageCropper only works with 3 or more dimensions."), QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); setDefaultGUI(); return; } vtkSmartPointer imageMat = image->GetGeometry()->GetVtkMatrix(); // check whether the image geometry is rotated, if so, no pixel aligned cropping or masking can be performed if ((imageMat->GetElement(1, 0) == 0.0) && (imageMat->GetElement(0, 1) == 0.0) && (imageMat->GetElement(1, 2) == 0.0) && (imageMat->GetElement(2, 1) == 0.0) && (imageMat->GetElement(2, 0) == 0.0) && (imageMat->GetElement(0, 2) == 0.0)) { rotationEnabled = false; m_Controls.labelWarningRotation->setVisible(false); } else { rotationEnabled = true; m_Controls.labelWarningRotation->setStyleSheet(" QLabel { color: rgb(255, 0, 0) }"); m_Controls.labelWarningRotation->setVisible(true); } this->CreateBoundingShapeInteractor(rotationEnabled); m_CroppingObjectNode = m_Controls.boundingShapeSelector->GetSelectedNode(); if (m_CroppingObjectNode != nullptr) { this->OnDataSelectionChanged(m_CroppingObjectNode); m_BoundingShapeInteractor->EnableInteraction(true); m_BoundingShapeInteractor->SetDataNode(this->m_CroppingObjectNode); m_Controls.boundingShapeSelector->setEnabled(true); } if (image->GetPixelType().GetPixelType() == itk::ImageIOBase::SCALAR) { // Might be changed with the upcoming new image statistics plugin //(recomputation might be very expensive for large images ;) ) auto statistics = image->GetStatistics(); auto minPixelValue = statistics->GetScalarValueMin(); auto maxPixelValue = statistics->GetScalarValueMax(); if (minPixelValue < std::numeric_limits::min()) { minPixelValue = std::numeric_limits::min(); } if (maxPixelValue > std::numeric_limits::max()) { maxPixelValue = std::numeric_limits::max(); } m_Controls.spinBoxOutsidePixelValue->setEnabled(true); m_Controls.spinBoxOutsidePixelValue->setMaximum(static_cast(maxPixelValue)); m_Controls.spinBoxOutsidePixelValue->setMinimum(static_cast(minPixelValue)); m_Controls.spinBoxOutsidePixelValue->setValue(static_cast(minPixelValue)); } else { m_Controls.spinBoxOutsidePixelValue->setEnabled(false); } unsigned int dim = image->GetDimension(); if (dim < 2 || dim > 4) { m_Controls.labelWarningImage->setStyleSheet(" QLabel { color: rgb(255, 0, 0) }"); m_Controls.labelWarningImage->setText(QString::fromStdString("Select an image.")); m_ParentWidget->setEnabled(false); } if (m_CroppingObjectNode != nullptr) { m_Controls.buttonCropping->setEnabled(true); m_Controls.buttonMasking->setEnabled(true); m_Controls.boundingShapeSelector->setEnabled(true); m_Controls.labelWarningBB->setVisible(false); } else { m_Controls.buttonCropping->setEnabled(false); m_Controls.buttonMasking->setEnabled(false); m_Controls.boundingShapeSelector->setEnabled(false); m_Controls.labelWarningBB->setVisible(true); } return; } // iterate all selected objects, adjust warning visibility setDefaultGUI(); m_ParentWidget->setEnabled(true); m_Controls.labelWarningRotation->setVisible(false); } } } -void QmitkImageCropper::NodeRemoved(const mitk::DataNode * node) -{ - QList::iterator it = m_BoundingObjectNames.begin(); - while (it != m_BoundingObjectNames.end()) - { - if (node->GetName() == it->toStdString()) - { - it = m_BoundingObjectNames.erase(it); - } - else - { - ++it; - } - } -} - void QmitkImageCropper::OnComboBoxSelectionChanged(const mitk::DataNode* node) { mitk::DataNode* selectedNode = const_cast(node); if (selectedNode != nullptr) { if (!m_ImageNode.IsExpired()) selectedNode->SetDataInteractor(m_ImageNode.Lock()->GetDataInteractor()); // m_ImageNode->GetDataInteractor()->SetDataNode(selectedNode); m_ImageNode = selectedNode; } } void QmitkImageCropper::OnSliderValueChanged(int slidervalue) { m_CropOutsideValue = slidervalue; } void QmitkImageCropper::DoMasking() { this->ProcessImage(true); } void QmitkImageCropper::DoCropping() { this->ProcessImage(false); } void QmitkImageCropper::ProcessImage(bool mask) { // cropping only possible if valid bounding shape as well as a valid image are loaded QList nodes = this->GetDataManagerSelection(); auto renderWindowPart = this->GetRenderWindowPart(OPEN); int timeStep = renderWindowPart->GetTimeNavigationController()->GetTime()->GetPos(); if (nodes.empty()) return; mitk::DataNode* node = nodes[0]; if (node == nullptr) { QMessageBox::information(nullptr, "Warning", "Please load and select an image before starting image processing."); return; } if (m_CroppingObject == nullptr) { QMessageBox::information(nullptr, "Warning", "Please load and select a cropping object before starting image processing."); return; } mitk::BaseData* data = node->GetData(); //get data from node if (data != nullptr) { QString imageName; if (mask) { imageName = QString::fromStdString(node->GetName() + "_" + m_CroppingObjectNode->GetName() + "_masked"); } else { imageName = QString::fromStdString(node->GetName() + "_" + m_CroppingObjectNode->GetName() + "_cropped"); } if (m_Controls.checkBoxCropTimeStepOnly->isChecked()) { imageName = imageName + "_T" + QString::number(timeStep); } // image and bounding shape ok, set as input auto croppedImageNode = mitk::DataNode::New(); auto cutter = mitk::BoundingShapeCropper::New(); cutter->SetGeometry(m_CroppingObject); // adjustable in advanced settings cutter->SetUseWholeInputRegion(mask); //either mask (mask=true) or crop (mask=false) cutter->SetOutsideValue(m_CropOutsideValue); cutter->SetUseCropTimeStepOnly(m_Controls.checkBoxCropTimeStepOnly->isChecked()); cutter->SetCurrentTimeStep(timeStep); // TODO: Add support for MultiLayer (right now only Mulitlabel support) mitk::LabelSetImage* labelsetImageInput = dynamic_cast(data); if (labelsetImageInput != nullptr) { cutter->SetInput(labelsetImageInput); // do the actual cutting try { cutter->Update(); } catch (const itk::ExceptionObject& e) { std::string message = std::string("The Cropping filter could not process because of: \n ") + e.GetDescription(); QMessageBox::warning(nullptr, tr("Cropping not possible!"), tr(message.c_str()), QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); return; } auto labelSetImage = mitk::LabelSetImage::New(); labelSetImage->InitializeByLabeledImage(cutter->GetOutput()); for (unsigned int i = 0; i < labelsetImageInput->GetNumberOfLayers(); i++) { labelSetImage->AddLabelSetToLayer(i, labelsetImageInput->GetLabelSet(i)); } croppedImageNode->SetData(labelSetImage); croppedImageNode->SetProperty("name", mitk::StringProperty::New(imageName.toStdString())); //add cropping result to the current data storage as child node to the image node if (!m_Controls.checkOverwriteImage->isChecked()) { if (!this->GetDataStorage()->Exists(croppedImageNode)) { this->GetDataStorage()->Add(croppedImageNode, m_ImageNode.Lock()); } } else // original image will be overwritten by the result image and the bounding box of the result is adjusted { node->SetData(labelSetImage); node->Modified(); // Adjust coordinate system by doing a reinit on auto tempDataStorage = mitk::DataStorage::SetOfObjects::New(); tempDataStorage->InsertElement(0, node); // initialize the views to the bounding geometry auto bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(tempDataStorage); mitk::RenderingManager::GetInstance()->InitializeViews(bounds); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } else { mitk::Image::Pointer imageInput = dynamic_cast(data); if (imageInput != nullptr) { cutter->SetInput(imageInput); // do the actual cutting try { cutter->Update(); } catch (const itk::ExceptionObject& e) { std::string message = std::string("The Cropping filter could not process because of: \n ") + e.GetDescription(); QMessageBox::warning(nullptr, tr("Cropping not possible!"), tr(message.c_str()), QMessageBox::Ok, QMessageBox::NoButton, QMessageBox::NoButton); return; } //add cropping result to the current data storage as child node to the image node if (!m_Controls.checkOverwriteImage->isChecked()) { croppedImageNode->SetData(cutter->GetOutput()); croppedImageNode->SetProperty("name", mitk::StringProperty::New(imageName.toStdString())); croppedImageNode->SetProperty("color", mitk::ColorProperty::New(1.0, 1.0, 1.0)); croppedImageNode->SetProperty("layer", mitk::IntProperty::New(99)); // arbitrary, copied from segmentation functionality if (!this->GetDataStorage()->Exists(croppedImageNode)) { this->GetDataStorage()->Add(croppedImageNode, m_ImageNode.Lock()); } } else // original image will be overwritten by the result image and the bounding box of the result is adjusted { node->SetData(cutter->GetOutput()); node->Modified(); // Adjust coordinate system by doing a reinit on auto tempDataStorage = mitk::DataStorage::SetOfObjects::New(); tempDataStorage->InsertElement(0, node); // initialize the views to the bounding geometry auto bounds = this->GetDataStorage()->ComputeBoundingGeometry3D(tempDataStorage); mitk::RenderingManager::GetInstance()->InitializeViews(bounds); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } } } } else { QMessageBox::information(nullptr, "Warning", "Please load and select an image before starting image processing."); } } diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.h b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.h index 6c70c8fe40..845ab34055 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.h +++ b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/QmitkImageCropper.h @@ -1,179 +1,173 @@ /*========================================================================= Program: Medical Imaging & Interaction Toolkit Language: C++ Date: $Date$ Version: $Revision$ Copyright (c) German Cancer Research Center, Division of Medical and Biological Informatics. All rights reserved. See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. This software is distributed WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the above copyright notices for more information. =========================================================================*/ #ifndef QmitkImageCropper_h #define QmitkImageCropper_h #include #ifdef WIN32 #pragma warning( disable : 4250 ) #endif #include #include "QmitkRegisterClasses.h" #include #include "itkCommand.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "ui_ImageCropperControls.h" #include "usServiceRegistration.h" /*! @brief QmitkImageCropperView \warning This class is not yet documented. Use "git blame" and ask the author to provide basic documentation. \sa QmitkFunctionality \ingroup ${plugin_target}_internal */ class QmitkImageCropper : public QmitkAbstractView { // this is needed for all Qt objects that should have a Qt meta-object // (everything that derives from QObject and wants to have signal/slots) private: Q_OBJECT public: /*! @brief Constructor. Called by SampleApp (or other apps that use functionalities) */ QmitkImageCropper(QObject *parent = 0); virtual ~QmitkImageCropper(); static const std::string VIEW_ID; virtual void CreateQtPartControl(QWidget *parent); virtual void SetFocus() override; /*! @brief Creates the Qt connections needed */ QWidget* GetControls(); /// @brief Called when the user clicks the GUI button protected slots: /*! * @brief Creates a new bounding object */ virtual void DoCreateNewBoundingObject(); /*! * @brief Whenever Crop button is pressed, issue a cropping action */ void DoCropping(); /*! * @brief Whenever Mask button is pressed, issue a masking action */ void DoMasking(); /*! * @brief Dis- or enable the advanced setting section */ void OnAdvancedSettingsButtonToggled(); /*! * @brief Updates current selection of the bounding object */ void OnDataSelectionChanged(const mitk::DataNode* node); /*! * @brief Sets the scalar value for outside pixels in case of masking */ void OnSliderValueChanged(int slidervalue); protected: /*! @brief called by QmitkFunctionality when DataManager's selection has changed */ void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; /*! - @brief called by QmitkFunctionality when DataNode is removed from DataManager - */ - void NodeRemoved(const mitk::DataNode* node) override; - /*! @brief Sets the selected bounding object as current bounding object and set up interactor */ void OnComboBoxSelectionChanged(const mitk::DataNode* node); /*! * @brief Initializes a new bounding shape using the selected image geometry. */ mitk::Geometry3D::Pointer InitializeWithImageGeometry(mitk::BaseGeometry::Pointer geometry); void CreateBoundingShapeInteractor(bool rotationEnabled); private: /*! * The parent QWidget */ QWidget* m_ParentWidget; /*! * @brief A pointer to the node of the image to be cropped. */ mitk::WeakPointer m_ImageNode; /*! * @brief The cuboid used for cropping. */ mitk::GeometryData::Pointer m_CroppingObject; /*! * @brief Tree node of the cuboid used for cropping. */ mitk::DataNode::Pointer m_CroppingObjectNode; /*! * @brief Interactor for moving and scaling the cuboid */ mitk::BoundingShapeInteractor::Pointer m_BoundingShapeInteractor; void ProcessImage(bool crop); - QList m_BoundingObjectNames; - /*! * @brief Resets GUI to default */ void setDefaultGUI(); - QString getAdaptedBoundingObjectName(const QString& name) const; + QString AdaptBoundingObjectName(const QString& name) const; // cropping parameter mitk::ScalarType m_CropOutsideValue; bool m_Advanced; bool m_Active; bool m_ScrollEnabled; Ui::ImageCropperControls m_Controls; }; #endif // QmitkImageCropper_h diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/org_mitk_gui_qt_imagecropper_Activator.cpp b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/org_mitk_gui_qt_imagecropper_Activator.cpp index 61f852b699..5d51c6255e 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/org_mitk_gui_qt_imagecropper_Activator.cpp +++ b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/org_mitk_gui_qt_imagecropper_Activator.cpp @@ -1,46 +1,30 @@ -/*========================================================================= +/*=================================================================== -Program: Medical Imaging & Interaction Toolkit -Language: C++ -Date: $Date$ -Version: $Revision$ +The Medical Imaging Interaction Toolkit (MITK) -Copyright (c) German Cancer Research Center, Division of Medical and -Biological Informatics. All rights reserved. -See MITKCopyright.txt or http://www.mitk.org/copyright.html for details. +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 the above copyright notices for more information. +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 "org_mitk_gui_qt_imagecropper_Activator.h" +===================================================================*/ -#include +#include +#include "org_mitk_gui_qt_imagecropper_Activator.h" #include "QmitkImageCropper.h" -#include -#include - -US_INITIALIZE_MODULE - -namespace mitk { - - void org_mitk_gui_qt_imagecropper_Activator::start(ctkPluginContext* context) - { - RegisterBoundingShapeObjectFactory(); - BERRY_REGISTER_EXTENSION_CLASS(QmitkImageCropper, context) - } - - void org_mitk_gui_qt_imagecropper_Activator::stop(ctkPluginContext* context) - { - Q_UNUSED(context) - } +void mitk::org_mitk_gui_qt_imagecropper_Activator::start(ctkPluginContext* context) +{ + RegisterBoundingShapeObjectFactory(); + BERRY_REGISTER_EXTENSION_CLASS(QmitkImageCropper, context) } -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) -Q_EXPORT_PLUGIN2(org_mitk_gui_qt_imagecropper, mitk::PluginActivator) -#endif \ No newline at end of file +void mitk::org_mitk_gui_qt_imagecropper_Activator::stop(ctkPluginContext*) +{ +} diff --git a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/org_mitk_gui_qt_imagecropper_Activator.h b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/org_mitk_gui_qt_imagecropper_Activator.h index b271d44e65..88f376cbe3 100644 --- a/Plugins/org.mitk.gui.qt.imagecropper/src/internal/org_mitk_gui_qt_imagecropper_Activator.h +++ b/Plugins/org.mitk.gui.qt.imagecropper/src/internal/org_mitk_gui_qt_imagecropper_Activator.h @@ -1,42 +1,36 @@ /*=================================================================== 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 org_mitk_gui_qt_imagecropper_Activator_h #define org_mitk_gui_qt_imagecropper_Activator_h #include -namespace mitk { - - class org_mitk_gui_qt_imagecropper_Activator : - public QObject, public ctkPluginActivator +namespace mitk { - Q_OBJECT - -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) + class org_mitk_gui_qt_imagecropper_Activator : public QObject, public ctkPluginActivator + { + Q_OBJECT Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_imagecropper") -#endif Q_INTERFACES(ctkPluginActivator) -public: - - void start(ctkPluginContext* context) override; - void stop(ctkPluginContext* context) override; - -}; // PluginActivator - + public: + void start(ctkPluginContext* context) override; + void stop(ctkPluginContext* context) override; + }; } -#endif // org_mitk_gui_qt_imagecropper_Activator_h +#endif diff --git a/Plugins/org.mitk.gui.qt.lasercontrol/resources/iconLaserControl.svg b/Plugins/org.mitk.gui.qt.lasercontrol/resources/iconLaserControl.svg index 949e311a9f..639a54b9c3 100644 --- a/Plugins/org.mitk.gui.qt.lasercontrol/resources/iconLaserControl.svg +++ b/Plugins/org.mitk.gui.qt.lasercontrol/resources/iconLaserControl.svg @@ -1,88 +1,88 @@ image/svg+xml \ No newline at end of file + inkscape:connector-curvature="0" /> diff --git a/Plugins/org.mitk.gui.qt.measurementtoolbox/resources/bar-chart.svg b/Plugins/org.mitk.gui.qt.measurementtoolbox/resources/bar-chart.svg index 308bf09546..5bae539eb8 100644 --- a/Plugins/org.mitk.gui.qt.measurementtoolbox/resources/bar-chart.svg +++ b/Plugins/org.mitk.gui.qt.measurementtoolbox/resources/bar-chart.svg @@ -1,54 +1,57 @@ image/svg+xml + + inkscape:zoom="4" + inkscape:cx="-105.61111" + inkscape:cy="108.17143" + inkscape:window-x="-8" + inkscape:window-y="-8" + inkscape:window-maximized="1" + inkscape:current-layer="svg2" + units="px" /> + style="fill:#00ff00;fill-opacity:1;stroke:none;stroke-width:0.99999994" + inkscape:connector-curvature="0" /> diff --git a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker_ScreenshotMakerInterface.png b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker_ScreenshotMakerInterface.png index cbf2067d84..567bee6f1d 100644 Binary files a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker_ScreenshotMakerInterface.png and b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkMovieMaker_ScreenshotMakerInterface.png differ diff --git a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkScreenshotMaker.dox b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkScreenshotMaker.dox index 05b657bdeb..71a6a17ed4 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkScreenshotMaker.dox +++ b/Plugins/org.mitk.gui.qt.moviemaker/documentation/UserManual/QmitkScreenshotMaker.dox @@ -1,19 +1,19 @@ /** \page org_mitk_views_screenshotmaker The Screenshot Maker This view provides the functionality to create and save screenshots of the data. Available sections: - \ref QmitkScreenshotMakerUserManualUse \imageMacro{QmitkMovieMaker_ScreenshotMakerInterface.png,"The Screenshot Maker User Interface",7.09} \section QmitkScreenshotMakerUserManualUse Usage The first section offers the option of creating a screenshot of the last activated render window (thus the one, which was last clicked into). Upon clicking the button, the Screenshot Maker asks for a filename in which the screenshot is to be stored. The multiplanar Screenshot button asks for a folder, where screenshots of the three 2D views will be stored with default names. The high resolution screenshot section works the same as the simple screenshot section, aside from the fact, that the user can choose a magnification factor. -In the option section one can rotate the camera in the 3D view by using the buttons. Furthermore one can choose the background colour for the screenshots, default is black. +In the option section one can choose the background color for the screenshots, default is black. */ diff --git a/Plugins/org.mitk.gui.qt.moviemaker/resources/camera.svg b/Plugins/org.mitk.gui.qt.moviemaker/resources/camera.svg index 2d02fb8175..83bd2c07d1 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/resources/camera.svg +++ b/Plugins/org.mitk.gui.qt.moviemaker/resources/camera.svg @@ -1,54 +1,57 @@ image/svg+xml + + inkscape:current-layer="svg2" + units="px" /> + style="fill:#00ff00;fill-opacity:1;stroke:none;stroke-width:0.99999964" + inkscape:connector-curvature="0" /> diff --git a/Plugins/org.mitk.gui.qt.moviemaker/resources/video-camera.svg b/Plugins/org.mitk.gui.qt.moviemaker/resources/video-camera.svg index 2ea461af15..2cb2d02eae 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/resources/video-camera.svg +++ b/Plugins/org.mitk.gui.qt.moviemaker/resources/video-camera.svg @@ -1,54 +1,57 @@ image/svg+xml + + inkscape:current-layer="svg2" + units="px" /> + style="fill:#00ff00;fill-opacity:1;stroke:none;stroke-width:1.00000167" + inkscape:connector-curvature="0" /> diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.cpp b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.cpp index 12b65c6b6e..413aca9909 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.cpp +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.cpp @@ -1,448 +1,427 @@ /*=================================================================== 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 "QmitkScreenshotMaker.h" //#include "QmitkMovieMakerControls.h" #include "QmitkStepperAdapter.h" #include "mitkVtkPropRenderer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include "qapplication.h" #include "vtkImageWriter.h" #include "vtkJPEGWriter.h" #include "vtkPNGWriter.h" #include "vtkRenderLargeImage.h" #include "vtkRenderWindowInteractor.h" #include "vtkRenderer.h" #include "vtkTestUtilities.h" #include #include "vtkMitkRenderProp.h" #include #include #include "vtkRenderWindowInteractor.h" #include #include "mitkSliceNavigationController.h" #include "mitkPlanarFigure.h" QmitkScreenshotMaker::QmitkScreenshotMaker(QObject *parent, const char * /*name*/) : QmitkAbstractView(), m_Controls(nullptr), m_BackgroundColor(QColor(0,0,0)), m_SelectedNode(0) { parentWidget = parent; } QmitkScreenshotMaker::~QmitkScreenshotMaker() { } void QmitkScreenshotMaker::CreateConnections() { if (m_Controls) { connect((QObject*) m_Controls->m_AllViews, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateMultiplanar3DHighresScreenshot())); - connect((QObject*) m_Controls->m_View1, SIGNAL(clicked()), (QObject*) this, SLOT(View1())); - connect((QObject*) m_Controls->m_View2, SIGNAL(clicked()), (QObject*) this, SLOT(View2())); - connect((QObject*) m_Controls->m_View3, SIGNAL(clicked()), (QObject*) this, SLOT(View3())); connect((QObject*) m_Controls->m_Shot, SIGNAL(clicked()), (QObject*) this, SLOT(GenerateMultiplanarScreenshots())); connect((QObject*) m_Controls->m_BackgroundColor, SIGNAL(clicked()), (QObject*) this, SLOT(SelectBackgroundColor())); connect((QObject*) m_Controls->btnScreenshot, SIGNAL(clicked()), this, SLOT(GenerateScreenshot())); connect((QObject*) m_Controls->m_HRScreenshot, SIGNAL(clicked()), this, SLOT(Generate3DHighresScreenshot())); QString styleSheet = "background-color:rgb(0,0,0)"; m_Controls->m_BackgroundColor->setStyleSheet(styleSheet); } } void QmitkScreenshotMaker::GenerateScreenshot() { if (m_LastFile.size()==0) m_LastFile = QDir::currentPath()+"/screenshot.png"; QString filter; QString fileName = QFileDialog::getSaveFileName(nullptr, "Save screenshot to...", m_LastFile, m_PNGExtension + ";;" + m_JPGExtension, &filter); if (fileName.size()>0) m_LastFile = fileName; auto renderWindowPart = this->GetRenderWindowPart(OPEN); mitk::BaseRenderer* renderer = renderWindowPart->GetActiveQmitkRenderWindow()->GetRenderer(); renderer = nullptr; // WORKAROUND FOR T23702 if (renderer == nullptr) { renderer = renderWindowPart->GetQmitkRenderWindow(m_Controls->m_DirectionBox->currentText())->GetRenderer(); if (renderer == nullptr) return; } this->TakeScreenshot(renderer->GetVtkRenderer(), 1, fileName, filter); } void QmitkScreenshotMaker::GenerateMultiplanarScreenshots() { if (m_LastPath.size()==0) m_LastPath = QDir::currentPath(); QString filePath = QFileDialog::getExistingDirectory(nullptr, "Save screenshots to...", m_LastPath); if (filePath.size()>0) m_LastPath = filePath; if( filePath.isEmpty() ) { return; } //emit StartBlockControls(); auto renderWindowPart = this->GetRenderWindowPart(OPEN); renderWindowPart->EnableDecorations(false, QStringList{mitk::IRenderWindowPart::DECORATION_CORNER_ANNOTATION}); QString fileName = "/axial.png"; int c = 1; while (QFile::exists(filePath+fileName)) { fileName = QString("/axial_"); fileName += QString::number(c); fileName += ".png"; c++; } vtkRenderer* renderer = renderWindowPart->GetQmitkRenderWindow("axial")->GetRenderer()->GetVtkRenderer(); if (renderer != nullptr) this->TakeScreenshot(renderer, 1, filePath+fileName); fileName = "/sagittal.png"; c = 1; while (QFile::exists(filePath+fileName)) { fileName = QString("/sagittal_"); fileName += QString::number(c); fileName += ".png"; c++; } renderer = renderWindowPart->GetQmitkRenderWindow("sagittal")->GetRenderer()->GetVtkRenderer(); if (renderer != nullptr) this->TakeScreenshot(renderer, 1, filePath+fileName); fileName = "/coronal.png"; c = 1; while (QFile::exists(filePath+fileName)) { fileName = QString("/coronal_"); fileName += QString::number(c); fileName += ".png"; c++; } renderer = renderWindowPart->GetQmitkRenderWindow("coronal")->GetRenderer()->GetVtkRenderer(); if (renderer != nullptr) this->TakeScreenshot(renderer, 1, filePath+fileName); /// TODO I do not find a simple way of doing this through the render window part API, /// however, I am also not convinced that this code is needed at all. The colour /// of the crosshair planes is never set to any colour other than these. /// I suggest a new 'mitk::DataNode* mitk::ILinkedRendererPart::GetSlicingPlane(const std::string& name) const' /// function to introduce that could return the individual ("axial", "sagittal" or /// "coronal" crosshair planes. // mitk::DataNode* n = renderWindowPart->GetSlicingPlane("axial"); // if (n) // { // n->SetProperty( "color", mitk::ColorProperty::New( 1,0,0 ) ); // } // // n = renderWindowPart->GetSlicingPlane("sagittal"); // if (n) // { // n->SetProperty( "color", mitk::ColorProperty::New( 0,1,0 ) ); // } // // n = renderWindowPart->GetSlicingPlane("coronal"); // if (n) // { // n->SetProperty( "color", mitk::ColorProperty::New( 0,0,1 ) ); // } renderWindowPart->EnableDecorations(true, QStringList{mitk::IRenderWindowPart::DECORATION_CORNER_ANNOTATION}); } void QmitkScreenshotMaker::Generate3DHighresScreenshot() { if (m_LastFile.size()==0) m_LastFile = QDir::currentPath()+"/3D_screenshot.png"; QString filter; QString fileName = QFileDialog::getSaveFileName(nullptr, "Save screenshot to...", m_LastFile, m_PNGExtension + ";;" + m_JPGExtension, &filter); if (fileName.size()>0) m_LastFile = fileName; GenerateHR3DAtlasScreenshots(fileName, filter); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkScreenshotMaker::GenerateMultiplanar3DHighresScreenshot() { if (m_LastPath.size()==0) m_LastPath = QDir::currentPath(); QString filePath = QFileDialog::getExistingDirectory( nullptr, "Save screenshots to...", m_LastPath); if (filePath.size()>0) m_LastPath = filePath; if( filePath.isEmpty() ) { return; } QString fileName = "/3D_View1.png"; int c = 1; while (QFile::exists(filePath+fileName)) { fileName = QString("/3D_View1_"); fileName += QString::number(c); fileName += ".png"; c++; } GetCam()->Azimuth( -7.5 ); GetCam()->Roll(-4); GenerateHR3DAtlasScreenshots(filePath+fileName); GetCam()->Roll(4); fileName = "/3D_View2.png"; c = 1; while (QFile::exists(filePath+fileName)) { fileName = QString("/3D_View2_"); fileName += QString::number(c); fileName += ".png"; c++; } GetCam()->Azimuth( 90 ); GetCam()->Elevation( 4 ); GenerateHR3DAtlasScreenshots(filePath+fileName); fileName = "/3D_View3.png"; c = 1; while (QFile::exists(filePath+fileName)) { fileName = QString("/3D_View3_"); fileName += QString::number(c); fileName += ".png"; c++; } GetCam()->Elevation( 90 ); GetCam()->Roll( -2.5 ); GenerateHR3DAtlasScreenshots(filePath+fileName); mitk::RenderingManager::GetInstance()->RequestUpdateAll(); } void QmitkScreenshotMaker::GenerateHR3DAtlasScreenshots(QString fileName, QString filter) { // only works correctly for 3D RenderWindow this->GetRenderWindowPart()->EnableDecorations(false, QStringList{mitk::IRenderWindowPart::DECORATION_CORNER_ANNOTATION}); vtkRenderer* renderer = this->GetRenderWindowPart()->GetQmitkRenderWindow("3d")->GetRenderer()->GetVtkRenderer(); if (renderer == nullptr) return; this->TakeScreenshot(renderer, this->m_Controls->m_MagFactor->text().toFloat(), fileName, filter); this->GetRenderWindowPart()->EnableDecorations(true, QStringList{mitk::IRenderWindowPart::DECORATION_CORNER_ANNOTATION}); } vtkCamera* QmitkScreenshotMaker::GetCam() { mitk::BaseRenderer* renderer = this->GetRenderWindowPart(OPEN)->GetQmitkRenderWindow("3d")->GetRenderer(); vtkCamera* cam = 0; const mitk::VtkPropRenderer *propRenderer = dynamic_cast( renderer ); if (propRenderer) { // get vtk renderer vtkRenderer* vtkrenderer = propRenderer->GetVtkRenderer(); if (vtkrenderer) { // get vtk camera vtkCamera* vtkcam = vtkrenderer->GetActiveCamera(); if (vtkcam) { // vtk smart pointer handling cam = vtkcam; cam->Register( nullptr ); } } } return cam; } -void QmitkScreenshotMaker::View1() -{ - GetCam()->Elevation( 45 ); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); -} - -void QmitkScreenshotMaker::View2() -{ - GetCam()->Azimuth(45); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); -} - -void QmitkScreenshotMaker::View3() -{ - GetCam()->Roll(45); - mitk::RenderingManager::GetInstance()->RequestUpdateAll(); -} - void QmitkScreenshotMaker::OnSelectionChanged(berry::IWorkbenchPart::Pointer /*part*/, const QList& nodes) { if(nodes.size()) m_SelectedNode = nodes[0]; } void QmitkScreenshotMaker::CreateQtPartControl(QWidget *parent) { if (!m_Controls) { m_Parent = parent; m_Controls = new Ui::QmitkScreenshotMakerControls; m_Controls->setupUi(parent); // Initialize "Selected Window" combo box const mitk::RenderingManager::RenderWindowVector rwv = mitk::RenderingManager::GetInstance()->GetAllRegisteredRenderWindows(); } this->CreateConnections(); } void QmitkScreenshotMaker::SetFocus() { m_Controls->btnScreenshot->setFocus(); } void QmitkScreenshotMaker::RenderWindowPartActivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { m_Parent->setEnabled(true); } void QmitkScreenshotMaker::RenderWindowPartDeactivated(mitk::IRenderWindowPart* /*renderWindowPart*/) { m_Parent->setEnabled(false); } void QmitkScreenshotMaker::TakeScreenshot(vtkRenderer* renderer, unsigned int magnificationFactor, QString fileName, QString filter) { if ((renderer == nullptr) ||(magnificationFactor < 1) || fileName.isEmpty()) return; bool doubleBuffering( renderer->GetRenderWindow()->GetDoubleBuffer() ); renderer->GetRenderWindow()->DoubleBufferOff(); vtkImageWriter* fileWriter = nullptr; QFileInfo fi(fileName); QString suffix = fi.suffix().toLower(); if (suffix.isEmpty() || (suffix != "png" && suffix != "jpg" && suffix != "jpeg")) { if (filter == m_PNGExtension) { suffix = "png"; } else if (filter == m_JPGExtension) { suffix = "jpg"; } fileName += "." + suffix; } if (suffix.compare("jpg", Qt::CaseInsensitive) == 0 || suffix.compare("jpeg", Qt::CaseInsensitive) == 0) { vtkJPEGWriter* w = vtkJPEGWriter::New(); w->SetQuality(100); w->ProgressiveOff(); fileWriter = w; } else //default is png { fileWriter = vtkPNGWriter::New(); } vtkRenderLargeImage* magnifier = vtkRenderLargeImage::New(); magnifier->SetInput(renderer); magnifier->SetMagnification(magnificationFactor); //magnifier->Update(); fileWriter->SetInputConnection(magnifier->GetOutputPort()); fileWriter->SetFileName(fileName.toLatin1()); // vtkRenderLargeImage has problems with different layers, therefore we have to // temporarily deactivate all other layers. // we set the background to white, because it is nicer than black... double oldBackground[3]; renderer->GetBackground(oldBackground); // QColor color = QColorDialog::getColor(); double bgcolor[] = {m_BackgroundColor.red()/255.0, m_BackgroundColor.green()/255.0, m_BackgroundColor.blue()/255.0}; renderer->SetBackground(bgcolor); mitk::IRenderWindowPart* renderWindowPart = this->GetRenderWindowPart(); renderWindowPart->EnableDecorations(false); fileWriter->Write(); fileWriter->Delete(); renderWindowPart->EnableDecorations(true); renderer->SetBackground(oldBackground); renderer->GetRenderWindow()->SetDoubleBuffer(doubleBuffering); } void QmitkScreenshotMaker::SelectBackgroundColor() { m_BackgroundColor = QColorDialog::getColor(); m_Controls->m_BackgroundColor->setAutoFillBackground(true); QString styleSheet = "background-color:rgb("; styleSheet.append(QString::number(m_BackgroundColor.red())); styleSheet.append(","); styleSheet.append(QString::number(m_BackgroundColor.green())); styleSheet.append(","); styleSheet.append(QString::number(m_BackgroundColor.blue())); styleSheet.append(")"); m_Controls->m_BackgroundColor->setStyleSheet(styleSheet); } diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.h b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.h index d5028f4715..3fde4127d5 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.h +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMaker.h @@ -1,132 +1,129 @@ /*=================================================================== 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. ===================================================================*/ #if !defined(QMITK_ScreenshotMaker_H__INCLUDED) #define QMITK_ScreenshotMaker_H__INCLUDED #include #include #include "mitkCameraRotationController.h" #include "mitkStepper.h" #include "mitkMultiStepper.h" #include "mitkMovieGenerator.h" #include "itkCommand.h" #include "vtkEventQtSlotConnect.h" #include "vtkRenderWindow.h" #include "mitkVtkPropRenderer.h" #include "ui_QmitkScreenshotMakerControls.h" //#include "../MovieMakerDll.h" //class QmitkMovieMakerControls; class QmitkStepperAdapter; class vtkCamera; class QTimer; class QTime; /** * \brief View for creating movies (AVIs) */ class QmitkScreenshotMaker: public QmitkAbstractView, public mitk::IRenderWindowPartListener { Q_OBJECT public: /** \brief Constructor. */ QmitkScreenshotMaker(QObject *parent=0, const char *name=0); /** \brief Destructor. */ virtual ~QmitkScreenshotMaker(); /** \brief Method for creating the widget containing the application * controls, like sliders, buttons etc. */ virtual void CreateQtPartControl(QWidget *parent) override; // virtual QWidget * CreateControlWidget(QWidget *parent); /// /// Sets the focus to an internal widget. /// virtual void SetFocus() override; /** \brief Method for creating the connections of main and control widget. */ virtual void CreateConnections(); /** \brief Method for creating an QAction object, i.e. button & menu entry. * @param parent the parent QWidget */ // virtual QAction * CreateAction(QActionGroup *parent); /// /// Called when a RenderWindowPart becomes available. /// virtual void RenderWindowPartActivated(mitk::IRenderWindowPart* renderWindowPart) override; /// /// Called when a RenderWindowPart becomes unavailable. /// virtual void RenderWindowPartDeactivated(mitk::IRenderWindowPart* renderWindowPart) override; signals: protected slots: void GenerateScreenshot(); void GenerateMultiplanarScreenshots(); void Generate3DHighresScreenshot(); void GenerateMultiplanar3DHighresScreenshot(); - void View1(); - void View2(); - void View3(); void SelectBackgroundColor(); protected: QObject *parentWidget; QWidget* m_Parent; vtkEventQtSlotConnect * connections; vtkRenderWindow * renderWindow; mitk::VtkPropRenderer::Pointer m_PropRenderer; Ui::QmitkScreenshotMakerControls* m_Controls; private: virtual void OnSelectionChanged(berry::IWorkbenchPart::Pointer part, const QList& nodes) override; vtkCamera* GetCam(); void GenerateHR3DAtlasScreenshots(QString fileName, QString filter = ""); void GenerateMultiplanarScreenshots(QString fileName); /*! \brief taking a screenshot "from" the specified renderer \param magnificationFactor specifying the quality of the screenshot (the magnification of the actual RenderWindow size) \param fileName file location and name where the screenshot should be saved */ void TakeScreenshot(vtkRenderer* renderer, unsigned int magnificationFactor, QString fileName, QString filter = ""); QColor m_BackgroundColor; mitk::DataNode* m_SelectedNode; QString m_LastPath; QString m_LastFile; QString m_PNGExtension = "PNG File (*.png)"; QString m_JPGExtension = "JPEG File (*.jpg)"; }; #endif // !defined(QMITK_ScreenshotMaker_H__INCLUDED) diff --git a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMakerControls.ui b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMakerControls.ui index d406327559..f80d180dac 100644 --- a/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMakerControls.ui +++ b/Plugins/org.mitk.gui.qt.moviemaker/src/internal/QmitkScreenshotMakerControls.ui @@ -1,241 +1,175 @@ QmitkScreenshotMakerControls 0 0 315 368 ScreenshotMaker 2D Screenshots axial coronal sagittal Single Multiplanar 3D Screenshots (High-res) Single Multiplanar 0 0 Upsampling: 1 4 Options - - - - 30 - 30 - - - - - 30 - 30 - - - - Rotate 3D camera 45° around x-axis. - - - x - - - - - - - - 30 - 30 - - - - - 30 - 30 - - - - Rotate 3D camera 45° around y-axis. - + - y + Background Color: - + 30 30 30 30 - - Rotate 3D camera 45° around z-axis. - - z + Qt::Horizontal - 36 + 40 20 - - - - Background Color: - - - - - - - - 30 - 30 - - - - - 30 - 30 - - - - - - - Qt::Vertical 20 31 diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.cpp b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.cpp index b06e0921fe..00d418896c 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.cpp +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.cpp @@ -1,69 +1,64 @@ /*=================================================================== 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 "mitkPluginActivator.h" #include "QmitkMultiLabelSegmentationView.h" #include "QmitkThresholdAction.h" #include "QmitkCreatePolygonModelAction.h" #include "QmitkAutocropAction.h" #include "QmitkConvertSurfaceToLabelAction.h" #include "QmitkConvertMaskToLabelAction.h" #include "QmitkConvertToMultiLabelSegmentationAction.h" #include "QmitkCreateMultiLabelSegmentationAction.h" #include "QmitkMultiLabelSegmentationPreferencePage.h" #include "QmitkLoadMultiLabelPresetAction.h" #include "QmitkCreateMultiLabelPresetAction.h" #include "SegmentationUtilities/QmitkMultiLabelSegmentationUtilitiesView.h" #include ctkPluginContext* mitk::PluginActivator::m_Context = nullptr; //MLI TODO US_INITIALIZE_MODULE //("MultiLabelSegmentation", "liborg_mitk_gui_qt_multilabelsegmentation") void mitk::PluginActivator::start(ctkPluginContext *context) { BERRY_REGISTER_EXTENSION_CLASS(QmitkMultiLabelSegmentationView, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkThresholdAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkCreatePolygonModelAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkAutocropAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkConvertSurfaceToLabelAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkConvertMaskToLabelAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkConvertToMultiLabelSegmentationAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkCreateMultiLabelSegmentationAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkCreateMultiLabelPresetAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkLoadMultiLabelPresetAction, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkMultiLabelSegmentationPreferencePage, context) BERRY_REGISTER_EXTENSION_CLASS(QmitkMultiLabelSegmentationUtilitiesView, context) m_Context = context; } -void mitk::PluginActivator::stop(ctkPluginContext* context) +void mitk::PluginActivator::stop(ctkPluginContext*) { - Q_UNUSED(context) - m_Context = nullptr; } ctkPluginContext* mitk::PluginActivator::getContext() { return m_Context; } - -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) -Q_EXPORT_PLUGIN2(org_mitk_gui_qt_multilabelsegmentation, mitk::PluginActivator) -#endif diff --git a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.h b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.h index b2fe5addce..af9792be73 100644 --- a/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.h +++ b/Plugins/org.mitk.gui.qt.multilabelsegmentation/src/internal/mitkPluginActivator.h @@ -1,44 +1,41 @@ /*=================================================================== 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 MITKPLUGINACTIVATOR_H -#define MITKPLUGINACTIVATOR_H -// Parent classes -#include +#ifndef org_mitk_gui_qt_multilabelsegmentation_Activator_h +#define org_mitk_gui_qt_multilabelsegmentation_Activator_h + #include namespace mitk { class PluginActivator : public QObject, public ctkPluginActivator { Q_OBJECT -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) - Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_multilabelsegmentation") -#endif + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_multilabelsegmentation") Q_INTERFACES(ctkPluginActivator) public: void start(ctkPluginContext *context); void stop(ctkPluginContext *context); static ctkPluginContext* getContext(); private: static ctkPluginContext* m_Context; }; } #endif diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/resources/pai.svg b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/resources/pai.svg index da31b05f86..8002f7c6ec 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/resources/pai.svg +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/resources/pai.svg @@ -1,49 +1,49 @@ image/svg+xml \ No newline at end of file + style="stroke:none;fill:#00ff00;fill-opacity:1" /> diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/org_mitk_gui_qt_photoacoustics_imageprocessing_Activator.cpp b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/org_mitk_gui_qt_photoacoustics_imageprocessing_Activator.cpp index 9b447585f8..42459b35e7 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/org_mitk_gui_qt_photoacoustics_imageprocessing_Activator.cpp +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/org_mitk_gui_qt_photoacoustics_imageprocessing_Activator.cpp @@ -1,40 +1,27 @@ /*=================================================================== 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 "org_mitk_gui_qt_photoacoustics_imageprocessing_Activator.h" - -#include - #include "PAImageProcessing.h" -namespace mitk { - -void org_mitk_gui_qt_photoacoustics_imageprocessing_Activator::start(ctkPluginContext* context) +void mitk::org_mitk_gui_qt_photoacoustics_imageprocessing_Activator::start(ctkPluginContext* context) { BERRY_REGISTER_EXTENSION_CLASS(PAImageProcessing, context) } -void org_mitk_gui_qt_photoacoustics_imageprocessing_Activator::stop(ctkPluginContext* context) +void mitk::org_mitk_gui_qt_photoacoustics_imageprocessing_Activator::stop(ctkPluginContext*) { - Q_UNUSED(context) } - -} - -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - Q_EXPORT_PLUGIN2(org_mitk_gui_qt_photoacoustics_imageprocessing, mitk::org_mitk_gui_qt_photoacoustics_imageprocessing_Activator) -#endif diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/org_mitk_gui_qt_photoacoustics_imageprocessing_Activator.h b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/org_mitk_gui_qt_photoacoustics_imageprocessing_Activator.h index ef25444bcd..149114d452 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/org_mitk_gui_qt_photoacoustics_imageprocessing_Activator.h +++ b/Plugins/org.mitk.gui.qt.photoacoustics.imageprocessing/src/internal/org_mitk_gui_qt_photoacoustics_imageprocessing_Activator.h @@ -1,43 +1,36 @@ /*=================================================================== 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 org_mitk_gui_qt_photoacoustics_imageprocessing_Activator_h #define org_mitk_gui_qt_photoacoustics_imageprocessing_Activator_h #include -namespace mitk { - -class org_mitk_gui_qt_photoacoustics_imageprocessing_Activator : - public QObject, public ctkPluginActivator +namespace mitk { - Q_OBJECT -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) - Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_photoacoustics_imageprocessing") -#endif - Q_INTERFACES(ctkPluginActivator) - -public: - - void start(ctkPluginContext* context); - void stop(ctkPluginContext* context); - -}; // org_mitk_gui_qt_photoacoustics_imageprocessing_Activator - + class org_mitk_gui_qt_photoacoustics_imageprocessing_Activator : public QObject, public ctkPluginActivator + { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_photoacoustics_imageprocessing") + Q_INTERFACES(ctkPluginActivator) + + public: + void start(ctkPluginContext* context); + void stop(ctkPluginContext* context); + }; } -#endif // org_mitk_gui_qt_photoacoustics_imageprocessing_Activator_h +#endif diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/resources/iconPAUSViewer.svg b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/resources/iconPAUSViewer.svg index 8e87197c19..fa91872af4 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/resources/iconPAUSViewer.svg +++ b/Plugins/org.mitk.gui.qt.photoacoustics.pausviewer/resources/iconPAUSViewer.svg @@ -1,62 +1,62 @@ image/svg+xml \ No newline at end of file + y="1301.3301" /> diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/resources/pai_simulation.svg b/Plugins/org.mitk.gui.qt.photoacoustics.simulation/resources/pai_simulation.svg index ab962c118b..23e71640e5 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/resources/pai_simulation.svg +++ b/Plugins/org.mitk.gui.qt.photoacoustics.simulation/resources/pai_simulation.svg @@ -1,74 +1,74 @@ image/svg+xml \ No newline at end of file + style="fill:none;stroke:#00ff00;stroke-width:56.69291306;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1" /> diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/org_mitk_gui_qt_photoacousticsimulation_Activator.cpp b/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/org_mitk_gui_qt_photoacousticsimulation_Activator.cpp index 397fe254f5..67678aa34b 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/org_mitk_gui_qt_photoacousticsimulation_Activator.cpp +++ b/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/org_mitk_gui_qt_photoacousticsimulation_Activator.cpp @@ -1,40 +1,27 @@ /*=================================================================== 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 "org_mitk_gui_qt_photoacousticsimulation_Activator.h" - -#include - #include "PASimulator.h" -namespace mitk { - -void org_mitk_gui_qt_photoacousticsimulation_Activator::start(ctkPluginContext* context) +void mitk::org_mitk_gui_qt_photoacousticsimulation_Activator::start(ctkPluginContext* context) { BERRY_REGISTER_EXTENSION_CLASS(PASimulator, context) } -void org_mitk_gui_qt_photoacousticsimulation_Activator::stop(ctkPluginContext* context) +void mitk::org_mitk_gui_qt_photoacousticsimulation_Activator::stop(ctkPluginContext*) { - Q_UNUSED(context) } - -} - -#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0) - Q_EXPORT_PLUGIN2(org_mitk_gui_qt_photoacousticsimulation, mitk::org_mitk_gui_qt_photoacousticsimulation_Activator) -#endif diff --git a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/org_mitk_gui_qt_photoacousticsimulation_Activator.h b/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/org_mitk_gui_qt_photoacousticsimulation_Activator.h index 76472b6d88..deb9da09c3 100644 --- a/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/org_mitk_gui_qt_photoacousticsimulation_Activator.h +++ b/Plugins/org.mitk.gui.qt.photoacoustics.simulation/src/internal/org_mitk_gui_qt_photoacousticsimulation_Activator.h @@ -1,43 +1,36 @@ /*=================================================================== 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 org_mitk_gui_qt_photoacousticsimulation_Activator_h #define org_mitk_gui_qt_photoacousticsimulation_Activator_h #include -namespace mitk { - -class org_mitk_gui_qt_photoacousticsimulation_Activator : - public QObject, public ctkPluginActivator +namespace mitk { - Q_OBJECT -#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0) - Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_photoacousticsimulation") -#endif - Q_INTERFACES(ctkPluginActivator) - -public: - - void start(ctkPluginContext* context); - void stop(ctkPluginContext* context); - -}; // org_mitk_gui_qt_photoacousticsimulation_Activator - + class org_mitk_gui_qt_photoacousticsimulation_Activator : public QObject, public ctkPluginActivator + { + Q_OBJECT + Q_PLUGIN_METADATA(IID "org_mitk_gui_qt_photoacousticsimulation") + Q_INTERFACES(ctkPluginActivator) + + public: + void start(ctkPluginContext* context); + void stop(ctkPluginContext* context); + }; } -#endif // org_mitk_gui_qt_photoacousticsimulation_Activator_h +#endif diff --git a/Plugins/org.mitk.gui.qt.pointsetinteraction/plugin.xml b/Plugins/org.mitk.gui.qt.pointsetinteraction/plugin.xml index 0f6f71c23d..6abe4aa718 100644 --- a/Plugins/org.mitk.gui.qt.pointsetinteraction/plugin.xml +++ b/Plugins/org.mitk.gui.qt.pointsetinteraction/plugin.xml @@ -1,10 +1,10 @@ diff --git a/Plugins/org.mitk.gui.qt.preprocessing.resampling/plugin.xml b/Plugins/org.mitk.gui.qt.preprocessing.resampling/plugin.xml index 98e852ca8a..54ddf557d0 100644 --- a/Plugins/org.mitk.gui.qt.preprocessing.resampling/plugin.xml +++ b/Plugins/org.mitk.gui.qt.preprocessing.resampling/plugin.xml @@ -1,20 +1,20 @@ - + Resampling an Image to an specific sizes diff --git a/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingViewControls.ui b/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingViewControls.ui index da47359e1b..46da982a20 100644 --- a/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingViewControls.ui +++ b/Plugins/org.mitk.gui.qt.preprocessing.resampling/src/internal/QmitkPreprocessingResamplingViewControls.ui @@ -1,316 +1,286 @@ QmitkPreprocessingResamplingViewControls 0 0 448 980 Form - Resample multiple images + Resample all selected images - - true - - - 0 - - - 6 - - - 0 - - - 6 - - Select an Image in Data Manager + Select an image in the Data Manager true false Output image will be 3D Choose time step if 4D (Slider for both images) false false Output image will be 3D Qt::Vertical 254 403 Resample single image - - true - - - 0 - - - 6 - - - 0 - - - 0 - true 0 0 Qt::LeftToRight Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter 5 -100.000000000000000 100.000000000000000 1.000000000000000 true 0 0 5 -100.000000000000000 100.000000000000000 1.000000000000000 true 0 0 5 -100.000000000000000 100.000000000000000 1.000000000000000 false Resampling Parameter false false x-spacing false false y-spacing false false Hide Original Image true false z-spacing false Interpolation: true 0 0 QmitkSliderNavigatorWidget QWidget
QmitkSliderNavigatorWidget.h
dsbParam1 dsbParam2 dsbParam3 cbParam4 cbHideOrig btnDoIt buttonExecuteOnMultipleImages leImage1
diff --git a/Plugins/org.mitk.gui.qt.properties/resources/property_list.svg b/Plugins/org.mitk.gui.qt.properties/resources/property_list.svg index fc92b414ed..d0e8f3e4ae 100644 --- a/Plugins/org.mitk.gui.qt.properties/resources/property_list.svg +++ b/Plugins/org.mitk.gui.qt.properties/resources/property_list.svg @@ -1,54 +1,54 @@ image/svg+xml diff --git a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation_IMGLiveWireUsage.PNG b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation_IMGLiveWireUsage.PNG index 85e7b4e2aa..88e58d95d8 100644 Binary files a/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation_IMGLiveWireUsage.PNG and b/Plugins/org.mitk.gui.qt.segmentation/documentation/UserManual/QmitkSegmentation_IMGLiveWireUsage.PNG differ diff --git a/Plugins/org.mitk.gui.qt.segmentation/plugin.xml b/Plugins/org.mitk.gui.qt.segmentation/plugin.xml index 322e175fee..56282d66a3 100644 --- a/Plugins/org.mitk.gui.qt.segmentation/plugin.xml +++ b/Plugins/org.mitk.gui.qt.segmentation/plugin.xml @@ -1,94 +1,94 @@ Allows the segmentation of images using different tools. - + Edit segmentations using standard operations. diff --git a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilViewControls.ui b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilViewControls.ui index b18eaa0099..ac4f331307 100644 --- a/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilViewControls.ui +++ b/Plugins/org.mitk.gui.qt.tofutil/src/internal/QmitkToFUtilViewControls.ui @@ -1,121 +1,121 @@ QmitkToFUtilViewControls 0 0 466 452 0 0 QmitkTemplate - - + + - - - - Qt::Vertical - - - - 20 - 311 - - - - - + 0 0 - + 0 0 - - - - + true 0 0 - + + + + + + + + Qt::Vertical + + + + 20 + 311 + + + + QmitkToFRecorderWidget QWidget
QmitkToFRecorderWidget.h
1
QmitkToFVisualisationSettingsWidget QWidget
QmitkToFVisualisationSettingsWidget.h
1
QmitkToFCompositeFilterWidget QWidget
QmitkToFCompositeFilterWidget.h
1
QmitkToFPointSetWidget QWidget
QmitkToFPointSetWidget.h
1
QmitkToFConnectionWidget QWidget
QmitkToFConnectionWidget.h
1
QmitkToFSurfaceGenerationWidget QWidget
QmitkToFSurfaceGenerationWidget.h
1
diff --git a/Plugins/org.mitk.gui.qt.viewnavigator/resources/view-manager.svg b/Plugins/org.mitk.gui.qt.viewnavigator/resources/view-manager.svg index 42903c095d..e86842ff3d 100644 --- a/Plugins/org.mitk.gui.qt.viewnavigator/resources/view-manager.svg +++ b/Plugins/org.mitk.gui.qt.viewnavigator/resources/view-manager.svg @@ -1,54 +1,57 @@ image/svg+xml + + inkscape:zoom="4" + inkscape:cx="216.70067" + inkscape:cy="104.11174" + inkscape:window-x="-8" + inkscape:window-y="-8" + inkscape:window-maximized="1" + inkscape:current-layer="svg2" + units="px" /> + style="fill:#00ff00;fill-opacity:1;stroke-width:1.00000525" + inkscape:connector-curvature="0" /> diff --git a/SuperBuild.cmake b/SuperBuild.cmake index d89a677015..fb9dbcfcf0 100644 --- a/SuperBuild.cmake +++ b/SuperBuild.cmake @@ -1,456 +1,453 @@ include(mitkFunctionInstallExternalCMakeProject) #----------------------------------------------------------------------------- # Convenient macro allowing to download a file #----------------------------------------------------------------------------- if(NOT MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL) set(MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL http://mitk.org/download/thirdparty) endif() macro(downloadFile url dest) file(DOWNLOAD ${url} ${dest} STATUS status) list(GET status 0 error_code) list(GET status 1 error_msg) if(error_code) message(FATAL_ERROR "error: Failed to download ${url} - ${error_msg}") endif() endmacro() #----------------------------------------------------------------------------- # MITK Prerequisites #----------------------------------------------------------------------------- if(UNIX AND NOT APPLE) include(mitkFunctionCheckPackageHeader) # Check for libxt-dev mitkFunctionCheckPackageHeader(StringDefs.h libxt-dev /usr/include/X11/) # Check for libtiff4-dev mitkFunctionCheckPackageHeader(tiff.h libtiff4-dev) - # Check for libwrap0-dev - mitkFunctionCheckPackageHeader(tcpd.h libwrap0-dev) - endif() # We need a proper patch program. On Linux and MacOS, we assume # that "patch" is available. On Windows, we download patch.exe # if not patch program is found. find_program(PATCH_COMMAND patch) if((NOT PATCH_COMMAND OR NOT EXISTS ${PATCH_COMMAND}) AND WIN32) downloadFile(${MITK_THIRDPARTY_DOWNLOAD_PREFIX_URL}/patch.exe ${CMAKE_CURRENT_BINARY_DIR}/patch.exe) find_program(PATCH_COMMAND patch ${CMAKE_CURRENT_BINARY_DIR}) endif() if(NOT PATCH_COMMAND) message(FATAL_ERROR "No patch program found.") endif() #----------------------------------------------------------------------------- # ExternalProjects #----------------------------------------------------------------------------- get_property(external_projects GLOBAL PROPERTY MITK_EXTERNAL_PROJECTS) if(MITK_CTEST_SCRIPT_MODE) # Write a file containing the list of enabled external project targets. # This file can be read by a ctest script to separately build projects. set(SUPERBUILD_TARGETS ) foreach(proj ${external_projects}) if(MITK_USE_${proj}) list(APPEND SUPERBUILD_TARGETS ${proj}) endif() endforeach() file(WRITE "${CMAKE_BINARY_DIR}/SuperBuildTargets.cmake" "set(SUPERBUILD_TARGETS ${SUPERBUILD_TARGETS})") endif() # A list of "nice" external projects, playing well together with CMake set(nice_external_projects ${external_projects}) list(REMOVE_ITEM nice_external_projects Boost Python) foreach(proj ${nice_external_projects}) if(MITK_USE_${proj}) set(EXTERNAL_${proj}_DIR "${${proj}_DIR}" CACHE PATH "Path to ${proj} build directory") mark_as_advanced(EXTERNAL_${proj}_DIR) if(EXTERNAL_${proj}_DIR) set(${proj}_DIR ${EXTERNAL_${proj}_DIR}) endif() endif() endforeach() set(EXTERNAL_BOOST_ROOT "${BOOST_ROOT}" CACHE PATH "Path to Boost directory") mark_as_advanced(EXTERNAL_BOOST_ROOT) if(EXTERNAL_BOOST_ROOT) set(BOOST_ROOT ${EXTERNAL_BOOST_ROOT}) endif() # Setup file for setting custom ctest vars configure_file( CMake/SuperbuildCTestCustom.cmake.in ${MITK_BINARY_DIR}/CTestCustom.cmake @ONLY ) if(BUILD_TESTING) set(EXTERNAL_MITK_DATA_DIR "${MITK_DATA_DIR}" CACHE PATH "Path to the MITK data directory") mark_as_advanced(EXTERNAL_MITK_DATA_DIR) if(EXTERNAL_MITK_DATA_DIR) set(MITK_DATA_DIR ${EXTERNAL_MITK_DATA_DIR}) endif() endif() #----------------------------------------------------------------------------- # External project settings #----------------------------------------------------------------------------- include(ExternalProject) set(ep_prefix "${CMAKE_BINARY_DIR}/ep") set_property(DIRECTORY PROPERTY EP_PREFIX ${ep_prefix}) # Compute -G arg for configuring external projects with the same CMake generator: if(CMAKE_EXTRA_GENERATOR) set(gen "${CMAKE_EXTRA_GENERATOR} - ${CMAKE_GENERATOR}") else() set(gen "${CMAKE_GENERATOR}") endif() # Use this value where semi-colons are needed in ep_add args: set(sep "^^") ## if(MSVC_VERSION) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /bigobj /MP") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /bigobj /MP") endif() # This is a workaround for passing linker flags # actually down to the linker invocation set(_cmake_required_flags_orig ${CMAKE_REQUIRED_FLAGS}) set(CMAKE_REQUIRED_FLAGS "-Wl,-rpath") mitkFunctionCheckCompilerFlags(${CMAKE_REQUIRED_FLAGS} _has_rpath_flag) set(CMAKE_REQUIRED_FLAGS ${_cmake_required_flags_orig}) set(_install_rpath_linkflag ) if(_has_rpath_flag) if(APPLE) set(_install_rpath_linkflag "-Wl,-rpath,@loader_path/../lib") else() set(_install_rpath_linkflag "-Wl,-rpath='$ORIGIN/../lib'") endif() endif() set(_install_rpath) if(APPLE) set(_install_rpath "@loader_path/../lib") elseif(UNIX) # this work for libraries as well as executables set(_install_rpath "\$ORIGIN/../lib") endif() set(ep_common_args -DCMAKE_CXX_EXTENSIONS:STRING=${CMAKE_CXX_EXTENSIONS} -DCMAKE_CXX_STANDARD:STRING=${CMAKE_CXX_STANDARD} -DCMAKE_CXX_STANDARD_REQUIRED:BOOL=${CMAKE_CXX_STANDARD_REQUIRED} -DCMAKE_MACOSX_RPATH:BOOL=TRUE "-DCMAKE_INSTALL_RPATH:STRING=${_install_rpath}" -DBUILD_TESTING:BOOL=OFF -DCMAKE_INSTALL_PREFIX:PATH= -DBUILD_SHARED_LIBS:BOOL=ON -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} -DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} "-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} ${MITK_CXX14_FLAG}" #debug flags -DCMAKE_CXX_FLAGS_DEBUG:STRING=${CMAKE_CXX_FLAGS_DEBUG} -DCMAKE_C_FLAGS_DEBUG:STRING=${CMAKE_C_FLAGS_DEBUG} #release flags -DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE} -DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE} #relwithdebinfo -DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DCMAKE_C_FLAGS_RELWITHDEBINFO:STRING=${CMAKE_C_FLAGS_RELWITHDEBINFO} #link flags -DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS} -DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS} -DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_MODULE_LINKER_FLAGS} ) set(DCMTK_CMAKE_DEBUG_POSTFIX ) # python libraries wont work with it if(NOT MITK_USE_Python) list(APPEND ep_common_args -DCMAKE_DEBUG_POSTFIX:STRING=d) set(DCMTK_CMAKE_DEBUG_POSTFIX d) endif() set(ep_common_cache_args ) set(ep_common_cache_default_args "-DCMAKE_PREFIX_PATH:PATH=;${CMAKE_PREFIX_PATH}" "-DCMAKE_INCLUDE_PATH:PATH=${CMAKE_INCLUDE_PATH}" "-DCMAKE_LIBRARY_PATH:PATH=${CMAKE_LIBRARY_PATH}" ) # Pass the CMAKE_OSX variables to external projects if(APPLE) set(MAC_OSX_ARCHITECTURE_ARGS -DCMAKE_OSX_ARCHITECTURES:PATH=${CMAKE_OSX_ARCHITECTURES} -DCMAKE_OSX_DEPLOYMENT_TARGET:PATH=${CMAKE_OSX_DEPLOYMENT_TARGET} -DCMAKE_OSX_SYSROOT:PATH=${CMAKE_OSX_SYSROOT} ) set(ep_common_args ${MAC_OSX_ARCHITECTURE_ARGS} ${ep_common_args} ) endif() set(mitk_superbuild_ep_args) set(mitk_depends ) # Include external projects include(CMakeExternals/MITKData.cmake) foreach(p ${external_projects}) if(EXISTS ${CMAKE_SOURCE_DIR}/CMakeExternals/${p}.cmake) include(CMakeExternals/${p}.cmake) else() foreach(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIRS}) get_filename_component(MITK_EXTENSION_DIR ${MITK_EXTENSION_DIR} ABSOLUTE) set(MITK_CMAKE_EXTERNALS_EXTENSION_DIR ${MITK_EXTENSION_DIR}/CMakeExternals) if(EXISTS ${MITK_CMAKE_EXTERNALS_EXTENSION_DIR}/${p}.cmake) include(${MITK_CMAKE_EXTERNALS_EXTENSION_DIR}/${p}.cmake) break() endif() endforeach() endif() list(APPEND mitk_superbuild_ep_args -DMITK_USE_${p}:BOOL=${MITK_USE_${p}} ) get_property(_package GLOBAL PROPERTY MITK_${p}_PACKAGE) if(_package) list(APPEND mitk_superbuild_ep_args -D${p}_DIR:PATH=${${p}_DIR}) endif() list(APPEND mitk_depends ${${p}_DEPENDS}) endforeach() if (SWIG_EXECUTABLE) list(APPEND mitk_superbuild_ep_args -DSWIG_EXECUTABLE=${SWIG_EXECUTABLE}) endif() #----------------------------------------------------------------------------- # Set superbuild boolean args #----------------------------------------------------------------------------- set(mitk_cmake_boolean_args BUILD_SHARED_LIBS WITH_COVERAGE BUILD_TESTING MITK_BUILD_ALL_PLUGINS MITK_BUILD_ALL_APPS MITK_BUILD_EXAMPLES MITK_USE_Qt5 MITK_USE_SYSTEM_Boost MITK_USE_BLUEBERRY MITK_USE_OpenCL MITK_ENABLE_PIC_READER ) #----------------------------------------------------------------------------- # Create the final variable containing superbuild boolean args #----------------------------------------------------------------------------- set(mitk_superbuild_boolean_args) foreach(mitk_cmake_arg ${mitk_cmake_boolean_args}) list(APPEND mitk_superbuild_boolean_args -D${mitk_cmake_arg}:BOOL=${${mitk_cmake_arg}}) endforeach() if(MITK_BUILD_ALL_PLUGINS) list(APPEND mitk_superbuild_boolean_args -DBLUEBERRY_BUILD_ALL_PLUGINS:BOOL=ON) endif() #----------------------------------------------------------------------------- # MITK Utilities #----------------------------------------------------------------------------- set(proj MITK-Utilities) ExternalProject_Add(${proj} DOWNLOAD_COMMAND "" CONFIGURE_COMMAND "" BUILD_COMMAND "" INSTALL_COMMAND "" DEPENDS ${mitk_depends} ) #----------------------------------------------------------------------------- # Additional MITK CXX/C Flags #----------------------------------------------------------------------------- set(MITK_ADDITIONAL_C_FLAGS "" CACHE STRING "Additional C Flags for MITK") set(MITK_ADDITIONAL_C_FLAGS_RELEASE "" CACHE STRING "Additional Release C Flags for MITK") set(MITK_ADDITIONAL_C_FLAGS_DEBUG "" CACHE STRING "Additional Debug C Flags for MITK") mark_as_advanced(MITK_ADDITIONAL_C_FLAGS MITK_ADDITIONAL_C_FLAGS_DEBUG MITK_ADDITIONAL_C_FLAGS_RELEASE) set(MITK_ADDITIONAL_CXX_FLAGS "" CACHE STRING "Additional CXX Flags for MITK") set(MITK_ADDITIONAL_CXX_FLAGS_RELEASE "" CACHE STRING "Additional Release CXX Flags for MITK") set(MITK_ADDITIONAL_CXX_FLAGS_DEBUG "" CACHE STRING "Additional Debug CXX Flags for MITK") mark_as_advanced(MITK_ADDITIONAL_CXX_FLAGS MITK_ADDITIONAL_CXX_FLAGS_DEBUG MITK_ADDITIONAL_CXX_FLAGS_RELEASE) set(MITK_ADDITIONAL_EXE_LINKER_FLAGS "" CACHE STRING "Additional exe linker flags for MITK") set(MITK_ADDITIONAL_SHARED_LINKER_FLAGS "" CACHE STRING "Additional shared linker flags for MITK") set(MITK_ADDITIONAL_MODULE_LINKER_FLAGS "" CACHE STRING "Additional module linker flags for MITK") mark_as_advanced(MITK_ADDITIONAL_EXE_LINKER_FLAGS MITK_ADDITIONAL_SHARED_LINKER_FLAGS MITK_ADDITIONAL_MODULE_LINKER_FLAGS) #----------------------------------------------------------------------------- # MITK Configure #----------------------------------------------------------------------------- if(MITK_INITIAL_CACHE_FILE) set(mitk_initial_cache_arg -C "${MITK_INITIAL_CACHE_FILE}") endif() set(mitk_optional_cache_args ) foreach(type RUNTIME ARCHIVE LIBRARY) if(DEFINED CTK_PLUGIN_${type}_OUTPUT_DIRECTORY) list(APPEND mitk_optional_cache_args -DCTK_PLUGIN_${type}_OUTPUT_DIRECTORY:PATH=${CTK_PLUGIN_${type}_OUTPUT_DIRECTORY}) endif() endforeach() # Optional python variables if(MITK_USE_Python) list(APPEND mitk_optional_cache_args -DMITK_USE_Python:BOOL=${MITK_USE_Python} -DPYTHON_EXECUTABLE:FILEPATH=${PYTHON_EXECUTABLE} -DPYTHON_INCLUDE_DIR:PATH=${PYTHON_INCLUDE_DIR} -DPYTHON_LIBRARY:FILEPATH=${PYTHON_LIBRARY} -DPYTHON_INCLUDE_DIR2:PATH=${PYTHON_INCLUDE_DIR2} ) endif() if(Eigen_INCLUDE_DIR) list(APPEND mitk_optional_cache_args -DEigen_INCLUDE_DIR:PATH=${Eigen_INCLUDE_DIR} ) endif() set(proj MITK-Configure) ExternalProject_Add(${proj} LIST_SEPARATOR ${sep} DOWNLOAD_COMMAND "" CMAKE_GENERATOR ${gen} CMAKE_CACHE_ARGS # --------------- Build options ---------------- -DCMAKE_INSTALL_PREFIX:PATH=${CMAKE_INSTALL_PREFIX} -DCMAKE_BUILD_TYPE:STRING=${CMAKE_BUILD_TYPE} "-DCMAKE_PREFIX_PATH:PATH=${ep_prefix};${CMAKE_PREFIX_PATH}" "-DCMAKE_LIBRARY_PATH:PATH=${CMAKE_LIBRARY_PATH}" "-DCMAKE_INCLUDE_PATH:PATH=${CMAKE_INCLUDE_PATH}" # --------------- Compile options ---------------- -DCMAKE_CXX_EXTENSIONS:STRING=${CMAKE_CXX_EXTENSIONS} -DCMAKE_CXX_STANDARD:STRING=${CMAKE_CXX_STANDARD} -DCMAKE_CXX_STANDARD_REQUIRED:BOOL=${CMAKE_CXX_STANDARD_REQUIRED} -DCMAKE_C_COMPILER:FILEPATH=${CMAKE_C_COMPILER} -DCMAKE_CXX_COMPILER:FILEPATH=${CMAKE_CXX_COMPILER} "-DCMAKE_C_FLAGS:STRING=${CMAKE_C_FLAGS} ${MITK_ADDITIONAL_C_FLAGS}" "-DCMAKE_CXX_FLAGS:STRING=${CMAKE_CXX_FLAGS} ${MITK_ADDITIONAL_CXX_FLAGS}" # debug flags "-DCMAKE_CXX_FLAGS_DEBUG:STRING=${CMAKE_CXX_FLAGS_DEBUG} ${MITK_ADDITIONAL_CXX_FLAGS_DEBUG}" "-DCMAKE_C_FLAGS_DEBUG:STRING=${CMAKE_C_FLAGS_DEBUG} ${MITK_ADDITIONAL_C_FLAGS_DEBUG}" # release flags "-DCMAKE_CXX_FLAGS_RELEASE:STRING=${CMAKE_CXX_FLAGS_RELEASE} ${MITK_ADDITIONAL_CXX_FLAGS_RELEASE}" "-DCMAKE_C_FLAGS_RELEASE:STRING=${CMAKE_C_FLAGS_RELEASE} ${MITK_ADDITIONAL_C_FLAGS_RELEASE}" # relwithdebinfo -DCMAKE_CXX_FLAGS_RELWITHDEBINFO:STRING=${CMAKE_CXX_FLAGS_RELWITHDEBINFO} -DCMAKE_C_FLAGS_RELWITHDEBINFO:STRING=${CMAKE_C_FLAGS_RELWITHDEBINFO} # link flags "-DCMAKE_EXE_LINKER_FLAGS:STRING=${CMAKE_EXE_LINKER_FLAGS} ${MITK_ADDITIONAL_EXE_LINKER_FLAGS}" "-DCMAKE_SHARED_LINKER_FLAGS:STRING=${CMAKE_SHARED_LINKER_FLAGS} ${MITK_ADDITIONAL_SHARED_LINKER_FLAGS}" "-DCMAKE_MODULE_LINKER_FLAGS:STRING=${CMAKE_MODULE_LINKER_FLAGS} ${MITK_ADDITIONAL_MODULE_LINKER_FLAGS}" # Output directories -DMITK_CMAKE_LIBRARY_OUTPUT_DIRECTORY:PATH=${MITK_CMAKE_LIBRARY_OUTPUT_DIRECTORY} -DMITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY:PATH=${MITK_CMAKE_RUNTIME_OUTPUT_DIRECTORY} -DMITK_CMAKE_ARCHIVE_OUTPUT_DIRECTORY:PATH=${MITK_CMAKE_ARCHIVE_OUTPUT_DIRECTORY} # ------------- Boolean build options -------------- ${mitk_superbuild_boolean_args} ${mitk_optional_cache_args} -DMITK_USE_SUPERBUILD:BOOL=OFF -DMITK_BUILD_CONFIGURATION:STRING=${MITK_BUILD_CONFIGURATION} -DCTEST_USE_LAUNCHERS:BOOL=${CTEST_USE_LAUNCHERS} # ----------------- Miscellaneous --------------- -DCMAKE_LIBRARY_PATH:PATH=${CMAKE_LIBRARY_PATH} -DCMAKE_INCLUDE_PATH:PATH=${CMAKE_INCLUDE_PATH} -DMITK_CTEST_SCRIPT_MODE:STRING=${MITK_CTEST_SCRIPT_MODE} -DMITK_SUPERBUILD_BINARY_DIR:PATH=${MITK_BINARY_DIR} -DMITK_MODULES_TO_BUILD:INTERNAL=${MITK_MODULES_TO_BUILD} -DMITK_WHITELIST:STRING=${MITK_WHITELIST} -DMITK_WHITELISTS_EXTERNAL_PATH:STRING=${MITK_WHITELISTS_EXTERNAL_PATH} -DMITK_WHITELISTS_INTERNAL_PATH:STRING=${MITK_WHITELISTS_INTERNAL_PATH} -DMITK_EXTENSION_DIRS:STRING=${MITK_EXTENSION_DIRS} -DMITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES:STRING=${MITK_ACCESSBYITK_INTEGRAL_PIXEL_TYPES} -DMITK_ACCESSBYITK_FLOATING_PIXEL_TYPES:STRING=${MITK_ACCESSBYITK_FLOATING_PIXEL_TYPES} -DMITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES:STRING=${MITK_ACCESSBYITK_COMPOSITE_PIXEL_TYPES} -DMITK_ACCESSBYITK_VECTOR_PIXEL_TYPES:STRING=${MITK_ACCESSBYITK_VECTOR_PIXEL_TYPES} -DMITK_ACCESSBYITK_DIMENSIONS:STRING=${MITK_ACCESSBYITK_DIMENSIONS} # --------------- External project options --------------- -DMITK_DATA_DIR:PATH=${MITK_DATA_DIR} -DMITK_EXTERNAL_PROJECT_PREFIX:PATH=${ep_prefix} -DCppMicroServices_DIR:PATH=${CppMicroServices_DIR} -DDCMTK_CMAKE_DEBUG_POSTFIX:STRING=${DCMTK_CMAKE_DEBUG_POSTFIX} -DBOOST_ROOT:PATH=${BOOST_ROOT} -DBOOST_LIBRARYDIR:PATH=${BOOST_LIBRARYDIR} -DMITK_USE_Boost_LIBRARIES:STRING=${MITK_USE_Boost_LIBRARIES} -DQt5_DIR:PATH=${Qt5_DIR} CMAKE_ARGS ${mitk_initial_cache_arg} ${MAC_OSX_ARCHITECTURE_ARGS} ${mitk_superbuild_ep_args} SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR} BINARY_DIR ${CMAKE_BINARY_DIR}/MITK-build BUILD_COMMAND "" INSTALL_COMMAND "" DEPENDS MITK-Utilities ) mitkFunctionInstallExternalCMakeProject(${proj}) #----------------------------------------------------------------------------- # MITK #----------------------------------------------------------------------------- if(CMAKE_GENERATOR MATCHES ".*Makefiles.*") set(mitk_build_cmd "$(MAKE)") else() set(mitk_build_cmd ${CMAKE_COMMAND} --build ${CMAKE_CURRENT_BINARY_DIR}/MITK-build --config ${CMAKE_CFG_INTDIR}) endif() if(NOT DEFINED SUPERBUILD_EXCLUDE_MITKBUILD_TARGET OR NOT SUPERBUILD_EXCLUDE_MITKBUILD_TARGET) set(MITKBUILD_TARGET_ALL_OPTION "ALL") else() set(MITKBUILD_TARGET_ALL_OPTION "") endif() add_custom_target(MITK-build ${MITKBUILD_TARGET_ALL_OPTION} COMMAND ${mitk_build_cmd} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/MITK-build DEPENDS MITK-Configure ) #----------------------------------------------------------------------------- # Custom target allowing to drive the build of the MITK project itself #----------------------------------------------------------------------------- add_custom_target(MITK COMMAND ${mitk_build_cmd} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/MITK-build )